Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Support serializing WebAssembly.Module objects #12140

Merged
merged 6 commits into from
Sep 29, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions cli/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,7 @@ fn create_web_worker_callback(ps: ProcState) -> Arc<CreateWebWorkerCb> {
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(),
};

Expand Down Expand Up @@ -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(),
};

Expand Down
4 changes: 4 additions & 0 deletions cli/proc_state.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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 {
Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -225,6 +228,7 @@ impl ProcState {
blob_store,
broadcast_channel,
shared_array_buffer_store,
compiled_wasm_module_store,
})))
}

Expand Down
1 change: 1 addition & 0 deletions cli/standalone.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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 =
Expand Down
33 changes: 33 additions & 0 deletions core/bindings.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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>(
&mut self,
scope: &mut v8::HandleScope<'s>,
Expand Down Expand Up @@ -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>(
&mut self,
scope: &mut v8::HandleScope<'s>,
Expand Down
1 change: 1 addition & 0 deletions core/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
69 changes: 46 additions & 23 deletions core/runtime.rs
Original file line number Diff line number Diff line change
Expand Up @@ -99,36 +99,48 @@ struct ModEvaluate {
sender: oneshot::Sender<Result<(), AnyError>>,
}

#[derive(Default, Clone)]
pub struct SharedArrayBufferStore(Arc<Mutex<SharedArrayBufferStoreInner>>);
pub struct CrossIsolateStore<T>(Arc<Mutex<CrossIsolateStoreInner<T>>>);

#[derive(Default)]
pub struct SharedArrayBufferStoreInner {
buffers: HashMap<u32, v8::SharedRef<v8::BackingStore>>,
struct CrossIsolateStoreInner<T> {
map: HashMap<u32, T>,
last_id: u32,
}

impl SharedArrayBufferStore {
pub(crate) fn insert(
&self,
backing_store: v8::SharedRef<v8::BackingStore>,
) -> 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<T> CrossIsolateStore<T> {
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<v8::SharedRef<v8::BackingStore>> {
let mut buffers = self.0.lock().unwrap();
buffers.buffers.remove(&id)
pub(crate) fn take(&self, id: u32) -> Option<T> {
let mut store = self.0.lock().unwrap();
store.map.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
/// embedder slots.
pub(crate) struct JsRuntimeState {
Expand All @@ -149,6 +161,7 @@ pub(crate) struct JsRuntimeState {
pub(crate) have_unpolled_ops: bool,
pub(crate) op_state: Rc<RefCell<OpState>>,
pub(crate) shared_array_buffer_store: Option<SharedArrayBufferStore>,
pub(crate) compiled_wasm_module_store: Option<CompiledWasmModuleStore>,
waker: AtomicWaker,
}

Expand Down Expand Up @@ -238,11 +251,20 @@ pub struct RuntimeOptions {
/// (which it only does once), otherwise it's silenty dropped.
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
/// 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<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 {
Expand Down Expand Up @@ -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(),
Expand Down
1 change: 1 addition & 0 deletions runtime/examples/hello_runtime.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
};

Expand Down
3 changes: 3 additions & 0 deletions runtime/web_worker.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -285,6 +286,7 @@ pub struct WebWorkerOptions {
pub blob_store: BlobStore,
pub broadcast_channel: InMemoryBroadcastChannel,
pub shared_array_buffer_store: Option<SharedArrayBufferStore>,
pub compiled_wasm_module_store: Option<CompiledWasmModuleStore>,
pub cpu_count: usize,
}

Expand Down Expand Up @@ -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()
});
Expand Down
4 changes: 4 additions & 0 deletions runtime/worker.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -73,6 +74,7 @@ pub struct WorkerOptions {
pub blob_store: BlobStore,
pub broadcast_channel: InMemoryBroadcastChannel,
pub shared_array_buffer_store: Option<SharedArrayBufferStore>,
pub compiled_wasm_module_store: Option<CompiledWasmModuleStore>,
pub cpu_count: usize,
}

Expand Down Expand Up @@ -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()
});
Expand Down Expand Up @@ -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,
};

Expand Down
2 changes: 1 addition & 1 deletion tools/wpt/expectation.json
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down