From 3c9771deb2d615c47a2570023039c6a71f1c774b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bartek=20Iwa=C5=84czuk?= Date: Sat, 18 Mar 2023 18:30:04 -0400 Subject: [PATCH] Reland "perf(core): preserve ops between snapshots (#18080)" (#18272) Relanding 4b6305f4f25fc76f974bbdcc9cdb139d5ab8f5f4 --- bench_util/benches/op_baseline.rs | 32 +++- cli/build.rs | 3 +- cli/lsp/tsc.rs | 3 + cli/ops/bench.rs | 3 + cli/ops/mod.rs | 3 + cli/ops/testing.rs | 3 + cli/tsc/mod.rs | 11 +- core/bindings.rs | 158 ++++++++++-------- core/extensions.rs | 16 ++ core/ops.rs | 37 ++++ core/runtime.rs | 66 ++++---- core/snapshot_util.rs | 2 +- .../polyfills/internal/readline/utils.mjs | 8 +- ops/lib.rs | 2 + ops/optimizer_tests/async_nop.out | 1 + ops/optimizer_tests/async_result.out | 1 + ops/optimizer_tests/callback_options.out | 1 + ops/optimizer_tests/cow_str.out | 1 + ops/optimizer_tests/f64_slice.out | 1 + ops/optimizer_tests/incompatible_1.out | 1 + ops/optimizer_tests/issue16934.out | 1 + ops/optimizer_tests/issue16934_fast.out | 1 + .../op_blob_revoke_object_url.out | 1 + ops/optimizer_tests/op_ffi_ptr_value.out | 1 + ops/optimizer_tests/op_print.out | 1 + ops/optimizer_tests/op_state.out | 1 + ops/optimizer_tests/op_state_basic1.out | 1 + ops/optimizer_tests/op_state_generics.out | 1 + ops/optimizer_tests/op_state_result.out | 1 + ops/optimizer_tests/op_state_warning.out | 1 + .../op_state_with_transforms.out | 1 + ops/optimizer_tests/opstate_with_arity.out | 1 + ops/optimizer_tests/option_arg.out | 1 + ops/optimizer_tests/owned_string.out | 1 + .../param_mut_binding_warning.out | 1 + ops/optimizer_tests/raw_ptr.out | 1 + ops/optimizer_tests/serde_v8_value.out | 1 + ops/optimizer_tests/strings.out | 1 + ops/optimizer_tests/strings_result.out | 1 + ops/optimizer_tests/u64_result.out | 1 + ops/optimizer_tests/uint8array.out | 1 + ops/optimizer_tests/unit_result.out | 1 + ops/optimizer_tests/unit_result2.out | 1 + ops/optimizer_tests/unit_ret.out | 1 + ops/optimizer_tests/wasm_op.out | 1 + runtime/ops/fs_events.rs | 5 +- runtime/ops/http.rs | 3 + runtime/ops/os/mod.rs | 14 +- runtime/ops/permissions.rs | 5 +- runtime/ops/process.rs | 5 +- runtime/ops/runtime.rs | 5 +- runtime/ops/signal.rs | 5 +- runtime/ops/tty.rs | 5 +- runtime/ops/web_worker.rs | 5 +- runtime/ops/worker_host.rs | 5 +- 55 files changed, 301 insertions(+), 134 deletions(-) diff --git a/bench_util/benches/op_baseline.rs b/bench_util/benches/op_baseline.rs index 89fb3d2f3a..4b3bc0203c 100644 --- a/bench_util/benches/op_baseline.rs +++ b/bench_util/benches/op_baseline.rs @@ -9,7 +9,14 @@ use deno_bench_util::bencher::Bencher; use deno_core::op; use deno_core::Extension; -deno_core::extension!(bench_setup, ops = [op_pi_json, op_pi_async, op_nop]); +deno_core::extension!( + bench_setup, + ops = [ + // op_pi_json, + op_pi_async, + op_nop + ] +); fn setup() -> Vec { vec![bench_setup::init_ops()] @@ -18,10 +25,12 @@ fn setup() -> Vec { #[op] fn op_nop() {} -#[op] -fn op_pi_json() -> i64 { - 314159 -} +// TODO(bartlomieju): reenable, currently this op generates a fast function, +// which is wrong, because i64 is not a compatible type for fast call. +// #[op] +// fn op_pi_json() -> i64 { +// 314159 +// } // this is a function since async closures aren't stable #[op] @@ -29,9 +38,9 @@ async fn op_pi_async() -> i64 { 314159 } -fn bench_op_pi_json(b: &mut Bencher) { - bench_js_sync(b, r#"Deno.core.ops.op_pi_json();"#, setup); -} +// fn bench_op_pi_json(b: &mut Bencher) { +// bench_js_sync(b, r#"Deno.core.ops.op_pi_json();"#, setup); +// } fn bench_op_nop(b: &mut Bencher) { bench_js_sync(b, r#"Deno.core.ops.op_nop();"#, setup); @@ -41,6 +50,11 @@ fn bench_op_async(b: &mut Bencher) { bench_js_async(b, r#"Deno.core.opAsync("op_pi_async");"#, setup); } -benchmark_group!(benches, bench_op_pi_json, bench_op_nop, bench_op_async,); +benchmark_group!( + benches, + // bench_op_pi_json, + bench_op_nop, + bench_op_async, +); bench_or_profile!(benches); diff --git a/cli/build.rs b/cli/build.rs index c2269aca3d..173c8b85d4 100644 --- a/cli/build.rs +++ b/cli/build.rs @@ -5,7 +5,6 @@ use std::path::PathBuf; use deno_core::snapshot_util::*; use deno_core::Extension; -use deno_core::ExtensionBuilder; use deno_core::ExtensionFileSource; use deno_core::ExtensionFileSourceCode; use deno_runtime::deno_cache::SqliteBackedCache; @@ -318,7 +317,7 @@ deno_core::extension!( dir "js", "40_testing.js" ], - customizer = |ext: &mut ExtensionBuilder| { + customizer = |ext: &mut deno_core::ExtensionBuilder| { ext.esm(vec![ExtensionFileSource { specifier: "ext:cli/runtime/js/99_main.js", code: ExtensionFileSourceCode::LoadedFromFsDuringSnapshot( diff --git a/cli/lsp/tsc.rs b/cli/lsp/tsc.rs index 91eb6e24b5..c8d8103b9d 100644 --- a/cli/lsp/tsc.rs +++ b/cli/lsp/tsc.rs @@ -2843,6 +2843,9 @@ deno_core::extension!(deno_tsc, options.performance, )); }, + customizer = |ext: &mut deno_core::ExtensionBuilder| { + ext.force_op_registration(); + }, ); /// Instruct a language server runtime to start the language server and provide diff --git a/cli/ops/bench.rs b/cli/ops/bench.rs index 6fa9edee88..86498cd7cd 100644 --- a/cli/ops/bench.rs +++ b/cli/ops/bench.rs @@ -38,6 +38,9 @@ deno_core::extension!(deno_bench, state.put(options.sender); state.put(options.filter); }, + customizer = |ext: &mut deno_core::ExtensionBuilder| { + ext.force_op_registration(); + }, ); #[derive(Clone)] diff --git a/cli/ops/mod.rs b/cli/ops/mod.rs index c12409514d..4d5595e098 100644 --- a/cli/ops/mod.rs +++ b/cli/ops/mod.rs @@ -21,6 +21,9 @@ deno_core::extension!(deno_cli, state = |state, options| { state.put(options.ps); }, + customizer = |ext: &mut deno_core::ExtensionBuilder| { + ext.force_op_registration(); + }, ); #[op] diff --git a/cli/ops/testing.rs b/cli/ops/testing.rs index 0849f1c7a0..8b5c95feae 100644 --- a/cli/ops/testing.rs +++ b/cli/ops/testing.rs @@ -44,6 +44,9 @@ deno_core::extension!(deno_test, state.put(options.fail_fast_tracker); state.put(options.filter); }, + customizer = |ext: &mut deno_core::ExtensionBuilder| { + ext.force_op_registration(); + }, ); #[derive(Clone)] diff --git a/cli/tsc/mod.rs b/cli/tsc/mod.rs index 45589780ff..48ab131fee 100644 --- a/cli/tsc/mod.rs +++ b/cli/tsc/mod.rs @@ -114,7 +114,13 @@ pub fn get_types_declaration_file_text(unstable: bool) -> String { } fn get_asset_texts_from_new_runtime() -> Result, AnyError> { - deno_core::extension!(deno_cli_tsc, ops_fn = deno_ops,); + deno_core::extension!( + deno_cli_tsc, + ops_fn = deno_ops, + customizer = |ext: &mut deno_core::ExtensionBuilder| { + ext.force_op_registration(); + }, + ); // the assets are stored within the typescript isolate, so take them out of there let mut runtime = JsRuntime::new(RuntimeOptions { @@ -846,6 +852,9 @@ pub fn exec(request: Request) -> Result { .unwrap(), )); }, + customizer = |ext: &mut deno_core::ExtensionBuilder| { + ext.force_op_registration(); + }, ); let startup_source = "globalThis.startup({ legacyFlag: false })"; diff --git a/core/bindings.rs b/core/bindings.rs index 7970f9aaba..52db40f0da 100644 --- a/core/bindings.rs +++ b/core/bindings.rs @@ -19,24 +19,22 @@ use crate::snapshot_util::SnapshotOptions; use crate::JsRealm; use crate::JsRuntime; -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(), - }, - ]; +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(), + }); for ctx in ops { let ctx_ptr = ctx as *const OpCtx as _; @@ -44,12 +42,13 @@ pub(crate) fn external_references( references.push(v8::ExternalReference { function: ctx.decl.v8_fn_ptr, }); - if !snapshot_options.will_snapshot() { - if let Some(fast_fn) = &ctx.decl.fast_fn { - references.push(v8::ExternalReference { - pointer: fast_fn.function() as _, - }); - } + 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 _, + }); } } @@ -114,9 +113,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(); - // Snapshot already registered `Deno.core.ops` but - // extensions may provide ops that aren't part of the snapshot. - if snapshot_options.loaded() { + 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. // Grab the Deno.core.ops object & init it let deno_obj: v8::Local = global .get(scope, deno_str.into()) @@ -133,34 +132,58 @@ pub(crate) fn initialize_context<'s>( .expect("Deno.core.ops to exist") .try_into() .unwrap(); - for ctx in op_ctxs { - add_op_to_deno_core_ops(scope, ops_obj, ctx, snapshot_options); + 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); } - 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 @@ -183,7 +206,6 @@ fn add_op_to_deno_core_ops( scope: &mut v8::HandleScope<'_>, obj: v8::Local, op_ctx: &OpCtx, - snapshot_options: SnapshotOptions, ) { let op_ctx_ptr = op_ctx as *const OpCtx as *const c_void; let key = @@ -193,24 +215,14 @@ fn add_op_to_deno_core_ops( let builder = v8::FunctionTemplate::builder_raw(op_ctx.decl.v8_fn_ptr) .data(external.into()); - // 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) - } + 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, + ) } else { builder.build(scope) }; diff --git a/core/extensions.rs b/core/extensions.rs index 728ebd5128..2a578429b9 100644 --- a/core/extensions.rs +++ b/core/extensions.rs @@ -53,6 +53,7 @@ pub struct OpDecl { pub is_unstable: bool, pub is_v8: bool, pub fast_fn: Option>, + pub force_registration: bool, } impl OpDecl { @@ -240,6 +241,7 @@ macro_rules! extension { #[inline(always)] #[allow(unused_variables)] + #[allow(clippy::redundant_closure_call)] fn with_customizer(ext: &mut $crate::ExtensionBuilder) { $( ($customizer_fn)(ext); )? } @@ -325,6 +327,7 @@ 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 @@ -394,6 +397,7 @@ 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) } @@ -447,6 +451,7 @@ pub struct ExtensionBuilder { event_loop_middleware: Option>, name: &'static str, deps: &'static [&'static str], + force_op_registration: bool, } impl ExtensionBuilder { @@ -494,6 +499,15 @@ 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); @@ -511,6 +525,7 @@ impl ExtensionBuilder { initialized: false, enabled: true, name: self.name, + force_op_registration: self.force_op_registration, deps, } } @@ -532,6 +547,7 @@ 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 ca465c821e..3a276082f9 100644 --- a/core/ops.rs +++ b/core/ops.rs @@ -19,10 +19,13 @@ 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. /// @@ -155,11 +158,45 @@ pub struct OpCtx { pub id: OpId, pub state: Rc>, pub decl: Rc, + pub fast_fn_c_info: Option>, pub runtime_state: Weak>, // 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, + state: Rc>, + runtime_state: Weak>, + ) -> 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 a08e651349..f1aa63f23c 100644 --- a/core/runtime.rs +++ b/core/runtime.rs @@ -319,6 +319,7 @@ 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 @@ -375,12 +376,8 @@ impl JsRuntime { let op_ctxs = ops .into_iter() .enumerate() - .map(|(id, decl)| OpCtx { - id, - state: op_state.clone(), - runtime_state: weak.clone(), - decl: Rc::new(decl), - realm_idx: 0, + .map(|(id, decl)| { + OpCtx::new(id, 0, Rc::new(decl), op_state.clone(), weak.clone()) }) .collect::>() .into_boxed_slice(); @@ -389,7 +386,7 @@ impl JsRuntime { options.startup_snapshot.is_some(), options.will_snapshot, ); - let refs = bindings::external_references(&op_ctxs, snapshot_options); + let refs = bindings::external_references(&op_ctxs); // V8 takes ownership of external_references. let refs: &'static v8::ExternalReferences = Box::leak(Box::new(refs)); let global_context; @@ -398,7 +395,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); @@ -460,6 +457,7 @@ impl JsRuntime { isolate_ptr.write(isolate); isolate_ptr.read() }; + global_context.open(&mut isolate).set_slot( &mut isolate, Rc::new(RefCell::new(ContextState { @@ -620,12 +618,14 @@ impl JsRuntime { .borrow() .op_ctxs .iter() - .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, + .map(|op_ctx| { + OpCtx::new( + op_ctx.id, + realm_idx, + op_ctx.decl.clone(), + op_ctx.state.clone(), + op_ctx.runtime_state.clone(), + ) }) .collect(); @@ -927,18 +927,6 @@ 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::(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. @@ -3556,10 +3544,18 @@ pub mod tests { } } + #[op] + fn op_test() -> Result { + 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() }); @@ -3594,6 +3590,9 @@ 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() }); @@ -3609,6 +3608,9 @@ 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() }); @@ -3616,7 +3618,7 @@ pub mod tests { let source_code = r#"(async () => { const mod = await import("file:///400.js"); - return mod.f400(); + return mod.f400() + " " + Deno.core.ops.op_test(); })();"# .to_string(); let val = runtime3.execute_script(".", &source_code).unwrap(); @@ -3625,7 +3627,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"); + assert_eq!(str_, "hello world test"); } } @@ -4600,7 +4602,13 @@ Deno.core.opAsync("op_async_serialize_object_with_numbers_as_keys", { Ok(String::from("Test")) } - deno_core::extension!(test_ext, ops = [op_test]); + deno_core::extension!( + test_ext, + ops = [op_test], + customizer = |ext: &mut deno_core::ExtensionBuilder| { + ext.force_op_registration(); + }, + ); 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 74bd7d8a33..20019f5cc7 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, PartialEq, Eq)] +#[derive(Copy, Clone, Debug, PartialEq, Eq)] pub(crate) enum SnapshotOptions { Load, CreateFromExisting, diff --git a/ext/node/polyfills/internal/readline/utils.mjs b/ext/node/polyfills/internal/readline/utils.mjs index 6224f112b3..0727950dfc 100644 --- a/ext/node/polyfills/internal/readline/utils.mjs +++ b/ext/node/polyfills/internal/readline/utils.mjs @@ -38,10 +38,10 @@ export function CSI(strings, ...args) { } CSI.kEscape = kEscape; -CSI.kClearToLineBeginning = CSI`1K`; -CSI.kClearToLineEnd = CSI`0K`; -CSI.kClearLine = CSI`2K`; -CSI.kClearScreenDown = CSI`0J`; +CSI.kClearToLineBeginning = `${kEscape}[1K`; +CSI.kClearToLineEnd = `${kEscape}[0K`; +CSI.kClearLine = `${kEscape}[2K`; +CSI.kClearScreenDown = `${kEscape}[0J`; // TODO(BridgeAR): Treat combined characters as single character, i.e, // 'a\u0301' and '\u0301a' (both have the same visual output). diff --git a/ops/lib.rs b/ops/lib.rs index f7c69ec8a4..d5f24c0d06 100644 --- a/ops/lib.rs +++ b/ops/lib.rs @@ -145,6 +145,7 @@ impl Op { is_async: #is_async, is_unstable: #is_unstable, is_v8: #is_v8, + force_registration: false, } } @@ -201,6 +202,7 @@ impl Op { is_async: #is_async, is_unstable: #is_unstable, is_v8: #is_v8, + force_registration: false, } } diff --git a/ops/optimizer_tests/async_nop.out b/ops/optimizer_tests/async_nop.out index d1e9534063..abb195bd5e 100644 --- a/ops/optimizer_tests/async_nop.out +++ b/ops/optimizer_tests/async_nop.out @@ -26,6 +26,7 @@ impl op_void_async { is_async: true, is_unstable: false, is_v8: false, + force_registration: false, } } #[inline] diff --git a/ops/optimizer_tests/async_result.out b/ops/optimizer_tests/async_result.out index 1d45b11f17..785031cab9 100644 --- a/ops/optimizer_tests/async_result.out +++ b/ops/optimizer_tests/async_result.out @@ -26,6 +26,7 @@ impl op_async_result { is_async: true, is_unstable: false, is_v8: false, + force_registration: false, } } #[inline] diff --git a/ops/optimizer_tests/callback_options.out b/ops/optimizer_tests/callback_options.out index 3a18be60f7..201ec90ced 100644 --- a/ops/optimizer_tests/callback_options.out +++ b/ops/optimizer_tests/callback_options.out @@ -26,6 +26,7 @@ impl op_fallback { is_async: false, is_unstable: false, is_v8: false, + force_registration: false, } } #[inline] diff --git a/ops/optimizer_tests/cow_str.out b/ops/optimizer_tests/cow_str.out index e676057630..b25c0dcb86 100644 --- a/ops/optimizer_tests/cow_str.out +++ b/ops/optimizer_tests/cow_str.out @@ -26,6 +26,7 @@ impl op_cow_str { is_async: false, is_unstable: false, is_v8: false, + force_registration: false, } } #[inline] diff --git a/ops/optimizer_tests/f64_slice.out b/ops/optimizer_tests/f64_slice.out index dd982b1937..46108e4e8e 100644 --- a/ops/optimizer_tests/f64_slice.out +++ b/ops/optimizer_tests/f64_slice.out @@ -26,6 +26,7 @@ impl op_f64_buf { is_async: false, is_unstable: false, is_v8: false, + force_registration: false, } } #[inline] diff --git a/ops/optimizer_tests/incompatible_1.out b/ops/optimizer_tests/incompatible_1.out index cedfb1a8f9..4bd26ecccd 100644 --- a/ops/optimizer_tests/incompatible_1.out +++ b/ops/optimizer_tests/incompatible_1.out @@ -22,6 +22,7 @@ impl op_sync_serialize_object_with_numbers_as_keys { is_async: false, is_unstable: false, is_v8: false, + force_registration: false, } } #[inline] diff --git a/ops/optimizer_tests/issue16934.out b/ops/optimizer_tests/issue16934.out index 2b8df30d29..5b0b208f32 100644 --- a/ops/optimizer_tests/issue16934.out +++ b/ops/optimizer_tests/issue16934.out @@ -22,6 +22,7 @@ impl send_stdin { is_async: true, is_unstable: false, is_v8: false, + force_registration: false, } } #[inline] diff --git a/ops/optimizer_tests/issue16934_fast.out b/ops/optimizer_tests/issue16934_fast.out index cf1e416800..704329e4aa 100644 --- a/ops/optimizer_tests/issue16934_fast.out +++ b/ops/optimizer_tests/issue16934_fast.out @@ -22,6 +22,7 @@ impl send_stdin { is_async: true, is_unstable: false, is_v8: false, + force_registration: false, } } #[inline] diff --git a/ops/optimizer_tests/op_blob_revoke_object_url.out b/ops/optimizer_tests/op_blob_revoke_object_url.out index 8c5a569a50..83d3e1d04f 100644 --- a/ops/optimizer_tests/op_blob_revoke_object_url.out +++ b/ops/optimizer_tests/op_blob_revoke_object_url.out @@ -22,6 +22,7 @@ impl op_blob_revoke_object_url { is_async: false, is_unstable: false, is_v8: false, + force_registration: false, } } #[inline] diff --git a/ops/optimizer_tests/op_ffi_ptr_value.out b/ops/optimizer_tests/op_ffi_ptr_value.out index df38b72278..4a2cae2171 100644 --- a/ops/optimizer_tests/op_ffi_ptr_value.out +++ b/ops/optimizer_tests/op_ffi_ptr_value.out @@ -26,6 +26,7 @@ impl op_ffi_ptr_value { is_async: false, is_unstable: false, is_v8: false, + force_registration: false, } } #[inline] diff --git a/ops/optimizer_tests/op_print.out b/ops/optimizer_tests/op_print.out index f22553c767..38602b3c10 100644 --- a/ops/optimizer_tests/op_print.out +++ b/ops/optimizer_tests/op_print.out @@ -22,6 +22,7 @@ impl op_print { is_async: false, is_unstable: false, is_v8: false, + force_registration: false, } } #[inline] diff --git a/ops/optimizer_tests/op_state.out b/ops/optimizer_tests/op_state.out index 619a097482..f3fdb14a0f 100644 --- a/ops/optimizer_tests/op_state.out +++ b/ops/optimizer_tests/op_state.out @@ -26,6 +26,7 @@ impl op_set_exit_code { is_async: false, is_unstable: false, is_v8: false, + force_registration: false, } } #[inline] diff --git a/ops/optimizer_tests/op_state_basic1.out b/ops/optimizer_tests/op_state_basic1.out index b2926753ea..0895b7e7d1 100644 --- a/ops/optimizer_tests/op_state_basic1.out +++ b/ops/optimizer_tests/op_state_basic1.out @@ -26,6 +26,7 @@ impl foo { is_async: false, is_unstable: false, is_v8: false, + force_registration: false, } } #[inline] diff --git a/ops/optimizer_tests/op_state_generics.out b/ops/optimizer_tests/op_state_generics.out index 88eeefe148..e92e12616e 100644 --- a/ops/optimizer_tests/op_state_generics.out +++ b/ops/optimizer_tests/op_state_generics.out @@ -32,6 +32,7 @@ impl op_foo { is_async: false, is_unstable: false, is_v8: false, + force_registration: false, } } #[inline] diff --git a/ops/optimizer_tests/op_state_result.out b/ops/optimizer_tests/op_state_result.out index fb0fdb25f4..2c5c042d7a 100644 --- a/ops/optimizer_tests/op_state_result.out +++ b/ops/optimizer_tests/op_state_result.out @@ -26,6 +26,7 @@ impl foo { is_async: false, is_unstable: false, is_v8: false, + force_registration: false, } } #[inline] diff --git a/ops/optimizer_tests/op_state_warning.out b/ops/optimizer_tests/op_state_warning.out index 5a4b481c4f..ef8a8e0afc 100644 --- a/ops/optimizer_tests/op_state_warning.out +++ b/ops/optimizer_tests/op_state_warning.out @@ -26,6 +26,7 @@ impl op_listen { is_async: false, is_unstable: false, is_v8: false, + force_registration: false, } } #[inline] diff --git a/ops/optimizer_tests/op_state_with_transforms.out b/ops/optimizer_tests/op_state_with_transforms.out index 07e1fefb93..9532016f48 100644 --- a/ops/optimizer_tests/op_state_with_transforms.out +++ b/ops/optimizer_tests/op_state_with_transforms.out @@ -32,6 +32,7 @@ impl op_now { is_async: false, is_unstable: false, is_v8: false, + force_registration: false, } } #[inline] diff --git a/ops/optimizer_tests/opstate_with_arity.out b/ops/optimizer_tests/opstate_with_arity.out index ab4e905d5b..e4c6097610 100644 --- a/ops/optimizer_tests/opstate_with_arity.out +++ b/ops/optimizer_tests/opstate_with_arity.out @@ -26,6 +26,7 @@ impl op_add_4 { is_async: false, is_unstable: false, is_v8: false, + force_registration: false, } } #[inline] diff --git a/ops/optimizer_tests/option_arg.out b/ops/optimizer_tests/option_arg.out index 14dca54877..3790ef4fa6 100644 --- a/ops/optimizer_tests/option_arg.out +++ b/ops/optimizer_tests/option_arg.out @@ -22,6 +22,7 @@ impl op_try_close { is_async: false, is_unstable: false, is_v8: false, + force_registration: false, } } #[inline] diff --git a/ops/optimizer_tests/owned_string.out b/ops/optimizer_tests/owned_string.out index 62fb45ed7a..023a900718 100644 --- a/ops/optimizer_tests/owned_string.out +++ b/ops/optimizer_tests/owned_string.out @@ -26,6 +26,7 @@ impl op_string_length { is_async: false, is_unstable: false, is_v8: false, + force_registration: false, } } #[inline] diff --git a/ops/optimizer_tests/param_mut_binding_warning.out b/ops/optimizer_tests/param_mut_binding_warning.out index 3a93a738f7..1655ece761 100644 --- a/ops/optimizer_tests/param_mut_binding_warning.out +++ b/ops/optimizer_tests/param_mut_binding_warning.out @@ -22,6 +22,7 @@ impl op_read_sync { is_async: false, is_unstable: false, is_v8: false, + force_registration: false, } } #[inline] diff --git a/ops/optimizer_tests/raw_ptr.out b/ops/optimizer_tests/raw_ptr.out index 12f93f99d5..7ca92878fa 100644 --- a/ops/optimizer_tests/raw_ptr.out +++ b/ops/optimizer_tests/raw_ptr.out @@ -32,6 +32,7 @@ impl op_ffi_ptr_of { is_async: false, is_unstable: false, is_v8: false, + force_registration: false, } } #[inline] diff --git a/ops/optimizer_tests/serde_v8_value.out b/ops/optimizer_tests/serde_v8_value.out index 6ee56d4606..d8086c7f9a 100644 --- a/ops/optimizer_tests/serde_v8_value.out +++ b/ops/optimizer_tests/serde_v8_value.out @@ -26,6 +26,7 @@ impl op_is_proxy { is_async: false, is_unstable: false, is_v8: false, + force_registration: false, } } #[inline] diff --git a/ops/optimizer_tests/strings.out b/ops/optimizer_tests/strings.out index 623ff1bbb0..9712e46877 100644 --- a/ops/optimizer_tests/strings.out +++ b/ops/optimizer_tests/strings.out @@ -26,6 +26,7 @@ impl op_string_length { is_async: false, is_unstable: false, is_v8: false, + force_registration: false, } } #[inline] diff --git a/ops/optimizer_tests/strings_result.out b/ops/optimizer_tests/strings_result.out index fd847d9ca8..6ef5963a69 100644 --- a/ops/optimizer_tests/strings_result.out +++ b/ops/optimizer_tests/strings_result.out @@ -22,6 +22,7 @@ impl op_string_length { is_async: false, is_unstable: false, is_v8: false, + force_registration: false, } } #[inline] diff --git a/ops/optimizer_tests/u64_result.out b/ops/optimizer_tests/u64_result.out index efe6c9d23f..6744e65acb 100644 --- a/ops/optimizer_tests/u64_result.out +++ b/ops/optimizer_tests/u64_result.out @@ -22,6 +22,7 @@ impl op_bench_now { is_async: false, is_unstable: false, is_v8: false, + force_registration: false, } } #[inline] diff --git a/ops/optimizer_tests/uint8array.out b/ops/optimizer_tests/uint8array.out index 49926c747b..a26e25e4f3 100644 --- a/ops/optimizer_tests/uint8array.out +++ b/ops/optimizer_tests/uint8array.out @@ -26,6 +26,7 @@ impl op_import_spki_x25519 { is_async: false, is_unstable: false, is_v8: false, + force_registration: false, } } #[inline] diff --git a/ops/optimizer_tests/unit_result.out b/ops/optimizer_tests/unit_result.out index 0a66f4fe61..ab9f158df4 100644 --- a/ops/optimizer_tests/unit_result.out +++ b/ops/optimizer_tests/unit_result.out @@ -26,6 +26,7 @@ impl op_unit_result { is_async: false, is_unstable: false, is_v8: false, + force_registration: false, } } #[inline] diff --git a/ops/optimizer_tests/unit_result2.out b/ops/optimizer_tests/unit_result2.out index 045f022faf..4a03270d87 100644 --- a/ops/optimizer_tests/unit_result2.out +++ b/ops/optimizer_tests/unit_result2.out @@ -26,6 +26,7 @@ impl op_set_nodelay { is_async: false, is_unstable: false, is_v8: false, + force_registration: false, } } #[inline] diff --git a/ops/optimizer_tests/unit_ret.out b/ops/optimizer_tests/unit_ret.out index a3a0d5ea92..942d907e95 100644 --- a/ops/optimizer_tests/unit_ret.out +++ b/ops/optimizer_tests/unit_ret.out @@ -26,6 +26,7 @@ impl op_unit { is_async: false, is_unstable: false, is_v8: false, + force_registration: false, } } #[inline] diff --git a/ops/optimizer_tests/wasm_op.out b/ops/optimizer_tests/wasm_op.out index 8359262929..acc00b3b17 100644 --- a/ops/optimizer_tests/wasm_op.out +++ b/ops/optimizer_tests/wasm_op.out @@ -26,6 +26,7 @@ impl op_wasm { is_async: false, is_unstable: false, is_v8: false, + force_registration: false, } } #[inline] diff --git a/runtime/ops/fs_events.rs b/runtime/ops/fs_events.rs index 05cc22152f..27e76b3d34 100644 --- a/runtime/ops/fs_events.rs +++ b/runtime/ops/fs_events.rs @@ -30,7 +30,10 @@ use tokio::sync::mpsc; deno_core::extension!( deno_fs_events, - ops = [op_fs_events_open, op_fs_events_poll] + ops = [op_fs_events_open, op_fs_events_poll], + customizer = |ext: &mut deno_core::ExtensionBuilder| { + ext.force_op_registration(); + }, ); struct FsEventsResource { diff --git a/runtime/ops/http.rs b/runtime/ops/http.rs index b9899b4e3f..3a316d8003 100644 --- a/runtime/ops/http.rs +++ b/runtime/ops/http.rs @@ -30,6 +30,9 @@ use tokio::net::UnixStream; deno_core::extension!( deno_http_runtime, ops = [op_http_start, op_http_upgrade, op_flash_upgrade_http], + customizer = |ext: &mut deno_core::ExtensionBuilder| { + ext.force_op_registration(); + }, ); #[op] diff --git a/runtime/ops/os/mod.rs b/runtime/ops/os/mod.rs index b346293954..70a1263018 100644 --- a/runtime/ops/os/mod.rs +++ b/runtime/ops/os/mod.rs @@ -48,23 +48,23 @@ deno_core::extension!( state = |state, options| { state.put::(options.exit_code); }, + customizer = |ext: &mut deno_core::ExtensionBuilder| { + ext.force_op_registration(); + } ); deno_core::extension!( deno_os_worker, ops_fn = deno_ops, middleware = |op| match op.name { - "op_exit" => noop_op::decl(), - "op_set_exit_code" => noop_op::decl(), + "op_exit" | "op_set_exit_code" => op.disable(), _ => op, }, + customizer = |ext: &mut deno_core::ExtensionBuilder| { + ext.force_op_registration(); + } ); -#[op] -fn noop_op() -> Result<(), AnyError> { - Ok(()) -} - #[op] fn op_exec_path(state: &mut OpState) -> Result { let current_exe = env::current_exe().unwrap(); diff --git a/runtime/ops/permissions.rs b/runtime/ops/permissions.rs index c08d11e4af..6f7b98a304 100644 --- a/runtime/ops/permissions.rs +++ b/runtime/ops/permissions.rs @@ -17,7 +17,10 @@ deno_core::extension!( op_query_permission, op_revoke_permission, op_request_permission, - ] + ], + customizer = |ext: &mut deno_core::ExtensionBuilder| { + ext.force_op_registration(); + }, ); #[derive(Deserialize)] diff --git a/runtime/ops/process.rs b/runtime/ops/process.rs index a15b63f808..cf8740255d 100644 --- a/runtime/ops/process.rs +++ b/runtime/ops/process.rs @@ -107,7 +107,10 @@ deno_core::extension!( deprecated::op_run, deprecated::op_run_status, deprecated::op_kill, - ] + ], + customizer = |ext: &mut deno_core::ExtensionBuilder| { + ext.force_op_registration(); + }, ); struct ChildResource(tokio::process::Child); diff --git a/runtime/ops/runtime.rs b/runtime/ops/runtime.rs index a77e888c82..8802f9cd6c 100644 --- a/runtime/ops/runtime.rs +++ b/runtime/ops/runtime.rs @@ -12,7 +12,10 @@ deno_core::extension!( options = { main_module: ModuleSpecifier }, state = |state, options| { state.put::(options.main_module); - } + }, + customizer = |ext: &mut deno_core::ExtensionBuilder| { + ext.force_op_registration(); + }, ); #[op] diff --git a/runtime/ops/signal.rs b/runtime/ops/signal.rs index 9cc261d854..93e1cfef28 100644 --- a/runtime/ops/signal.rs +++ b/runtime/ops/signal.rs @@ -31,7 +31,10 @@ use tokio::signal::windows::CtrlC; deno_core::extension!( deno_signal, - ops = [op_signal_bind, op_signal_unbind, op_signal_poll] + ops = [op_signal_bind, op_signal_unbind, op_signal_poll], + customizer = |ext: &mut deno_core::ExtensionBuilder| { + ext.force_op_registration(); + }, ); #[cfg(unix)] diff --git a/runtime/ops/tty.rs b/runtime/ops/tty.rs index 60144e408a..3146f22e22 100644 --- a/runtime/ops/tty.rs +++ b/runtime/ops/tty.rs @@ -34,7 +34,10 @@ fn get_windows_handle( deno_core::extension!( deno_tty, - ops = [op_stdin_set_raw, op_isatty, op_console_size] + ops = [op_stdin_set_raw, op_isatty, op_console_size], + customizer = |ext: &mut deno_core::ExtensionBuilder| { + ext.force_op_registration(); + }, ); // ref: diff --git a/runtime/ops/web_worker.rs b/runtime/ops/web_worker.rs index 45137913e4..7952a03f26 100644 --- a/runtime/ops/web_worker.rs +++ b/runtime/ops/web_worker.rs @@ -24,7 +24,10 @@ deno_core::extension!( op_worker_close, op_worker_get_type, op_worker_sync_fetch, - ] + ], + customizer = |ext: &mut deno_core::ExtensionBuilder| { + ext.force_op_registration(); + }, ); #[op] diff --git a/runtime/ops/worker_host.rs b/runtime/ops/worker_host.rs index 26c99efab0..d5285ec890 100644 --- a/runtime/ops/worker_host.rs +++ b/runtime/ops/worker_host.rs @@ -118,7 +118,10 @@ deno_core::extension!( let format_js_error_fn_holder = FormatJsErrorFnHolder(options.format_js_error_fn); state.put::(format_js_error_fn_holder); - } + }, + customizer = |ext: &mut deno_core::ExtensionBuilder| { + ext.force_op_registration(); + }, ); #[derive(Deserialize)]