diff options
Diffstat (limited to 'core')
-rw-r--r-- | core/bindings.rs | 158 | ||||
-rw-r--r-- | core/extensions.rs | 16 | ||||
-rw-r--r-- | core/ops.rs | 37 | ||||
-rw-r--r-- | core/runtime.rs | 66 | ||||
-rw-r--r-- | core/snapshot_util.rs | 2 |
5 files changed, 103 insertions, 176 deletions
diff --git a/core/bindings.rs b/core/bindings.rs index 52db40f0d..7970f9aab 100644 --- a/core/bindings.rs +++ b/core/bindings.rs @@ -19,22 +19,24 @@ use crate::snapshot_util::SnapshotOptions; use crate::JsRealm; use crate::JsRuntime; -pub(crate) fn external_references(ops: &[OpCtx]) -> v8::ExternalReferences { - // Overallocate a bit, it's better than having to resize the vector. - let mut references = Vec::with_capacity(4 + ops.len() * 4); - - references.push(v8::ExternalReference { - function: call_console.map_fn_to(), - }); - references.push(v8::ExternalReference { - function: import_meta_resolve.map_fn_to(), - }); - references.push(v8::ExternalReference { - function: catch_dynamic_import_promise_error.map_fn_to(), - }); - references.push(v8::ExternalReference { - function: empty_fn.map_fn_to(), - }); +pub(crate) fn external_references( + ops: &[OpCtx], + snapshot_options: SnapshotOptions, +) -> v8::ExternalReferences { + let mut references = vec![ + v8::ExternalReference { + function: call_console.map_fn_to(), + }, + v8::ExternalReference { + function: import_meta_resolve.map_fn_to(), + }, + v8::ExternalReference { + function: catch_dynamic_import_promise_error.map_fn_to(), + }, + v8::ExternalReference { + function: empty_fn.map_fn_to(), + }, + ]; for ctx in ops { let ctx_ptr = ctx as *const OpCtx as _; @@ -42,13 +44,12 @@ pub(crate) fn external_references(ops: &[OpCtx]) -> v8::ExternalReferences { references.push(v8::ExternalReference { function: ctx.decl.v8_fn_ptr, }); - if let Some(fast_fn) = &ctx.decl.fast_fn { - references.push(v8::ExternalReference { - pointer: fast_fn.function() as _, - }); - references.push(v8::ExternalReference { - pointer: ctx.fast_fn_c_info.unwrap().as_ptr() as _, - }); + if !snapshot_options.will_snapshot() { + if let Some(fast_fn) = &ctx.decl.fast_fn { + references.push(v8::ExternalReference { + pointer: fast_fn.function() as _, + }); + } } } @@ -113,9 +114,9 @@ pub(crate) fn initialize_context<'s>( v8::String::new_external_onebyte_static(scope, b"core").unwrap(); let ops_str = v8::String::new_external_onebyte_static(scope, b"ops").unwrap(); - let ops_obj = if snapshot_options.loaded() { - // Snapshot already registered `Deno.core.ops` but - // extensions may provide ops that aren't part of the snapshot. + // Snapshot already registered `Deno.core.ops` but + // extensions may provide ops that aren't part of the snapshot. + if snapshot_options.loaded() { // Grab the Deno.core.ops object & init it let deno_obj: v8::Local<v8::Object> = global .get(scope, deno_str.into()) @@ -132,58 +133,34 @@ pub(crate) fn initialize_context<'s>( .expect("Deno.core.ops to exist") .try_into() .unwrap(); - ops_obj - } else { - // globalThis.Deno = { core: { } }; - let deno_obj = v8::Object::new(scope); - global.set(scope, deno_str.into(), deno_obj.into()); - - let core_obj = v8::Object::new(scope); - deno_obj.set(scope, core_str.into(), core_obj.into()); - - // Bind functions to Deno.core.* - set_func(scope, core_obj, "callConsole", call_console); - - // Bind v8 console object to Deno.core.console - let extra_binding_obj = context.get_extras_binding_object(scope); - let console_str = - v8::String::new_external_onebyte_static(scope, b"console").unwrap(); - let console_obj = extra_binding_obj.get(scope, console_str.into()).unwrap(); - core_obj.set(scope, console_str.into(), console_obj); - - // Bind functions to Deno.core.ops.* - let ops_obj = v8::Object::new(scope); - core_obj.set(scope, ops_str.into(), ops_obj.into()); - ops_obj - }; - - if matches!(snapshot_options, SnapshotOptions::Load) { - // Only register ops that have `force_registration` flag set to true, - // the remaining ones should already be in the snapshot. - for op_ctx in op_ctxs - .iter() - .filter(|op_ctx| op_ctx.decl.force_registration) - { - add_op_to_deno_core_ops(scope, ops_obj, op_ctx); - } - } else if matches!(snapshot_options, SnapshotOptions::CreateFromExisting) { - // Register all ops, probing for which ones are already registered. - for op_ctx in op_ctxs { - let key = v8::String::new_external_onebyte_static( - scope, - op_ctx.decl.name.as_bytes(), - ) - .unwrap(); - if ops_obj.get(scope, key.into()).is_some() { - continue; - } - add_op_to_deno_core_ops(scope, ops_obj, op_ctx); - } - } else { - // In other cases register all ops unconditionally. - for op_ctx in op_ctxs { - add_op_to_deno_core_ops(scope, ops_obj, op_ctx); + for ctx in op_ctxs { + add_op_to_deno_core_ops(scope, ops_obj, ctx, snapshot_options); } + return context; + } + + // global.Deno = { core: { } }; + let deno_obj = v8::Object::new(scope); + global.set(scope, deno_str.into(), deno_obj.into()); + + let core_obj = v8::Object::new(scope); + deno_obj.set(scope, core_str.into(), core_obj.into()); + + // Bind functions to Deno.core.* + set_func(scope, core_obj, "callConsole", call_console); + + // Bind v8 console object to Deno.core.console + let extra_binding_obj = context.get_extras_binding_object(scope); + let console_str = + v8::String::new_external_onebyte_static(scope, b"console").unwrap(); + let console_obj = extra_binding_obj.get(scope, console_str.into()).unwrap(); + core_obj.set(scope, console_str.into(), console_obj); + + // Bind functions to Deno.core.ops.* + let ops_obj = v8::Object::new(scope); + core_obj.set(scope, ops_str.into(), ops_obj.into()); + for ctx in op_ctxs { + add_op_to_deno_core_ops(scope, ops_obj, ctx, snapshot_options); } context @@ -206,6 +183,7 @@ fn add_op_to_deno_core_ops( scope: &mut v8::HandleScope<'_>, obj: v8::Local<v8::Object>, op_ctx: &OpCtx, + snapshot_options: SnapshotOptions, ) { let op_ctx_ptr = op_ctx as *const OpCtx as *const c_void; let key = @@ -215,14 +193,24 @@ fn add_op_to_deno_core_ops( let builder = v8::FunctionTemplate::builder_raw(op_ctx.decl.v8_fn_ptr) .data(external.into()); - let templ = if let Some(fast_function) = &op_ctx.decl.fast_fn { - builder.build_fast( - scope, - &**fast_function, - Some(op_ctx.fast_fn_c_info.unwrap().as_ptr()), - None, - None, - ) + // TODO(bartlomieju): this should be cleaned up once we update Fast Calls API + // If this is a fast op, we don't want it to be in the snapshot. + // Only initialize once snapshot is loaded. + let maybe_fast_fn = + if op_ctx.decl.fast_fn.is_some() && snapshot_options.loaded() { + &op_ctx.decl.fast_fn + } else { + &None + }; + + let templ = if let Some(fast_function) = maybe_fast_fn { + // Don't initialize fast ops when snapshotting, the external references count mismatch. + if !snapshot_options.will_snapshot() { + // TODO(@littledivy): Support fast api overloads in ops. + builder.build_fast(scope, &**fast_function, None, None, None) + } else { + builder.build(scope) + } } else { builder.build(scope) }; diff --git a/core/extensions.rs b/core/extensions.rs index 2a578429b..728ebd512 100644 --- a/core/extensions.rs +++ b/core/extensions.rs @@ -53,7 +53,6 @@ pub struct OpDecl { pub is_unstable: bool, pub is_v8: bool, pub fast_fn: Option<Box<dyn FastFunction>>, - pub force_registration: bool, } impl OpDecl { @@ -241,7 +240,6 @@ macro_rules! extension { #[inline(always)] #[allow(unused_variables)] - #[allow(clippy::redundant_closure_call)] fn with_customizer(ext: &mut $crate::ExtensionBuilder) { $( ($customizer_fn)(ext); )? } @@ -327,7 +325,6 @@ pub struct Extension { enabled: bool, name: &'static str, deps: Option<&'static [&'static str]>, - force_op_registration: bool, } // Note: this used to be a trait, but we "downgraded" it to a single concrete type @@ -397,7 +394,6 @@ impl Extension { let mut ops = self.ops.take()?; for op in ops.iter_mut() { op.enabled = self.enabled && op.enabled; - op.force_registration = self.force_op_registration; } Some(ops) } @@ -451,7 +447,6 @@ pub struct ExtensionBuilder { event_loop_middleware: Option<Box<OpEventLoopFn>>, name: &'static str, deps: &'static [&'static str], - force_op_registration: bool, } impl ExtensionBuilder { @@ -499,15 +494,6 @@ impl ExtensionBuilder { self } - /// Mark that ops from this extension should be added to `Deno.core.ops` - /// unconditionally. This is useful is some ops are not available - /// during snapshotting, as ops are not registered by default when a - /// `JsRuntime` is created with an existing snapshot. - pub fn force_op_registration(&mut self) -> &mut Self { - self.force_op_registration = true; - self - } - /// Consume the [`ExtensionBuilder`] and return an [`Extension`]. pub fn take(self) -> Extension { let js_files = Some(self.js); @@ -525,7 +511,6 @@ impl ExtensionBuilder { initialized: false, enabled: true, name: self.name, - force_op_registration: self.force_op_registration, deps, } } @@ -547,7 +532,6 @@ impl ExtensionBuilder { enabled: true, name: self.name, deps, - force_op_registration: self.force_op_registration, } } } diff --git a/core/ops.rs b/core/ops.rs index 3a276082f..ca465c821 100644 --- a/core/ops.rs +++ b/core/ops.rs @@ -19,13 +19,10 @@ use std::cell::RefCell; use std::ops::Deref; use std::ops::DerefMut; use std::pin::Pin; -use std::ptr::NonNull; use std::rc::Rc; use std::rc::Weak; use std::task::Context; use std::task::Poll; -use v8::fast_api::CFunctionInfo; -use v8::fast_api::CTypeInfo; /// Wrapper around a Future, which causes that Future to be polled immediately. /// @@ -158,45 +155,11 @@ pub struct OpCtx { pub id: OpId, pub state: Rc<RefCell<OpState>>, pub decl: Rc<OpDecl>, - pub fast_fn_c_info: Option<NonNull<v8::fast_api::CFunctionInfo>>, pub runtime_state: Weak<RefCell<JsRuntimeState>>, // Index of the current realm into `JsRuntimeState::known_realms`. pub realm_idx: RealmIdx, } -impl OpCtx { - pub fn new( - id: OpId, - realm_idx: RealmIdx, - decl: Rc<OpDecl>, - state: Rc<RefCell<OpState>>, - runtime_state: Weak<RefCell<JsRuntimeState>>, - ) -> Self { - let mut fast_fn_c_info = None; - - if let Some(fast_fn) = &decl.fast_fn { - let args = CTypeInfo::new_from_slice(fast_fn.args()); - let ret = CTypeInfo::new(fast_fn.return_type()); - - // SAFETY: all arguments are coming from the trait and they have - // static lifetime - let c_fn = unsafe { - CFunctionInfo::new(args.as_ptr(), fast_fn.args().len(), ret.as_ptr()) - }; - fast_fn_c_info = Some(c_fn); - } - - OpCtx { - id, - state, - runtime_state, - decl, - realm_idx, - fast_fn_c_info, - } - } -} - /// Maintains the resources and ops inside a JS runtime. pub struct OpState { pub resource_table: ResourceTable, diff --git a/core/runtime.rs b/core/runtime.rs index f1aa63f23..a08e65134 100644 --- a/core/runtime.rs +++ b/core/runtime.rs @@ -319,7 +319,6 @@ impl JsRuntime { DENO_INIT.call_once(move || v8_init(v8_platform, options.will_snapshot)); // Add builtins extension - // TODO(bartlomieju): remove this in favor of `SnapshotOptions`. let has_startup_snapshot = options.startup_snapshot.is_some(); if !has_startup_snapshot { options @@ -376,8 +375,12 @@ impl JsRuntime { let op_ctxs = ops .into_iter() .enumerate() - .map(|(id, decl)| { - OpCtx::new(id, 0, Rc::new(decl), op_state.clone(), weak.clone()) + .map(|(id, decl)| OpCtx { + id, + state: op_state.clone(), + runtime_state: weak.clone(), + decl: Rc::new(decl), + realm_idx: 0, }) .collect::<Vec<_>>() .into_boxed_slice(); @@ -386,7 +389,7 @@ impl JsRuntime { options.startup_snapshot.is_some(), options.will_snapshot, ); - let refs = bindings::external_references(&op_ctxs); + let refs = bindings::external_references(&op_ctxs, snapshot_options); // V8 takes ownership of external_references. let refs: &'static v8::ExternalReferences = Box::leak(Box::new(refs)); let global_context; @@ -395,7 +398,7 @@ impl JsRuntime { let (mut isolate, snapshot_options) = if snapshot_options.will_snapshot() { let snapshot_creator = snapshot_util::create_snapshot_creator(refs, options.startup_snapshot); - eprintln!("create snapshot {:#?}", snapshot_options); + let mut isolate = JsRuntime::setup_isolate(snapshot_creator); { let scope = &mut v8::HandleScope::new(&mut isolate); @@ -457,7 +460,6 @@ impl JsRuntime { isolate_ptr.write(isolate); isolate_ptr.read() }; - global_context.open(&mut isolate).set_slot( &mut isolate, Rc::new(RefCell::new(ContextState { @@ -618,14 +620,12 @@ impl JsRuntime { .borrow() .op_ctxs .iter() - .map(|op_ctx| { - OpCtx::new( - op_ctx.id, - realm_idx, - op_ctx.decl.clone(), - op_ctx.state.clone(), - op_ctx.runtime_state.clone(), - ) + .map(|op_ctx| OpCtx { + id: op_ctx.id, + state: op_ctx.state.clone(), + decl: op_ctx.decl.clone(), + runtime_state: op_ctx.runtime_state.clone(), + realm_idx, }) .collect(); @@ -927,6 +927,18 @@ impl JsRuntime { /// /// `Error` can usually be downcast to `JsError`. pub fn snapshot(mut self) -> v8::StartupData { + // Nuke Deno.core.ops.* to avoid ExternalReference snapshotting issues + // TODO(@AaronO): make ops stable across snapshots + { + let scope = &mut self.handle_scope(); + let o = Self::eval::<v8::Object>(scope, "Deno.core.ops").unwrap(); + let names = o.get_own_property_names(scope, Default::default()).unwrap(); + for i in 0..names.length() { + let key = names.get_index(scope, i).unwrap(); + o.delete(scope, key); + } + } + self.state.borrow_mut().inspector.take(); // Serialize the module map and store its data in the snapshot. @@ -3544,18 +3556,10 @@ pub mod tests { } } - #[op] - fn op_test() -> Result<String, Error> { - Ok(String::from("test")) - } - let loader = Rc::new(ModsLoader::default()); let mut runtime = JsRuntime::new(RuntimeOptions { module_loader: Some(loader.clone()), will_snapshot: true, - extensions: vec![Extension::builder("text_ext") - .ops(vec![op_test::decl()]) - .build()], ..Default::default() }); @@ -3590,9 +3594,6 @@ pub mod tests { module_loader: Some(loader.clone()), will_snapshot: true, startup_snapshot: Some(Snapshot::JustCreated(snapshot)), - extensions: vec![Extension::builder("text_ext") - .ops(vec![op_test::decl()]) - .build()], ..Default::default() }); @@ -3608,9 +3609,6 @@ pub mod tests { let mut runtime3 = JsRuntime::new(RuntimeOptions { module_loader: Some(loader), startup_snapshot: Some(Snapshot::JustCreated(snapshot2)), - extensions: vec![Extension::builder("text_ext") - .ops(vec![op_test::decl()]) - .build()], ..Default::default() }); @@ -3618,7 +3616,7 @@ pub mod tests { let source_code = r#"(async () => { const mod = await import("file:///400.js"); - return mod.f400() + " " + Deno.core.ops.op_test(); + return mod.f400(); })();"# .to_string(); let val = runtime3.execute_script(".", &source_code).unwrap(); @@ -3627,7 +3625,7 @@ pub mod tests { let scope = &mut runtime3.handle_scope(); let value = v8::Local::new(scope, val); let str_ = value.to_string(scope).unwrap().to_rust_string_lossy(scope); - assert_eq!(str_, "hello world test"); + assert_eq!(str_, "hello world"); } } @@ -4602,13 +4600,7 @@ Deno.core.opAsync("op_async_serialize_object_with_numbers_as_keys", { Ok(String::from("Test")) } - deno_core::extension!( - test_ext, - ops = [op_test], - customizer = |ext: &mut deno_core::ExtensionBuilder| { - ext.force_op_registration(); - }, - ); + deno_core::extension!(test_ext, ops = [op_test]); let mut runtime = JsRuntime::new(RuntimeOptions { startup_snapshot: Some(Snapshot::Boxed(snapshot)), extensions: vec![test_ext::init_ops()], diff --git a/core/snapshot_util.rs b/core/snapshot_util.rs index 20019f5cc..74bd7d8a3 100644 --- a/core/snapshot_util.rs +++ b/core/snapshot_util.rs @@ -121,7 +121,7 @@ fn data_error_to_panic(err: v8::DataError) -> ! { } } -#[derive(Copy, Clone, Debug, PartialEq, Eq)] +#[derive(Copy, Clone, PartialEq, Eq)] pub(crate) enum SnapshotOptions { Load, CreateFromExisting, |