Skip to content

Commit

Permalink
Implement the ShadowRealm constuctor
Browse files Browse the repository at this point in the history
  • Loading branch information
andreubotella committed Oct 8, 2022
1 parent 3061a58 commit 726a785
Show file tree
Hide file tree
Showing 2 changed files with 86 additions and 60 deletions.
20 changes: 20 additions & 0 deletions core/bindings.rs
Original file line number Diff line number Diff line change
@@ -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;
Expand Down Expand Up @@ -596,3 +597,22 @@ pub fn throw_type_error(scope: &mut v8::HandleScope, message: impl AsRef<str>) {
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<v8::Local<'s, v8::Context>> {
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
}
}
}
126 changes: 66 additions & 60 deletions core/runtime.rs
Original file line number Diff line number Diff line change
Expand Up @@ -83,9 +83,8 @@ pub struct JsRuntime {
v8_isolate: Option<v8::OwnedIsolate>,
snapshot_creator: Option<v8::SnapshotCreator>,
has_snapshotted: bool,
built_from_snapshot: bool,
allocations: IsolateAllocations,
extensions: Vec<Extension>,
//extensions: Vec<Extension>,
event_loop_middlewares: Vec<Box<OpEventLoopFn>>,
}

Expand Down Expand Up @@ -190,6 +189,8 @@ pub(crate) struct JsRuntimeState {
pub(crate) dispatched_exceptions: VecDeque<v8::Global<v8::Value>>,
inspector: Option<Rc<RefCell<JsRuntimeInspector>>>,
waker: AtomicWaker,
runtime_built_from_snapshot: bool,
extensions: Vec<Extension>,
}

impl Drop for JsRuntime {
Expand Down Expand Up @@ -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
})));

{
Expand All @@ -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
}
Expand All @@ -503,25 +511,26 @@ impl JsRuntime {
}

pub fn create_realm(&mut self) -> Result<JsRealm, Error> {
Self::create_realm_from_scope(&mut self.handle_scope())
}

pub fn create_realm_from_scope(
scope: &mut v8::HandleScope,
) -> Result<JsRealm, Error> {
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::<RefCell<ContextState>>::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)));
Expand All @@ -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)
}
Expand All @@ -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,
);
Expand All @@ -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<Extension> = 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<OpDecl> {
// Middleware
Expand Down Expand Up @@ -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<Extension> = std::mem::take(&mut self.extensions);

// Setup state
for e in extensions.iter_mut() {
Expand All @@ -631,9 +627,6 @@ impl JsRuntime {
}
}

// Restore extensions
self.extensions = extensions;

Ok(())
}

Expand Down Expand Up @@ -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::<v8::Function>(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::<v8::Function>(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::<v8::Function>(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::<v8::Function>(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()
Expand Down Expand Up @@ -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,
Expand Down

0 comments on commit 726a785

Please sign in to comment.