diff options
author | Divy Srivastava <dj.srivastava23@gmail.com> | 2022-11-27 05:54:28 -0800 |
---|---|---|
committer | GitHub <noreply@github.com> | 2022-11-27 19:24:28 +0530 |
commit | ca66978a5aadddf7895b49b44076c574e7e6a0b0 (patch) | |
tree | 65d93f524bc5fea23cef4e75b02de275833158e1 /core/examples | |
parent | 9ffc6acdbb3326dde74c803332547b0ae33e483a (diff) |
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]>,
) {
// ...
}
```
Diffstat (limited to 'core/examples')
-rw-r--r-- | core/examples/wasm.js | 28 | ||||
-rw-r--r-- | core/examples/wasm.rs | 67 | ||||
-rw-r--r-- | core/examples/wasm.ts | 7 |
3 files changed, 102 insertions, 0 deletions
diff --git a/core/examples/wasm.js b/core/examples/wasm.js new file mode 100644 index 000000000..69e475639 --- /dev/null +++ b/core/examples/wasm.js @@ -0,0 +1,28 @@ +// Copyright 2018-2022 the Deno authors. All rights reserved. MIT license. + +// asc wasm.ts --exportStart --initialMemory 6400 -O -o wasm.wasm +// deno-fmt-ignore +const bytes = new Uint8Array([ + 0, 97, 115, 109, 1, 0, 0, 0, 1, 4, 1, 96, 0, 0, 2, + 15, 1, 3, 111, 112, 115, 7, 111, 112, 95, 119, 97, 115, 109, 0, + 0, 3, 3, 2, 0, 0, 5, 4, 1, 0, 128, 50, 7, 36, 4, + 7, 111, 112, 95, 119, 97, 115, 109, 0, 0, 4, 99, 97, 108, 108, + 0, 1, 6, 109, 101, 109, 111, 114, 121, 2, 0, 6, 95, 115, 116, + 97, 114, 116, 0, 2, 10, 10, 2, 4, 0, 16, 0, 11, 3, 0, + 1, 11 + ]); + +const { ops } = Deno.core; + +const module = new WebAssembly.Module(bytes); +const instance = new WebAssembly.Instance(module, { ops }); +ops.op_set_wasm_mem(instance.exports.memory); + +instance.exports.call(); + +const memory = instance.exports.memory; +const view = new Uint8Array(memory.buffer); + +if (view[0] !== 69) { + throw new Error("Expected first byte to be 69"); +} diff --git a/core/examples/wasm.rs b/core/examples/wasm.rs new file mode 100644 index 000000000..ef68d8aa4 --- /dev/null +++ b/core/examples/wasm.rs @@ -0,0 +1,67 @@ +// Copyright 2018-2022 the Deno authors. All rights reserved. MIT license. + +use deno_core::op; +use deno_core::Extension; +use deno_core::JsRuntime; +use deno_core::RuntimeOptions; +use std::mem::transmute; +use std::ptr::NonNull; + +// This is a hack to make the `#[op]` macro work with +// deno_core examples. +// You can remove this: + +use deno_core::*; + +struct WasmMemory(NonNull<v8::WasmMemoryObject>); + +fn wasm_memory_unchecked(state: &mut OpState) -> &mut [u8] { + let WasmMemory(global) = state.borrow::<WasmMemory>(); + // SAFETY: `v8::Local` is always non-null pointer; the `HandleScope` is + // already on the stack, but we don't have access to it. + let memory_object = unsafe { + transmute::<NonNull<v8::WasmMemoryObject>, v8::Local<v8::WasmMemoryObject>>( + *global, + ) + }; + let backing_store = memory_object.buffer().get_backing_store(); + let ptr = backing_store.data().unwrap().as_ptr() as *mut u8; + let len = backing_store.byte_length(); + // SAFETY: `ptr` is a valid pointer to `len` bytes. + unsafe { std::slice::from_raw_parts_mut(ptr, len) } +} + +#[op(wasm)] +fn op_wasm(state: &mut OpState, memory: Option<&mut [u8]>) { + let memory = memory.unwrap_or_else(|| wasm_memory_unchecked(state)); + memory[0] = 69; +} + +#[op(v8)] +fn op_set_wasm_mem( + scope: &mut v8::HandleScope, + state: &mut OpState, + memory: serde_v8::Value, +) { + let memory = + v8::Local::<v8::WasmMemoryObject>::try_from(memory.v8_value).unwrap(); + let global = v8::Global::new(scope, memory); + state.put(WasmMemory(global.into_raw())); +} + +fn main() { + // Build a deno_core::Extension providing custom ops + let ext = Extension::builder() + .ops(vec![op_wasm::decl(), op_set_wasm_mem::decl()]) + .build(); + + // Initialize a runtime instance + let mut runtime = JsRuntime::new(RuntimeOptions { + extensions: vec![ext], + ..Default::default() + }); + + runtime + .execute_script("<usage>", include_str!("wasm.js")) + .unwrap(); +} diff --git a/core/examples/wasm.ts b/core/examples/wasm.ts new file mode 100644 index 000000000..cdb9cf78c --- /dev/null +++ b/core/examples/wasm.ts @@ -0,0 +1,7 @@ +// Copyright 2018-2022 the Deno authors. All rights reserved. MIT license. + +export declare function op_wasm(): void; + +export function call(): void { + op_wasm(); +} |