From ca66978a5aadddf7895b49b44076c574e7e6a0b0 Mon Sep 17 00:00:00 2001 From: Divy Srivastava Date: Sun, 27 Nov 2022 05:54:28 -0800 Subject: feat(ops): fast calls for Wasm (#16776) This PR introduces Wasm ops. These calls are optimized for entry from Wasm land. The `#[op(wasm)]` attribute is opt-in. Last parameter `Option<&mut [u8]>` is the memory slice of the Wasm module *when entered from a Fast API call*. Otherwise, the user is expected to implement logic to obtain the memory if `None` ```rust #[op(wasm)] pub fn op_args_get( offset: i32, buffer_offset: i32, memory: Option<&mut [u8]>, ) { // ... } ``` --- ops/optimizer.rs | 54 +++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 53 insertions(+), 1 deletion(-) (limited to 'ops/optimizer.rs') diff --git a/ops/optimizer.rs b/ops/optimizer.rs index 8fa2ab1f5..d25857032 100644 --- a/ops/optimizer.rs +++ b/ops/optimizer.rs @@ -26,6 +26,7 @@ enum TransformKind { SliceU32(bool), SliceU8(bool), PtrU8, + WasmMemory, } impl Transform { @@ -50,6 +51,13 @@ impl Transform { } } + fn wasm_memory(index: usize) -> Self { + Transform { + kind: TransformKind::WasmMemory, + index, + } + } + fn u8_ptr(index: usize) -> Self { Transform { kind: TransformKind::PtrU8, @@ -124,6 +132,16 @@ impl Transform { }; }) } + TransformKind::WasmMemory => { + // Note: `ty` is correctly set to __opts by the fast call tier. + q!(Vars { var: &ident, core }, { + let var = unsafe { + &*(__opts.wasm_memory + as *const core::v8::fast_api::FastApiTypedArray) + } + .get_storage_if_aligned(); + }) + } // *const u8 TransformKind::PtrU8 => { *ty = @@ -201,6 +219,8 @@ pub(crate) struct Optimizer { // Do we depend on FastApiCallbackOptions? pub(crate) needs_fast_callback_option: bool, + pub(crate) has_wasm_memory: bool, + pub(crate) fast_result: Option, pub(crate) fast_parameters: Vec, @@ -262,6 +282,9 @@ impl Optimizer { self.is_async = op.is_async; self.fast_compatible = true; + // Just assume for now. We will validate later. + self.has_wasm_memory = op.attrs.is_wasm; + let sig = &op.item.sig; // Analyze return type @@ -419,7 +442,32 @@ impl Optimizer { TypeReference { elem, .. }, ))) = args.last() { - if let Type::Path(TypePath { + if self.has_wasm_memory { + // -> Option<&mut [u8]> + if let Type::Slice(TypeSlice { elem, .. }) = &**elem { + if let Type::Path(TypePath { + path: Path { segments, .. }, + .. + }) = &**elem + { + let segment = single_segment(segments)?; + + match segment { + // Is `T` a u8? + PathSegment { ident, .. } if ident == "u8" => { + self.needs_fast_callback_option = true; + assert!(self + .transforms + .insert(index, Transform::wasm_memory(index)) + .is_none()); + } + _ => { + return Err(BailoutReason::FastUnsupportedParamType) + } + } + } + } + } else if let Type::Path(TypePath { path: Path { segments, .. }, .. }) = &**elem @@ -654,6 +702,10 @@ mod tests { .expect("Failed to read expected file"); let mut attrs = Attributes::default(); + if source.contains("// @test-attr:wasm") { + attrs.must_be_fast = true; + attrs.is_wasm = true; + } if source.contains("// @test-attr:fast") { attrs.must_be_fast = true; } -- cgit v1.2.3