diff --git a/core/bindings.rs b/core/bindings.rs index 2ce3bc4928ecc1..719c1e1356e95d 100644 --- a/core/bindings.rs +++ b/core/bindings.rs @@ -1,6 +1,7 @@ // Copyright 2018-2022 the Deno authors. All rights reserved. MIT license. use crate::error::is_instance_of_error; +use crate::error::to_v8_error; use crate::modules::get_asserted_module_type_from_assertions; use crate::modules::parse_import_assertions; use crate::modules::validate_import_assertions; @@ -596,3 +597,22 @@ pub fn throw_type_error(scope: &mut v8::HandleScope, message: impl AsRef) { let exception = v8::Exception::type_error(scope, message); scope.throw_exception(exception); } + +pub fn host_create_shadow_realm_callback<'s>( + scope: &mut v8::HandleScope<'s>, +) -> Option> { + match JsRuntime::create_realm_from_scope(scope) { + Ok(realm) => { + let context = realm.context(); + Some(v8::Local::new(scope, context)) + } + Err(error) => { + let state_rc = JsRuntime::state(scope); + let op_state_rc = &state_rc.borrow().op_state; + let exception = + to_v8_error(scope, op_state_rc.borrow().get_error_class_fn, &error); + scope.throw_exception(exception); + None + } + } +} diff --git a/core/runtime.rs b/core/runtime.rs index b2f65195043c3e..7eacae0191585e 100644 --- a/core/runtime.rs +++ b/core/runtime.rs @@ -83,9 +83,8 @@ pub struct JsRuntime { v8_isolate: Option, snapshot_creator: Option, has_snapshotted: bool, - built_from_snapshot: bool, allocations: IsolateAllocations, - extensions: Vec, + //extensions: Vec, event_loop_middlewares: Vec>, } @@ -190,6 +189,8 @@ pub(crate) struct JsRuntimeState { pub(crate) dispatched_exceptions: VecDeque>, inspector: Option>>, waker: AtomicWaker, + runtime_built_from_snapshot: bool, + extensions: Vec, } impl Drop for JsRuntime { @@ -448,6 +449,8 @@ impl JsRuntime { dispatched_exceptions: Default::default(), inspector: Some(inspector), waker: AtomicWaker::new(), + runtime_built_from_snapshot: has_startup_snapshot, + extensions: vec![], // Will be replaced later }))); { @@ -462,24 +465,29 @@ impl JsRuntime { v8_isolate: Some(isolate), snapshot_creator: maybe_snapshot_creator, has_snapshotted: false, - built_from_snapshot: has_startup_snapshot, allocations: IsolateAllocations::default(), event_loop_middlewares: Vec::with_capacity(options.extensions.len()), - extensions: options.extensions, }; // Init resources and ops before extensions to make sure they are // available during the initialization process. - js_runtime.init_extension_ops().unwrap(); + js_runtime + .init_extension_ops(&mut options.extensions) + .unwrap(); // TODO(@AaronO): diff extensions inited in snapshot and those provided // for now we assume that snapshot and extensions always match if !has_startup_snapshot { let realm = js_runtime.global_realm(); - js_runtime.init_extension_js(&realm).unwrap(); + realm + .init_extension_js(js_runtime.v8_isolate(), &options.extensions) + .unwrap(); } // Init callbacks (opresolve) let global_realm = js_runtime.global_realm(); - js_runtime.init_cbs(&global_realm); + Self::init_cbs(&mut js_runtime.handle_scope(), &global_realm); + + Self::state(js_runtime.v8_isolate()).borrow_mut().extensions = + options.extensions; js_runtime } @@ -503,25 +511,26 @@ impl JsRuntime { } pub fn create_realm(&mut self) -> Result { + Self::create_realm_from_scope(&mut self.handle_scope()) + } + + pub fn create_realm_from_scope( + scope: &mut v8::HandleScope, + ) -> Result { + let state_rc = Self::state(scope); + let runtime_built_from_snapshot = + state_rc.borrow().runtime_built_from_snapshot; + let realm = { - // SAFETY: Having the scope tied to self's lifetime makes it impossible to - // reference self.ops while the scope is alive. Here we turn it into an - // unbound lifetime, which is sound because 1. it only lives until the end - // of this block, and 2. the HandleScope only has access to the isolate, - // and nothing else we're accessing from self does. - let scope = &mut v8::HandleScope::new(unsafe { - &mut *(self.v8_isolate() as *mut v8::OwnedIsolate) - }); + let mut state = state_rc.borrow_mut(); + let context = bindings::initialize_context( scope, - &Self::state(self.v8_isolate()).borrow().op_ctxs, - self.built_from_snapshot, + &state.op_ctxs, + runtime_built_from_snapshot, ); context.set_slot(scope, Rc::>::default()); - let state_rc = Self::state(scope); - let mut state = state_rc.borrow_mut(); - let module_map = ModuleMap::new(state.module_loader.clone(), state.op_state.clone()); context.set_slot(scope, Rc::new(RefCell::new(module_map))); @@ -531,11 +540,11 @@ impl JsRuntime { JsRealm::new(v8::Global::new(scope, context)) }; - if !self.built_from_snapshot { - self.init_extension_js(&realm)?; + if !runtime_built_from_snapshot { + realm.init_extension_js(scope, &state_rc.borrow().extensions)?; } - self.init_cbs(&realm); + Self::init_cbs(scope, &realm); Ok(realm) } @@ -553,6 +562,9 @@ impl JsRuntime { isolate.set_host_import_module_dynamically_callback( bindings::host_import_module_dynamically_callback, ); + isolate.set_host_create_shadow_realm_context_callback( + bindings::host_create_shadow_realm_callback, + ); isolate.set_wasm_async_resolve_promise_callback( bindings::wasm_async_resolve_promise_callback, ); @@ -564,23 +576,6 @@ impl JsRuntime { s.clone() } - /// Initializes JS of provided Extensions in the given realm - fn init_extension_js(&mut self, realm: &JsRealm) -> Result<(), Error> { - // Take extensions to avoid double-borrow - let mut extensions: Vec = std::mem::take(&mut self.extensions); - for m in extensions.iter_mut() { - let js_files = m.init_js(); - for (filename, source) in js_files { - // TODO(@AaronO): use JsRuntime::execute_static() here to move src off heap - realm.execute_script(self.v8_isolate(), filename, source)?; - } - } - // Restore extensions - self.extensions = extensions; - - Ok(()) - } - /// Collects ops from extensions & applies middleware fn collect_ops(extensions: &mut [Extension]) -> Vec { // Middleware @@ -615,10 +610,11 @@ impl JsRuntime { } /// Initializes ops of provided Extensions - fn init_extension_ops(&mut self) -> Result<(), Error> { + fn init_extension_ops( + &mut self, + extensions: &mut [Extension], + ) -> Result<(), Error> { let op_state = self.op_state(); - // Take extensions to avoid double-borrow - let mut extensions: Vec = std::mem::take(&mut self.extensions); // Setup state for e in extensions.iter_mut() { @@ -631,9 +627,6 @@ impl JsRuntime { } } - // Restore extensions - self.extensions = extensions; - Ok(()) } @@ -688,21 +681,18 @@ impl JsRuntime { } /// Grabs a reference to core.js' opresolve & syncOpsCache() - fn init_cbs(&mut self, realm: &JsRealm) { - let (recv_cb, build_custom_error_cb) = { - let scope = &mut realm.handle_scope(self.v8_isolate()); - let recv_cb = - Self::grab_global::(scope, "Deno.core.opresolve") - .expect("Deno.core.opresolve is undefined in the realm"); - let recv_cb = v8::Global::new(scope, recv_cb); - let build_custom_error_cb = - Self::grab_global::(scope, "Deno.core.buildCustomError") - .expect("Deno.core.buildCustomError is undefined in the realm"); - let build_custom_error_cb = v8::Global::new(scope, build_custom_error_cb); - (recv_cb, build_custom_error_cb) - }; + fn init_cbs(scope: &mut v8::HandleScope, realm: &JsRealm) { + let recv_cb = + Self::grab_global::(scope, "Deno.core.opresolve") + .expect("Deno.core.opresolve is undefined in the realm"); + let recv_cb = v8::Global::new(scope, recv_cb); + let build_custom_error_cb = + Self::grab_global::(scope, "Deno.core.buildCustomError") + .expect("Deno.core.buildCustomError is undefined in the realm"); + let build_custom_error_cb = v8::Global::new(scope, build_custom_error_cb); + // Put global handle in callback state - let state = realm.state(self.v8_isolate()); + let state = realm.state(scope); state.borrow_mut().js_recv_cb.replace(recv_cb); state .borrow_mut() @@ -1626,6 +1616,22 @@ impl JsRealm { self.0.open(scope).global(scope) } + /// Initializes JS of provided Extensions in the given realm + fn init_extension_js( + &self, + isolate: &mut v8::Isolate, + extensions: &[Extension], + ) -> Result<(), Error> { + for m in extensions.iter() { + let js_files = m.init_js(); + for (filename, source) in js_files { + // TODO(@AaronO): use JsRuntime::execute_static() here to move src off heap + self.execute_script(isolate, filename, source)?; + } + } + Ok(()) + } + pub(crate) fn module_map( &self, isolate: &mut v8::Isolate,