From cdb252af0aa7251f339a77638b32af89f112d13d Mon Sep 17 00:00:00 2001 From: Andreu Botella Date: Wed, 29 Sep 2021 10:47:24 +0200 Subject: [PATCH] feat: support serializing `WebAssembly.Module` objects (#12140) --- cli/main.rs | 2 + cli/proc_state.rs | 4 ++ cli/standalone.rs | 1 + core/bindings.rs | 33 +++++++++++++++ core/lib.rs | 1 + core/runtime.rs | 69 ++++++++++++++++++++----------- runtime/examples/hello_runtime.rs | 1 + runtime/web_worker.rs | 3 ++ runtime/worker.rs | 4 ++ tools/wpt/expectation.json | 2 +- 10 files changed, 96 insertions(+), 24 deletions(-) diff --git a/cli/main.rs b/cli/main.rs index a217d2cf47..ba16ea590d 100644 --- a/cli/main.rs +++ b/cli/main.rs @@ -134,6 +134,7 @@ fn create_web_worker_callback(ps: ProcState) -> Arc { blob_store: ps.blob_store.clone(), broadcast_channel: ps.broadcast_channel.clone(), shared_array_buffer_store: Some(ps.shared_array_buffer_store.clone()), + compiled_wasm_module_store: Some(ps.compiled_wasm_module_store.clone()), cpu_count: num_cpus::get(), }; @@ -222,6 +223,7 @@ pub fn create_main_worker( blob_store: ps.blob_store.clone(), broadcast_channel: ps.broadcast_channel.clone(), shared_array_buffer_store: Some(ps.shared_array_buffer_store.clone()), + compiled_wasm_module_store: Some(ps.compiled_wasm_module_store.clone()), cpu_count: num_cpus::get(), }; diff --git a/cli/proc_state.rs b/cli/proc_state.rs index e6bc5f9970..2c61ba51f6 100644 --- a/cli/proc_state.rs +++ b/cli/proc_state.rs @@ -23,6 +23,7 @@ use deno_core::error::Context; use deno_core::parking_lot::Mutex; use deno_core::resolve_url; use deno_core::url::Url; +use deno_core::CompiledWasmModuleStore; use deno_core::ModuleSource; use deno_core::ModuleSpecifier; use deno_core::SharedArrayBufferStore; @@ -66,6 +67,7 @@ pub struct Inner { pub blob_store: BlobStore, pub broadcast_channel: InMemoryBroadcastChannel, pub shared_array_buffer_store: SharedArrayBufferStore, + pub compiled_wasm_module_store: CompiledWasmModuleStore, } impl Deref for ProcState { @@ -155,6 +157,7 @@ impl ProcState { let blob_store = BlobStore::default(); let broadcast_channel = InMemoryBroadcastChannel::default(); let shared_array_buffer_store = SharedArrayBufferStore::default(); + let compiled_wasm_module_store = CompiledWasmModuleStore::default(); let file_fetcher = FileFetcher::new( http_cache, @@ -225,6 +228,7 @@ impl ProcState { blob_store, broadcast_channel, shared_array_buffer_store, + compiled_wasm_module_store, }))) } diff --git a/cli/standalone.rs b/cli/standalone.rs index 3db2981e41..914eeaddf1 100644 --- a/cli/standalone.rs +++ b/cli/standalone.rs @@ -252,6 +252,7 @@ pub async fn run( blob_store, broadcast_channel, shared_array_buffer_store: None, + compiled_wasm_module_store: None, cpu_count: num_cpus::get(), }; let mut worker = diff --git a/core/bindings.rs b/core/bindings.rs index 5d9b0bdb80..3bff22e50c 100644 --- a/core/bindings.rs +++ b/core/bindings.rs @@ -665,6 +665,23 @@ impl<'a> v8::ValueSerializerImpl for SerializeDeserialize<'a> { } } + fn get_wasm_module_transfer_id( + &mut self, + scope: &mut HandleScope<'_>, + module: Local, + ) -> Option { + let state_rc = JsRuntime::state(scope); + let state = state_rc.borrow_mut(); + if let Some(compiled_wasm_module_store) = &state.compiled_wasm_module_store + { + let compiled_wasm_module = module.get_compiled_module(); + let id = compiled_wasm_module_store.insert(compiled_wasm_module); + Some(id) + } else { + None + } + } + fn write_host_object<'s>( &mut self, scope: &mut v8::HandleScope<'s>, @@ -704,6 +721,22 @@ impl<'a> v8::ValueDeserializerImpl for SerializeDeserialize<'a> { } } + fn get_wasm_module_from_id<'s>( + &mut self, + scope: &mut HandleScope<'s>, + clone_id: u32, + ) -> Option> { + let state_rc = JsRuntime::state(scope); + let state = state_rc.borrow_mut(); + if let Some(compiled_wasm_module_store) = &state.compiled_wasm_module_store + { + let compiled_module = compiled_wasm_module_store.take(clone_id)?; + v8::WasmModuleObject::from_compiled_module(scope, &compiled_module) + } else { + None + } + } + fn read_host_object<'s>( &mut self, scope: &mut v8::HandleScope<'s>, diff --git a/core/lib.rs b/core/lib.rs index 76b3a4f378..22509c4628 100644 --- a/core/lib.rs +++ b/core/lib.rs @@ -58,6 +58,7 @@ pub use crate::modules::ModuleLoader; pub use crate::modules::ModuleSource; pub use crate::modules::ModuleSourceFuture; pub use crate::modules::NoopModuleLoader; +pub use crate::runtime::CompiledWasmModuleStore; pub use crate::runtime::SharedArrayBufferStore; // TODO(bartlomieju): this struct should be implementation // detail nad not be public diff --git a/core/runtime.rs b/core/runtime.rs index ddbfea0c17..9a60a65eda 100644 --- a/core/runtime.rs +++ b/core/runtime.rs @@ -99,36 +99,48 @@ struct ModEvaluate { sender: oneshot::Sender>, } -#[derive(Default, Clone)] -pub struct SharedArrayBufferStore(Arc>); +pub struct CrossIsolateStore(Arc>>); -#[derive(Default)] -pub struct SharedArrayBufferStoreInner { - buffers: HashMap>, +struct CrossIsolateStoreInner { + map: HashMap, last_id: u32, } -impl SharedArrayBufferStore { - pub(crate) fn insert( - &self, - backing_store: v8::SharedRef, - ) -> u32 { - let mut buffers = self.0.lock().unwrap(); - let last_id = buffers.last_id; - buffers.buffers.insert(last_id, backing_store); - buffers.last_id += 1; +impl CrossIsolateStore { + pub(crate) fn insert(&self, value: T) -> u32 { + let mut store = self.0.lock().unwrap(); + let last_id = store.last_id; + store.map.insert(last_id, value); + store.last_id += 1; last_id } - pub(crate) fn take( - &self, - id: u32, - ) -> Option> { - let mut buffers = self.0.lock().unwrap(); - buffers.buffers.remove(&id) + pub(crate) fn take(&self, id: u32) -> Option { + let mut store = self.0.lock().unwrap(); + store.map.remove(&id) } } +impl Default for CrossIsolateStore { + fn default() -> Self { + CrossIsolateStore(Arc::new(Mutex::new(CrossIsolateStoreInner { + map: Default::default(), + last_id: 0, + }))) + } +} + +impl Clone for CrossIsolateStore { + fn clone(&self) -> Self { + Self(self.0.clone()) + } +} + +pub type SharedArrayBufferStore = + CrossIsolateStore>; + +pub type CompiledWasmModuleStore = CrossIsolateStore; + /// Internal state for JsRuntime which is stored in one of v8::Isolate's /// embedder slots. pub(crate) struct JsRuntimeState { @@ -149,6 +161,7 @@ pub(crate) struct JsRuntimeState { pub(crate) have_unpolled_ops: bool, pub(crate) op_state: Rc>, pub(crate) shared_array_buffer_store: Option, + pub(crate) compiled_wasm_module_store: Option, waker: AtomicWaker, } @@ -238,11 +251,20 @@ pub struct RuntimeOptions { /// (which it only does once), otherwise it's silenty dropped. pub v8_platform: Option>, - /// The buffer to use for transferring SharedArrayBuffers between isolates. + /// The store to use for transferring SharedArrayBuffers between isolates. /// If multiple isolates should have the possibility of sharing - /// SharedArrayBuffers, they should use the same SharedArrayBufferStore. If no - /// SharedArrayBufferStore is specified, SharedArrayBuffer can not be serialized. + /// SharedArrayBuffers, they should use the same [SharedArrayBufferStore]. If + /// no [SharedArrayBufferStore] is specified, SharedArrayBuffer can not be + /// serialized. pub shared_array_buffer_store: Option, + + /// The store to use for transferring `WebAssembly.Module` objects between + /// isolates. + /// If multiple isolates should have the possibility of sharing + /// `WebAssembly.Module` objects, they should use the same + /// [CompiledWasmModuleStore]. If no [CompiledWasmModuleStore] is specified, + /// `WebAssembly.Module` objects cannot be serialized. + pub compiled_wasm_module_store: Option, } impl JsRuntime { @@ -334,6 +356,7 @@ impl JsRuntime { pending_ops: FuturesUnordered::new(), pending_unref_ops: FuturesUnordered::new(), shared_array_buffer_store: options.shared_array_buffer_store, + compiled_wasm_module_store: options.compiled_wasm_module_store, op_state: op_state.clone(), have_unpolled_ops: false, waker: AtomicWaker::new(), diff --git a/runtime/examples/hello_runtime.rs b/runtime/examples/hello_runtime.rs index db63946941..eb6b5a5917 100644 --- a/runtime/examples/hello_runtime.rs +++ b/runtime/examples/hello_runtime.rs @@ -46,6 +46,7 @@ async fn main() -> Result<(), AnyError> { blob_store: BlobStore::default(), broadcast_channel: InMemoryBroadcastChannel::default(), shared_array_buffer_store: None, + compiled_wasm_module_store: None, cpu_count: 1, }; diff --git a/runtime/web_worker.rs b/runtime/web_worker.rs index 7dd4082923..98a8ae0769 100644 --- a/runtime/web_worker.rs +++ b/runtime/web_worker.rs @@ -19,6 +19,7 @@ use deno_core::serde_json; use deno_core::serde_json::json; use deno_core::v8; use deno_core::CancelHandle; +use deno_core::CompiledWasmModuleStore; use deno_core::Extension; use deno_core::GetErrorClassFn; use deno_core::JsErrorCreateFn; @@ -285,6 +286,7 @@ pub struct WebWorkerOptions { pub blob_store: BlobStore, pub broadcast_channel: InMemoryBroadcastChannel, pub shared_array_buffer_store: Option, + pub compiled_wasm_module_store: Option, pub cpu_count: usize, } @@ -384,6 +386,7 @@ impl WebWorker { js_error_create_fn: options.js_error_create_fn.clone(), get_error_class_fn: options.get_error_class_fn, shared_array_buffer_store: options.shared_array_buffer_store.clone(), + compiled_wasm_module_store: options.compiled_wasm_module_store.clone(), extensions, ..Default::default() }); diff --git a/runtime/worker.rs b/runtime/worker.rs index a689a32f03..709763c7d0 100644 --- a/runtime/worker.rs +++ b/runtime/worker.rs @@ -12,6 +12,7 @@ use deno_core::located_script_name; use deno_core::serde_json; use deno_core::serde_json::json; use deno_core::url::Url; +use deno_core::CompiledWasmModuleStore; use deno_core::Extension; use deno_core::GetErrorClassFn; use deno_core::JsErrorCreateFn; @@ -73,6 +74,7 @@ pub struct WorkerOptions { pub blob_store: BlobStore, pub broadcast_channel: InMemoryBroadcastChannel, pub shared_array_buffer_store: Option, + pub compiled_wasm_module_store: Option, pub cpu_count: usize, } @@ -156,6 +158,7 @@ impl MainWorker { js_error_create_fn: options.js_error_create_fn.clone(), get_error_class_fn: options.get_error_class_fn, shared_array_buffer_store: options.shared_array_buffer_store.clone(), + compiled_wasm_module_store: options.compiled_wasm_module_store.clone(), extensions, ..Default::default() }); @@ -345,6 +348,7 @@ mod tests { blob_store: BlobStore::default(), broadcast_channel: InMemoryBroadcastChannel::default(), shared_array_buffer_store: None, + compiled_wasm_module_store: None, cpu_count: 1, }; diff --git a/tools/wpt/expectation.json b/tools/wpt/expectation.json index ceaa0cc7bb..c7879ff825 100644 --- a/tools/wpt/expectation.json +++ b/tools/wpt/expectation.json @@ -13573,7 +13573,7 @@ "module": { "serialization-via-idb.any.html": false, "serialization-via-notifications-api.any.html": false, - "nested-worker-success.any.worker.html": false + "nested-worker-success.any.worker.html": true }, "arraybuffer": { "transfer.window.html": false