fix(core/runtime): sync_ops_cache if nuked Deno ns (#12302)

Decouple JsRuntime::sync_ops_cache() from the availability of the Deno.* namespace in the global scope

This avoids crashes when calling sync_ops_cache() on a bootstrapped WebWorker who has dropped its Deno.* namespace

It's also just cleaner and more robust ...
This commit is contained in:
Aaron O'Mullan 2021-10-04 11:45:41 +02:00 committed by GitHub
parent 11acdf1ea8
commit 4a1300edde
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23

View file

@ -146,6 +146,7 @@ pub type CompiledWasmModuleStore = CrossIsolateStore<v8::CompiledWasmModule>;
pub(crate) struct JsRuntimeState {
pub global_context: Option<v8::Global<v8::Context>>,
pub(crate) js_recv_cb: Option<v8::Global<v8::Function>>,
pub(crate) js_sync_cb: Option<v8::Global<v8::Function>>,
pub(crate) js_macrotask_cb: Option<v8::Global<v8::Function>>,
pub(crate) js_wasm_streaming_cb: Option<v8::Global<v8::Function>>,
pub(crate) pending_promise_exceptions:
@ -350,6 +351,7 @@ impl JsRuntime {
pending_mod_evaluate: None,
dyn_module_evaluate_idle_counter: 0,
js_recv_cb: None,
js_sync_cb: None,
js_macrotask_cb: None,
js_wasm_streaming_cb: None,
js_error_create_fn,
@ -386,9 +388,10 @@ impl JsRuntime {
}
// Init extension ops
js_runtime.init_extension_ops().unwrap();
// Init callbacks (opresolve & syncOpsCache)
js_runtime.init_cbs();
// Sync ops cache
js_runtime.sync_ops_cache();
// Init async ops callback
js_runtime.init_recv_cb();
js_runtime
}
@ -476,35 +479,44 @@ impl JsRuntime {
self.register_op(name, macroware(name, opfn));
}
}
// Sync ops cache
self.sync_ops_cache();
// Restore extensions
self.extensions = extensions;
Ok(())
}
/// Grabs a reference to core.js' opresolve
fn init_recv_cb(&mut self) {
let scope = &mut self.handle_scope();
// Get Deno.core.opresolve
let code = v8::String::new(scope, "Deno.core.opresolve").unwrap();
/// Grab a Global handle to a function returned by the given expression
fn grab_fn(
scope: &mut v8::HandleScope,
code: &str,
) -> v8::Global<v8::Function> {
let code = v8::String::new(scope, code).unwrap();
let script = v8::Script::compile(scope, code, None).unwrap();
let v8_value = script.run(scope).unwrap();
// Put global handle in state.js_recv_cb
let state_rc = JsRuntime::state(scope);
let mut state = state_rc.borrow_mut();
let cb = v8::Local::<v8::Function>::try_from(v8_value).unwrap();
state.js_recv_cb.replace(v8::Global::new(scope, cb));
v8::Global::new(scope, cb)
}
/// Grabs a reference to core.js' opresolve & syncOpsCache()
fn init_cbs(&mut self) {
let mut scope = self.handle_scope();
let recv_cb = Self::grab_fn(&mut scope, "Deno.core.opresolve");
let sync_cb = Self::grab_fn(&mut scope, "Deno.core.syncOpsCache");
// Put global handles in state
let state_rc = JsRuntime::state(&scope);
let mut state = state_rc.borrow_mut();
state.js_recv_cb.replace(recv_cb);
state.js_sync_cb.replace(sync_cb);
}
/// Ensures core.js has the latest op-name to op-id mappings
pub fn sync_ops_cache(&mut self) {
self
.execute_script("<anon>", "Deno.core.syncOpsCache()")
.unwrap();
let scope = &mut self.handle_scope();
let state_rc = JsRuntime::state(scope);
let js_sync_cb_handle = state_rc.borrow().js_sync_cb.clone().unwrap();
let js_sync_cb = js_sync_cb_handle.get(scope);
let this = v8::undefined(scope).into();
js_sync_cb.call(scope, this, &[]);
}
/// Returns the runtime's op state, which can be used to maintain ops
@ -590,6 +602,7 @@ impl JsRuntime {
))));
// Drop other v8::Global handles before snapshotting
std::mem::take(&mut state.borrow_mut().js_recv_cb);
std::mem::take(&mut state.borrow_mut().js_sync_cb);
let snapshot_creator = self.snapshot_creator.as_mut().unwrap();
let snapshot = snapshot_creator