1
0
Fork 0
mirror of https://github.com/denoland/deno.git synced 2025-01-21 21:50:00 -05:00

feat: support serializing WebAssembly.Module objects (#12140)

This commit is contained in:
Andreu Botella 2021-09-29 10:47:24 +02:00 committed by GitHub
parent 5b526e5d17
commit cdb252af0a
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
10 changed files with 96 additions and 24 deletions

View file

@ -134,6 +134,7 @@ fn create_web_worker_callback(ps: ProcState) -> Arc<CreateWebWorkerCb> {
blob_store: ps.blob_store.clone(), blob_store: ps.blob_store.clone(),
broadcast_channel: ps.broadcast_channel.clone(), broadcast_channel: ps.broadcast_channel.clone(),
shared_array_buffer_store: Some(ps.shared_array_buffer_store.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(), cpu_count: num_cpus::get(),
}; };
@ -222,6 +223,7 @@ pub fn create_main_worker(
blob_store: ps.blob_store.clone(), blob_store: ps.blob_store.clone(),
broadcast_channel: ps.broadcast_channel.clone(), broadcast_channel: ps.broadcast_channel.clone(),
shared_array_buffer_store: Some(ps.shared_array_buffer_store.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(), cpu_count: num_cpus::get(),
}; };

View file

@ -23,6 +23,7 @@ use deno_core::error::Context;
use deno_core::parking_lot::Mutex; use deno_core::parking_lot::Mutex;
use deno_core::resolve_url; use deno_core::resolve_url;
use deno_core::url::Url; use deno_core::url::Url;
use deno_core::CompiledWasmModuleStore;
use deno_core::ModuleSource; use deno_core::ModuleSource;
use deno_core::ModuleSpecifier; use deno_core::ModuleSpecifier;
use deno_core::SharedArrayBufferStore; use deno_core::SharedArrayBufferStore;
@ -66,6 +67,7 @@ pub struct Inner {
pub blob_store: BlobStore, pub blob_store: BlobStore,
pub broadcast_channel: InMemoryBroadcastChannel, pub broadcast_channel: InMemoryBroadcastChannel,
pub shared_array_buffer_store: SharedArrayBufferStore, pub shared_array_buffer_store: SharedArrayBufferStore,
pub compiled_wasm_module_store: CompiledWasmModuleStore,
} }
impl Deref for ProcState { impl Deref for ProcState {
@ -155,6 +157,7 @@ impl ProcState {
let blob_store = BlobStore::default(); let blob_store = BlobStore::default();
let broadcast_channel = InMemoryBroadcastChannel::default(); let broadcast_channel = InMemoryBroadcastChannel::default();
let shared_array_buffer_store = SharedArrayBufferStore::default(); let shared_array_buffer_store = SharedArrayBufferStore::default();
let compiled_wasm_module_store = CompiledWasmModuleStore::default();
let file_fetcher = FileFetcher::new( let file_fetcher = FileFetcher::new(
http_cache, http_cache,
@ -225,6 +228,7 @@ impl ProcState {
blob_store, blob_store,
broadcast_channel, broadcast_channel,
shared_array_buffer_store, shared_array_buffer_store,
compiled_wasm_module_store,
}))) })))
} }

View file

@ -252,6 +252,7 @@ pub async fn run(
blob_store, blob_store,
broadcast_channel, broadcast_channel,
shared_array_buffer_store: None, shared_array_buffer_store: None,
compiled_wasm_module_store: None,
cpu_count: num_cpus::get(), cpu_count: num_cpus::get(),
}; };
let mut worker = let mut worker =

View file

@ -665,6 +665,23 @@ impl<'a> v8::ValueSerializerImpl for SerializeDeserialize<'a> {
} }
} }
fn get_wasm_module_transfer_id(
&mut self,
scope: &mut HandleScope<'_>,
module: Local<v8::WasmModuleObject>,
) -> Option<u32> {
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>( fn write_host_object<'s>(
&mut self, &mut self,
scope: &mut v8::HandleScope<'s>, 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<Local<'s, v8::WasmModuleObject>> {
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>( fn read_host_object<'s>(
&mut self, &mut self,
scope: &mut v8::HandleScope<'s>, scope: &mut v8::HandleScope<'s>,

View file

@ -58,6 +58,7 @@ pub use crate::modules::ModuleLoader;
pub use crate::modules::ModuleSource; pub use crate::modules::ModuleSource;
pub use crate::modules::ModuleSourceFuture; pub use crate::modules::ModuleSourceFuture;
pub use crate::modules::NoopModuleLoader; pub use crate::modules::NoopModuleLoader;
pub use crate::runtime::CompiledWasmModuleStore;
pub use crate::runtime::SharedArrayBufferStore; pub use crate::runtime::SharedArrayBufferStore;
// TODO(bartlomieju): this struct should be implementation // TODO(bartlomieju): this struct should be implementation
// detail nad not be public // detail nad not be public

View file

@ -99,36 +99,48 @@ struct ModEvaluate {
sender: oneshot::Sender<Result<(), AnyError>>, sender: oneshot::Sender<Result<(), AnyError>>,
} }
#[derive(Default, Clone)] pub struct CrossIsolateStore<T>(Arc<Mutex<CrossIsolateStoreInner<T>>>);
pub struct SharedArrayBufferStore(Arc<Mutex<SharedArrayBufferStoreInner>>);
#[derive(Default)] struct CrossIsolateStoreInner<T> {
pub struct SharedArrayBufferStoreInner { map: HashMap<u32, T>,
buffers: HashMap<u32, v8::SharedRef<v8::BackingStore>>,
last_id: u32, last_id: u32,
} }
impl SharedArrayBufferStore { impl<T> CrossIsolateStore<T> {
pub(crate) fn insert( pub(crate) fn insert(&self, value: T) -> u32 {
&self, let mut store = self.0.lock().unwrap();
backing_store: v8::SharedRef<v8::BackingStore>, let last_id = store.last_id;
) -> u32 { store.map.insert(last_id, value);
let mut buffers = self.0.lock().unwrap(); store.last_id += 1;
let last_id = buffers.last_id;
buffers.buffers.insert(last_id, backing_store);
buffers.last_id += 1;
last_id last_id
} }
pub(crate) fn take( pub(crate) fn take(&self, id: u32) -> Option<T> {
&self, let mut store = self.0.lock().unwrap();
id: u32, store.map.remove(&id)
) -> Option<v8::SharedRef<v8::BackingStore>> {
let mut buffers = self.0.lock().unwrap();
buffers.buffers.remove(&id)
} }
} }
impl<T> Default for CrossIsolateStore<T> {
fn default() -> Self {
CrossIsolateStore(Arc::new(Mutex::new(CrossIsolateStoreInner {
map: Default::default(),
last_id: 0,
})))
}
}
impl<T> Clone for CrossIsolateStore<T> {
fn clone(&self) -> Self {
Self(self.0.clone())
}
}
pub type SharedArrayBufferStore =
CrossIsolateStore<v8::SharedRef<v8::BackingStore>>;
pub type CompiledWasmModuleStore = CrossIsolateStore<v8::CompiledWasmModule>;
/// Internal state for JsRuntime which is stored in one of v8::Isolate's /// Internal state for JsRuntime which is stored in one of v8::Isolate's
/// embedder slots. /// embedder slots.
pub(crate) struct JsRuntimeState { pub(crate) struct JsRuntimeState {
@ -149,6 +161,7 @@ pub(crate) struct JsRuntimeState {
pub(crate) have_unpolled_ops: bool, pub(crate) have_unpolled_ops: bool,
pub(crate) op_state: Rc<RefCell<OpState>>, pub(crate) op_state: Rc<RefCell<OpState>>,
pub(crate) shared_array_buffer_store: Option<SharedArrayBufferStore>, pub(crate) shared_array_buffer_store: Option<SharedArrayBufferStore>,
pub(crate) compiled_wasm_module_store: Option<CompiledWasmModuleStore>,
waker: AtomicWaker, waker: AtomicWaker,
} }
@ -238,11 +251,20 @@ pub struct RuntimeOptions {
/// (which it only does once), otherwise it's silenty dropped. /// (which it only does once), otherwise it's silenty dropped.
pub v8_platform: Option<v8::SharedRef<v8::Platform>>, pub v8_platform: Option<v8::SharedRef<v8::Platform>>,
/// 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 /// If multiple isolates should have the possibility of sharing
/// SharedArrayBuffers, they should use the same SharedArrayBufferStore. If no /// SharedArrayBuffers, they should use the same [SharedArrayBufferStore]. If
/// SharedArrayBufferStore is specified, SharedArrayBuffer can not be serialized. /// no [SharedArrayBufferStore] is specified, SharedArrayBuffer can not be
/// serialized.
pub shared_array_buffer_store: Option<SharedArrayBufferStore>, pub shared_array_buffer_store: Option<SharedArrayBufferStore>,
/// 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<CompiledWasmModuleStore>,
} }
impl JsRuntime { impl JsRuntime {
@ -334,6 +356,7 @@ impl JsRuntime {
pending_ops: FuturesUnordered::new(), pending_ops: FuturesUnordered::new(),
pending_unref_ops: FuturesUnordered::new(), pending_unref_ops: FuturesUnordered::new(),
shared_array_buffer_store: options.shared_array_buffer_store, shared_array_buffer_store: options.shared_array_buffer_store,
compiled_wasm_module_store: options.compiled_wasm_module_store,
op_state: op_state.clone(), op_state: op_state.clone(),
have_unpolled_ops: false, have_unpolled_ops: false,
waker: AtomicWaker::new(), waker: AtomicWaker::new(),

View file

@ -46,6 +46,7 @@ async fn main() -> Result<(), AnyError> {
blob_store: BlobStore::default(), blob_store: BlobStore::default(),
broadcast_channel: InMemoryBroadcastChannel::default(), broadcast_channel: InMemoryBroadcastChannel::default(),
shared_array_buffer_store: None, shared_array_buffer_store: None,
compiled_wasm_module_store: None,
cpu_count: 1, cpu_count: 1,
}; };

View file

@ -19,6 +19,7 @@ use deno_core::serde_json;
use deno_core::serde_json::json; use deno_core::serde_json::json;
use deno_core::v8; use deno_core::v8;
use deno_core::CancelHandle; use deno_core::CancelHandle;
use deno_core::CompiledWasmModuleStore;
use deno_core::Extension; use deno_core::Extension;
use deno_core::GetErrorClassFn; use deno_core::GetErrorClassFn;
use deno_core::JsErrorCreateFn; use deno_core::JsErrorCreateFn;
@ -285,6 +286,7 @@ pub struct WebWorkerOptions {
pub blob_store: BlobStore, pub blob_store: BlobStore,
pub broadcast_channel: InMemoryBroadcastChannel, pub broadcast_channel: InMemoryBroadcastChannel,
pub shared_array_buffer_store: Option<SharedArrayBufferStore>, pub shared_array_buffer_store: Option<SharedArrayBufferStore>,
pub compiled_wasm_module_store: Option<CompiledWasmModuleStore>,
pub cpu_count: usize, pub cpu_count: usize,
} }
@ -384,6 +386,7 @@ impl WebWorker {
js_error_create_fn: options.js_error_create_fn.clone(), js_error_create_fn: options.js_error_create_fn.clone(),
get_error_class_fn: options.get_error_class_fn, get_error_class_fn: options.get_error_class_fn,
shared_array_buffer_store: options.shared_array_buffer_store.clone(), shared_array_buffer_store: options.shared_array_buffer_store.clone(),
compiled_wasm_module_store: options.compiled_wasm_module_store.clone(),
extensions, extensions,
..Default::default() ..Default::default()
}); });

View file

@ -12,6 +12,7 @@ use deno_core::located_script_name;
use deno_core::serde_json; use deno_core::serde_json;
use deno_core::serde_json::json; use deno_core::serde_json::json;
use deno_core::url::Url; use deno_core::url::Url;
use deno_core::CompiledWasmModuleStore;
use deno_core::Extension; use deno_core::Extension;
use deno_core::GetErrorClassFn; use deno_core::GetErrorClassFn;
use deno_core::JsErrorCreateFn; use deno_core::JsErrorCreateFn;
@ -73,6 +74,7 @@ pub struct WorkerOptions {
pub blob_store: BlobStore, pub blob_store: BlobStore,
pub broadcast_channel: InMemoryBroadcastChannel, pub broadcast_channel: InMemoryBroadcastChannel,
pub shared_array_buffer_store: Option<SharedArrayBufferStore>, pub shared_array_buffer_store: Option<SharedArrayBufferStore>,
pub compiled_wasm_module_store: Option<CompiledWasmModuleStore>,
pub cpu_count: usize, pub cpu_count: usize,
} }
@ -156,6 +158,7 @@ impl MainWorker {
js_error_create_fn: options.js_error_create_fn.clone(), js_error_create_fn: options.js_error_create_fn.clone(),
get_error_class_fn: options.get_error_class_fn, get_error_class_fn: options.get_error_class_fn,
shared_array_buffer_store: options.shared_array_buffer_store.clone(), shared_array_buffer_store: options.shared_array_buffer_store.clone(),
compiled_wasm_module_store: options.compiled_wasm_module_store.clone(),
extensions, extensions,
..Default::default() ..Default::default()
}); });
@ -345,6 +348,7 @@ mod tests {
blob_store: BlobStore::default(), blob_store: BlobStore::default(),
broadcast_channel: InMemoryBroadcastChannel::default(), broadcast_channel: InMemoryBroadcastChannel::default(),
shared_array_buffer_store: None, shared_array_buffer_store: None,
compiled_wasm_module_store: None,
cpu_count: 1, cpu_count: 1,
}; };

View file

@ -13573,7 +13573,7 @@
"module": { "module": {
"serialization-via-idb.any.html": false, "serialization-via-idb.any.html": false,
"serialization-via-notifications-api.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": { "arraybuffer": {
"transfer.window.html": false "transfer.window.html": false