From b4e42953e1d243f2eda20e5be6b845d60b7bf688 Mon Sep 17 00:00:00 2001 From: Divy Srivastava Date: Mon, 14 Mar 2022 23:14:15 +0530 Subject: [PATCH] feat(core): codegen ops (#13861) Co-authored-by: Aaron O'Mullan --- Cargo.lock | 21 ++ Cargo.toml | 1 + bench_util/benches/op_baseline.rs | 33 ++- cli/build.rs | 156 ++++++---- cli/lsp/tsc.rs | 115 +++++--- cli/ops/bench.rs | 23 +- cli/ops/errors.rs | 11 +- cli/ops/runtime_compiler.rs | 8 +- cli/ops/testing.rs | 20 +- cli/tsc.rs | 183 +++++++----- cli/tsc/99_main_compiler.js | 1 + core/01_core.js | 25 +- core/Cargo.toml | 1 + core/bindings.rs | 370 ++++++++++-------------- core/error_codes.rs | 2 +- core/examples/disable_ops.rs | 2 +- core/examples/hello_world.rs | 34 ++- core/examples/http_bench_json_ops.js | 4 +- core/examples/http_bench_json_ops.rs | 13 +- core/examples/schedule_task.rs | 12 +- core/extensions.rs | 9 +- core/lib.rs | 31 +- core/modules.rs | 41 ++- core/ops.rs | 149 ++-------- core/ops_builtin.rs | 94 ++++-- core/ops_json.rs | 166 ----------- core/ops_metrics.rs | 12 +- core/runtime.rs | 299 +++++++++---------- ext/broadcast_channel/lib.rs | 49 ++-- ext/crypto/decrypt.rs | 2 + ext/crypto/encrypt.rs | 3 + ext/crypto/export_key.rs | 2 + ext/crypto/generate_key.rs | 2 + ext/crypto/import_key.rs | 3 + ext/crypto/lib.rs | 41 +-- ext/fetch/lib.rs | 16 +- ext/ffi/lib.rs | 61 ++-- ext/http/lib.rs | 31 +- ext/net/lib.rs | 5 +- ext/net/ops.rs | 34 ++- ext/net/ops_tls.rs | 19 +- ext/url/lib.rs | 27 +- ext/url/urlpattern.rs | 3 + ext/web/blob.rs | 9 + ext/web/compression.rs | 4 + ext/web/lib.rs | 88 +++--- ext/web/message_port.rs | 5 + ext/web/timers.rs | 6 + ext/webgpu/src/binding.rs | 4 + ext/webgpu/src/buffer.rs | 6 + ext/webgpu/src/bundle.rs | 13 + ext/webgpu/src/command_encoder.rs | 15 + ext/webgpu/src/compute_pass.rs | 12 + ext/webgpu/src/lib.rs | 412 ++++++--------------------- ext/webgpu/src/pipeline.rs | 5 + ext/webgpu/src/queue.rs | 4 + ext/webgpu/src/render_pass.rs | 21 ++ ext/webgpu/src/sampler.rs | 2 + ext/webgpu/src/shader.rs | 2 + ext/webgpu/src/texture.rs | 3 + ext/websocket/lib.rs | 22 +- ext/webstorage/lib.rs | 26 +- ops/Cargo.toml | 17 ++ ops/README.md | 16 ++ ops/lib.rs | 264 +++++++++++++++++ runtime/ops/fs.rs | 163 +++++++---- runtime/ops/fs_events.rs | 11 +- runtime/ops/http.rs | 5 +- runtime/ops/io.rs | 9 +- runtime/ops/os.rs | 42 ++- runtime/ops/permissions.rs | 11 +- runtime/ops/process.rs | 13 +- runtime/ops/runtime.rs | 5 +- runtime/ops/signal.rs | 16 +- runtime/ops/tty.rs | 11 +- runtime/ops/web_worker.rs | 18 +- runtime/ops/web_worker/sync_fetch.rs | 2 + runtime/ops/worker_host.rs | 22 +- 78 files changed, 1754 insertions(+), 1664 deletions(-) delete mode 100644 core/ops_json.rs create mode 100644 ops/Cargo.toml create mode 100644 ops/README.md create mode 100644 ops/lib.rs diff --git a/Cargo.lock b/Cargo.lock index 1f5aa78837..0319d4d763 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -856,6 +856,7 @@ version = "0.122.0" dependencies = [ "anyhow", "deno_ast", + "deno_ops", "futures", "indexmap", "libc", @@ -1019,6 +1020,16 @@ dependencies = [ "trust-dns-resolver", ] +[[package]] +name = "deno_ops" +version = "0.1.1" +dependencies = [ + "proc-macro-crate", + "proc-macro2 1.0.36", + "quote 1.0.14", + "syn 1.0.85", +] + [[package]] name = "deno_runtime" version = "0.48.0" @@ -2925,6 +2936,16 @@ dependencies = [ "output_vt100", ] +[[package]] +name = "proc-macro-crate" +version = "1.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e17d47ce914bf4de440332250b0edd23ce48c005f59fab39d3335866b114f11a" +dependencies = [ + "thiserror", + "toml", +] + [[package]] name = "proc-macro-error" version = "1.0.4" diff --git a/Cargo.toml b/Cargo.toml index b76cd59712..57b93944e4 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -6,6 +6,7 @@ members = [ "bench_util", "cli", "core", + "ops", "runtime", "serde_v8", "test_ffi", diff --git a/bench_util/benches/op_baseline.rs b/bench_util/benches/op_baseline.rs index 10b5a6f6e8..929e573cdb 100644 --- a/bench_util/benches/op_baseline.rs +++ b/bench_util/benches/op_baseline.rs @@ -3,11 +3,9 @@ use deno_bench_util::bencher::{benchmark_group, Bencher}; use deno_bench_util::{bench_js_async, bench_js_sync}; use deno_core::error::AnyError; -use deno_core::op_async; -use deno_core::op_sync; -use deno_core::serialize_op_result; +use deno_core::op; + use deno_core::Extension; -use deno_core::Op; use deno_core::OpState; use std::cell::RefCell; @@ -16,17 +14,25 @@ use std::rc::Rc; fn setup() -> Vec { vec![Extension::builder() .ops(vec![ - ("pi_json", op_sync(|_, _: (), _: ()| Ok(314159))), - ("pi_async", op_async(op_pi_async)), - ( - "nop", - Box::new(|state, _| Op::Sync(serialize_op_result(Ok(9), state))), - ), + op_pi_json::decl(), + op_pi_async::decl(), + op_nop::decl(), ]) .build()] } +#[op] +fn op_nop(_: &mut OpState, _: (), _: ()) -> Result<(), AnyError> { + Ok(()) +} + +#[op] +fn op_pi_json(_: &mut OpState, _: (), _: ()) -> Result { + Ok(314159) +} + // this is a function since async closures aren't stable +#[op] async fn op_pi_async( _: Rc>, _: (), @@ -36,15 +42,15 @@ async fn op_pi_async( } fn bench_op_pi_json(b: &mut Bencher) { - bench_js_sync(b, r#"Deno.core.opSync("pi_json", null);"#, setup); + bench_js_sync(b, r#"Deno.core.opSync("op_pi_json", null);"#, setup); } fn bench_op_nop(b: &mut Bencher) { - bench_js_sync(b, r#"Deno.core.opSync("nop", null, null, null);"#, setup); + bench_js_sync(b, r#"Deno.core.opSync("op_nop", null, null, null);"#, setup); } fn bench_op_async(b: &mut Bencher) { - bench_js_async(b, r#"Deno.core.opAsync("pi_async", null);"#, setup); + bench_js_async(b, r#"Deno.core.opAsync("op_pi_async", null);"#, setup); } fn bench_is_proxy(b: &mut Bencher) { @@ -58,4 +64,5 @@ benchmark_group!( bench_op_async, bench_is_proxy ); + bench_or_profile!(benches); diff --git a/cli/build.rs b/cli/build.rs index 26b27a955e..f1eb1829c4 100644 --- a/cli/build.rs +++ b/cli/build.rs @@ -1,11 +1,14 @@ // Copyright 2018-2022 the Deno authors. All rights reserved. MIT license. use deno_core::error::custom_error; -use deno_core::op_sync; +use deno_core::error::AnyError; +use deno_core::op; use deno_core::serde::Deserialize; use deno_core::serde_json::json; use deno_core::serde_json::Value; +use deno_core::Extension; use deno_core::JsRuntime; +use deno_core::OpState; use deno_core::RuntimeOptions; use regex::Regex; use std::collections::HashMap; @@ -185,79 +188,112 @@ fn create_compiler_snapshot( build_libs.push(op_lib.to_owned()); } - let re_asset = Regex::new(r"asset:/{3}lib\.(\S+)\.d\.ts").expect("bad regex"); - let build_specifier = "asset:///bootstrap.ts"; + #[op] + fn op_build_info( + state: &mut OpState, + _args: Value, + _: (), + ) -> Result { + let build_specifier = "asset:///bootstrap.ts"; + let build_libs = state.borrow::>(); + Ok(json!({ + "buildSpecifier": build_specifier, + "libs": build_libs, + })) + } - let mut js_runtime = JsRuntime::new(RuntimeOptions { - will_snapshot: true, - ..Default::default() - }); - js_runtime.register_op( - "op_build_info", - op_sync(move |_state, _args: Value, _: ()| { - Ok(json!({ - "buildSpecifier": build_specifier, - "libs": build_libs, - })) - }), - ); - js_runtime.register_op( - "op_cwd", - op_sync(move |_state, _args: Value, _: ()| Ok(json!("cache:///"))), - ); - // As of TypeScript 4.5, it tries to detect the existence of substitute lib - // files, which we currently don't use, so we just return false. - js_runtime.register_op( - "op_exists", - op_sync(move |_state, _args: LoadArgs, _: ()| Ok(json!(false))), - ); + #[op] + fn op_cwd( + _state: &mut OpState, + _args: Value, + _: (), + ) -> Result { + Ok(json!("cache:///")) + } + + #[op] + fn op_exists( + _state: &mut OpState, + _args: Value, + _: (), + ) -> Result { + Ok(json!(false)) + } + + #[op] // using the same op that is used in `tsc.rs` for loading modules and reading // files, but a slightly different implementation at build time. - js_runtime.register_op( - "op_load", - op_sync(move |_state, args: LoadArgs, _: ()| { - // we need a basic file to send to tsc to warm it up. - if args.specifier == build_specifier { + fn op_load( + state: &mut OpState, + args: LoadArgs, + _: (), + ) -> Result { + let op_crate_libs = state.borrow::>(); + let path_dts = state.borrow::(); + let re_asset = + Regex::new(r"asset:/{3}lib\.(\S+)\.d\.ts").expect("bad regex"); + let build_specifier = "asset:///bootstrap.ts"; + + // we need a basic file to send to tsc to warm it up. + if args.specifier == build_specifier { + Ok(json!({ + "data": r#"console.log("hello deno!");"#, + "hash": "1", + // this corresponds to `ts.ScriptKind.TypeScript` + "scriptKind": 3 + })) + // specifiers come across as `asset:///lib.{lib_name}.d.ts` and we need to + // parse out just the name so we can lookup the asset. + } else if let Some(caps) = re_asset.captures(&args.specifier) { + if let Some(lib) = caps.get(1).map(|m| m.as_str()) { + // if it comes from an op crate, we were supplied with the path to the + // file. + let path = if let Some(op_crate_lib) = op_crate_libs.get(lib) { + PathBuf::from(op_crate_lib).canonicalize().unwrap() + // otherwise we are will generate the path ourself + } else { + path_dts.join(format!("lib.{}.d.ts", lib)) + }; + let data = std::fs::read_to_string(path)?; Ok(json!({ - "data": r#"console.log("hello deno!");"#, + "data": data, "hash": "1", // this corresponds to `ts.ScriptKind.TypeScript` "scriptKind": 3 })) - // specifiers come across as `asset:///lib.{lib_name}.d.ts` and we need to - // parse out just the name so we can lookup the asset. - } else if let Some(caps) = re_asset.captures(&args.specifier) { - if let Some(lib) = caps.get(1).map(|m| m.as_str()) { - // if it comes from an op crate, we were supplied with the path to the - // file. - let path = if let Some(op_crate_lib) = op_crate_libs.get(lib) { - PathBuf::from(op_crate_lib).canonicalize().unwrap() - // otherwise we are will generate the path ourself - } else { - path_dts.join(format!("lib.{}.d.ts", lib)) - }; - let data = std::fs::read_to_string(path)?; - Ok(json!({ - "data": data, - "hash": "1", - // this corresponds to `ts.ScriptKind.TypeScript` - "scriptKind": 3 - })) - } else { - Err(custom_error( - "InvalidSpecifier", - format!("An invalid specifier was requested: {}", args.specifier), - )) - } } else { Err(custom_error( "InvalidSpecifier", format!("An invalid specifier was requested: {}", args.specifier), )) } - }), - ); - js_runtime.sync_ops_cache(); + } else { + Err(custom_error( + "InvalidSpecifier", + format!("An invalid specifier was requested: {}", args.specifier), + )) + } + } + let js_runtime = JsRuntime::new(RuntimeOptions { + will_snapshot: true, + extensions: vec![Extension::builder() + .ops(vec![ + op_build_info::decl(), + op_cwd::decl(), + op_exists::decl(), + op_load::decl(), + ]) + .state(move |state| { + state.put(op_crate_libs.clone()); + state.put(build_libs.clone()); + state.put(path_dts.clone()); + + Ok(()) + }) + .build()], + ..Default::default() + }); + create_snapshot(js_runtime, snapshot_path, files); } diff --git a/cli/lsp/tsc.rs b/cli/lsp/tsc.rs index b849f44e96..648045f4e7 100644 --- a/cli/lsp/tsc.rs +++ b/cli/lsp/tsc.rs @@ -27,7 +27,7 @@ use deno_core::anyhow::anyhow; use deno_core::error::custom_error; use deno_core::error::AnyError; use deno_core::located_script_name; -use deno_core::op_sync; +use deno_core::op; use deno_core::parking_lot::Mutex; use deno_core::resolve_url; use deno_core::serde::de; @@ -40,7 +40,7 @@ use deno_core::url::Url; use deno_core::Extension; use deno_core::JsRuntime; use deno_core::ModuleSpecifier; -use deno_core::OpFn; +use deno_core::OpState; use deno_core::RuntimeOptions; use deno_runtime::tokio_util::create_basic_runtime; use log::error; @@ -2502,19 +2502,6 @@ fn normalize_specifier>( .map_err(|err| err.into()) } -// buffer-less json_sync ops -fn op_lsp(op_fn: F) -> Box -where - F: Fn(&mut State, V) -> Result + 'static, - V: de::DeserializeOwned, - R: Serialize + 'static, -{ - op_sync(move |s, args, _: ()| { - let state = s.borrow_mut::(); - op_fn(state, args) - }) -} - #[derive(Debug, Deserialize, Serialize)] #[serde(rename_all = "camelCase")] struct SourceSnapshotArgs { @@ -2524,10 +2511,13 @@ struct SourceSnapshotArgs { /// The language service is dropping a reference to a source file snapshot, and /// we can drop our version of that document. +#[op] fn op_dispose( - state: &mut State, + state: &mut OpState, args: SourceSnapshotArgs, + _: (), ) -> Result { + let state = state.borrow_mut::(); let mark = state.performance.mark("op_dispose", Some(&args)); let specifier = state.normalize_specifier(&args.specifier)?; state.snapshots.remove(&(specifier, args.version.into())); @@ -2541,7 +2531,13 @@ struct SpecifierArgs { specifier: String, } -fn op_exists(state: &mut State, args: SpecifierArgs) -> Result { +#[op] +fn op_exists( + state: &mut OpState, + args: SpecifierArgs, + _: (), +) -> Result { + let state = state.borrow_mut::(); // we don't measure the performance of op_exists anymore because as of TS 4.5 // it is noisy with all the checking for custom libs, that we can't see the // forrest for the trees as well as it compounds any lsp performance @@ -2569,10 +2565,13 @@ struct GetChangeRangeArgs { /// The language service wants to compare an old snapshot with a new snapshot to /// determine what source has changed. +#[op] fn op_get_change_range( - state: &mut State, + state: &mut OpState, args: GetChangeRangeArgs, + _: (), ) -> Result { + let state = state.borrow_mut::(); let mark = state.performance.mark("op_get_change_range", Some(&args)); let specifier = state.normalize_specifier(&args.specifier)?; cache_snapshot(state, &specifier, args.version.clone())?; @@ -2613,10 +2612,13 @@ fn op_get_change_range( r } +#[op] fn op_get_length( - state: &mut State, + state: &mut OpState, args: SourceSnapshotArgs, + _: (), ) -> Result { + let state = state.borrow_mut::(); let mark = state.performance.mark("op_get_length", Some(&args)); let specifier = state.normalize_specifier(args.specifier)?; let r = if let Some(Some(asset)) = @@ -2644,10 +2646,13 @@ struct GetTextArgs { end: usize, } +#[op] fn op_get_text( - state: &mut State, + state: &mut OpState, args: GetTextArgs, + _: (), ) -> Result { + let state = state.borrow_mut::(); let mark = state.performance.mark("op_get_text", Some(&args)); let specifier = state.normalize_specifier(args.specifier)?; let maybe_asset = state.state_snapshot.assets.get_cached(&specifier); @@ -2664,14 +2669,23 @@ fn op_get_text( Ok(text::slice(content, args.start..args.end).to_string()) } -fn op_is_cancelled(state: &mut State, _: ()) -> Result { +#[op] +fn op_is_cancelled( + state: &mut OpState, + _: (), + _: (), +) -> Result { + let state = state.borrow_mut::(); Ok(state.token.is_cancelled()) } +#[op] fn op_load( - state: &mut State, + state: &mut OpState, args: SpecifierArgs, + _: (), ) -> Result, AnyError> { + let state = state.borrow_mut::(); let mark = state.performance.mark("op_load", Some(&args)); let specifier = state.normalize_specifier(args.specifier)?; let document = state.state_snapshot.documents.get(&specifier); @@ -2679,10 +2693,13 @@ fn op_load( Ok(document.map(|d| d.content().to_string())) } +#[op] fn op_resolve( - state: &mut State, + state: &mut OpState, args: ResolveArgs, + _: (), ) -> Result>, AnyError> { + let state = state.borrow_mut::(); let mark = state.performance.mark("op_resolve", Some(&args)); let referrer = state.normalize_specifier(&args.base)?; @@ -2713,15 +2730,24 @@ fn op_resolve( result } -fn op_respond(state: &mut State, args: Response) -> Result { +#[op] +fn op_respond( + state: &mut OpState, + args: Response, + _: (), +) -> Result { + let state = state.borrow_mut::(); state.response = Some(args); Ok(true) } +#[op] fn op_script_names( - state: &mut State, + state: &mut OpState, _args: Value, + _: (), ) -> Result, AnyError> { + let state = state.borrow_mut::(); Ok( state .state_snapshot @@ -2739,10 +2765,13 @@ struct ScriptVersionArgs { specifier: String, } +#[op] fn op_script_version( - state: &mut State, + state: &mut OpState, args: ScriptVersionArgs, + _: (), ) -> Result, AnyError> { + let state = state.borrow_mut::(); // this op is very "noisy" and measuring its performance is not useful, so we // don't measure it uniquely anymore. let specifier = state.normalize_specifier(args.specifier)?; @@ -2776,17 +2805,17 @@ fn js_runtime(performance: Arc) -> JsRuntime { fn init_extension(performance: Arc) -> Extension { Extension::builder() .ops(vec![ - ("op_dispose", op_lsp(op_dispose)), - ("op_exists", op_lsp(op_exists)), - ("op_get_change_range", op_lsp(op_get_change_range)), - ("op_get_length", op_lsp(op_get_length)), - ("op_get_text", op_lsp(op_get_text)), - ("op_is_cancelled", op_lsp(op_is_cancelled)), - ("op_load", op_lsp(op_load)), - ("op_resolve", op_lsp(op_resolve)), - ("op_respond", op_lsp(op_respond)), - ("op_script_names", op_lsp(op_script_names)), - ("op_script_version", op_lsp(op_script_version)), + op_dispose::decl(), + op_exists::decl(), + op_get_change_range::decl(), + op_get_length::decl(), + op_get_text::decl(), + op_is_cancelled::decl(), + op_load::decl(), + op_resolve::decl(), + op_respond::decl(), + op_script_names::decl(), + op_script_version::decl(), ]) .state(move |state| { state.put(State::new( @@ -3832,7 +3861,7 @@ mod tests { #[test] fn test_op_exists() { - let (_, state_snapshot, _) = setup( + let (mut rt, state_snapshot, _) = setup( false, json!({ "target": "esnext", @@ -3843,12 +3872,16 @@ mod tests { &[], ); let performance = Arc::new(Performance::default()); - let mut state = State::new(state_snapshot, performance); - let actual = op_exists( - &mut state, + let state = State::new(state_snapshot, performance); + let op_state = rt.op_state(); + let mut op_state = op_state.borrow_mut(); + op_state.put(state); + let actual = op_exists::call( + &mut op_state, SpecifierArgs { specifier: "/error/unknown:something/index.d.ts".to_string(), }, + (), ); assert!(actual.is_ok()); let actual = actual.unwrap(); diff --git a/cli/ops/bench.rs b/cli/ops/bench.rs index b535e12363..ab15a2b4b0 100644 --- a/cli/ops/bench.rs +++ b/cli/ops/bench.rs @@ -1,7 +1,7 @@ use crate::tools::bench::BenchEvent; use deno_core::error::generic_error; use deno_core::error::AnyError; -use deno_core::op_sync; +use deno_core::op; use deno_core::Extension; use deno_core::ModuleSpecifier; use deno_core::OpState; @@ -15,17 +15,11 @@ use uuid::Uuid; pub fn init(sender: UnboundedSender) -> Extension { Extension::builder() .ops(vec![ - ( - "op_pledge_test_permissions", - op_sync(op_pledge_test_permissions), - ), - ( - "op_restore_test_permissions", - op_sync(op_restore_test_permissions), - ), - ("op_get_bench_origin", op_sync(op_get_bench_origin)), - ("op_dispatch_bench_event", op_sync(op_dispatch_bench_event)), - ("op_bench_now", op_sync(op_bench_now)), + op_pledge_test_permissions::decl(), + op_restore_test_permissions::decl(), + op_get_bench_origin::decl(), + op_dispatch_bench_event::decl(), + op_bench_now::decl(), ]) .state(move |state| { state.put(sender.clone()); @@ -37,6 +31,7 @@ pub fn init(sender: UnboundedSender) -> Extension { #[derive(Clone)] struct PermissionsHolder(Uuid, Permissions); +#[op] pub fn op_pledge_test_permissions( state: &mut OpState, args: ChildPermissionsArg, @@ -55,6 +50,7 @@ pub fn op_pledge_test_permissions( Ok(token) } +#[op] pub fn op_restore_test_permissions( state: &mut OpState, token: Uuid, @@ -73,6 +69,7 @@ pub fn op_restore_test_permissions( } } +#[op] fn op_get_bench_origin( state: &mut OpState, _: (), @@ -81,6 +78,7 @@ fn op_get_bench_origin( Ok(state.borrow::().to_string()) } +#[op] fn op_dispatch_bench_event( state: &mut OpState, event: BenchEvent, @@ -92,6 +90,7 @@ fn op_dispatch_bench_event( Ok(()) } +#[op] fn op_bench_now(state: &mut OpState, _: (), _: ()) -> Result { let ns = state.borrow::().elapsed().as_nanos(); let ns_u64 = u64::try_from(ns)?; diff --git a/cli/ops/errors.rs b/cli/ops/errors.rs index a9193b0cda..c215ade418 100644 --- a/cli/ops/errors.rs +++ b/cli/ops/errors.rs @@ -6,7 +6,7 @@ use crate::proc_state::ProcState; use crate::source_maps::get_orig_position; use crate::source_maps::CachedMaps; use deno_core::error::AnyError; -use deno_core::op_sync; +use deno_core::op; use deno_core::serde_json; use deno_core::serde_json::json; use deno_core::serde_json::Value; @@ -19,9 +19,9 @@ use std::collections::HashMap; pub fn init() -> Extension { Extension::builder() .ops(vec![ - ("op_apply_source_map", op_sync(op_apply_source_map)), - ("op_format_diagnostic", op_sync(op_format_diagnostic)), - ("op_format_file_name", op_sync(op_format_file_name)), + op_apply_source_map::decl(), + op_format_diagnostic::decl(), + op_format_file_name::decl(), ]) .build() } @@ -42,6 +42,7 @@ struct AppliedSourceMap { column_number: u32, } +#[op] fn op_apply_source_map( state: &mut OpState, args: ApplySourceMap, @@ -66,6 +67,7 @@ fn op_apply_source_map( }) } +#[op] fn op_format_diagnostic( _state: &mut OpState, args: Value, @@ -75,6 +77,7 @@ fn op_format_diagnostic( Ok(json!(diagnostic.to_string())) } +#[op] fn op_format_file_name( _state: &mut OpState, file_name: String, diff --git a/cli/ops/runtime_compiler.rs b/cli/ops/runtime_compiler.rs index 3df93862d6..6fb8d688c6 100644 --- a/cli/ops/runtime_compiler.rs +++ b/cli/ops/runtime_compiler.rs @@ -16,7 +16,8 @@ use deno_core::anyhow::Context; use deno_core::error::custom_error; use deno_core::error::generic_error; use deno_core::error::AnyError; -use deno_core::op_async; + +use deno_core::op; use deno_core::parking_lot::RwLock; use deno_core::resolve_url_or_path; use deno_core::serde_json; @@ -35,9 +36,7 @@ use std::rc::Rc; use std::sync::Arc; pub fn init() -> Extension { - Extension::builder() - .ops(vec![("op_emit", op_async(op_emit))]) - .build() + Extension::builder().ops(vec![op_emit::decl()]).build() } #[derive(Debug, Deserialize)] @@ -141,6 +140,7 @@ fn to_maybe_jsx_import_source_module( } } +#[op] async fn op_emit( state: Rc>, args: EmitArgs, diff --git a/cli/ops/testing.rs b/cli/ops/testing.rs index b8995db83d..ebaa819e1b 100644 --- a/cli/ops/testing.rs +++ b/cli/ops/testing.rs @@ -1,7 +1,7 @@ use crate::tools::test::TestEvent; use deno_core::error::generic_error; use deno_core::error::AnyError; -use deno_core::op_sync; +use deno_core::op; use deno_core::Extension; use deno_core::ModuleSpecifier; use deno_core::OpState; @@ -14,16 +14,10 @@ use uuid::Uuid; pub fn init(sender: UnboundedSender) -> Extension { Extension::builder() .ops(vec![ - ( - "op_pledge_test_permissions", - op_sync(op_pledge_test_permissions), - ), - ( - "op_restore_test_permissions", - op_sync(op_restore_test_permissions), - ), - ("op_get_test_origin", op_sync(op_get_test_origin)), - ("op_dispatch_test_event", op_sync(op_dispatch_test_event)), + op_pledge_test_permissions::decl(), + op_restore_test_permissions::decl(), + op_get_test_origin::decl(), + op_dispatch_test_event::decl(), ]) .state(move |state| { state.put(sender.clone()); @@ -35,6 +29,7 @@ pub fn init(sender: UnboundedSender) -> Extension { #[derive(Clone)] struct PermissionsHolder(Uuid, Permissions); +#[op] pub fn op_pledge_test_permissions( state: &mut OpState, args: ChildPermissionsArg, @@ -53,6 +48,7 @@ pub fn op_pledge_test_permissions( Ok(token) } +#[op] pub fn op_restore_test_permissions( state: &mut OpState, token: Uuid, @@ -71,6 +67,7 @@ pub fn op_restore_test_permissions( } } +#[op] fn op_get_test_origin( state: &mut OpState, _: (), @@ -79,6 +76,7 @@ fn op_get_test_origin( Ok(state.borrow::().to_string()) } +#[op] fn op_dispatch_test_event( state: &mut OpState, event: TestEvent, diff --git a/cli/tsc.rs b/cli/tsc.rs index 421d95dc59..ddb8a442e8 100644 --- a/cli/tsc.rs +++ b/cli/tsc.rs @@ -11,18 +11,18 @@ use deno_core::anyhow::anyhow; use deno_core::anyhow::Context; use deno_core::error::AnyError; use deno_core::located_script_name; -use deno_core::op_sync; +use deno_core::op; use deno_core::parking_lot::RwLock; use deno_core::resolve_url_or_path; -use deno_core::serde::de; use deno_core::serde::Deserialize; use deno_core::serde::Serialize; use deno_core::serde_json; use deno_core::serde_json::json; use deno_core::serde_json::Value; +use deno_core::Extension; use deno_core::JsRuntime; use deno_core::ModuleSpecifier; -use deno_core::OpFn; +use deno_core::OpState; use deno_core::RuntimeOptions; use deno_core::Snapshot; use deno_graph::Resolved; @@ -298,18 +298,6 @@ fn normalize_specifier(specifier: &str) -> Result { .map_err(|err| err.into()) } -fn op(op_fn: F) -> Box -where - F: Fn(&mut State, V) -> Result + 'static, - V: de::DeserializeOwned, - R: Serialize + 'static, -{ - op_sync(move |s, args, _: ()| { - let state = s.borrow_mut::(); - op_fn(state, args) - }) -} - #[derive(Debug, Deserialize)] #[serde(rename_all = "camelCase")] struct CreateHashArgs { @@ -318,7 +306,13 @@ struct CreateHashArgs { data: String, } -fn op_create_hash(state: &mut State, args: Value) -> Result { +#[op] +fn op_create_hash( + s: &mut OpState, + args: Value, + _: (), +) -> Result { + let state = s.borrow_mut::(); let v: CreateHashArgs = serde_json::from_value(args) .context("Invalid request from JavaScript for \"op_create_hash\".")?; let mut data = vec![v.data.as_bytes().to_owned()]; @@ -327,7 +321,9 @@ fn op_create_hash(state: &mut State, args: Value) -> Result { Ok(json!({ "hash": hash })) } -fn op_cwd(state: &mut State, _args: Value) -> Result { +#[op] +fn op_cwd(s: &mut OpState, _args: Value, _: ()) -> Result { + let state = s.borrow_mut::(); if let Some(config_specifier) = &state.maybe_config_specifier { let cwd = config_specifier.join("./")?; Ok(cwd.to_string()) @@ -350,7 +346,13 @@ struct EmitArgs { maybe_specifiers: Option>, } -fn op_emit(state: &mut State, args: EmitArgs) -> Result { +#[op] +fn op_emit( + state: &mut OpState, + args: EmitArgs, + _: (), +) -> Result { + let state = state.borrow_mut::(); match args.file_name.as_ref() { "deno:///.tsbuildinfo" => state.maybe_tsbuildinfo = Some(args.data), _ => { @@ -403,7 +405,13 @@ struct ExistsArgs { specifier: String, } -fn op_exists(state: &mut State, args: ExistsArgs) -> Result { +#[op] +fn op_exists( + state: &mut OpState, + args: ExistsArgs, + _: (), +) -> Result { + let state = state.borrow_mut::(); let graph_data = state.graph_data.read(); if let Ok(specifier) = normalize_specifier(&args.specifier) { if specifier.scheme() == "asset" || specifier.scheme() == "data" { @@ -443,7 +451,9 @@ fn as_ts_script_kind(media_type: &MediaType) -> i32 { } } -fn op_load(state: &mut State, args: Value) -> Result { +#[op] +fn op_load(state: &mut OpState, args: Value, _: ()) -> Result { + let state = state.borrow_mut::(); let v: LoadArgs = serde_json::from_value(args) .context("Invalid request from JavaScript for \"op_load\".")?; let specifier = normalize_specifier(&v.specifier) @@ -507,7 +517,13 @@ pub struct ResolveArgs { pub specifiers: Vec, } -fn op_resolve(state: &mut State, args: ResolveArgs) -> Result { +#[op] +fn op_resolve( + state: &mut OpState, + args: ResolveArgs, + _: (), +) -> Result { + let state = state.borrow_mut::(); let mut resolved: Vec<(String, String)> = Vec::new(); let referrer = if let Some(remapped_specifier) = state.remapped_specifiers.get(&args.base) @@ -612,7 +628,13 @@ struct RespondArgs { pub stats: emit::Stats, } -fn op_respond(state: &mut State, args: Value) -> Result { +#[op] +fn op_respond( + state: &mut OpState, + args: Value, + _: (), +) -> Result { + let state = state.borrow_mut::(); let v: RespondArgs = serde_json::from_value(args) .context("Error converting the result for \"op_respond\".")?; state.maybe_response = Some(v); @@ -623,10 +645,6 @@ fn op_respond(state: &mut State, args: Value) -> Result { /// contains information, like any emitted files, diagnostics, statistics and /// optionally an updated TypeScript build info. pub(crate) fn exec(request: Request) -> Result { - let mut runtime = JsRuntime::new(RuntimeOptions { - startup_snapshot: Some(compiler_snapshot()), - ..Default::default() - }); // tsc cannot handle root specifiers that don't have one of the "acceptable" // extensions. Therefore, we have to check the root modules against their // extensions and remap any that are unacceptable to tsc and add them to the @@ -654,28 +672,32 @@ pub(crate) fn exec(request: Request) -> Result { } }) .collect(); - - { - let op_state = runtime.op_state(); - let mut op_state = op_state.borrow_mut(); - op_state.put(State::new( - request.graph_data, - request.hash_data.clone(), - request.maybe_config_specifier.clone(), - request.maybe_tsbuildinfo.clone(), - root_map, - remapped_specifiers, - )); - } - - runtime.register_op("op_cwd", op(op_cwd)); - runtime.register_op("op_create_hash", op(op_create_hash)); - runtime.register_op("op_emit", op(op_emit)); - runtime.register_op("op_exists", op(op_exists)); - runtime.register_op("op_load", op(op_load)); - runtime.register_op("op_resolve", op(op_resolve)); - runtime.register_op("op_respond", op(op_respond)); - runtime.sync_ops_cache(); + let mut runtime = JsRuntime::new(RuntimeOptions { + startup_snapshot: Some(compiler_snapshot()), + extensions: vec![Extension::builder() + .ops(vec![ + op_cwd::decl(), + op_create_hash::decl(), + op_emit::decl(), + op_exists::decl(), + op_load::decl(), + op_resolve::decl(), + op_respond::decl(), + ]) + .state(move |state| { + state.put(State::new( + request.graph_data.clone(), + request.hash_data.clone(), + request.maybe_config_specifier.clone(), + request.maybe_tsbuildinfo.clone(), + root_map.clone(), + remapped_specifiers.clone(), + )); + Ok(()) + }) + .build()], + ..Default::default() + }); let startup_source = "globalThis.startup({ legacyFlag: false })"; let request_value = json!({ @@ -720,6 +742,7 @@ mod tests { use crate::diagnostics::DiagnosticCategory; use crate::emit::Stats; use deno_core::futures::future; + use deno_core::OpState; use deno_graph::ModuleKind; use std::fs; @@ -757,7 +780,7 @@ mod tests { maybe_specifier: Option, maybe_hash_data: Option>>, maybe_tsbuildinfo: Option, - ) -> State { + ) -> OpState { let specifier = maybe_specifier .unwrap_or_else(|| resolve_url_or_path("file:///main.ts").unwrap()); let hash_data = maybe_hash_data.unwrap_or_else(|| vec![b"".to_vec()]); @@ -774,14 +797,17 @@ mod tests { None, ) .await; - State::new( + let state = State::new( Arc::new(RwLock::new((&graph).into())), hash_data, None, maybe_tsbuildinfo, HashMap::new(), HashMap::new(), - ) + ); + let mut op_state = OpState::new(1); + op_state.put(state); + op_state } async fn test_exec( @@ -852,9 +878,12 @@ mod tests { #[tokio::test] async fn test_create_hash() { let mut state = setup(None, Some(vec![b"something".to_vec()]), None).await; - let actual = - op_create_hash(&mut state, json!({ "data": "some sort of content" })) - .expect("could not invoke op"); + let actual = op_create_hash::call( + &mut state, + json!({ "data": "some sort of content" }), + (), + ) + .expect("could not invoke op"); assert_eq!( actual, json!({"hash": "ae92df8f104748768838916857a1623b6a3c593110131b0a00f81ad9dac16511"}) @@ -898,16 +927,18 @@ mod tests { #[tokio::test] async fn test_emit() { let mut state = setup(None, None, None).await; - let actual = op_emit( + let actual = op_emit::call( &mut state, EmitArgs { data: "some file content".to_string(), file_name: "cache:///some/file.js".to_string(), maybe_specifiers: Some(vec!["file:///some/file.ts".to_string()]), }, + (), ) .expect("should have invoked op"); assert_eq!(actual, json!(true)); + let state = state.borrow::(); assert_eq!(state.emitted_files.len(), 1); assert!(state.maybe_tsbuildinfo.is_none()); assert_eq!( @@ -926,7 +957,7 @@ mod tests { #[tokio::test] async fn test_emit_strange_specifier() { let mut state = setup(None, None, None).await; - let actual = op_emit( + let actual = op_emit::call( &mut state, EmitArgs { data: "some file content".to_string(), @@ -935,9 +966,11 @@ mod tests { vec!["file:///some/file.ts?q=.json".to_string()], ), }, + (), ) .expect("should have invoked op"); assert_eq!(actual, json!(true)); + let state = state.borrow::(); assert_eq!(state.emitted_files.len(), 1); assert!(state.maybe_tsbuildinfo.is_none()); assert_eq!( @@ -956,16 +989,18 @@ mod tests { #[tokio::test] async fn test_emit_tsbuildinfo() { let mut state = setup(None, None, None).await; - let actual = op_emit( + let actual = op_emit::call( &mut state, EmitArgs { data: "some file content".to_string(), file_name: "deno:///.tsbuildinfo".to_string(), maybe_specifiers: None, }, + (), ) .expect("should have invoked op"); assert_eq!(actual, json!(true)); + let state = state.borrow::(); assert_eq!(state.emitted_files.len(), 0); assert_eq!( state.maybe_tsbuildinfo, @@ -981,9 +1016,10 @@ mod tests { Some("some content".to_string()), ) .await; - let actual = op_load( + let actual = op_load::call( &mut state, json!({ "specifier": "https://deno.land/x/mod.ts"}), + (), ) .expect("should have invoked op"); assert_eq!( @@ -1012,9 +1048,12 @@ mod tests { Some("some content".to_string()), ) .await; - let value = - op_load(&mut state, json!({ "specifier": "asset:///lib.dom.d.ts" })) - .expect("should have invoked op"); + let value = op_load::call( + &mut state, + json!({ "specifier": "asset:///lib.dom.d.ts" }), + (), + ) + .expect("should have invoked op"); let actual: LoadResponse = serde_json::from_value(value).expect("failed to deserialize"); let expected = get_asset("lib.dom.d.ts").unwrap(); @@ -1031,9 +1070,12 @@ mod tests { Some("some content".to_string()), ) .await; - let actual = - op_load(&mut state, json!({ "specifier": "deno:///.tsbuildinfo"})) - .expect("should have invoked op"); + let actual = op_load::call( + &mut state, + json!({ "specifier": "deno:///.tsbuildinfo"}), + (), + ) + .expect("should have invoked op"); assert_eq!( actual, json!({ @@ -1047,9 +1089,10 @@ mod tests { #[tokio::test] async fn test_load_missing_specifier() { let mut state = setup(None, None, None).await; - let actual = op_load( + let actual = op_load::call( &mut state, json!({ "specifier": "https://deno.land/x/mod.ts"}), + (), ) .expect("should have invoked op"); assert_eq!( @@ -1070,12 +1113,13 @@ mod tests { None, ) .await; - let actual = op_resolve( + let actual = op_resolve::call( &mut state, ResolveArgs { base: "https://deno.land/x/a.ts".to_string(), specifiers: vec!["./b.ts".to_string()], }, + (), ) .expect("should have invoked op"); assert_eq!(actual, json!([["https://deno.land/x/b.ts", ".ts"]])); @@ -1089,12 +1133,13 @@ mod tests { None, ) .await; - let actual = op_resolve( + let actual = op_resolve::call( &mut state, ResolveArgs { base: "https://deno.land/x/a.ts".to_string(), specifiers: vec!["./bad.ts".to_string()], }, + (), ) .expect("should have not errored"); assert_eq!( @@ -1106,7 +1151,7 @@ mod tests { #[tokio::test] async fn test_respond() { let mut state = setup(None, None, None).await; - let actual = op_respond( + let actual = op_respond::call( &mut state, json!({ "diagnostics": [ @@ -1118,9 +1163,11 @@ mod tests { ], "stats": [["a", 12]] }), + (), ) .expect("should have invoked op"); assert_eq!(actual, json!(true)); + let state = state.borrow::(); assert_eq!( state.maybe_response, Some(RespondArgs { diff --git a/cli/tsc/99_main_compiler.js b/cli/tsc/99_main_compiler.js index 7215360a02..c124703a8c 100644 --- a/cli/tsc/99_main_compiler.js +++ b/cli/tsc/99_main_compiler.js @@ -921,6 +921,7 @@ delete Object.prototype.__proto__; // A build time only op that provides some setup information that is used to // ensure the snapshot is setup properly. /** @type {{ buildSpecifier: string; libs: string[] }} */ + const { buildSpecifier, libs } = core.opSync("op_build_info", {}); for (const lib of libs) { const specifier = `lib.${lib}.d.ts`; diff --git a/core/01_core.js b/core/01_core.js index b6c72e5d21..747d692414 100644 --- a/core/01_core.js +++ b/core/01_core.js @@ -16,7 +16,6 @@ ErrorCaptureStackTrace, Promise, ObjectEntries, - ObjectFreeze, ObjectFromEntries, MapPrototypeGet, MapPrototypeDelete, @@ -27,11 +26,12 @@ ObjectAssign, SymbolFor, } = window.__bootstrap.primordials; + const ops = window.Deno.core.ops; + const opIds = Object.keys(ops).reduce((a, v, i) => ({ ...a, [v]: i }), {}); // Available on start due to bindings. - const { opcallSync, opcallAsync, refOp_, unrefOp_ } = window.Deno.core; + const { refOp_, unrefOp_ } = window.Deno.core; - let opsCache = {}; const errorMap = {}; // Builtin v8 / JS errors registerErrorClass("Error", Error); @@ -110,15 +110,6 @@ return promiseRing[idx] != NO_PROMISE; } - function ops() { - return opsCache; - } - - function syncOpsCache() { - // op id 0 is a special value to retrieve the map of registered ops. - opsCache = ObjectFreeze(ObjectFromEntries(opcallSync(0))); - } - function opresolve() { for (let i = 0; i < arguments.length; i += 2) { const promiseId = arguments[i]; @@ -160,7 +151,7 @@ function opAsync(opName, arg1 = null, arg2 = null) { const promiseId = nextPromiseId++; - const maybeError = opcallAsync(opsCache[opName], promiseId, arg1, arg2); + const maybeError = ops[opName](opIds[opName], promiseId, arg1, arg2); // Handle sync error (e.g: error parsing args) if (maybeError) return unwrapOpResult(maybeError); let p = PromisePrototypeThen(setPromise(promiseId), unwrapOpResult); @@ -179,8 +170,8 @@ return p; } - function opSync(opName, arg1 = null, arg2 = null) { - return unwrapOpResult(opcallSync(opsCache[opName], arg1, arg2)); + function opSync(opName, arg1, arg2) { + return unwrapOpResult(ops[opName](opIds[opName], arg1, arg2)); } function refOp(promiseId) { @@ -228,7 +219,7 @@ function metrics() { const [aggregate, perOps] = opSync("op_metrics"); aggregate.ops = ObjectFromEntries(ArrayPrototypeMap( - ObjectEntries(opsCache), + ObjectEntries(opIds), ([opName, opId]) => [opName, perOps[opId]], )); return aggregate; @@ -257,7 +248,6 @@ const core = ObjectAssign(globalThis.Deno.core, { opAsync, opSync, - ops, close, tryClose, read, @@ -269,7 +259,6 @@ registerErrorBuilder, registerErrorClass, opresolve, - syncOpsCache, BadResource, BadResourcePrototype, Interrupted, diff --git a/core/Cargo.toml b/core/Cargo.toml index db18b025e4..b8ae6bff44 100644 --- a/core/Cargo.toml +++ b/core/Cargo.toml @@ -14,6 +14,7 @@ path = "lib.rs" [dependencies] anyhow = "1.0.55" +deno_ops = { path = "../ops", version = "0.1.0" } futures = "0.3.21" indexmap = "1.7.0" libc = "0.2.106" diff --git a/core/bindings.rs b/core/bindings.rs index f84711abf7..4e5c68675a 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::extensions::OpPair; use crate::modules::get_module_type_from_assertions; use crate::modules::parse_import_assertions; use crate::modules::validate_import_assertions; @@ -8,21 +9,18 @@ use crate::modules::ImportAssertionsKind; use crate::modules::ModuleMap; use crate::resolve_url_or_path; use crate::JsRuntime; -use crate::Op; -use crate::OpId; -use crate::OpPayload; -use crate::OpResult; -use crate::OpTable; +use crate::OpState; use crate::PromiseId; use crate::ZeroCopyBuf; use anyhow::Error; use log::debug; -use once_cell::sync::Lazy; use serde::Deserialize; use serde::Serialize; use serde_v8::to_v8; use std::cell::RefCell; use std::option::Option; +use std::os::raw::c_void; +use std::rc::Rc; use url::Url; use v8::HandleScope; use v8::Local; @@ -31,88 +29,88 @@ use v8::SharedArrayBuffer; use v8::ValueDeserializerHelper; use v8::ValueSerializerHelper; -const UNDEFINED_OP_ID_MSG: &str = - "invalid op id: received `undefined` instead of an integer. -This error is often caused by a typo in an op name, or not calling -JsRuntime::sync_ops_cache() after JsRuntime initialization."; - -pub static EXTERNAL_REFERENCES: Lazy = - Lazy::new(|| { - v8::ExternalReferences::new(&[ - v8::ExternalReference { - function: opcall_async.map_fn_to(), - }, - v8::ExternalReference { - function: opcall_sync.map_fn_to(), - }, - v8::ExternalReference { - function: ref_op.map_fn_to(), - }, - v8::ExternalReference { - function: unref_op.map_fn_to(), - }, - v8::ExternalReference { - function: set_macrotask_callback.map_fn_to(), - }, - v8::ExternalReference { - function: set_nexttick_callback.map_fn_to(), - }, - v8::ExternalReference { - function: set_promise_reject_callback.map_fn_to(), - }, - v8::ExternalReference { - function: set_uncaught_exception_callback.map_fn_to(), - }, - v8::ExternalReference { - function: run_microtasks.map_fn_to(), - }, - v8::ExternalReference { - function: has_tick_scheduled.map_fn_to(), - }, - v8::ExternalReference { - function: set_has_tick_scheduled.map_fn_to(), - }, - v8::ExternalReference { - function: eval_context.map_fn_to(), - }, - v8::ExternalReference { - function: queue_microtask.map_fn_to(), - }, - v8::ExternalReference { - function: create_host_object.map_fn_to(), - }, - v8::ExternalReference { - function: encode.map_fn_to(), - }, - v8::ExternalReference { - function: decode.map_fn_to(), - }, - v8::ExternalReference { - function: serialize.map_fn_to(), - }, - v8::ExternalReference { - function: deserialize.map_fn_to(), - }, - v8::ExternalReference { - function: get_promise_details.map_fn_to(), - }, - v8::ExternalReference { - function: get_proxy_details.map_fn_to(), - }, - v8::ExternalReference { - function: is_proxy.map_fn_to(), - }, - v8::ExternalReference { - function: memory_usage.map_fn_to(), - }, - v8::ExternalReference { - function: call_console.map_fn_to(), - }, - v8::ExternalReference { - function: set_wasm_streaming_callback.map_fn_to(), - }, - ]) +pub fn external_references( + ops: &[OpPair], + op_state: Rc>, +) -> v8::ExternalReferences { + let mut refs = vec![ + v8::ExternalReference { + function: ref_op.map_fn_to(), + }, + v8::ExternalReference { + function: unref_op.map_fn_to(), + }, + v8::ExternalReference { + function: set_macrotask_callback.map_fn_to(), + }, + v8::ExternalReference { + function: set_nexttick_callback.map_fn_to(), + }, + v8::ExternalReference { + function: set_promise_reject_callback.map_fn_to(), + }, + v8::ExternalReference { + function: set_uncaught_exception_callback.map_fn_to(), + }, + v8::ExternalReference { + function: run_microtasks.map_fn_to(), + }, + v8::ExternalReference { + function: has_tick_scheduled.map_fn_to(), + }, + v8::ExternalReference { + function: set_has_tick_scheduled.map_fn_to(), + }, + v8::ExternalReference { + function: eval_context.map_fn_to(), + }, + v8::ExternalReference { + function: queue_microtask.map_fn_to(), + }, + v8::ExternalReference { + function: create_host_object.map_fn_to(), + }, + v8::ExternalReference { + function: encode.map_fn_to(), + }, + v8::ExternalReference { + function: decode.map_fn_to(), + }, + v8::ExternalReference { + function: serialize.map_fn_to(), + }, + v8::ExternalReference { + function: deserialize.map_fn_to(), + }, + v8::ExternalReference { + function: get_promise_details.map_fn_to(), + }, + v8::ExternalReference { + function: get_proxy_details.map_fn_to(), + }, + v8::ExternalReference { + function: is_proxy.map_fn_to(), + }, + v8::ExternalReference { + function: memory_usage.map_fn_to(), + }, + v8::ExternalReference { + function: call_console.map_fn_to(), + }, + v8::ExternalReference { + function: set_wasm_streaming_callback.map_fn_to(), + }, + ]; + let op_refs = ops + .iter() + .map(|(_, opref)| v8::ExternalReference { function: *opref }); + refs.extend(op_refs); + let raw_op_state = Rc::as_ptr(&op_state) as *mut c_void; + refs.push(v8::ExternalReference { + pointer: raw_op_state, }); + v8::ExternalReferences::new(&refs) +} pub fn script_origin<'a>( s: &mut v8::HandleScope<'a>, @@ -154,6 +152,9 @@ pub fn module_origin<'a>( pub fn initialize_context<'s>( scope: &mut v8::HandleScope<'s, ()>, + ops: &[OpPair], + snapshot_loaded: bool, + op_state: Rc>, ) -> v8::Local<'s, v8::Context> { let scope = &mut v8::EscapableHandleScope::new(scope); @@ -162,17 +163,43 @@ pub fn initialize_context<'s>( let scope = &mut v8::ContextScope::new(scope, context); - // global.Deno = { core: {} }; let deno_key = v8::String::new(scope, "Deno").unwrap(); + let core_key = v8::String::new(scope, "core").unwrap(); + let ops_key = v8::String::new(scope, "ops").unwrap(); + // Snapshot already registered `Deno.core.ops` but + // extensions may provide ops that aren't part of the snapshot. + // + // TODO(@littledivy): This is extra complexity for + // a really weird usecase. Remove this once all + // tsc ops are static at snapshot time. + if snapshot_loaded { + // Grab Deno.core.ops object + let deno_val = global.get(scope, deno_key.into()).unwrap(); + let deno_val = v8::Local::::try_from(deno_val) + .expect("`Deno` not in global scope."); + let core_val = deno_val.get(scope, core_key.into()).unwrap(); + let core_val = v8::Local::::try_from(core_val) + .expect("`Deno.core` not in global scope"); + let ops_val = core_val.get(scope, ops_key.into()).unwrap(); + let ops_val = v8::Local::::try_from(ops_val) + .expect("`Deno.core.ops` not in global scope"); + + let raw_op_state = Rc::as_ptr(&op_state) as *const c_void; + for (name, opfn) in ops { + set_func_raw(scope, ops_val, name, *opfn, raw_op_state); + } + return scope.escape(context); + } + + // global.Deno = { core: { ops: {} } }; let deno_val = v8::Object::new(scope); global.set(scope, deno_key.into(), deno_val.into()); - let core_key = v8::String::new(scope, "core").unwrap(); let core_val = v8::Object::new(scope); deno_val.set(scope, core_key.into(), core_val.into()); + let ops_val = v8::Object::new(scope); + core_val.set(scope, ops_key.into(), ops_val.into()); // Bind functions to Deno.core.* - set_func(scope, core_val, "opcallSync", opcall_sync); - set_func(scope, core_val, "opcallAsync", opcall_async); set_func(scope, core_val, "refOp_", ref_op); set_func(scope, core_val, "unrefOp_", unref_op); set_func( @@ -227,10 +254,14 @@ pub fn initialize_context<'s>( // Direct bindings on `window`. set_func(scope, global, "queueMicrotask", queue_microtask); + // Bind functions to Deno.core.ops.* + let raw_op_state = Rc::as_ptr(&op_state) as *const c_void; + for (name, opfn) in ops { + set_func_raw(scope, ops_val, name, *opfn, raw_op_state); + } scope.escape(context) } -#[inline(always)] pub fn set_func( scope: &mut v8::HandleScope<'_>, obj: v8::Local, @@ -238,8 +269,26 @@ pub fn set_func( callback: impl v8::MapFnTo, ) { let key = v8::String::new(scope, name).unwrap(); - let tmpl = v8::FunctionTemplate::new(scope, callback); - let val = tmpl.get_function(scope).unwrap(); + let val = v8::Function::new(scope, callback).unwrap(); + val.set_name(key); + obj.set(scope, key.into(), val.into()); +} + +// Register a raw v8::FunctionCallback +// with some external data. +pub fn set_func_raw( + scope: &mut v8::HandleScope<'_>, + obj: v8::Local, + name: &'static str, + callback: v8::FunctionCallback, + external_data: *const c_void, +) { + let key = v8::String::new(scope, name).unwrap(); + let external = v8::External::new(scope, external_data as *mut c_void); + let val = v8::Function::builder_raw(callback) + .data(external.into()) + .build(scope) + .unwrap(); val.set_name(key); obj.set(scope, key.into(), val.into()); } @@ -460,137 +509,6 @@ pub extern "C" fn promise_reject_callback(message: v8::PromiseRejectMessage) { } } -fn opcall_sync<'s>( - scope: &mut v8::HandleScope<'s>, - args: v8::FunctionCallbackArguments, - mut rv: v8::ReturnValue, -) { - let state_rc = JsRuntime::state(scope); - let state = state_rc.borrow_mut(); - - let op_id = match v8::Local::::try_from(args.get(0)) - .map(|l| l.value() as OpId) - .map_err(Error::from) - { - Ok(op_id) => op_id, - Err(err) => { - let msg = if args.get(0).is_undefined() { - UNDEFINED_OP_ID_MSG.to_string() - } else { - format!("invalid op id: {}", err) - }; - throw_type_error(scope, msg); - return; - } - }; - - // opcall(0) returns obj of all ops, handle as special case - if op_id == 0 { - // TODO: Serialize as HashMap when serde_v8 supports maps ... - let ops = OpTable::op_entries(state.op_state.clone()); - rv.set(to_v8(scope, ops).unwrap()); - return; - } - - // Deserializable args (may be structured args or ZeroCopyBuf) - let a = args.get(1); - let b = args.get(2); - - let payload = OpPayload { - scope, - a, - b, - op_id, - promise_id: 0, - }; - let op = OpTable::route_op(op_id, state.op_state.clone(), payload); - match op { - Op::Sync(result) => { - state.op_state.borrow().tracker.track_sync(op_id); - rv.set(result.to_v8(scope).unwrap()); - } - Op::NotFound => { - throw_type_error(scope, format!("Unknown op id: {}", op_id)); - } - // Async ops (ref or unref) - _ => { - throw_type_error( - scope, - format!("Can not call an async op [{}] with opSync()", op_id), - ); - } - } -} - -fn opcall_async<'s>( - scope: &mut v8::HandleScope<'s>, - args: v8::FunctionCallbackArguments, - mut rv: v8::ReturnValue, -) { - let state_rc = JsRuntime::state(scope); - let mut state = state_rc.borrow_mut(); - - let op_id = match v8::Local::::try_from(args.get(0)) - .map(|l| l.value() as OpId) - .map_err(Error::from) - { - Ok(op_id) => op_id, - Err(err) => { - let msg = if args.get(0).is_undefined() { - UNDEFINED_OP_ID_MSG.to_string() - } else { - format!("invalid op id: {}", err) - }; - throw_type_error(scope, msg); - return; - } - }; - - // PromiseId - let arg1 = args.get(1); - let promise_id = v8::Local::::try_from(arg1) - .map(|l| l.value() as PromiseId) - .map_err(Error::from); - // Fail if promise id invalid (not an int) - let promise_id: PromiseId = match promise_id { - Ok(promise_id) => promise_id, - Err(err) => { - throw_type_error(scope, format!("invalid promise id: {}", err)); - return; - } - }; - - // Deserializable args (may be structured args or ZeroCopyBuf) - let a = args.get(2); - let b = args.get(3); - - let payload = OpPayload { - scope, - a, - b, - op_id, - promise_id, - }; - let op = OpTable::route_op(op_id, state.op_state.clone(), payload); - match op { - Op::Sync(result) => match result { - OpResult::Ok(_) => throw_type_error( - scope, - format!("Can not call a sync op [{}] with opAsync()", op_id), - ), - OpResult::Err(_) => rv.set(result.to_v8(scope).unwrap()), - }, - Op::Async(fut) => { - state.op_state.borrow().tracker.track_async(op_id); - state.pending_ops.push(fut); - state.have_unpolled_ops = true; - } - Op::NotFound => { - throw_type_error(scope, format!("Unknown op id: {}", op_id)); - } - } -} - fn ref_op<'s>( scope: &mut v8::HandleScope<'s>, args: v8::FunctionCallbackArguments, @@ -1471,7 +1389,7 @@ fn is_proxy( rv.set(v8::Boolean::new(scope, args.get(0).is_proxy()).into()) } -fn throw_type_error(scope: &mut v8::HandleScope, message: impl AsRef) { +pub fn throw_type_error(scope: &mut v8::HandleScope, message: impl AsRef) { let message = v8::String::new(scope, message.as_ref()).unwrap(); let exception = v8::Exception::type_error(scope, message); scope.throw_exception(exception); diff --git a/core/error_codes.rs b/core/error_codes.rs index 43a6c43919..b34cbe639f 100644 --- a/core/error_codes.rs +++ b/core/error_codes.rs @@ -1,6 +1,6 @@ use anyhow::Error; -pub(crate) fn get_error_code(err: &Error) -> Option<&'static str> { +pub fn get_error_code(err: &Error) -> Option<&'static str> { err .downcast_ref::() .map(|e| match e.raw_os_error() { diff --git a/core/examples/disable_ops.rs b/core/examples/disable_ops.rs index 0612845c8c..9565d6e7f7 100644 --- a/core/examples/disable_ops.rs +++ b/core/examples/disable_ops.rs @@ -9,7 +9,7 @@ use deno_core::RuntimeOptions; fn main() { let my_ext = Extension::builder() .middleware(|name, opfn| match name { - "op_print" => deno_core::void_op_sync(), + "op_print" => deno_core::void_op_sync::v8_cb(), _ => opfn, }) .build(); diff --git a/core/examples/hello_world.rs b/core/examples/hello_world.rs index 42c9779f3d..bfca5447c5 100644 --- a/core/examples/hello_world.rs +++ b/core/examples/hello_world.rs @@ -2,27 +2,37 @@ //! This example shows you how to define ops in Rust and then call them from //! JavaScript. -use deno_core::op_sync; +use deno_core::op; use deno_core::Extension; use deno_core::JsRuntime; +use deno_core::OpState; use deno_core::RuntimeOptions; +// This is a hack to make the `#[op]` macro work with +// deno_core examples. +// You can remove this: +use deno_core::*; + +#[op] +fn op_sum( + _state: &mut OpState, + nums: Vec, + _: (), +) -> Result { + // Sum inputs + let sum = nums.iter().fold(0.0, |a, v| a + v); + // return as a Result + Ok(sum) +} + fn main() { // Build a deno_core::Extension providing custom ops let ext = Extension::builder() .ops(vec![ // An op for summing an array of numbers - ( - "op_sum", - // The op-layer automatically deserializes inputs - // and serializes the returned Result & value - op_sync(|_state, nums: Vec, _: ()| { - // Sum inputs - let sum = nums.iter().fold(0.0, |a, v| a + v); - // return as a Result - Ok(sum) - }), - ), + // The op-layer automatically deserializes inputs + // and serializes the returned Result & value + op_sum::decl(), ]) .build(); diff --git a/core/examples/http_bench_json_ops.js b/core/examples/http_bench_json_ops.js index 22e1b468c5..5b16776f40 100644 --- a/core/examples/http_bench_json_ops.js +++ b/core/examples/http_bench_json_ops.js @@ -11,12 +11,12 @@ const responseBuf = new Uint8Array( /** Listens on 0.0.0.0:4500, returns rid. */ function listen() { - return Deno.core.opSync("listen"); + return Deno.core.opSync("op_listen"); } /** Accepts a connection, returns rid. */ function accept(serverRid) { - return Deno.core.opAsync("accept", serverRid); + return Deno.core.opAsync("op_accept", serverRid); } async function serve(rid) { diff --git a/core/examples/http_bench_json_ops.rs b/core/examples/http_bench_json_ops.rs index 9e60df4a4b..3f608eeae2 100644 --- a/core/examples/http_bench_json_ops.rs +++ b/core/examples/http_bench_json_ops.rs @@ -1,5 +1,6 @@ // Copyright 2018-2022 the Deno authors. All rights reserved. MIT license. use deno_core::anyhow::Error; +use deno_core::op; use deno_core::AsyncRefCell; use deno_core::AsyncResult; use deno_core::CancelHandle; @@ -17,6 +18,11 @@ use std::rc::Rc; use tokio::io::AsyncReadExt; use tokio::io::AsyncWriteExt; +// This is a hack to make the `#[op]` macro work with +// deno_core examples. +// You can remove this: +use deno_core::*; + struct Logger; impl log::Log for Logger { @@ -119,10 +125,7 @@ impl From for TcpStream { fn create_js_runtime() -> JsRuntime { let ext = deno_core::Extension::builder() - .ops(vec![ - ("listen", deno_core::op_sync(op_listen)), - ("accept", deno_core::op_async(op_accept)), - ]) + .ops(vec![op_listen::decl(), op_accept::decl()]) .build(); JsRuntime::new(deno_core::RuntimeOptions { @@ -131,6 +134,7 @@ fn create_js_runtime() -> JsRuntime { }) } +#[op] fn op_listen(state: &mut OpState, _: (), _: ()) -> Result { log::debug!("listen"); let addr = "127.0.0.1:4544".parse::().unwrap(); @@ -141,6 +145,7 @@ fn op_listen(state: &mut OpState, _: (), _: ()) -> Result { Ok(rid) } +#[op] async fn op_accept( state: Rc>, rid: ResourceId, diff --git a/core/examples/schedule_task.rs b/core/examples/schedule_task.rs index 2f4909b4fa..3ada864178 100644 --- a/core/examples/schedule_task.rs +++ b/core/examples/schedule_task.rs @@ -1,6 +1,7 @@ // Copyright 2018-2022 the Deno authors. All rights reserved. MIT license. use deno_core::anyhow::Error; +use deno_core::op; use deno_core::Extension; use deno_core::JsRuntime; use deno_core::OpState; @@ -9,14 +10,16 @@ use futures::channel::mpsc; use futures::stream::StreamExt; use std::task::Poll; +// This is a hack to make the `#[op]` macro work with +// deno_core examples. +// You can remove this: +use deno_core::*; + type Task = Box; fn main() { let my_ext = Extension::builder() - .ops(vec![( - "op_schedule_task", - deno_core::op_sync(op_schedule_task), - )]) + .ops(vec![op_schedule_task::decl()]) .event_loop_middleware(|state, cx| { let recv = state.borrow_mut::>(); let mut ref_loop = false; @@ -58,6 +61,7 @@ fn main() { runtime.block_on(future).unwrap(); } +#[op] fn op_schedule_task(state: &mut OpState, i: u8, _: ()) -> Result<(), Error> { let tx = state.borrow_mut::>(); tx.unbounded_send(Box::new(move || println!("Hello, world! x{}", i))) diff --git a/core/extensions.rs b/core/extensions.rs index 031cb073aa..7361165f02 100644 --- a/core/extensions.rs +++ b/core/extensions.rs @@ -1,12 +1,13 @@ -use crate::OpFn; +// Copyright 2018-2022 the Deno authors. All rights reserved. MIT license. use crate::OpState; use anyhow::Error; use std::task::Context; pub type SourcePair = (&'static str, Box); pub type SourceLoadFn = dyn Fn() -> Result; -pub type OpPair = (&'static str, Box); -pub type OpMiddlewareFn = dyn Fn(&'static str, Box) -> Box; +pub type OpFnRef = v8::FunctionCallback; +pub type OpPair = (&'static str, OpFnRef); +pub type OpMiddlewareFn = dyn Fn(&'static str, OpFnRef) -> OpFnRef; pub type OpStateFn = dyn Fn(&mut OpState) -> Result<(), Error>; pub type OpEventLoopFn = dyn Fn(&mut OpState, &mut Context) -> bool; @@ -108,7 +109,7 @@ impl ExtensionBuilder { pub fn middleware(&mut self, middleware_fn: F) -> &mut Self where - F: Fn(&'static str, Box) -> Box + 'static, + F: Fn(&'static str, OpFnRef) -> OpFnRef + 'static, { self.middleware = Some(Box::new(middleware_fn)); self diff --git a/core/lib.rs b/core/lib.rs index 2f46c1ffc9..29cdbba010 100644 --- a/core/lib.rs +++ b/core/lib.rs @@ -13,7 +13,6 @@ mod modules; mod normalize_path; mod ops; mod ops_builtin; -mod ops_json; mod ops_metrics; mod resources; mod runtime; @@ -44,6 +43,10 @@ pub use crate::async_cell::AsyncRefCell; pub use crate::async_cell::AsyncRefFuture; pub use crate::async_cell::RcLike; pub use crate::async_cell::RcRef; +pub use crate::extensions::Extension; +pub use crate::extensions::ExtensionBuilder; +pub use crate::extensions::OpMiddlewareFn; +pub use crate::extensions::OpPair; pub use crate::flags::v8_set_flags; pub use crate::inspector::InspectorMsg; pub use crate::inspector::InspectorMsgKind; @@ -65,24 +68,21 @@ pub use crate::modules::ModuleSourceFuture; pub use crate::modules::ModuleType; pub use crate::modules::NoopModuleLoader; pub use crate::normalize_path::normalize_path; -pub use crate::ops::serialize_op_result; pub use crate::ops::Op; pub use crate::ops::OpAsyncFuture; pub use crate::ops::OpCall; +pub use crate::ops::OpError; pub use crate::ops::OpFn; pub use crate::ops::OpId; -pub use crate::ops::OpPayload; pub use crate::ops::OpResult; pub use crate::ops::OpState; -pub use crate::ops::OpTable; pub use crate::ops::PromiseId; pub use crate::ops_builtin::op_close; pub use crate::ops_builtin::op_print; pub use crate::ops_builtin::op_resources; -pub use crate::ops_json::op_async; -pub use crate::ops_json::op_sync; -pub use crate::ops_json::void_op_async; -pub use crate::ops_json::void_op_sync; +pub use crate::ops_builtin::void_op_async; +pub use crate::ops_builtin::void_op_sync; +pub use crate::ops_metrics::OpsTracker; pub use crate::resources::AsyncResult; pub use crate::resources::Resource; pub use crate::resources::ResourceId; @@ -95,16 +95,21 @@ pub use crate::runtime::JsRuntime; pub use crate::runtime::RuntimeOptions; pub use crate::runtime::SharedArrayBufferStore; pub use crate::runtime::Snapshot; -// pub use crate::runtime_modules::include_js_files!; -pub use crate::extensions::Extension; -pub use crate::extensions::ExtensionBuilder; -pub use crate::extensions::OpMiddlewareFn; -pub use crate::extensions::OpPair; +pub use deno_ops::op; pub fn v8_version() -> &'static str { v8::V8::get_version() } +/// An internal module re-exporting funcs used by the #[op] (`deno_ops`) macro +#[doc(hidden)] +pub mod _ops { + pub use super::bindings::throw_type_error; + pub use super::error_codes::get_error_code; + pub use super::ops::to_op_result; + pub use super::runtime::queue_async_op; +} + /// A helper macro that will return a call site in Rust code. Should be /// used when executing internal one-line scripts for JsRuntime lifecycle. /// diff --git a/core/modules.rs b/core/modules.rs index d4a0a86ef7..7c52741934 100644 --- a/core/modules.rs +++ b/core/modules.rs @@ -1073,13 +1073,11 @@ impl ModuleMap { #[cfg(test)] mod tests { use super::*; - use crate::ops::OpCall; - use crate::serialize_op_result; + use crate::error::AnyError; use crate::Extension; use crate::JsRuntime; - use crate::Op; - use crate::OpPayload; use crate::RuntimeOptions; + use deno_ops::op; use futures::future::FutureExt; use parking_lot::Mutex; use std::fmt; @@ -1088,6 +1086,10 @@ mod tests { use std::path::PathBuf; use std::sync::atomic::{AtomicUsize, Ordering}; use std::sync::Arc; + // deno_ops macros generate code assuming deno_core in scope. + mod deno_core { + pub use crate::*; + } // TODO(ry) Sadly FuturesUnordered requires the current task to be set. So // even though we are only using poll() in these tests and not Tokio, we must @@ -1401,20 +1403,16 @@ import "/a.js"; let loader = Rc::new(ModsLoader::default()); let resolve_count = loader.count.clone(); - let dispatch_count = Arc::new(AtomicUsize::new(0)); - let dispatch_count_ = dispatch_count.clone(); + static DISPATCH_COUNT: AtomicUsize = AtomicUsize::new(0); - let op_test = move |state, payload: OpPayload| -> Op { - dispatch_count_.fetch_add(1, Ordering::Relaxed); - let (control, _): (u8, ()) = payload.deserialize().unwrap(); + #[op] + fn op_test(_: &mut OpState, control: u8, _: ()) -> Result { + DISPATCH_COUNT.fetch_add(1, Ordering::Relaxed); assert_eq!(control, 42); - let resp = (0, 1, serialize_op_result(Ok(43), state)); - Op::Async(OpCall::ready(resp)) - }; + Ok(43) + } - let ext = Extension::builder() - .ops(vec![("op_test", Box::new(op_test))]) - .build(); + let ext = Extension::builder().ops(vec![op_test::decl()]).build(); let mut runtime = JsRuntime::new(RuntimeOptions { extensions: vec![ext], @@ -1435,7 +1433,7 @@ import "/a.js"; ) .unwrap(); - assert_eq!(dispatch_count.load(Ordering::Relaxed), 0); + assert_eq!(DISPATCH_COUNT.load(Ordering::Relaxed), 0); let module_map_rc = JsRuntime::module_map(runtime.v8_isolate()); @@ -1452,12 +1450,12 @@ import "/a.js"; import { b } from './b.js' if (b() != 'b') throw Error(); let control = 42; - Deno.core.opAsync("op_test", control); + Deno.core.opSync("op_test", control); "#, ) .unwrap(); - assert_eq!(dispatch_count.load(Ordering::Relaxed), 0); + assert_eq!(DISPATCH_COUNT.load(Ordering::Relaxed), 0); let imports = module_map.get_requested_modules(mod_a); assert_eq!( imports, @@ -1481,14 +1479,14 @@ import "/a.js"; }; runtime.instantiate_module(mod_b).unwrap(); - assert_eq!(dispatch_count.load(Ordering::Relaxed), 0); + assert_eq!(DISPATCH_COUNT.load(Ordering::Relaxed), 0); assert_eq!(resolve_count.load(Ordering::SeqCst), 1); runtime.instantiate_module(mod_a).unwrap(); - assert_eq!(dispatch_count.load(Ordering::Relaxed), 0); + assert_eq!(DISPATCH_COUNT.load(Ordering::Relaxed), 0); let _ = runtime.mod_evaluate(mod_a); - assert_eq!(dispatch_count.load(Ordering::Relaxed), 1); + assert_eq!(DISPATCH_COUNT.load(Ordering::Relaxed), 1); } #[test] @@ -1766,7 +1764,6 @@ import "/a.js"; module_loader: Some(loader), ..Default::default() }); - runtime.sync_ops_cache(); runtime .execute_script( "file:///dyn_import3.js", diff --git a/core/ops.rs b/core/ops.rs index 50197c9be3..42718b8ff7 100644 --- a/core/ops.rs +++ b/core/ops.rs @@ -1,10 +1,9 @@ // Copyright 2018-2022 the Deno authors. All rights reserved. MIT license. -use crate::error::type_error; use crate::gotham_state::GothamState; -use crate::ops_metrics::OpsTracker; use crate::resources::ResourceTable; use crate::runtime::GetErrorClassFn; +use crate::OpsTracker; use anyhow::Error; use futures::future::maybe_done; use futures::future::FusedFuture; @@ -12,23 +11,19 @@ use futures::future::MaybeDone; use futures::ready; use futures::task::noop_waker; use futures::Future; -use indexmap::IndexMap; -use serde::de::DeserializeOwned; use serde::Serialize; -use std::cell::RefCell; use std::cell::UnsafeCell; -use std::iter::once; use std::ops::Deref; use std::ops::DerefMut; use std::pin::Pin; -use std::rc::Rc; use std::task::Context; use std::task::Poll; /// Wrapper around a Future, which causes that Future to be polled immediately. -/// (Background: ops are stored in a `FuturesUnordered` structure which polls +/// +/// Background: ops are stored in a `FuturesUnordered` structure which polls /// them, but without the `OpCall` wrapper this doesn't happen until the next -/// turn of the event loop, which is too late for certain ops.) +/// turn of the event loop, which is too late for certain ops. pub struct OpCall(MaybeDone>>>); impl OpCall { @@ -83,32 +78,10 @@ where pub type PromiseId = i32; pub type OpAsyncFuture = OpCall<(PromiseId, OpId, OpResult)>; -pub type OpFn = dyn Fn(Rc>, OpPayload) -> Op + 'static; +pub type OpFn = + fn(&mut v8::HandleScope, v8::FunctionCallbackArguments, v8::ReturnValue); pub type OpId = usize; -pub struct OpPayload<'a, 'b, 'c> { - pub(crate) scope: &'a mut v8::HandleScope<'b>, - pub(crate) a: v8::Local<'c, v8::Value>, - pub(crate) b: v8::Local<'c, v8::Value>, - pub(crate) op_id: OpId, - pub(crate) promise_id: PromiseId, -} - -impl<'a, 'b, 'c> OpPayload<'a, 'b, 'c> { - pub fn deserialize( - self, - ) -> Result<(T, U), Error> { - let a: T = serde_v8::from_v8(self.scope, self.a) - .map_err(Error::from) - .map_err(|e| type_error(format!("Error parsing args: {}", e)))?; - - let b: U = serde_v8::from_v8(self.scope, self.b) - .map_err(Error::from) - .map_err(|e| type_error(format!("Error parsing args: {}", e)))?; - Ok((a, b)) - } -} - pub enum Op { Sync(OpResult), Async(OpAsyncFuture), @@ -141,39 +114,43 @@ pub struct OpError { code: Option<&'static str>, } -pub fn serialize_op_result( +impl OpError { + pub fn new(get_class: GetErrorClassFn, err: Error) -> Self { + Self { + class_name: (get_class)(&err), + message: err.to_string(), + code: crate::error_codes::get_error_code(&err), + } + } +} + +pub fn to_op_result( + get_class: GetErrorClassFn, result: Result, - state: Rc>, ) -> OpResult { match result { Ok(v) => OpResult::Ok(v.into()), - Err(err) => OpResult::Err(OpError { - class_name: (state.borrow().get_error_class_fn)(&err), - message: err.to_string(), - code: crate::error_codes::get_error_code(&err), - }), + Err(err) => OpResult::Err(OpError::new(get_class, err)), } } /// Maintains the resources and ops inside a JS runtime. pub struct OpState { pub resource_table: ResourceTable, - pub op_table: OpTable, pub get_error_class_fn: GetErrorClassFn, - pub(crate) tracker: OpsTracker, + pub tracker: OpsTracker, gotham_state: GothamState, } impl OpState { - pub(crate) fn new() -> OpState { + pub fn new(ops_count: usize) -> OpState { OpState { resource_table: Default::default(), - op_table: OpTable::default(), get_error_class_fn: &|_| "Error", - tracker: OpsTracker { - ops: UnsafeCell::new(Vec::with_capacity(256)), - }, gotham_state: Default::default(), + tracker: OpsTracker { + ops: UnsafeCell::new(vec![Default::default(); ops_count]), + }, } } } @@ -191,81 +168,3 @@ impl DerefMut for OpState { &mut self.gotham_state } } - -/// Collection for storing registered ops. The special 'get_op_catalog' -/// op with OpId `0` is automatically added when the OpTable is created. -pub struct OpTable(IndexMap>); - -impl OpTable { - pub fn register_op(&mut self, name: &str, op_fn: F) -> OpId - where - F: Fn(Rc>, OpPayload) -> Op + 'static, - { - let (op_id, prev) = self.0.insert_full(name.to_owned(), Rc::new(op_fn)); - assert!(prev.is_none()); - op_id - } - - pub fn op_entries(state: Rc>) -> Vec<(String, OpId)> { - state.borrow().op_table.0.keys().cloned().zip(0..).collect() - } - - pub fn route_op( - op_id: OpId, - state: Rc>, - payload: OpPayload, - ) -> Op { - let op_fn = state - .borrow() - .op_table - .0 - .get_index(op_id) - .map(|(_, op_fn)| op_fn.clone()); - match op_fn { - Some(f) => (f)(state, payload), - None => Op::NotFound, - } - } -} - -impl Default for OpTable { - fn default() -> Self { - fn dummy(_state: Rc>, _p: OpPayload) -> Op { - unreachable!() - } - Self(once(("ops".to_owned(), Rc::new(dummy) as _)).collect()) - } -} - -#[cfg(test)] -mod tests { - use super::*; - - #[test] - fn op_table() { - let state = Rc::new(RefCell::new(OpState::new())); - - let foo_id; - let bar_id; - { - let op_table = &mut state.borrow_mut().op_table; - foo_id = - op_table.register_op("foo", |_, _| Op::Sync(OpResult::Ok(321.into()))); - assert_eq!(foo_id, 1); - bar_id = - op_table.register_op("bar", |_, _| Op::Sync(OpResult::Ok(123.into()))); - assert_eq!(bar_id, 2); - } - - let mut catalog_entries = OpTable::op_entries(state); - catalog_entries.sort_by(|(_, id1), (_, id2)| id1.partial_cmp(id2).unwrap()); - assert_eq!( - catalog_entries, - vec![ - ("ops".to_owned(), 0), - ("foo".to_owned(), 1), - ("bar".to_owned(), 2) - ] - ); - } -} diff --git a/core/ops_builtin.rs b/core/ops_builtin.rs index d759bc5ba1..14d8c6e39e 100644 --- a/core/ops_builtin.rs +++ b/core/ops_builtin.rs @@ -1,16 +1,13 @@ use crate::error::type_error; use crate::include_js_files; -use crate::op_async; -use crate::op_sync; use crate::ops_metrics::OpMetrics; use crate::resources::ResourceId; -use crate::void_op_async; -use crate::void_op_sync; use crate::Extension; use crate::OpState; use crate::Resource; use crate::ZeroCopyBuf; use anyhow::Error; +use deno_ops::op; use std::cell::RefCell; use std::io::{stderr, stdout, Write}; use std::rc::Rc; @@ -24,29 +21,40 @@ pub(crate) fn init_builtins() -> Extension { "02_error.js", )) .ops(vec![ - ("op_close", op_sync(op_close)), - ("op_try_close", op_sync(op_try_close)), - ("op_print", op_sync(op_print)), - ("op_resources", op_sync(op_resources)), - ("op_wasm_streaming_feed", op_sync(op_wasm_streaming_feed)), - ("op_wasm_streaming_abort", op_sync(op_wasm_streaming_abort)), - ( - "op_wasm_streaming_set_url", - op_sync(op_wasm_streaming_set_url), - ), - ("op_metrics", op_sync(op_metrics)), - ("op_void_sync", void_op_sync()), - ("op_void_async", void_op_async()), - // TODO(@AaronO): track IO metrics for builtin streams - ("op_read", op_async(op_read)), - ("op_write", op_async(op_write)), - ("op_shutdown", op_async(op_shutdown)), + op_close::decl(), + op_try_close::decl(), + op_print::decl(), + op_resources::decl(), + op_wasm_streaming_feed::decl(), + op_wasm_streaming_abort::decl(), + op_wasm_streaming_set_url::decl(), + op_void_sync::decl(), + op_void_async::decl(), + // // TODO(@AaronO): track IO metrics for builtin streams + op_read::decl(), + op_write::decl(), + op_shutdown::decl(), + op_metrics::decl(), ]) .build() } +#[op] +pub fn void_op_sync(_: &mut OpState, _: (), _: ()) -> Result<(), Error> { + Ok(()) +} + +pub async fn void_op_async( + _state: Rc>, + _: (), + _: (), +) -> Result<(), Error> { + Ok(()) +} + /// Return map of resources with id as key /// and string representation as value. +#[op] pub fn op_resources( state: &mut OpState, _: (), @@ -60,7 +68,22 @@ pub fn op_resources( Ok(serialized_resources) } +#[op] +pub fn op_void_sync(_state: &mut OpState, _: (), _: ()) -> Result<(), Error> { + Ok(()) +} + +#[op] +pub async fn op_void_async( + _state: Rc>, + _: (), + _: (), +) -> Result<(), Error> { + Ok(()) +} + /// Remove a resource from the resource table. +#[op] pub fn op_close( state: &mut OpState, rid: Option, @@ -75,6 +98,7 @@ pub fn op_close( /// Try to remove a resource from the resource table. If there is no resource /// with the specified `rid`, this is a no-op. +#[op] pub fn op_try_close( state: &mut OpState, rid: Option, @@ -87,7 +111,19 @@ pub fn op_try_close( Ok(()) } +#[op] +pub fn op_metrics( + state: &mut OpState, + _: (), + _: (), +) -> Result<(OpMetrics, Vec), Error> { + let aggregate = state.tracker.aggregate(); + let per_op = state.tracker.per_op(); + Ok((aggregate, per_op)) +} + /// Builtin utility to print to stdout/stderr +#[op] pub fn op_print( _state: &mut OpState, msg: String, @@ -119,6 +155,7 @@ impl Resource for WasmStreamingResource { } /// Feed bytes to WasmStreamingResource. +#[op] pub fn op_wasm_streaming_feed( state: &mut OpState, rid: ResourceId, @@ -133,6 +170,7 @@ pub fn op_wasm_streaming_feed( } /// Abort a WasmStreamingResource. +#[op] pub fn op_wasm_streaming_abort( state: &mut OpState, rid: ResourceId, @@ -153,6 +191,7 @@ pub fn op_wasm_streaming_abort( Ok(()) } +#[op] pub fn op_wasm_streaming_set_url( state: &mut OpState, rid: ResourceId, @@ -166,16 +205,7 @@ pub fn op_wasm_streaming_set_url( Ok(()) } -pub fn op_metrics( - state: &mut OpState, - _: (), - _: (), -) -> Result<(OpMetrics, Vec), Error> { - let aggregate = state.tracker.aggregate(); - let per_op = state.tracker.per_op(); - Ok((aggregate, per_op)) -} - +#[op] async fn op_read( state: Rc>, rid: ResourceId, @@ -185,6 +215,7 @@ async fn op_read( resource.read(buf).await.map(|n| n as u32) } +#[op] async fn op_write( state: Rc>, rid: ResourceId, @@ -194,6 +225,7 @@ async fn op_write( resource.write(buf).await.map(|n| n as u32) } +#[op] async fn op_shutdown( state: Rc>, rid: ResourceId, diff --git a/core/ops_json.rs b/core/ops_json.rs deleted file mode 100644 index 6d8af602fa..0000000000 --- a/core/ops_json.rs +++ /dev/null @@ -1,166 +0,0 @@ -// Copyright 2018-2022 the Deno authors. All rights reserved. MIT license. - -use crate::ops::OpCall; -use crate::serialize_op_result; -use crate::Op; -use crate::OpFn; -use crate::OpState; -use anyhow::Error; -use serde::de::DeserializeOwned; -use serde::Serialize; -use std::cell::RefCell; -use std::future::Future; -use std::rc::Rc; - -/// A helper function that returns a sync NOP OpFn -/// -/// It's mainly intended for embedders who want to disable ops, see ./examples/disable_ops.rs -pub fn void_op_sync() -> Box { - op_sync(|_, _: (), _: ()| Ok(())) -} - -/// A helper function that returns an async NOP OpFn -/// -/// It's mainly intended for embedders who want to disable ops, see ./examples/disable_ops.rs -pub fn void_op_async() -> Box { - op_async(|_, _: (), _: ()| futures::future::ok(())) -} - -/// Creates an op that passes data synchronously using JSON. -/// -/// The provided function `op_fn` has the following parameters: -/// * `&mut OpState`: the op state, can be used to read/write resources in the runtime from an op. -/// * `V`: the deserializable value that is passed to the Rust function. -/// * `&mut [ZeroCopyBuf]`: raw bytes passed along, usually not needed if the JSON value is used. -/// -/// `op_fn` returns a serializable value, which is directly returned to JavaScript. -/// -/// When registering an op like this... -/// ```ignore -/// let mut runtime = JsRuntime::new(...); -/// runtime.register_op("hello", deno_core::op_sync(Self::hello_op)); -/// runtime.sync_ops_cache(); -/// ``` -/// -/// ...it can be invoked from JS using the provided name, for example: -/// ```js -/// let result = Deno.core.opSync("hello", args); -/// ``` -/// -/// `runtime.sync_ops_cache()` must be called after registering new ops -/// A more complete example is available in the examples directory. -pub fn op_sync(op_fn: F) -> Box -where - F: Fn(&mut OpState, A, B) -> Result + 'static, - A: DeserializeOwned, - B: DeserializeOwned, - R: Serialize + 'static, -{ - Box::new(move |state, payload| -> Op { - let result = payload - .deserialize() - .and_then(|(a, b)| op_fn(&mut state.borrow_mut(), a, b)); - Op::Sync(serialize_op_result(result, state)) - }) -} - -/// Creates an op that passes data asynchronously using JSON. -/// -/// When this op is dispatched, the runtime doesn't exit while processing it. -/// -/// The provided function `op_fn` has the following parameters: -/// * `Rc`: the op state, can be used to read/write resources in the runtime from an op. -/// * `V`: the deserializable value that is passed to the Rust function. -/// * `BufVec`: raw bytes passed along, usually not needed if the JSON value is used. -/// -/// `op_fn` returns a future, whose output is a serializable value. This value will be asynchronously -/// returned to JavaScript. -/// -/// When registering an op like this... -/// ```ignore -/// let mut runtime = JsRuntime::new(...); -/// runtime.register_op("hello", deno_core::op_async(Self::hello_op)); -/// runtime.sync_ops_cache(); -/// ``` -/// -/// ...it can be invoked from JS using the provided name, for example: -/// ```js -/// let future = Deno.core.opAsync("hello", args); -/// ``` -/// -/// `runtime.sync_ops_cache()` must be called after registering new ops -/// A more complete example is available in the examples directory. -pub fn op_async(op_fn: F) -> Box -where - F: Fn(Rc>, A, B) -> R + 'static, - A: DeserializeOwned, - B: DeserializeOwned, - R: Future> + 'static, - RV: Serialize + 'static, -{ - Box::new(move |state, payload| -> Op { - let op_id = payload.op_id; - let pid = payload.promise_id; - // Deserialize args, sync error on failure - let args = match payload.deserialize() { - Ok(args) => args, - Err(err) => { - return Op::Sync(serialize_op_result(Err::<(), Error>(err), state)) - } - }; - let (a, b) = args; - - use crate::futures::FutureExt; - let fut = op_fn(state.clone(), a, b) - .map(move |result| (pid, op_id, serialize_op_result(result, state))); - Op::Async(OpCall::eager(fut)) - }) -} - -#[cfg(test)] -mod tests { - use super::*; - - #[tokio::test] - async fn op_async_stack_trace() { - async fn op_throw( - _state: Rc>, - msg: Option, - _: (), - ) -> Result<(), Error> { - assert_eq!(msg.unwrap(), "hello"); - Err(crate::error::generic_error("foo")) - } - - let ext = crate::Extension::builder() - .ops(vec![("op_throw", op_async(op_throw))]) - .build(); - - let mut runtime = crate::JsRuntime::new(crate::RuntimeOptions { - extensions: vec![ext], - ..Default::default() - }); - - runtime - .execute_script( - "", - r#" - async function f1() { - await Deno.core.opAsync('op_throw', 'hello'); - } - - async function f2() { - await f1(); - } - - f2(); - "#, - ) - .unwrap(); - let e = runtime.run_event_loop(false).await.unwrap_err().to_string(); - println!("{}", e); - assert!(e.contains("Error: foo")); - assert!(e.contains("at async f1 (:")); - assert!(e.contains("at async f2 (:")); - } -} diff --git a/core/ops_metrics.rs b/core/ops_metrics.rs index 35c1faf1c5..b068aa0eec 100644 --- a/core/ops_metrics.rs +++ b/core/ops_metrics.rs @@ -59,20 +59,10 @@ impl OpsTracker { unsafe { &mut *self.ops.get() } } - #[inline] - fn ensure_capacity(ops: &mut Vec, op_id: OpId) { - if op_id >= ops.len() { - ops.resize(1 + op_id, OpMetrics::default()) - } - } - #[allow(clippy::mut_from_ref)] #[inline] fn metrics_mut(&self, id: OpId) -> &mut OpMetrics { - let ops = self.ops_mut(); - // TODO(@AaronO): Pre-alloc capacity at runtime init once we forbid post-boot op registrations - Self::ensure_capacity(ops, id); - unsafe { ops.get_unchecked_mut(id) } + unsafe { self.ops_mut().get_unchecked_mut(id) } } #[inline] diff --git a/core/runtime.rs b/core/runtime.rs index 7555bc301f..a4fa0c51ff 100644 --- a/core/runtime.rs +++ b/core/runtime.rs @@ -6,6 +6,7 @@ use crate::error::generic_error; use crate::error::ErrWithV8Handle; use crate::error::JsError; use crate::extensions::OpEventLoopFn; +use crate::extensions::OpPair; use crate::inspector::JsRuntimeInspector; use crate::module_specifier::ModuleSpecifier; use crate::modules::ModuleId; @@ -16,13 +17,13 @@ use crate::modules::NoopModuleLoader; use crate::ops::*; use crate::Extension; use crate::OpMiddlewareFn; -use crate::OpPayload; use crate::OpResult; use crate::OpState; use crate::PromiseId; use anyhow::Error; use futures::channel::oneshot; use futures::future::poll_fn; +use futures::future::Future; use futures::future::FutureExt; use futures::stream::FuturesUnordered; use futures::stream::StreamExt; @@ -143,7 +144,6 @@ pub type CompiledWasmModuleStore = CrossIsolateStore; pub(crate) struct JsRuntimeState { pub global_context: Option>, pub(crate) js_recv_cb: Option>, - pub(crate) js_sync_cb: Option>, pub(crate) js_macrotask_cbs: Vec>, pub(crate) js_nexttick_cbs: Vec>, pub(crate) js_promise_reject_cb: Option>, @@ -279,17 +279,37 @@ impl JsRuntime { let has_startup_snapshot = options.startup_snapshot.is_some(); + let js_error_create_fn = options + .js_error_create_fn + .unwrap_or_else(|| Rc::new(JsError::create)); + + // Add builtins extension + options + .extensions + .insert(0, crate::ops_builtin::init_builtins()); + + let ops = Self::collect_ops(&mut options.extensions); + let mut op_state = OpState::new(ops.len()); + + if let Some(get_error_class_fn) = options.get_error_class_fn { + op_state.get_error_class_fn = get_error_class_fn; + } + + let op_state = Rc::new(RefCell::new(op_state)); + + let refs = bindings::external_references(&ops, op_state.clone()); + let refs: &'static v8::ExternalReferences = Box::leak(Box::new(refs)); let global_context; let (mut isolate, maybe_snapshot_creator) = if options.will_snapshot { // TODO(ry) Support loading snapshots before snapshotting. assert!(options.startup_snapshot.is_none()); - let mut creator = - v8::SnapshotCreator::new(Some(&bindings::EXTERNAL_REFERENCES)); + let mut creator = v8::SnapshotCreator::new(Some(refs)); let isolate = unsafe { creator.get_owned_isolate() }; let mut isolate = JsRuntime::setup_isolate(isolate); { let scope = &mut v8::HandleScope::new(&mut isolate); - let context = bindings::initialize_context(scope); + let context = + bindings::initialize_context(scope, &ops, false, op_state.clone()); global_context = v8::Global::new(scope, context); creator.set_default_context(context); } @@ -299,7 +319,7 @@ impl JsRuntime { .create_params .take() .unwrap_or_else(v8::Isolate::create_params) - .external_references(&**bindings::EXTERNAL_REFERENCES); + .external_references(&**refs); let snapshot_loaded = if let Some(snapshot) = options.startup_snapshot { params = match snapshot { Snapshot::Static(data) => params.snapshot_blob(data), @@ -315,13 +335,13 @@ impl JsRuntime { let mut isolate = JsRuntime::setup_isolate(isolate); { let scope = &mut v8::HandleScope::new(&mut isolate); - let context = if snapshot_loaded { - v8::Context::new(scope) - } else { - // If no snapshot is provided, we initialize the context with empty - // main source code and source maps. - bindings::initialize_context(scope) - }; + let context = bindings::initialize_context( + scope, + &ops, + snapshot_loaded, + op_state.clone(), + ); + global_context = v8::Global::new(scope, context); } (isolate, None) @@ -334,17 +354,6 @@ impl JsRuntime { .module_loader .unwrap_or_else(|| Rc::new(NoopModuleLoader)); - let js_error_create_fn = options - .js_error_create_fn - .unwrap_or_else(|| Rc::new(JsError::create)); - let mut op_state = OpState::new(); - - if let Some(get_error_class_fn) = options.get_error_class_fn { - op_state.get_error_class_fn = get_error_class_fn; - } - - let op_state = Rc::new(RefCell::new(op_state)); - isolate.set_slot(Rc::new(RefCell::new(JsRuntimeState { global_context: Some(global_context), pending_promise_exceptions: HashMap::new(), @@ -352,7 +361,6 @@ impl JsRuntime { pending_mod_evaluate: None, dyn_module_evaluate_idle_counter: 0, js_recv_cb: None, - js_sync_cb: None, js_macrotask_cbs: vec![], js_nexttick_cbs: vec![], js_promise_reject_cb: None, @@ -372,11 +380,6 @@ impl JsRuntime { let module_map = ModuleMap::new(loader, op_state); isolate.set_slot(Rc::new(RefCell::new(module_map))); - // Add builtins extension - options - .extensions - .insert(0, crate::ops_builtin::init_builtins()); - let mut js_runtime = Self { v8_isolate: Some(isolate), inspector: Some(inspector), @@ -394,10 +397,8 @@ impl JsRuntime { } // Init extension ops js_runtime.init_extension_ops().unwrap(); - // Init callbacks (opresolve & syncOpsCache) + // Init callbacks (opresolve) js_runtime.init_cbs(); - // Sync ops cache - js_runtime.sync_ops_cache(); js_runtime } @@ -461,34 +462,44 @@ impl JsRuntime { Ok(()) } + /// Collects ops from extensions & applies middleware + fn collect_ops(extensions: &mut [Extension]) -> Vec { + // Middleware + let middleware: Vec> = extensions + .iter_mut() + .filter_map(|e| e.init_middleware()) + .collect(); + + // macroware wraps an opfn in all the middleware + let macroware = + move |name, opfn| middleware.iter().fold(opfn, |opfn, m| m(name, opfn)); + + // Flatten ops & apply middlware + extensions + .iter_mut() + .filter_map(|e| e.init_ops()) + .flatten() + .map(|(name, opfn)| (name, macroware(name, opfn))) + .collect() + } + /// Initializes ops of provided Extensions fn init_extension_ops(&mut self) -> Result<(), Error> { let op_state = self.op_state(); // Take extensions to avoid double-borrow let mut extensions: Vec = std::mem::take(&mut self.extensions); - // Middleware - let middleware: Vec> = extensions - .iter_mut() - .filter_map(|e| e.init_middleware()) - .collect(); - // macroware wraps an opfn in all the middleware - let macroware = - move |name, opfn| middleware.iter().fold(opfn, |opfn, m| m(name, opfn)); - - // Register ops + // Setup state for e in extensions.iter_mut() { + // ops are already registered during in bindings::initialize_context(); e.init_state(&mut op_state.borrow_mut())?; - // Register each op after middlewaring it - let ops = e.init_ops().unwrap_or_default(); - for (name, opfn) in ops { - self.register_op(name, macroware(name, opfn)); - } + // Setup event-loop middleware if let Some(middleware) = e.init_event_loop_middleware() { self.event_loop_middlewares.push(middleware); } } + // Restore extensions self.extensions = extensions; @@ -511,22 +522,10 @@ impl JsRuntime { 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) { - 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.open(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 @@ -612,7 +611,6 @@ 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 @@ -623,27 +621,6 @@ impl JsRuntime { snapshot } - /// Registers an op that can be called from JavaScript. - /// - /// The _op_ mechanism allows to expose Rust functions to the JS runtime, - /// which can be called using the provided `name`. - /// - /// This function provides byte-level bindings. To pass data via JSON, the - /// following functions can be passed as an argument for `op_fn`: - /// * [op_sync()](fn.op_sync.html) - /// * [op_async()](fn.op_async.html) - pub fn register_op(&mut self, name: &str, op_fn: F) -> OpId - where - F: Fn(Rc>, OpPayload) -> Op + 'static, - { - Self::state(self.v8_isolate()) - .borrow_mut() - .op_state - .borrow_mut() - .op_table - .register_op(name, op_fn) - } - /// Registers a callback on the isolate when the memory limits are approached. /// Use this to prevent V8 from crashing the process when reaching the limit. /// @@ -1552,13 +1529,11 @@ impl JsRuntime { let mut state = state_rc.borrow_mut(); state.have_unpolled_ops = false; - let op_state = state.op_state.clone(); - while let Poll::Ready(Some(item)) = state.pending_ops.poll_next_unpin(cx) { let (promise_id, op_id, resp) = item; - op_state.borrow().tracker.track_async_completed(op_id); state.unrefed_ops.remove(&promise_id); + state.op_state.borrow().tracker.track_async_completed(op_id); args.push(v8::Integer::new(scope, promise_id as i32).into()); args.push(resp.to_v8(scope).unwrap()); } @@ -1654,22 +1629,37 @@ impl JsRuntime { } } +#[inline] +pub fn queue_async_op( + scope: &v8::Isolate, + op: impl Future + 'static, +) { + let state_rc = JsRuntime::state(scope); + let mut state = state_rc.borrow_mut(); + state.pending_ops.push(OpCall::eager(op)); + state.have_unpolled_ops = true; +} + #[cfg(test)] pub mod tests { use super::*; use crate::error::custom_error; + use crate::error::AnyError; use crate::modules::ModuleSource; use crate::modules::ModuleSourceFuture; use crate::modules::ModuleType; - use crate::op_async; - use crate::op_sync; use crate::ZeroCopyBuf; + use deno_ops::op; use futures::future::lazy; use std::ops::FnOnce; use std::pin::Pin; use std::rc::Rc; use std::sync::atomic::{AtomicUsize, Ordering}; use std::sync::Arc; + // deno_ops macros generate code assuming deno_core in scope. + mod deno_core { + pub use crate::*; + } pub fn run_in_task(f: F) where @@ -1689,26 +1679,26 @@ pub mod tests { dispatch_count: Arc, } - fn op_test(rc_op_state: Rc>, payload: OpPayload) -> Op { - let rc_op_state2 = rc_op_state.clone(); - let op_state_ = rc_op_state2.borrow(); + #[op] + async fn op_test( + rc_op_state: Rc>, + control: u8, + buf: Option, + ) -> Result { + let op_state_ = rc_op_state.borrow(); let test_state = op_state_.borrow::(); test_state.dispatch_count.fetch_add(1, Ordering::Relaxed); - let (control, buf): (u8, Option) = - payload.deserialize().unwrap(); match test_state.mode { Mode::Async => { assert_eq!(control, 42); - let resp = (0, 1, serialize_op_result(Ok(43), rc_op_state)); - Op::Async(OpCall::ready(resp)) + Ok(43) } Mode::AsyncZeroCopy(has_buffer) => { assert_eq!(buf.is_some(), has_buffer); if let Some(buf) = buf { assert_eq!(buf.len(), 1); } - let resp = (0, 1, serialize_op_result(Ok(43), rc_op_state)); - Op::Async(OpCall::ready(resp)) + Ok(43) } } } @@ -1717,7 +1707,7 @@ pub mod tests { let dispatch_count = Arc::new(AtomicUsize::new(0)); let dispatch_count2 = dispatch_count.clone(); let ext = Extension::builder() - .ops(vec![("op_test", Box::new(op_test))]) + .ops(vec![op_test::decl()]) .state(move |state| { state.put(TestState { mode, @@ -2027,30 +2017,6 @@ pub mod tests { v8_isolate_handle.terminate_execution(); } - #[test] - fn test_pre_dispatch() { - run_in_task(|cx| { - let (mut runtime, _dispatch_count) = setup(Mode::Async); - runtime - .execute_script( - "bad_op_id.js", - r#" - let thrown; - try { - Deno.core.opcallSync(100, null, null); - } catch (e) { - thrown = e; - } - assert(String(thrown) === "TypeError: Unknown op id: 100"); - "#, - ) - .unwrap(); - if let Poll::Ready(Err(_)) = runtime.poll_event_loop(cx, false) { - unreachable!(); - } - }); - } - #[test] fn syntax_error() { let mut runtime = JsRuntime::new(Default::default()); @@ -2095,6 +2061,7 @@ pub mod tests { #[test] fn test_error_builder() { + #[op] fn op_err(_: &mut OpState, _: (), _: ()) -> Result<(), Error> { Err(custom_error("DOMExceptionOperationError", "abc")) } @@ -2104,9 +2071,7 @@ pub mod tests { } run_in_task(|cx| { - let ext = Extension::builder() - .ops(vec![("op_err", op_sync(op_err))]) - .build(); + let ext = Extension::builder().ops(vec![op_err::decl()]).build(); let mut runtime = JsRuntime::new(RuntimeOptions { extensions: vec![ext], get_error_class_fn: Some(&get_error_class_name), @@ -2177,7 +2142,7 @@ pub mod tests { }); let cb_handle = runtime.v8_isolate().thread_safe_handle(); - let callback_invoke_count = Rc::new(AtomicUsize::default()); + let callback_invoke_count = Rc::new(AtomicUsize::new(0)); let inner_invoke_count = Rc::clone(&callback_invoke_count); runtime.add_near_heap_limit_callback( @@ -2221,7 +2186,7 @@ pub mod tests { }); let cb_handle = runtime.v8_isolate().thread_safe_handle(); - let callback_invoke_count_first = Rc::new(AtomicUsize::default()); + let callback_invoke_count_first = Rc::new(AtomicUsize::new(0)); let inner_invoke_count_first = Rc::clone(&callback_invoke_count_first); runtime.add_near_heap_limit_callback( move |current_limit, _initial_limit| { @@ -2230,7 +2195,7 @@ pub mod tests { }, ); - let callback_invoke_count_second = Rc::new(AtomicUsize::default()); + let callback_invoke_count_second = Rc::new(AtomicUsize::new(0)); let inner_invoke_count_second = Rc::clone(&callback_invoke_count_second); runtime.add_near_heap_limit_callback( move |current_limit, _initial_limit| { @@ -2500,6 +2465,7 @@ assertEquals(1, notify_return_value); async fn test_async_opstate_borrow() { struct InnerState(u64); + #[op] async fn op_async_borrow( op_state: Rc>, _: (), @@ -2519,7 +2485,7 @@ assertEquals(1, notify_return_value); } let extension = Extension::builder() - .ops(vec![("op_async_borrow", op_async(op_async_borrow))]) + .ops(vec![op_async_borrow::decl()]) .state(|state| { state.put(InnerState(42)); Ok(()) @@ -2542,6 +2508,7 @@ assertEquals(1, notify_return_value); #[tokio::test] async fn test_set_macrotask_callback_set_next_tick_callback() { + #[op] async fn op_async_sleep( _op_state: Rc>, _: (), @@ -2553,7 +2520,7 @@ assertEquals(1, notify_return_value); } let extension = Extension::builder() - .ops(vec![("op_async_sleep", op_async(op_async_sleep))]) + .ops(vec![op_async_sleep::decl()]) .build(); let mut runtime = JsRuntime::new(RuntimeOptions { @@ -2617,25 +2584,23 @@ assertEquals(1, notify_return_value); fn test_has_tick_scheduled() { use futures::task::ArcWake; - let macrotask = Arc::new(AtomicUsize::default()); - let macrotask_ = Arc::clone(¯otask); + static MACROTASK: AtomicUsize = AtomicUsize::new(0); + static NEXT_TICK: AtomicUsize = AtomicUsize::new(0); - let next_tick = Arc::new(AtomicUsize::default()); - let next_tick_ = Arc::clone(&next_tick); - - let op_macrotask = move |_: &mut OpState, _: (), _: ()| { - macrotask_.fetch_add(1, Ordering::Relaxed); + #[op] + fn op_macrotask(_: &mut OpState, _: (), _: ()) -> Result<(), AnyError> { + MACROTASK.fetch_add(1, Ordering::Relaxed); Ok(()) - }; + } - let op_next_tick = move |_: &mut OpState, _: (), _: ()| { - next_tick_.fetch_add(1, Ordering::Relaxed); + #[op] + fn op_next_tick(_: &mut OpState, _: (), _: ()) -> Result<(), AnyError> { + NEXT_TICK.fetch_add(1, Ordering::Relaxed); Ok(()) - }; + } let extension = Extension::builder() - .ops(vec![("op_macrotask", op_sync(op_macrotask))]) - .ops(vec![("op_next_tick", op_sync(op_next_tick))]) + .ops(vec![op_macrotask::decl(), op_next_tick::decl()]) .build(); let mut runtime = JsRuntime::new(RuntimeOptions { @@ -2670,8 +2635,8 @@ assertEquals(1, notify_return_value); let cx = &mut Context::from_waker(&waker); assert!(matches!(runtime.poll_event_loop(cx, false), Poll::Pending)); - assert_eq!(1, macrotask.load(Ordering::Relaxed)); - assert_eq!(1, next_tick.load(Ordering::Relaxed)); + assert_eq!(1, MACROTASK.load(Ordering::Relaxed)); + assert_eq!(1, NEXT_TICK.load(Ordering::Relaxed)); assert_eq!(awoken_times.swap(0, Ordering::Relaxed), 1); assert!(matches!(runtime.poll_event_loop(cx, false), Poll::Pending)); assert_eq!(awoken_times.swap(0, Ordering::Relaxed), 1); @@ -2756,28 +2721,34 @@ assertEquals(1, notify_return_value); #[tokio::test] async fn test_set_promise_reject_callback() { - let promise_reject = Arc::new(AtomicUsize::default()); - let promise_reject_ = Arc::clone(&promise_reject); + static PROMISE_REJECT: AtomicUsize = AtomicUsize::new(0); + static UNCAUGHT_EXCEPTION: AtomicUsize = AtomicUsize::new(0); - let uncaught_exception = Arc::new(AtomicUsize::default()); - let uncaught_exception_ = Arc::clone(&uncaught_exception); - - let op_promise_reject = move |_: &mut OpState, _: (), _: ()| { - promise_reject_.fetch_add(1, Ordering::Relaxed); + #[op] + fn op_promise_reject( + _: &mut OpState, + _: (), + _: (), + ) -> Result<(), AnyError> { + PROMISE_REJECT.fetch_add(1, Ordering::Relaxed); Ok(()) - }; + } - let op_uncaught_exception = move |_: &mut OpState, _: (), _: ()| { - uncaught_exception_.fetch_add(1, Ordering::Relaxed); + #[op] + fn op_uncaught_exception( + _: &mut OpState, + _: (), + _: (), + ) -> Result<(), AnyError> { + UNCAUGHT_EXCEPTION.fetch_add(1, Ordering::Relaxed); Ok(()) - }; + } let extension = Extension::builder() - .ops(vec![("op_promise_reject", op_sync(op_promise_reject))]) - .ops(vec![( - "op_uncaught_exception", - op_sync(op_uncaught_exception), - )]) + .ops(vec![ + op_promise_reject::decl(), + op_uncaught_exception::decl(), + ]) .build(); let mut runtime = JsRuntime::new(RuntimeOptions { @@ -2812,8 +2783,8 @@ assertEquals(1, notify_return_value); .unwrap(); runtime.run_event_loop(false).await.unwrap(); - assert_eq!(1, promise_reject.load(Ordering::Relaxed)); - assert_eq!(1, uncaught_exception.load(Ordering::Relaxed)); + assert_eq!(1, PROMISE_REJECT.load(Ordering::Relaxed)); + assert_eq!(1, UNCAUGHT_EXCEPTION.load(Ordering::Relaxed)); runtime .execute_script( @@ -2840,7 +2811,7 @@ assertEquals(1, notify_return_value); // printed to stderr. runtime.run_event_loop(false).await.unwrap(); - assert_eq!(2, promise_reject.load(Ordering::Relaxed)); - assert_eq!(2, uncaught_exception.load(Ordering::Relaxed)); + assert_eq!(2, PROMISE_REJECT.load(Ordering::Relaxed)); + assert_eq!(2, UNCAUGHT_EXCEPTION.load(Ordering::Relaxed)); } } diff --git a/ext/broadcast_channel/lib.rs b/ext/broadcast_channel/lib.rs index 91ee67674a..eff57c7dfe 100644 --- a/ext/broadcast_channel/lib.rs +++ b/ext/broadcast_channel/lib.rs @@ -8,8 +8,7 @@ pub use in_memory_broadcast_channel::InMemoryBroadcastChannelResource; use async_trait::async_trait; use deno_core::error::AnyError; use deno_core::include_js_files; -use deno_core::op_async; -use deno_core::op_sync; +use deno_core::op; use deno_core::Extension; use deno_core::OpState; use deno_core::Resource; @@ -43,11 +42,15 @@ pub type Message = (String, Vec); struct Unstable(bool); // --unstable -pub fn op_broadcast_subscribe( +#[op] +pub fn op_broadcast_subscribe( state: &mut OpState, _: (), _: (), -) -> Result { +) -> Result +where + BC: BroadcastChannel + 'static, +{ let unstable = state.borrow::().0; if !unstable { @@ -62,31 +65,43 @@ pub fn op_broadcast_subscribe( Ok(state.resource_table.add(resource)) } -pub fn op_broadcast_unsubscribe( +#[op] +pub fn op_broadcast_unsubscribe( state: &mut OpState, rid: ResourceId, _buf: (), -) -> Result<(), AnyError> { +) -> Result<(), AnyError> +where + BC: BroadcastChannel + 'static, +{ let resource = state.resource_table.get::(rid)?; let bc = state.borrow::(); bc.unsubscribe(&resource) } -pub async fn op_broadcast_send( +#[op] +pub async fn op_broadcast_send( state: Rc>, (rid, name): (ResourceId, String), buf: ZeroCopyBuf, -) -> Result<(), AnyError> { +) -> Result<(), AnyError> +where + BC: BroadcastChannel + 'static, +{ let resource = state.borrow().resource_table.get::(rid)?; let bc = state.borrow().borrow::().clone(); bc.send(&resource, name, buf.to_vec()).await } -pub async fn op_broadcast_recv( +#[op] +pub async fn op_broadcast_recv( state: Rc>, rid: ResourceId, _: (), -) -> Result, AnyError> { +) -> Result, AnyError> +where + BC: BroadcastChannel + 'static, +{ let resource = state.borrow().resource_table.get::(rid)?; let bc = state.borrow().borrow::().clone(); bc.recv(&resource).await @@ -102,16 +117,10 @@ pub fn init( "01_broadcast_channel.js", )) .ops(vec![ - ( - "op_broadcast_subscribe", - op_sync(op_broadcast_subscribe::), - ), - ( - "op_broadcast_unsubscribe", - op_sync(op_broadcast_unsubscribe::), - ), - ("op_broadcast_send", op_async(op_broadcast_send::)), - ("op_broadcast_recv", op_async(op_broadcast_recv::)), + op_broadcast_subscribe::decl::(), + op_broadcast_unsubscribe::decl::(), + op_broadcast_send::decl::(), + op_broadcast_recv::decl::(), ]) .state(move |state| { state.put(bc.clone()); diff --git a/ext/crypto/decrypt.rs b/ext/crypto/decrypt.rs index 801e72ea07..a8666de89e 100644 --- a/ext/crypto/decrypt.rs +++ b/ext/crypto/decrypt.rs @@ -24,6 +24,7 @@ use ctr::Ctr; use deno_core::error::custom_error; use deno_core::error::type_error; use deno_core::error::AnyError; +use deno_core::op; use deno_core::OpState; use deno_core::ZeroCopyBuf; use rsa::pkcs1::FromRsaPrivateKey; @@ -76,6 +77,7 @@ pub enum DecryptAlgorithm { }, } +#[op] pub async fn op_crypto_decrypt( _state: Rc>, opts: DecryptOptions, diff --git a/ext/crypto/encrypt.rs b/ext/crypto/encrypt.rs index 63f8af889c..b93ca0952b 100644 --- a/ext/crypto/encrypt.rs +++ b/ext/crypto/encrypt.rs @@ -16,6 +16,7 @@ use aes_gcm::AeadInPlace; use aes_gcm::NewAead; use aes_gcm::Nonce; use ctr::Ctr; +use deno_core::op; use block_modes::BlockMode; use ctr::cipher::StreamCipher; @@ -79,6 +80,8 @@ pub enum EncryptAlgorithm { key_length: usize, }, } + +#[op] pub async fn op_crypto_encrypt( _state: Rc>, opts: EncryptOptions, diff --git a/ext/crypto/export_key.rs b/ext/crypto/export_key.rs index 891aea92a8..8131f859d1 100644 --- a/ext/crypto/export_key.rs +++ b/ext/crypto/export_key.rs @@ -1,5 +1,6 @@ use deno_core::error::custom_error; use deno_core::error::AnyError; +use deno_core::op; use deno_core::OpState; use deno_core::ZeroCopyBuf; use rsa::pkcs1::UIntBytes; @@ -84,6 +85,7 @@ pub enum ExportKeyResult { }, } +#[op] pub fn op_crypto_export_key( _state: &mut OpState, opts: ExportKeyOptions, diff --git a/ext/crypto/generate_key.rs b/ext/crypto/generate_key.rs index 190a8b424f..9fe1b62f42 100644 --- a/ext/crypto/generate_key.rs +++ b/ext/crypto/generate_key.rs @@ -3,6 +3,7 @@ use std::rc::Rc; use crate::shared::*; use deno_core::error::AnyError; +use deno_core::op; use deno_core::OpState; use deno_core::ZeroCopyBuf; use elliptic_curve::rand_core::OsRng; @@ -41,6 +42,7 @@ pub enum GenerateKeyOptions { }, } +#[op] pub async fn op_crypto_generate_key( _state: Rc>, opts: GenerateKeyOptions, diff --git a/ext/crypto/import_key.rs b/ext/crypto/import_key.rs index b929f38bb7..3d29c9947c 100644 --- a/ext/crypto/import_key.rs +++ b/ext/crypto/import_key.rs @@ -1,4 +1,5 @@ use deno_core::error::AnyError; +use deno_core::op; use deno_core::OpState; use deno_core::ZeroCopyBuf; use elliptic_curve::pkcs8::der::Decodable as Pkcs8Decodable; @@ -81,11 +82,13 @@ pub enum ImportKeyResult { #[serde(rename_all = "camelCase")] Ec { raw_data: RawKeyData }, #[serde(rename_all = "camelCase")] + #[allow(dead_code)] Aes { raw_data: RawKeyData }, #[serde(rename_all = "camelCase")] Hmac { raw_data: RawKeyData }, } +#[op] pub fn op_crypto_import_key( _state: &mut OpState, opts: ImportKeyOptions, diff --git a/ext/crypto/lib.rs b/ext/crypto/lib.rs index 69381e1391..3b33830d3e 100644 --- a/ext/crypto/lib.rs +++ b/ext/crypto/lib.rs @@ -9,8 +9,8 @@ use deno_core::error::not_supported; use deno_core::error::type_error; use deno_core::error::AnyError; use deno_core::include_js_files; -use deno_core::op_async; -use deno_core::op_sync; +use deno_core::op; + use deno_core::Extension; use deno_core::OpState; use deno_core::ZeroCopyBuf; @@ -88,22 +88,19 @@ pub fn init(maybe_seed: Option) -> Extension { "01_webidl.js", )) .ops(vec![ - ( - "op_crypto_get_random_values", - op_sync(op_crypto_get_random_values), - ), - ("op_crypto_generate_key", op_async(op_crypto_generate_key)), - ("op_crypto_sign_key", op_async(op_crypto_sign_key)), - ("op_crypto_verify_key", op_async(op_crypto_verify_key)), - ("op_crypto_derive_bits", op_async(op_crypto_derive_bits)), - ("op_crypto_import_key", op_sync(op_crypto_import_key)), - ("op_crypto_export_key", op_sync(op_crypto_export_key)), - ("op_crypto_encrypt", op_async(op_crypto_encrypt)), - ("op_crypto_decrypt", op_async(op_crypto_decrypt)), - ("op_crypto_subtle_digest", op_async(op_crypto_subtle_digest)), - ("op_crypto_random_uuid", op_sync(op_crypto_random_uuid)), - ("op_crypto_wrap_key", op_sync(op_crypto_wrap_key)), - ("op_crypto_unwrap_key", op_sync(op_crypto_unwrap_key)), + op_crypto_get_random_values::decl(), + op_crypto_generate_key::decl(), + op_crypto_sign_key::decl(), + op_crypto_verify_key::decl(), + op_crypto_derive_bits::decl(), + op_crypto_import_key::decl(), + op_crypto_export_key::decl(), + op_crypto_encrypt::decl(), + op_crypto_decrypt::decl(), + op_crypto_subtle_digest::decl(), + op_crypto_random_uuid::decl(), + op_crypto_wrap_key::decl(), + op_crypto_unwrap_key::decl(), ]) .state(move |state| { if let Some(seed) = maybe_seed { @@ -114,6 +111,7 @@ pub fn init(maybe_seed: Option) -> Extension { .build() } +#[op] pub fn op_crypto_get_random_values( state: &mut OpState, mut zero_copy: ZeroCopyBuf, @@ -170,6 +168,7 @@ pub struct SignArg { named_curve: Option, } +#[op] pub async fn op_crypto_sign_key( _state: Rc>, args: SignArg, @@ -324,6 +323,7 @@ pub struct VerifyArg { named_curve: Option, } +#[op] pub async fn op_crypto_verify_key( _state: Rc>, args: VerifyArg, @@ -484,6 +484,7 @@ pub struct DeriveKeyArg { info: Option, } +#[op] pub async fn op_crypto_derive_bits( _state: Rc>, args: DeriveKeyArg, @@ -789,6 +790,7 @@ impl<'a> TryFrom> } } +#[op] pub fn op_crypto_random_uuid( state: &mut OpState, _: (), @@ -808,6 +810,7 @@ pub fn op_crypto_random_uuid( Ok(uuid.to_string()) } +#[op] pub async fn op_crypto_subtle_digest( _state: Rc>, algorithm: CryptoHash, @@ -831,6 +834,7 @@ pub struct WrapUnwrapKeyArg { algorithm: Algorithm, } +#[op] pub fn op_crypto_wrap_key( _state: &mut OpState, args: WrapUnwrapKeyArg, @@ -860,6 +864,7 @@ pub fn op_crypto_wrap_key( } } +#[op] pub fn op_crypto_unwrap_key( _state: &mut OpState, args: WrapUnwrapKeyArg, diff --git a/ext/fetch/lib.rs b/ext/fetch/lib.rs index e1859e8e3a..7a0c9b16f2 100644 --- a/ext/fetch/lib.rs +++ b/ext/fetch/lib.rs @@ -9,8 +9,8 @@ use deno_core::futures::Future; use deno_core::futures::Stream; use deno_core::futures::StreamExt; use deno_core::include_js_files; -use deno_core::op_async; -use deno_core::op_sync; +use deno_core::op; + use deno_core::url::Url; use deno_core::AsyncRefCell; use deno_core::AsyncResult; @@ -100,12 +100,9 @@ where "26_fetch.js", )) .ops(vec![ - ("op_fetch", op_sync(op_fetch::)), - ("op_fetch_send", op_async(op_fetch_send)), - ( - "op_fetch_custom_client", - op_sync(op_fetch_custom_client::), - ), + op_fetch::decl::(), + op_fetch_send::decl(), + op_fetch_custom_client::decl::(), ]) .state(move |state| { state.put::(options.clone()); @@ -192,6 +189,7 @@ pub struct FetchReturn { cancel_handle_rid: Option, } +#[op] pub fn op_fetch( state: &mut OpState, args: FetchArgs, @@ -367,6 +365,7 @@ pub struct FetchResponse { response_rid: ResourceId, } +#[op] pub async fn op_fetch_send( state: Rc>, rid: ResourceId, @@ -525,6 +524,7 @@ pub struct CreateHttpClientOptions { private_key: Option, } +#[op] pub fn op_fetch_custom_client( state: &mut OpState, args: CreateHttpClientOptions, diff --git a/ext/ffi/lib.rs b/ext/ffi/lib.rs index f2e7bb175a..b4d8712f4e 100644 --- a/ext/ffi/lib.rs +++ b/ext/ffi/lib.rs @@ -6,8 +6,8 @@ use deno_core::error::range_error; use deno_core::error::type_error; use deno_core::error::AnyError; use deno_core::include_js_files; -use deno_core::op_async; -use deno_core::op_sync; +use deno_core::op; + use deno_core::serde_json; use deno_core::serde_json::json; use deno_core::serde_json::Value; @@ -140,27 +140,24 @@ pub fn init(unstable: bool) -> Extension { "00_ffi.js", )) .ops(vec![ - ("op_ffi_load", op_sync(op_ffi_load::

)), - ("op_ffi_get_static", op_sync(op_ffi_get_static)), - ("op_ffi_call", op_sync(op_ffi_call)), - ("op_ffi_call_nonblocking", op_async(op_ffi_call_nonblocking)), - ("op_ffi_call_ptr", op_sync(op_ffi_call_ptr)), - ( - "op_ffi_call_ptr_nonblocking", - op_async(op_ffi_call_ptr_nonblocking), - ), - ("op_ffi_ptr_of", op_sync(op_ffi_ptr_of::

)), - ("op_ffi_buf_copy_into", op_sync(op_ffi_buf_copy_into::

)), - ("op_ffi_cstr_read", op_sync(op_ffi_cstr_read::

)), - ("op_ffi_read_u8", op_sync(op_ffi_read_u8::

)), - ("op_ffi_read_i8", op_sync(op_ffi_read_i8::

)), - ("op_ffi_read_u16", op_sync(op_ffi_read_u16::

)), - ("op_ffi_read_i16", op_sync(op_ffi_read_i16::

)), - ("op_ffi_read_u32", op_sync(op_ffi_read_u32::

)), - ("op_ffi_read_i32", op_sync(op_ffi_read_i32::

)), - ("op_ffi_read_u64", op_sync(op_ffi_read_u64::

)), - ("op_ffi_read_f32", op_sync(op_ffi_read_f32::

)), - ("op_ffi_read_f64", op_sync(op_ffi_read_f64::

)), + op_ffi_load::decl::

(), + op_ffi_get_static::decl(), + op_ffi_call::decl(), + op_ffi_call_nonblocking::decl(), + op_ffi_call_ptr::decl(), + op_ffi_call_ptr_nonblocking::decl(), + op_ffi_ptr_of::decl::

(), + op_ffi_buf_copy_into::decl::

(), + op_ffi_cstr_read::decl::

(), + op_ffi_read_u8::decl::

(), + op_ffi_read_i8::decl::

(), + op_ffi_read_u16::decl::

(), + op_ffi_read_i16::decl::

(), + op_ffi_read_u32::decl::

(), + op_ffi_read_i32::decl::

(), + op_ffi_read_u64::decl::

(), + op_ffi_read_f32::decl::

(), + op_ffi_read_f64::decl::

(), ]) .state(move |state| { // Stolen from deno_webgpu, is there a better option? @@ -464,6 +461,7 @@ pub(crate) fn format_error(e: dlopen::Error, path: String) -> String { } } +#[op] fn op_ffi_load( state: &mut deno_core::OpState, args: FfiLoadArgs, @@ -650,6 +648,7 @@ fn ffi_call(args: FfiCallArgs, symbol: &Symbol) -> Result { }) } +#[op] fn op_ffi_call_ptr( _state: &mut deno_core::OpState, args: FfiCallPtrArgs, @@ -659,6 +658,7 @@ fn op_ffi_call_ptr( ffi_call(args.into(), &symbol) } +#[op] async fn op_ffi_call_ptr_nonblocking( _state: Rc>, args: FfiCallPtrArgs, @@ -678,6 +678,7 @@ struct FfiGetArgs { r#type: NativeType, } +#[op] fn op_ffi_get_static( state: &mut deno_core::OpState, args: FfiGetArgs, @@ -735,6 +736,7 @@ fn op_ffi_get_static( }) } +#[op] fn op_ffi_call( state: &mut deno_core::OpState, args: FfiCallArgs, @@ -753,6 +755,7 @@ fn op_ffi_call( } /// A non-blocking FFI call. +#[op] async fn op_ffi_call_nonblocking( state: Rc>, args: FfiCallArgs, @@ -773,6 +776,7 @@ async fn op_ffi_call_nonblocking( .unwrap() } +#[op] fn op_ffi_ptr_of( state: &mut deno_core::OpState, buf: ZeroCopyBuf, @@ -787,6 +791,7 @@ where Ok(U32x2::from(buf.as_ptr() as u64)) } +#[op] fn op_ffi_buf_copy_into( state: &mut deno_core::OpState, (src, mut dst, len): (U32x2, ZeroCopyBuf, usize), @@ -809,6 +814,7 @@ where } } +#[op] fn op_ffi_cstr_read( state: &mut deno_core::OpState, ptr: U32x2, @@ -824,6 +830,7 @@ where Ok(unsafe { CStr::from_ptr(ptr) }.to_str()?.to_string()) } +#[op] fn op_ffi_read_u8( state: &mut deno_core::OpState, ptr: U32x2, @@ -838,6 +845,7 @@ where Ok(unsafe { ptr::read_unaligned(u64::from(ptr) as *const u8) }) } +#[op] fn op_ffi_read_i8( state: &mut deno_core::OpState, ptr: U32x2, @@ -852,6 +860,7 @@ where Ok(unsafe { ptr::read_unaligned(u64::from(ptr) as *const i8) }) } +#[op] fn op_ffi_read_u16( state: &mut deno_core::OpState, ptr: U32x2, @@ -866,6 +875,7 @@ where Ok(unsafe { ptr::read_unaligned(u64::from(ptr) as *const u16) }) } +#[op] fn op_ffi_read_i16( state: &mut deno_core::OpState, ptr: U32x2, @@ -880,6 +890,7 @@ where Ok(unsafe { ptr::read_unaligned(u64::from(ptr) as *const i16) }) } +#[op] fn op_ffi_read_u32( state: &mut deno_core::OpState, ptr: U32x2, @@ -894,6 +905,7 @@ where Ok(unsafe { ptr::read_unaligned(u64::from(ptr) as *const u32) }) } +#[op] fn op_ffi_read_i32( state: &mut deno_core::OpState, ptr: U32x2, @@ -908,6 +920,7 @@ where Ok(unsafe { ptr::read_unaligned(u64::from(ptr) as *const i32) }) } +#[op] fn op_ffi_read_u64( state: &mut deno_core::OpState, ptr: U32x2, @@ -924,6 +937,7 @@ where })) } +#[op] fn op_ffi_read_f32( state: &mut deno_core::OpState, ptr: U32x2, @@ -938,6 +952,7 @@ where Ok(unsafe { ptr::read_unaligned(u64::from(ptr) as *const f32) }) } +#[op] fn op_ffi_read_f64( state: &mut deno_core::OpState, ptr: U32x2, diff --git a/ext/http/lib.rs b/ext/http/lib.rs index ae5ddb9c3a..a89c7a4a1e 100644 --- a/ext/http/lib.rs +++ b/ext/http/lib.rs @@ -20,8 +20,8 @@ use deno_core::futures::FutureExt; use deno_core::futures::StreamExt; use deno_core::futures::TryFutureExt; use deno_core::include_js_files; -use deno_core::op_async; -use deno_core::op_sync; +use deno_core::op; + use deno_core::AsyncRefCell; use deno_core::ByteString; use deno_core::CancelFuture; @@ -72,19 +72,13 @@ pub fn init() -> Extension { "01_http.js", )) .ops(vec![ - ("op_http_accept", op_async(op_http_accept)), - ("op_http_read", op_async(op_http_read)), - ("op_http_write_headers", op_async(op_http_write_headers)), - ("op_http_write", op_async(op_http_write)), - ("op_http_shutdown", op_async(op_http_shutdown)), - ( - "op_http_websocket_accept_header", - op_sync(op_http_websocket_accept_header), - ), - ( - "op_http_upgrade_websocket", - op_async(op_http_upgrade_websocket), - ), + op_http_accept::decl(), + op_http_read::decl(), + op_http_write_headers::decl(), + op_http_write::decl(), + op_http_shutdown::decl(), + op_http_websocket_accept_header::decl(), + op_http_upgrade_websocket::decl(), ]) .build() } @@ -371,6 +365,7 @@ struct NextRequestResponse( String, ); +#[op] async fn op_http_accept( state: Rc>, rid: ResourceId, @@ -501,6 +496,7 @@ struct RespondArgs( Vec<(ByteString, ByteString)>, ); +#[op] async fn op_http_write_headers( state: Rc>, args: RespondArgs, @@ -697,6 +693,7 @@ async fn op_http_write_headers( } } +#[op] async fn op_http_write( state: Rc>, rid: ResourceId, @@ -737,6 +734,7 @@ async fn op_http_write( /// Gracefully closes the write half of the HTTP stream. Note that this does not /// remove the HTTP stream resource from the resource table; it still has to be /// closed with `Deno.core.close()`. +#[op] async fn op_http_shutdown( state: Rc>, rid: ResourceId, @@ -751,6 +749,7 @@ async fn op_http_shutdown( Ok(()) } +#[op] async fn op_http_read( state: Rc>, rid: ResourceId, @@ -799,6 +798,7 @@ async fn op_http_read( fut.try_or_cancel(cancel_handle).await } +#[op] fn op_http_websocket_accept_header( _: &mut OpState, key: String, @@ -811,6 +811,7 @@ fn op_http_websocket_accept_header( Ok(base64::encode(digest)) } +#[op] async fn op_http_upgrade_websocket( state: Rc>, rid: ResourceId, diff --git a/ext/net/lib.rs b/ext/net/lib.rs index c9b888a65f..84358210ec 100644 --- a/ext/net/lib.rs +++ b/ext/net/lib.rs @@ -76,9 +76,6 @@ pub fn init( unstable: bool, unsafely_ignore_certificate_errors: Option>, ) -> Extension { - let mut ops_to_register = vec![]; - ops_to_register.extend(ops::init::

()); - ops_to_register.extend(ops_tls::init::

()); Extension::builder() .js(include_js_files!( prefix "deno:ext/net", @@ -86,7 +83,7 @@ pub fn init( "02_tls.js", "04_net_unstable.js", )) - .ops(ops_to_register) + .ops([&ops::init::

()[..], &ops_tls::init::

()[..]].concat()) .state(move |state| { state.put(DefaultTlsOptions { root_cert_store: root_cert_store.clone(), diff --git a/ext/net/ops.rs b/ext/net/ops.rs index 682ba0acb8..2c9129ebf5 100644 --- a/ext/net/ops.rs +++ b/ext/net/ops.rs @@ -9,8 +9,8 @@ use deno_core::error::custom_error; use deno_core::error::generic_error; use deno_core::error::type_error; use deno_core::error::AnyError; -use deno_core::op_async; -use deno_core::op_sync; +use deno_core::op; + use deno_core::AsyncRefCell; use deno_core::ByteString; use deno_core::CancelHandle; @@ -52,14 +52,14 @@ use std::path::Path; pub fn init() -> Vec { vec![ - ("op_net_accept", op_async(op_net_accept)), - ("op_net_connect", op_async(op_net_connect::

)), - ("op_net_listen", op_sync(op_net_listen::

)), - ("op_dgram_recv", op_async(op_dgram_recv)), - ("op_dgram_send", op_async(op_dgram_send::

)), - ("op_dns_resolve", op_async(op_dns_resolve::

)), - ("op_set_nodelay", op_sync(op_set_nodelay::

)), - ("op_set_keepalive", op_sync(op_set_keepalive::

)), + op_net_accept::decl(), + op_net_connect::decl::

(), + op_net_listen::decl::

(), + op_dgram_recv::decl(), + op_dgram_send::decl::

(), + op_dns_resolve::decl::

(), + op_set_nodelay::decl::

(), + op_set_keepalive::decl::

(), ] } @@ -158,6 +158,7 @@ async fn accept_tcp( }) } +#[op] async fn op_net_accept( state: Rc>, args: AcceptArgs, @@ -210,6 +211,7 @@ async fn receive_udp( }) } +#[op] async fn op_dgram_recv( state: Rc>, args: ReceiveArgs, @@ -231,6 +233,7 @@ struct SendArgs { transport_args: ArgsEnum, } +#[op] async fn op_dgram_send( state: Rc>, args: SendArgs, @@ -299,6 +302,7 @@ pub struct ConnectArgs { transport_args: ArgsEnum, } +#[op] pub async fn op_net_connect( state: Rc>, args: ConnectArgs, @@ -474,6 +478,7 @@ fn listen_udp( Ok((rid, local_addr)) } +#[op] fn op_net_listen( state: &mut OpState, args: ListenArgs, @@ -613,6 +618,7 @@ pub struct NameServer { port: u16, } +#[op] pub async fn op_dns_resolve( state: Rc>, args: ResolveAddrArgs, @@ -681,6 +687,7 @@ where Ok(results) } +#[op] pub fn op_set_nodelay( state: &mut OpState, rid: ResourceId, @@ -692,6 +699,7 @@ pub fn op_set_nodelay( resource.set_nodelay(nodelay) } +#[op] pub fn op_set_keepalive( state: &mut OpState, rid: ResourceId, @@ -877,7 +885,7 @@ mod tests { #[tokio::test(flavor = "multi_thread", worker_threads = 1)] async fn tcp_set_no_delay() { let set_nodelay = Box::new(|state: &mut OpState, rid| { - op_set_nodelay::(state, rid, true).unwrap(); + op_set_nodelay::call::(state, rid, true).unwrap(); }); let test_fn = Box::new(|socket: SockRef| { assert!(socket.nodelay().unwrap()); @@ -889,7 +897,7 @@ mod tests { #[tokio::test(flavor = "multi_thread", worker_threads = 1)] async fn tcp_set_keepalive() { let set_keepalive = Box::new(|state: &mut OpState, rid| { - op_set_keepalive::(state, rid, true).unwrap(); + op_set_keepalive::call::(state, rid, true).unwrap(); }); let test_fn = Box::new(|socket: SockRef| { assert!(!socket.nodelay().unwrap()); @@ -934,7 +942,7 @@ mod tests { }; let connect_fut = - op_net_connect::(conn_state, connect_args, ()); + op_net_connect::call::(conn_state, connect_args, ()); let conn = connect_fut.await.unwrap(); let rid = conn.rid; diff --git a/ext/net/ops_tls.rs b/ext/net/ops_tls.rs index 01f29b2adb..6289d963fc 100644 --- a/ext/net/ops_tls.rs +++ b/ext/net/ops_tls.rs @@ -25,8 +25,8 @@ use deno_core::futures::task::Poll; use deno_core::futures::task::RawWaker; use deno_core::futures::task::RawWakerVTable; use deno_core::futures::task::Waker; -use deno_core::op_async; -use deno_core::op_sync; +use deno_core::op; + use deno_core::parking_lot::Mutex; use deno_core::AsyncRefCell; use deno_core::AsyncResult; @@ -644,11 +644,11 @@ impl Write for ImplementWriteTrait<'_, TcpStream> { pub fn init() -> Vec { vec![ - ("op_tls_start", op_async(op_tls_start::

)), - ("op_tls_connect", op_async(op_tls_connect::

)), - ("op_tls_listen", op_sync(op_tls_listen::

)), - ("op_tls_accept", op_async(op_tls_accept)), - ("op_tls_handshake", op_async(op_tls_handshake)), + op_tls_start::decl::

(), + op_tls_connect::decl::

(), + op_tls_listen::decl::

(), + op_tls_accept::decl(), + op_tls_handshake::decl(), ] } @@ -765,6 +765,7 @@ pub struct StartTlsArgs { alpn_protocols: Option>, } +#[op] pub async fn op_tls_start( state: Rc>, args: StartTlsArgs, @@ -857,6 +858,7 @@ where }) } +#[op] pub async fn op_tls_connect( state: Rc>, args: ConnectTlsArgs, @@ -1016,6 +1018,7 @@ pub struct ListenTlsArgs { alpn_protocols: Option>, } +#[op] pub fn op_tls_listen( state: &mut OpState, args: ListenTlsArgs, @@ -1112,6 +1115,7 @@ where }) } +#[op] pub async fn op_tls_accept( state: Rc>, rid: ResourceId, @@ -1163,6 +1167,7 @@ pub async fn op_tls_accept( }) } +#[op] pub async fn op_tls_handshake( state: Rc>, rid: ResourceId, diff --git a/ext/url/lib.rs b/ext/url/lib.rs index f8d659f006..a82b3e7028 100644 --- a/ext/url/lib.rs +++ b/ext/url/lib.rs @@ -7,7 +7,7 @@ use deno_core::error::type_error; use deno_core::error::uri_error; use deno_core::error::AnyError; use deno_core::include_js_files; -use deno_core::op_sync; +use deno_core::op; use deno_core::url::form_urlencoded; use deno_core::url::quirks; use deno_core::url::Url; @@ -26,21 +26,12 @@ pub fn init() -> Extension { "01_urlpattern.js", )) .ops(vec![ - ("op_url_parse", op_sync(op_url_parse)), - ("op_url_reparse", op_sync(op_url_reparse)), - ( - "op_url_parse_search_params", - op_sync(op_url_parse_search_params), - ), - ( - "op_url_stringify_search_params", - op_sync(op_url_stringify_search_params), - ), - ("op_urlpattern_parse", op_sync(op_urlpattern_parse)), - ( - "op_urlpattern_process_match_input", - op_sync(op_urlpattern_process_match_input), - ), + op_url_parse::decl(), + op_url_reparse::decl(), + op_url_parse_search_params::decl(), + op_url_stringify_search_params::decl(), + op_urlpattern_parse::decl(), + op_urlpattern_process_match_input::decl(), ]) .build() } @@ -65,6 +56,7 @@ type UrlParts = String; /// Parse `UrlParseArgs::href` with an optional `UrlParseArgs::base_href`, or an /// optional part to "set" after parsing. Return `UrlParts`. +#[op] pub fn op_url_parse( _state: &mut deno_core::OpState, href: String, @@ -98,6 +90,7 @@ pub enum UrlSetter { Username = 9, } +#[op] pub fn op_url_reparse( _state: &mut deno_core::OpState, href: String, @@ -167,6 +160,7 @@ fn url_result( ) } +#[op] pub fn op_url_parse_search_params( _state: &mut deno_core::OpState, args: Option, @@ -186,6 +180,7 @@ pub fn op_url_parse_search_params( Ok(params) } +#[op] pub fn op_url_stringify_search_params( _state: &mut deno_core::OpState, args: Vec<(String, String)>, diff --git a/ext/url/urlpattern.rs b/ext/url/urlpattern.rs index b9f53665fb..4e6b4e4a07 100644 --- a/ext/url/urlpattern.rs +++ b/ext/url/urlpattern.rs @@ -1,11 +1,13 @@ use deno_core::error::type_error; use deno_core::error::AnyError; +use deno_core::op; use urlpattern::quirks; use urlpattern::quirks::MatchInput; use urlpattern::quirks::StringOrInit; use urlpattern::quirks::UrlPattern; +#[op] pub fn op_urlpattern_parse( _state: &mut deno_core::OpState, input: StringOrInit, @@ -23,6 +25,7 @@ pub fn op_urlpattern_parse( Ok(pattern) } +#[op] pub fn op_urlpattern_process_match_input( _state: &mut deno_core::OpState, input: StringOrInit, diff --git a/ext/web/blob.rs b/ext/web/blob.rs index 37e93c8533..ad7f6c5823 100644 --- a/ext/web/blob.rs +++ b/ext/web/blob.rs @@ -1,5 +1,7 @@ use async_trait::async_trait; use deno_core::error::type_error; +use deno_core::op; + use deno_core::parking_lot::Mutex; use deno_core::url::Url; use deno_core::ZeroCopyBuf; @@ -157,6 +159,7 @@ impl BlobPart for SlicedBlobPart { } } +#[op] pub fn op_blob_create_part( state: &mut deno_core::OpState, data: ZeroCopyBuf, @@ -175,6 +178,7 @@ pub struct SliceOptions { len: usize, } +#[op] pub fn op_blob_slice_part( state: &mut deno_core::OpState, id: Uuid, @@ -200,6 +204,7 @@ pub fn op_blob_slice_part( Ok(id) } +#[op] pub async fn op_blob_read_part( state: Rc>, id: Uuid, @@ -215,6 +220,7 @@ pub async fn op_blob_read_part( Ok(ZeroCopyBuf::from(buf.to_vec())) } +#[op] pub fn op_blob_remove_part( state: &mut deno_core::OpState, id: Uuid, @@ -225,6 +231,7 @@ pub fn op_blob_remove_part( Ok(()) } +#[op] pub fn op_blob_create_object_url( state: &mut deno_core::OpState, media_type: String, @@ -250,6 +257,7 @@ pub fn op_blob_create_object_url( Ok(url.to_string()) } +#[op] pub fn op_blob_revoke_object_url( state: &mut deno_core::OpState, url: String, @@ -273,6 +281,7 @@ pub struct ReturnBlobPart { pub size: usize, } +#[op] pub fn op_blob_from_object_url( state: &mut deno_core::OpState, url: String, diff --git a/ext/web/compression.rs b/ext/web/compression.rs index c84db75506..d38f65d6a8 100644 --- a/ext/web/compression.rs +++ b/ext/web/compression.rs @@ -1,6 +1,7 @@ // Copyright 2018-2022 the Deno authors. All rights reserved. MIT license. use deno_core::error::AnyError; +use deno_core::op; use deno_core::OpState; use deno_core::Resource; use deno_core::ResourceId; @@ -32,6 +33,7 @@ impl Resource for CompressionResource { } } +#[op] pub fn op_compression_new( state: &mut OpState, format: String, @@ -53,6 +55,7 @@ pub fn op_compression_new( Ok(state.resource_table.add(resource)) } +#[op] pub fn op_compression_write( state: &mut OpState, rid: ResourceId, @@ -86,6 +89,7 @@ pub fn op_compression_write( Ok(out.into()) } +#[op] pub fn op_compression_finish( state: &mut OpState, rid: ResourceId, diff --git a/ext/web/lib.rs b/ext/web/lib.rs index f117bfb9dd..6c278cbb0d 100644 --- a/ext/web/lib.rs +++ b/ext/web/lib.rs @@ -9,8 +9,7 @@ use deno_core::error::range_error; use deno_core::error::type_error; use deno_core::error::AnyError; use deno_core::include_js_files; -use deno_core::op_async; -use deno_core::op_sync; +use deno_core::op; use deno_core::url::Url; use deno_core::ByteString; use deno_core::Extension; @@ -83,58 +82,31 @@ pub fn init( "15_performance.js", )) .ops(vec![ - ("op_base64_decode", op_sync(op_base64_decode)), - ("op_base64_encode", op_sync(op_base64_encode)), - ("op_base64_atob", op_sync(op_base64_atob)), - ("op_base64_btoa", op_sync(op_base64_btoa)), - ( - "op_encoding_normalize_label", - op_sync(op_encoding_normalize_label), - ), - ("op_encoding_new_decoder", op_sync(op_encoding_new_decoder)), - ("op_encoding_decode", op_sync(op_encoding_decode)), - ("op_encoding_encode_into", op_sync(op_encoding_encode_into)), - ("op_blob_create_part", op_sync(op_blob_create_part)), - ("op_blob_slice_part", op_sync(op_blob_slice_part)), - ("op_blob_read_part", op_async(op_blob_read_part)), - ("op_blob_remove_part", op_sync(op_blob_remove_part)), - ( - "op_blob_create_object_url", - op_sync(op_blob_create_object_url), - ), - ( - "op_blob_revoke_object_url", - op_sync(op_blob_revoke_object_url), - ), - ("op_blob_from_object_url", op_sync(op_blob_from_object_url)), - ( - "op_message_port_create_entangled", - op_sync(op_message_port_create_entangled), - ), - ( - "op_message_port_post_message", - op_sync(op_message_port_post_message), - ), - ( - "op_message_port_recv_message", - op_async(op_message_port_recv_message), - ), - ( - "op_compression_new", - op_sync(compression::op_compression_new), - ), - ( - "op_compression_write", - op_sync(compression::op_compression_write), - ), - ( - "op_compression_finish", - op_sync(compression::op_compression_finish), - ), - ("op_now", op_sync(op_now::

)), - ("op_timer_handle", op_sync(op_timer_handle)), - ("op_sleep", op_async(op_sleep)), - ("op_sleep_sync", op_sync(op_sleep_sync::

)), + op_base64_decode::decl(), + op_base64_encode::decl(), + op_base64_atob::decl(), + op_base64_btoa::decl(), + op_encoding_normalize_label::decl(), + op_encoding_new_decoder::decl(), + op_encoding_decode::decl(), + op_encoding_encode_into::decl(), + op_blob_create_part::decl(), + op_blob_slice_part::decl(), + op_blob_read_part::decl(), + op_blob_remove_part::decl(), + op_blob_create_object_url::decl(), + op_blob_revoke_object_url::decl(), + op_blob_from_object_url::decl(), + op_message_port_create_entangled::decl(), + op_message_port_post_message::decl(), + op_message_port_recv_message::decl(), + compression::op_compression_new::decl(), + compression::op_compression_write::decl(), + compression::op_compression_finish::decl(), + op_now::decl::

(), + op_timer_handle::decl(), + op_sleep::decl(), + op_sleep_sync::decl::

(), ]) .state(move |state| { state.put(blob_store.clone()); @@ -147,6 +119,7 @@ pub fn init( .build() } +#[op] fn op_base64_decode( _: &mut OpState, input: String, @@ -157,6 +130,7 @@ fn op_base64_decode( Ok(b64_decode(&input)?.into()) } +#[op] fn op_base64_atob( _: &mut OpState, s: ByteString, @@ -210,6 +184,7 @@ fn b64_decode(input: &[u8]) -> Result, AnyError> { Ok(out) } +#[op] fn op_base64_encode( _: &mut OpState, s: ZeroCopyBuf, @@ -218,6 +193,7 @@ fn op_base64_encode( Ok(b64_encode(&s)) } +#[op] fn op_base64_btoa( _: &mut OpState, s: ByteString, @@ -240,6 +216,7 @@ struct DecoderOptions { fatal: bool, } +#[op] fn op_encoding_normalize_label( _state: &mut OpState, label: String, @@ -255,6 +232,7 @@ fn op_encoding_normalize_label( Ok(encoding.name().to_lowercase()) } +#[op] fn op_encoding_new_decoder( state: &mut OpState, options: DecoderOptions, @@ -294,6 +272,7 @@ struct DecodeOptions { stream: bool, } +#[op] fn op_encoding_decode( state: &mut OpState, data: ZeroCopyBuf, @@ -357,6 +336,7 @@ struct EncodeIntoResult { written: usize, } +#[op] fn op_encoding_encode_into( _state: &mut OpState, input: String, diff --git a/ext/web/message_port.rs b/ext/web/message_port.rs index 8734f9b65c..7f2b18b3cc 100644 --- a/ext/web/message_port.rs +++ b/ext/web/message_port.rs @@ -4,6 +4,8 @@ use std::rc::Rc; use deno_core::error::type_error; use deno_core::error::AnyError; +use deno_core::op; + use deno_core::ZeroCopyBuf; use deno_core::{CancelFuture, Resource}; use deno_core::{CancelHandle, OpState}; @@ -104,6 +106,7 @@ impl Resource for MessagePortResource { } } +#[op] pub fn op_message_port_create_entangled( state: &mut OpState, _: (), @@ -185,6 +188,7 @@ pub struct JsMessageData { transferables: Vec, } +#[op] pub fn op_message_port_post_message( state: &mut OpState, rid: ResourceId, @@ -203,6 +207,7 @@ pub fn op_message_port_post_message( resource.port.send(state, data) } +#[op] pub async fn op_message_port_recv_message( state: Rc>, rid: ResourceId, diff --git a/ext/web/timers.rs b/ext/web/timers.rs index 7f17aa9691..9a78240f75 100644 --- a/ext/web/timers.rs +++ b/ext/web/timers.rs @@ -3,6 +3,8 @@ //! This module helps deno implement timers and performance APIs. use deno_core::error::AnyError; +use deno_core::op; + use deno_core::CancelFuture; use deno_core::CancelHandle; use deno_core::OpState; @@ -25,6 +27,7 @@ pub type StartTime = Instant; // since the start time of the deno runtime. // If the High precision flag is not set, the // nanoseconds are rounded on 2ms. +#[op] pub fn op_now( state: &mut OpState, _argument: (), @@ -64,6 +67,7 @@ impl Resource for TimerHandle { /// Creates a [`TimerHandle`] resource that can be used to cancel invocations of /// [`op_sleep`]. +#[op] pub fn op_timer_handle( state: &mut OpState, _: (), @@ -77,6 +81,7 @@ pub fn op_timer_handle( /// Waits asynchronously until either `millis` milliseconds have passed or the /// [`TimerHandle`] resource given by `rid` has been canceled. +#[op] pub async fn op_sleep( state: Rc>, millis: u64, @@ -89,6 +94,7 @@ pub async fn op_sleep( Ok(()) } +#[op] pub fn op_sleep_sync( state: &mut OpState, millis: u64, diff --git a/ext/webgpu/src/binding.rs b/ext/webgpu/src/binding.rs index 9a8fa455f2..7370f80343 100644 --- a/ext/webgpu/src/binding.rs +++ b/ext/webgpu/src/binding.rs @@ -1,6 +1,7 @@ // Copyright 2018-2022 the Deno authors. All rights reserved. MIT license. use deno_core::error::AnyError; +use deno_core::op; use deno_core::ResourceId; use deno_core::{OpState, Resource}; use serde::Deserialize; @@ -177,6 +178,7 @@ pub struct CreateBindGroupLayoutArgs { entries: Vec, } +#[op] pub fn op_webgpu_create_bind_group_layout( state: &mut OpState, args: CreateBindGroupLayoutArgs, @@ -220,6 +222,7 @@ pub struct CreatePipelineLayoutArgs { bind_group_layouts: Vec, } +#[op] pub fn op_webgpu_create_pipeline_layout( state: &mut OpState, args: CreatePipelineLayoutArgs, @@ -271,6 +274,7 @@ pub struct CreateBindGroupArgs { entries: Vec, } +#[op] pub fn op_webgpu_create_bind_group( state: &mut OpState, args: CreateBindGroupArgs, diff --git a/ext/webgpu/src/buffer.rs b/ext/webgpu/src/buffer.rs index 3f2c078831..ce3a78d011 100644 --- a/ext/webgpu/src/buffer.rs +++ b/ext/webgpu/src/buffer.rs @@ -3,6 +3,8 @@ use deno_core::error::type_error; use deno_core::error::AnyError; use deno_core::futures::channel::oneshot; +use deno_core::op; + use deno_core::OpState; use deno_core::Resource; use deno_core::ResourceId; @@ -40,6 +42,7 @@ pub struct CreateBufferArgs { mapped_at_creation: bool, } +#[op] pub fn op_webgpu_create_buffer( state: &mut OpState, args: CreateBufferArgs, @@ -76,6 +79,7 @@ pub struct BufferGetMapAsyncArgs { size: u64, } +#[op] pub async fn op_webgpu_buffer_get_map_async( state: Rc>, args: BufferGetMapAsyncArgs, @@ -167,6 +171,7 @@ pub struct BufferGetMappedRangeArgs { size: Option, } +#[op] pub fn op_webgpu_buffer_get_mapped_range( state: &mut OpState, args: BufferGetMappedRangeArgs, @@ -204,6 +209,7 @@ pub struct BufferUnmapArgs { mapped_rid: ResourceId, } +#[op] pub fn op_webgpu_buffer_unmap( state: &mut OpState, args: BufferUnmapArgs, diff --git a/ext/webgpu/src/bundle.rs b/ext/webgpu/src/bundle.rs index ea327651a5..4a08073026 100644 --- a/ext/webgpu/src/bundle.rs +++ b/ext/webgpu/src/bundle.rs @@ -1,6 +1,7 @@ // Copyright 2018-2022 the Deno authors. All rights reserved. MIT license. use deno_core::error::AnyError; +use deno_core::op; use deno_core::ResourceId; use deno_core::ZeroCopyBuf; use deno_core::{OpState, Resource}; @@ -39,6 +40,7 @@ pub struct CreateRenderBundleEncoderArgs { stencil_read_only: bool, } +#[op] pub fn op_webgpu_create_render_bundle_encoder( state: &mut OpState, args: CreateRenderBundleEncoderArgs, @@ -99,6 +101,7 @@ pub struct RenderBundleEncoderFinishArgs { label: Option, } +#[op] pub fn op_webgpu_render_bundle_encoder_finish( state: &mut OpState, args: RenderBundleEncoderFinishArgs, @@ -135,6 +138,7 @@ pub struct RenderBundleEncoderSetBindGroupArgs { dynamic_offsets_data_length: usize, } +#[op] pub fn op_webgpu_render_bundle_encoder_set_bind_group( state: &mut OpState, args: RenderBundleEncoderSetBindGroupArgs, @@ -189,6 +193,7 @@ pub struct RenderBundleEncoderPushDebugGroupArgs { group_label: String, } +#[op] pub fn op_webgpu_render_bundle_encoder_push_debug_group( state: &mut OpState, args: RenderBundleEncoderPushDebugGroupArgs, @@ -218,6 +223,7 @@ pub struct RenderBundleEncoderPopDebugGroupArgs { render_bundle_encoder_rid: ResourceId, } +#[op] pub fn op_webgpu_render_bundle_encoder_pop_debug_group( state: &mut OpState, args: RenderBundleEncoderPopDebugGroupArgs, @@ -242,6 +248,7 @@ pub struct RenderBundleEncoderInsertDebugMarkerArgs { marker_label: String, } +#[op] pub fn op_webgpu_render_bundle_encoder_insert_debug_marker( state: &mut OpState, args: RenderBundleEncoderInsertDebugMarkerArgs, @@ -272,6 +279,7 @@ pub struct RenderBundleEncoderSetPipelineArgs { pipeline: ResourceId, } +#[op] pub fn op_webgpu_render_bundle_encoder_set_pipeline( state: &mut OpState, args: RenderBundleEncoderSetPipelineArgs, @@ -304,6 +312,7 @@ pub struct RenderBundleEncoderSetIndexBufferArgs { size: u64, } +#[op] pub fn op_webgpu_render_bundle_encoder_set_index_buffer( state: &mut OpState, args: RenderBundleEncoderSetIndexBufferArgs, @@ -340,6 +349,7 @@ pub struct RenderBundleEncoderSetVertexBufferArgs { size: u64, } +#[op] pub fn op_webgpu_render_bundle_encoder_set_vertex_buffer( state: &mut OpState, args: RenderBundleEncoderSetVertexBufferArgs, @@ -374,6 +384,7 @@ pub struct RenderBundleEncoderDrawArgs { first_instance: u32, } +#[op] pub fn op_webgpu_render_bundle_encoder_draw( state: &mut OpState, args: RenderBundleEncoderDrawArgs, @@ -406,6 +417,7 @@ pub struct RenderBundleEncoderDrawIndexedArgs { first_instance: u32, } +#[op] pub fn op_webgpu_render_bundle_encoder_draw_indexed( state: &mut OpState, args: RenderBundleEncoderDrawIndexedArgs, @@ -436,6 +448,7 @@ pub struct RenderBundleEncoderDrawIndirectArgs { indirect_offset: u64, } +#[op] pub fn op_webgpu_render_bundle_encoder_draw_indirect( state: &mut OpState, args: RenderBundleEncoderDrawIndirectArgs, diff --git a/ext/webgpu/src/command_encoder.rs b/ext/webgpu/src/command_encoder.rs index 894b08f274..c81b2abf6d 100644 --- a/ext/webgpu/src/command_encoder.rs +++ b/ext/webgpu/src/command_encoder.rs @@ -1,6 +1,7 @@ // Copyright 2018-2022 the Deno authors. All rights reserved. MIT license. use deno_core::error::AnyError; +use deno_core::op; use deno_core::ResourceId; use deno_core::{OpState, Resource}; use serde::Deserialize; @@ -36,6 +37,7 @@ pub struct CreateCommandEncoderArgs { _measure_execution_time: Option, // not yet implemented } +#[op] pub fn op_webgpu_create_command_encoder( state: &mut OpState, args: CreateCommandEncoderArgs, @@ -96,6 +98,7 @@ pub struct CommandEncoderBeginRenderPassArgs { _occlusion_query_set: Option, // not yet implemented } +#[op] pub fn op_webgpu_command_encoder_begin_render_pass( state: &mut OpState, args: CommandEncoderBeginRenderPassArgs, @@ -214,6 +217,7 @@ pub struct CommandEncoderBeginComputePassArgs { label: Option, } +#[op] pub fn op_webgpu_command_encoder_begin_compute_pass( state: &mut OpState, args: CommandEncoderBeginComputePassArgs, @@ -252,6 +256,7 @@ pub struct CommandEncoderCopyBufferToBufferArgs { size: u64, } +#[op] pub fn op_webgpu_command_encoder_copy_buffer_to_buffer( state: &mut OpState, args: CommandEncoderCopyBufferToBufferArgs, @@ -310,6 +315,7 @@ pub struct CommandEncoderCopyBufferToTextureArgs { copy_size: wgpu_types::Extent3d, } +#[op] pub fn op_webgpu_command_encoder_copy_buffer_to_texture( state: &mut OpState, args: CommandEncoderCopyBufferToTextureArgs, @@ -360,6 +366,7 @@ pub struct CommandEncoderCopyTextureToBufferArgs { copy_size: wgpu_types::Extent3d, } +#[op] pub fn op_webgpu_command_encoder_copy_texture_to_buffer( state: &mut OpState, args: CommandEncoderCopyTextureToBufferArgs, @@ -414,6 +421,7 @@ pub struct CommandEncoderCopyTextureToTextureArgs { copy_size: wgpu_types::Extent3d, } +#[op] pub fn op_webgpu_command_encoder_copy_texture_to_texture( state: &mut OpState, args: CommandEncoderCopyTextureToTextureArgs, @@ -462,6 +470,7 @@ pub struct CommandEncoderClearBufferArgs { size: u64, } +#[op] pub fn op_webgpu_command_encoder_clear_buffer( state: &mut OpState, args: CommandEncoderClearBufferArgs, @@ -491,6 +500,7 @@ pub struct CommandEncoderPushDebugGroupArgs { group_label: String, } +#[op] pub fn op_webgpu_command_encoder_push_debug_group( state: &mut OpState, args: CommandEncoderPushDebugGroupArgs, @@ -512,6 +522,7 @@ pub struct CommandEncoderPopDebugGroupArgs { command_encoder_rid: ResourceId, } +#[op] pub fn op_webgpu_command_encoder_pop_debug_group( state: &mut OpState, args: CommandEncoderPopDebugGroupArgs, @@ -533,6 +544,7 @@ pub struct CommandEncoderInsertDebugMarkerArgs { marker_label: String, } +#[op] pub fn op_webgpu_command_encoder_insert_debug_marker( state: &mut OpState, args: CommandEncoderInsertDebugMarkerArgs, @@ -558,6 +570,7 @@ pub struct CommandEncoderWriteTimestampArgs { query_index: u32, } +#[op] pub fn op_webgpu_command_encoder_write_timestamp( state: &mut OpState, args: CommandEncoderWriteTimestampArgs, @@ -590,6 +603,7 @@ pub struct CommandEncoderResolveQuerySetArgs { destination_offset: u64, } +#[op] pub fn op_webgpu_command_encoder_resolve_query_set( state: &mut OpState, args: CommandEncoderResolveQuerySetArgs, @@ -624,6 +638,7 @@ pub struct CommandEncoderFinishArgs { label: Option, } +#[op] pub fn op_webgpu_command_encoder_finish( state: &mut OpState, args: CommandEncoderFinishArgs, diff --git a/ext/webgpu/src/compute_pass.rs b/ext/webgpu/src/compute_pass.rs index 03d9163cb2..e6ebdc098e 100644 --- a/ext/webgpu/src/compute_pass.rs +++ b/ext/webgpu/src/compute_pass.rs @@ -1,6 +1,7 @@ // Copyright 2018-2022 the Deno authors. All rights reserved. MIT license. use deno_core::error::AnyError; +use deno_core::op; use deno_core::ResourceId; use deno_core::ZeroCopyBuf; use deno_core::{OpState, Resource}; @@ -26,6 +27,7 @@ pub struct ComputePassSetPipelineArgs { pipeline: ResourceId, } +#[op] pub fn op_webgpu_compute_pass_set_pipeline( state: &mut OpState, args: ComputePassSetPipelineArgs, @@ -56,6 +58,7 @@ pub struct ComputePassDispatchArgs { z: u32, } +#[op] pub fn op_webgpu_compute_pass_dispatch( state: &mut OpState, args: ComputePassDispatchArgs, @@ -83,6 +86,7 @@ pub struct ComputePassDispatchIndirectArgs { indirect_offset: u64, } +#[op] pub fn op_webgpu_compute_pass_dispatch_indirect( state: &mut OpState, args: ComputePassDispatchIndirectArgs, @@ -112,6 +116,7 @@ pub struct ComputePassBeginPipelineStatisticsQueryArgs { query_index: u32, } +#[op] pub fn op_webgpu_compute_pass_begin_pipeline_statistics_query( state: &mut OpState, args: ComputePassBeginPipelineStatisticsQueryArgs, @@ -139,6 +144,7 @@ pub struct ComputePassEndPipelineStatisticsQueryArgs { compute_pass_rid: ResourceId, } +#[op] pub fn op_webgpu_compute_pass_end_pipeline_statistics_query( state: &mut OpState, args: ComputePassEndPipelineStatisticsQueryArgs, @@ -163,6 +169,7 @@ pub struct ComputePassWriteTimestampArgs { query_index: u32, } +#[op] pub fn op_webgpu_compute_pass_write_timestamp( state: &mut OpState, args: ComputePassWriteTimestampArgs, @@ -191,6 +198,7 @@ pub struct ComputePassEndPassArgs { compute_pass_rid: ResourceId, } +#[op] pub fn op_webgpu_compute_pass_end_pass( state: &mut OpState, args: ComputePassEndPassArgs, @@ -225,6 +233,7 @@ pub struct ComputePassSetBindGroupArgs { dynamic_offsets_data_length: usize, } +#[op] pub fn op_webgpu_compute_pass_set_bind_group( state: &mut OpState, args: ComputePassSetBindGroupArgs, @@ -278,6 +287,7 @@ pub struct ComputePassPushDebugGroupArgs { group_label: String, } +#[op] pub fn op_webgpu_compute_pass_push_debug_group( state: &mut OpState, args: ComputePassPushDebugGroupArgs, @@ -307,6 +317,7 @@ pub struct ComputePassPopDebugGroupArgs { compute_pass_rid: ResourceId, } +#[op] pub fn op_webgpu_compute_pass_pop_debug_group( state: &mut OpState, args: ComputePassPopDebugGroupArgs, @@ -330,6 +341,7 @@ pub struct ComputePassInsertDebugMarkerArgs { marker_label: String, } +#[op] pub fn op_webgpu_compute_pass_insert_debug_marker( state: &mut OpState, args: ComputePassInsertDebugMarkerArgs, diff --git a/ext/webgpu/src/lib.rs b/ext/webgpu/src/lib.rs index 9d227a51e4..d1eba20ba2 100644 --- a/ext/webgpu/src/lib.rs +++ b/ext/webgpu/src/lib.rs @@ -2,10 +2,10 @@ use deno_core::error::AnyError; use deno_core::include_js_files; -use deno_core::op_async; -use deno_core::op_sync; +use deno_core::op; + use deno_core::Extension; -use deno_core::OpFn; +use deno_core::OpPair; use deno_core::OpState; use deno_core::Resource; use deno_core::ResourceId; @@ -241,6 +241,7 @@ pub struct GpuAdapterDevice { is_software: bool, } +#[op] pub async fn op_webgpu_request_adapter( state: Rc>, args: RequestAdapterArgs, @@ -439,6 +440,7 @@ impl From for wgpu_types::Features { } } +#[op] pub async fn op_webgpu_request_device( state: Rc>, args: RequestDeviceArgs, @@ -539,6 +541,7 @@ impl From for wgpu_types::QueryType { } } +#[op] pub fn op_webgpu_create_query_set( state: &mut OpState, args: CreateQuerySetArgs, @@ -562,347 +565,102 @@ pub fn op_webgpu_create_query_set( ) => state, WebGpuQuerySet) } -fn declare_webgpu_ops() -> Vec<(&'static str, Box)> { +fn declare_webgpu_ops() -> Vec { vec![ // Request device/adapter - ( - "op_webgpu_request_adapter", - op_async(op_webgpu_request_adapter), - ), - ( - "op_webgpu_request_device", - op_async(op_webgpu_request_device), - ), + op_webgpu_request_adapter::decl(), + op_webgpu_request_device::decl(), // Query Set - ( - "op_webgpu_create_query_set", - op_sync(op_webgpu_create_query_set), - ), + op_webgpu_create_query_set::decl(), // buffer - ( - "op_webgpu_create_buffer", - op_sync(buffer::op_webgpu_create_buffer), - ), - ( - "op_webgpu_buffer_get_mapped_range", - op_sync(buffer::op_webgpu_buffer_get_mapped_range), - ), - ( - "op_webgpu_buffer_unmap", - op_sync(buffer::op_webgpu_buffer_unmap), - ), + buffer::op_webgpu_create_buffer::decl(), + buffer::op_webgpu_buffer_get_mapped_range::decl(), + buffer::op_webgpu_buffer_unmap::decl(), // buffer async - ( - "op_webgpu_buffer_get_map_async", - op_async(buffer::op_webgpu_buffer_get_map_async), - ), + buffer::op_webgpu_buffer_get_map_async::decl(), // remaining sync ops // texture - ( - "op_webgpu_create_texture", - op_sync(texture::op_webgpu_create_texture), - ), - ( - "op_webgpu_create_texture_view", - op_sync(texture::op_webgpu_create_texture_view), - ), + texture::op_webgpu_create_texture::decl(), + texture::op_webgpu_create_texture_view::decl(), // sampler - ( - "op_webgpu_create_sampler", - op_sync(sampler::op_webgpu_create_sampler), - ), + sampler::op_webgpu_create_sampler::decl(), // binding - ( - "op_webgpu_create_bind_group_layout", - op_sync(binding::op_webgpu_create_bind_group_layout), - ), - ( - "op_webgpu_create_pipeline_layout", - op_sync(binding::op_webgpu_create_pipeline_layout), - ), - ( - "op_webgpu_create_bind_group", - op_sync(binding::op_webgpu_create_bind_group), - ), + binding::op_webgpu_create_bind_group_layout::decl(), + binding::op_webgpu_create_pipeline_layout::decl(), + binding::op_webgpu_create_bind_group::decl(), // pipeline - ( - "op_webgpu_create_compute_pipeline", - op_sync(pipeline::op_webgpu_create_compute_pipeline), - ), - ( - "op_webgpu_compute_pipeline_get_bind_group_layout", - op_sync(pipeline::op_webgpu_compute_pipeline_get_bind_group_layout), - ), - ( - "op_webgpu_create_render_pipeline", - op_sync(pipeline::op_webgpu_create_render_pipeline), - ), - ( - "op_webgpu_render_pipeline_get_bind_group_layout", - op_sync(pipeline::op_webgpu_render_pipeline_get_bind_group_layout), - ), + pipeline::op_webgpu_create_compute_pipeline::decl(), + pipeline::op_webgpu_compute_pipeline_get_bind_group_layout::decl(), + pipeline::op_webgpu_create_render_pipeline::decl(), + pipeline::op_webgpu_render_pipeline_get_bind_group_layout::decl(), // command_encoder - ( - "op_webgpu_create_command_encoder", - op_sync(command_encoder::op_webgpu_create_command_encoder), - ), - ( - "op_webgpu_command_encoder_begin_render_pass", - op_sync(command_encoder::op_webgpu_command_encoder_begin_render_pass), - ), - ( - "op_webgpu_command_encoder_begin_compute_pass", - op_sync(command_encoder::op_webgpu_command_encoder_begin_compute_pass), - ), - ( - "op_webgpu_command_encoder_copy_buffer_to_buffer", - op_sync(command_encoder::op_webgpu_command_encoder_copy_buffer_to_buffer), - ), - ( - "op_webgpu_command_encoder_copy_buffer_to_texture", - op_sync( - command_encoder::op_webgpu_command_encoder_copy_buffer_to_texture, - ), - ), - ( - "op_webgpu_command_encoder_copy_texture_to_buffer", - op_sync( - command_encoder::op_webgpu_command_encoder_copy_texture_to_buffer, - ), - ), - ( - "op_webgpu_command_encoder_copy_texture_to_texture", - op_sync( - command_encoder::op_webgpu_command_encoder_copy_texture_to_texture, - ), - ), - ( - "op_webgpu_command_encoder_clear_buffer", - op_sync(command_encoder::op_webgpu_command_encoder_clear_buffer), - ), - ( - "op_webgpu_command_encoder_push_debug_group", - op_sync(command_encoder::op_webgpu_command_encoder_push_debug_group), - ), - ( - "op_webgpu_command_encoder_pop_debug_group", - op_sync(command_encoder::op_webgpu_command_encoder_pop_debug_group), - ), - ( - "op_webgpu_command_encoder_insert_debug_marker", - op_sync(command_encoder::op_webgpu_command_encoder_insert_debug_marker), - ), - ( - "op_webgpu_command_encoder_write_timestamp", - op_sync(command_encoder::op_webgpu_command_encoder_write_timestamp), - ), - ( - "op_webgpu_command_encoder_resolve_query_set", - op_sync(command_encoder::op_webgpu_command_encoder_resolve_query_set), - ), - ( - "op_webgpu_command_encoder_finish", - op_sync(command_encoder::op_webgpu_command_encoder_finish), - ), + command_encoder::op_webgpu_create_command_encoder::decl(), + command_encoder::op_webgpu_command_encoder_begin_render_pass::decl(), + command_encoder::op_webgpu_command_encoder_begin_compute_pass::decl(), + command_encoder::op_webgpu_command_encoder_copy_buffer_to_buffer::decl(), + command_encoder::op_webgpu_command_encoder_copy_buffer_to_texture::decl(), + command_encoder::op_webgpu_command_encoder_copy_texture_to_buffer::decl(), + command_encoder::op_webgpu_command_encoder_copy_texture_to_texture::decl(), + command_encoder::op_webgpu_command_encoder_clear_buffer::decl(), + command_encoder::op_webgpu_command_encoder_push_debug_group::decl(), + command_encoder::op_webgpu_command_encoder_pop_debug_group::decl(), + command_encoder::op_webgpu_command_encoder_insert_debug_marker::decl(), + command_encoder::op_webgpu_command_encoder_write_timestamp::decl(), + command_encoder::op_webgpu_command_encoder_resolve_query_set::decl(), + command_encoder::op_webgpu_command_encoder_finish::decl(), // render_pass - ( - "op_webgpu_render_pass_set_viewport", - op_sync(render_pass::op_webgpu_render_pass_set_viewport), - ), - ( - "op_webgpu_render_pass_set_scissor_rect", - op_sync(render_pass::op_webgpu_render_pass_set_scissor_rect), - ), - ( - "op_webgpu_render_pass_set_blend_constant", - op_sync(render_pass::op_webgpu_render_pass_set_blend_constant), - ), - ( - "op_webgpu_render_pass_set_stencil_reference", - op_sync(render_pass::op_webgpu_render_pass_set_stencil_reference), - ), - ( - "op_webgpu_render_pass_begin_pipeline_statistics_query", - op_sync( - render_pass::op_webgpu_render_pass_begin_pipeline_statistics_query, - ), - ), - ( - "op_webgpu_render_pass_end_pipeline_statistics_query", - op_sync(render_pass::op_webgpu_render_pass_end_pipeline_statistics_query), - ), - ( - "op_webgpu_render_pass_write_timestamp", - op_sync(render_pass::op_webgpu_render_pass_write_timestamp), - ), - ( - "op_webgpu_render_pass_execute_bundles", - op_sync(render_pass::op_webgpu_render_pass_execute_bundles), - ), - ( - "op_webgpu_render_pass_end_pass", - op_sync(render_pass::op_webgpu_render_pass_end_pass), - ), - ( - "op_webgpu_render_pass_set_bind_group", - op_sync(render_pass::op_webgpu_render_pass_set_bind_group), - ), - ( - "op_webgpu_render_pass_push_debug_group", - op_sync(render_pass::op_webgpu_render_pass_push_debug_group), - ), - ( - "op_webgpu_render_pass_pop_debug_group", - op_sync(render_pass::op_webgpu_render_pass_pop_debug_group), - ), - ( - "op_webgpu_render_pass_insert_debug_marker", - op_sync(render_pass::op_webgpu_render_pass_insert_debug_marker), - ), - ( - "op_webgpu_render_pass_set_pipeline", - op_sync(render_pass::op_webgpu_render_pass_set_pipeline), - ), - ( - "op_webgpu_render_pass_set_index_buffer", - op_sync(render_pass::op_webgpu_render_pass_set_index_buffer), - ), - ( - "op_webgpu_render_pass_set_vertex_buffer", - op_sync(render_pass::op_webgpu_render_pass_set_vertex_buffer), - ), - ( - "op_webgpu_render_pass_draw", - op_sync(render_pass::op_webgpu_render_pass_draw), - ), - ( - "op_webgpu_render_pass_draw_indexed", - op_sync(render_pass::op_webgpu_render_pass_draw_indexed), - ), - ( - "op_webgpu_render_pass_draw_indirect", - op_sync(render_pass::op_webgpu_render_pass_draw_indirect), - ), - ( - "op_webgpu_render_pass_draw_indexed_indirect", - op_sync(render_pass::op_webgpu_render_pass_draw_indexed_indirect), - ), + render_pass::op_webgpu_render_pass_set_viewport::decl(), + render_pass::op_webgpu_render_pass_set_scissor_rect::decl(), + render_pass::op_webgpu_render_pass_set_blend_constant::decl(), + render_pass::op_webgpu_render_pass_set_stencil_reference::decl(), + render_pass::op_webgpu_render_pass_begin_pipeline_statistics_query::decl(), + render_pass::op_webgpu_render_pass_end_pipeline_statistics_query::decl(), + render_pass::op_webgpu_render_pass_write_timestamp::decl(), + render_pass::op_webgpu_render_pass_execute_bundles::decl(), + render_pass::op_webgpu_render_pass_end_pass::decl(), + render_pass::op_webgpu_render_pass_set_bind_group::decl(), + render_pass::op_webgpu_render_pass_push_debug_group::decl(), + render_pass::op_webgpu_render_pass_pop_debug_group::decl(), + render_pass::op_webgpu_render_pass_insert_debug_marker::decl(), + render_pass::op_webgpu_render_pass_set_pipeline::decl(), + render_pass::op_webgpu_render_pass_set_index_buffer::decl(), + render_pass::op_webgpu_render_pass_set_vertex_buffer::decl(), + render_pass::op_webgpu_render_pass_draw::decl(), + render_pass::op_webgpu_render_pass_draw_indexed::decl(), + render_pass::op_webgpu_render_pass_draw_indirect::decl(), + render_pass::op_webgpu_render_pass_draw_indexed_indirect::decl(), // compute_pass - ( - "op_webgpu_compute_pass_set_pipeline", - op_sync(compute_pass::op_webgpu_compute_pass_set_pipeline), - ), - ( - "op_webgpu_compute_pass_dispatch", - op_sync(compute_pass::op_webgpu_compute_pass_dispatch), - ), - ( - "op_webgpu_compute_pass_dispatch_indirect", - op_sync(compute_pass::op_webgpu_compute_pass_dispatch_indirect), - ), - ( - "op_webgpu_compute_pass_begin_pipeline_statistics_query", - op_sync( - compute_pass::op_webgpu_compute_pass_begin_pipeline_statistics_query, - ), - ), - ( - "op_webgpu_compute_pass_end_pipeline_statistics_query", - op_sync( - compute_pass::op_webgpu_compute_pass_end_pipeline_statistics_query, - ), - ), - ( - "op_webgpu_compute_pass_write_timestamp", - op_sync(compute_pass::op_webgpu_compute_pass_write_timestamp), - ), - ( - "op_webgpu_compute_pass_end_pass", - op_sync(compute_pass::op_webgpu_compute_pass_end_pass), - ), - ( - "op_webgpu_compute_pass_set_bind_group", - op_sync(compute_pass::op_webgpu_compute_pass_set_bind_group), - ), - ( - "op_webgpu_compute_pass_push_debug_group", - op_sync(compute_pass::op_webgpu_compute_pass_push_debug_group), - ), - ( - "op_webgpu_compute_pass_pop_debug_group", - op_sync(compute_pass::op_webgpu_compute_pass_pop_debug_group), - ), - ( - "op_webgpu_compute_pass_insert_debug_marker", - op_sync(compute_pass::op_webgpu_compute_pass_insert_debug_marker), + compute_pass::op_webgpu_compute_pass_set_pipeline::decl(), + compute_pass::op_webgpu_compute_pass_dispatch::decl(), + compute_pass::op_webgpu_compute_pass_dispatch_indirect::decl(), + compute_pass::op_webgpu_compute_pass_begin_pipeline_statistics_query::decl( ), + compute_pass::op_webgpu_compute_pass_end_pipeline_statistics_query::decl(), + compute_pass::op_webgpu_compute_pass_write_timestamp::decl(), + compute_pass::op_webgpu_compute_pass_end_pass::decl(), + compute_pass::op_webgpu_compute_pass_set_bind_group::decl(), + compute_pass::op_webgpu_compute_pass_push_debug_group::decl(), + compute_pass::op_webgpu_compute_pass_pop_debug_group::decl(), + compute_pass::op_webgpu_compute_pass_insert_debug_marker::decl(), // bundle - ( - "op_webgpu_create_render_bundle_encoder", - op_sync(bundle::op_webgpu_create_render_bundle_encoder), - ), - ( - "op_webgpu_render_bundle_encoder_finish", - op_sync(bundle::op_webgpu_render_bundle_encoder_finish), - ), - ( - "op_webgpu_render_bundle_encoder_set_bind_group", - op_sync(bundle::op_webgpu_render_bundle_encoder_set_bind_group), - ), - ( - "op_webgpu_render_bundle_encoder_push_debug_group", - op_sync(bundle::op_webgpu_render_bundle_encoder_push_debug_group), - ), - ( - "op_webgpu_render_bundle_encoder_pop_debug_group", - op_sync(bundle::op_webgpu_render_bundle_encoder_pop_debug_group), - ), - ( - "op_webgpu_render_bundle_encoder_insert_debug_marker", - op_sync(bundle::op_webgpu_render_bundle_encoder_insert_debug_marker), - ), - ( - "op_webgpu_render_bundle_encoder_set_pipeline", - op_sync(bundle::op_webgpu_render_bundle_encoder_set_pipeline), - ), - ( - "op_webgpu_render_bundle_encoder_set_index_buffer", - op_sync(bundle::op_webgpu_render_bundle_encoder_set_index_buffer), - ), - ( - "op_webgpu_render_bundle_encoder_set_vertex_buffer", - op_sync(bundle::op_webgpu_render_bundle_encoder_set_vertex_buffer), - ), - ( - "op_webgpu_render_bundle_encoder_draw", - op_sync(bundle::op_webgpu_render_bundle_encoder_draw), - ), - ( - "op_webgpu_render_bundle_encoder_draw_indexed", - op_sync(bundle::op_webgpu_render_bundle_encoder_draw_indexed), - ), - ( - "op_webgpu_render_bundle_encoder_draw_indirect", - op_sync(bundle::op_webgpu_render_bundle_encoder_draw_indirect), - ), + bundle::op_webgpu_create_render_bundle_encoder::decl(), + bundle::op_webgpu_render_bundle_encoder_finish::decl(), + bundle::op_webgpu_render_bundle_encoder_set_bind_group::decl(), + bundle::op_webgpu_render_bundle_encoder_push_debug_group::decl(), + bundle::op_webgpu_render_bundle_encoder_pop_debug_group::decl(), + bundle::op_webgpu_render_bundle_encoder_insert_debug_marker::decl(), + bundle::op_webgpu_render_bundle_encoder_set_pipeline::decl(), + bundle::op_webgpu_render_bundle_encoder_set_index_buffer::decl(), + bundle::op_webgpu_render_bundle_encoder_set_vertex_buffer::decl(), + bundle::op_webgpu_render_bundle_encoder_draw::decl(), + bundle::op_webgpu_render_bundle_encoder_draw_indexed::decl(), + bundle::op_webgpu_render_bundle_encoder_draw_indirect::decl(), // queue - ( - "op_webgpu_queue_submit", - op_sync(queue::op_webgpu_queue_submit), - ), - ( - "op_webgpu_write_buffer", - op_sync(queue::op_webgpu_write_buffer), - ), - ( - "op_webgpu_write_texture", - op_sync(queue::op_webgpu_write_texture), - ), + queue::op_webgpu_queue_submit::decl(), + queue::op_webgpu_write_buffer::decl(), + queue::op_webgpu_write_texture::decl(), // shader - ( - "op_webgpu_create_shader_module", - op_sync(shader::op_webgpu_create_shader_module), - ), + shader::op_webgpu_create_shader_module::decl(), ] } diff --git a/ext/webgpu/src/pipeline.rs b/ext/webgpu/src/pipeline.rs index 8327fb9465..6ea2a56776 100644 --- a/ext/webgpu/src/pipeline.rs +++ b/ext/webgpu/src/pipeline.rs @@ -1,6 +1,7 @@ // Copyright 2018-2022 the Deno authors. All rights reserved. MIT license. use deno_core::error::AnyError; +use deno_core::op; use deno_core::ResourceId; use deno_core::{OpState, Resource}; use serde::Deserialize; @@ -57,6 +58,7 @@ pub struct CreateComputePipelineArgs { compute: GpuProgrammableStage, } +#[op] pub fn op_webgpu_create_compute_pipeline( state: &mut OpState, args: CreateComputePipelineArgs, @@ -126,6 +128,7 @@ pub struct PipelineLayout { err: Option, } +#[op] pub fn op_webgpu_compute_pipeline_get_bind_group_layout( state: &mut OpState, args: ComputePipelineGetBindGroupLayoutArgs, @@ -303,6 +306,7 @@ pub struct CreateRenderPipelineArgs { fragment: Option, } +#[op] pub fn op_webgpu_create_render_pipeline( state: &mut OpState, args: CreateRenderPipelineArgs, @@ -404,6 +408,7 @@ pub struct RenderPipelineGetBindGroupLayoutArgs { index: u32, } +#[op] pub fn op_webgpu_render_pipeline_get_bind_group_layout( state: &mut OpState, args: RenderPipelineGetBindGroupLayoutArgs, diff --git a/ext/webgpu/src/queue.rs b/ext/webgpu/src/queue.rs index a662c4ead6..3853f00252 100644 --- a/ext/webgpu/src/queue.rs +++ b/ext/webgpu/src/queue.rs @@ -3,6 +3,7 @@ use std::num::NonZeroU32; use deno_core::error::AnyError; +use deno_core::op; use deno_core::OpState; use deno_core::ResourceId; use deno_core::ZeroCopyBuf; @@ -19,6 +20,7 @@ pub struct QueueSubmitArgs { command_buffers: Vec, } +#[op] pub fn op_webgpu_queue_submit( state: &mut OpState, args: QueueSubmitArgs, @@ -73,6 +75,7 @@ pub struct QueueWriteBufferArgs { size: Option, } +#[op] pub fn op_webgpu_write_buffer( state: &mut OpState, args: QueueWriteBufferArgs, @@ -111,6 +114,7 @@ pub struct QueueWriteTextureArgs { size: wgpu_types::Extent3d, } +#[op] pub fn op_webgpu_write_texture( state: &mut OpState, args: QueueWriteTextureArgs, diff --git a/ext/webgpu/src/render_pass.rs b/ext/webgpu/src/render_pass.rs index 469bf727e4..822b4c8c9c 100644 --- a/ext/webgpu/src/render_pass.rs +++ b/ext/webgpu/src/render_pass.rs @@ -2,6 +2,7 @@ use deno_core::error::type_error; use deno_core::error::AnyError; +use deno_core::op; use deno_core::ResourceId; use deno_core::ZeroCopyBuf; use deno_core::{OpState, Resource}; @@ -32,6 +33,7 @@ pub struct RenderPassSetViewportArgs { max_depth: f32, } +#[op] pub fn op_webgpu_render_pass_set_viewport( state: &mut OpState, args: RenderPassSetViewportArgs, @@ -64,6 +66,7 @@ pub struct RenderPassSetScissorRectArgs { height: u32, } +#[op] pub fn op_webgpu_render_pass_set_scissor_rect( state: &mut OpState, args: RenderPassSetScissorRectArgs, @@ -91,6 +94,7 @@ pub struct RenderPassSetBlendConstantArgs { color: wgpu_types::Color, } +#[op] pub fn op_webgpu_render_pass_set_blend_constant( state: &mut OpState, args: RenderPassSetBlendConstantArgs, @@ -115,6 +119,7 @@ pub struct RenderPassSetStencilReferenceArgs { reference: u32, } +#[op] pub fn op_webgpu_render_pass_set_stencil_reference( state: &mut OpState, args: RenderPassSetStencilReferenceArgs, @@ -140,6 +145,7 @@ pub struct RenderPassBeginPipelineStatisticsQueryArgs { query_index: u32, } +#[op] pub fn op_webgpu_render_pass_begin_pipeline_statistics_query( state: &mut OpState, args: RenderPassBeginPipelineStatisticsQueryArgs, @@ -167,6 +173,7 @@ pub struct RenderPassEndPipelineStatisticsQueryArgs { render_pass_rid: ResourceId, } +#[op] pub fn op_webgpu_render_pass_end_pipeline_statistics_query( state: &mut OpState, args: RenderPassEndPipelineStatisticsQueryArgs, @@ -191,6 +198,7 @@ pub struct RenderPassWriteTimestampArgs { query_index: u32, } +#[op] pub fn op_webgpu_render_pass_write_timestamp( state: &mut OpState, args: RenderPassWriteTimestampArgs, @@ -219,6 +227,7 @@ pub struct RenderPassExecuteBundlesArgs { bundles: Vec, } +#[op] pub fn op_webgpu_render_pass_execute_bundles( state: &mut OpState, args: RenderPassExecuteBundlesArgs, @@ -258,6 +267,7 @@ pub struct RenderPassEndPassArgs { render_pass_rid: ResourceId, } +#[op] pub fn op_webgpu_render_pass_end_pass( state: &mut OpState, args: RenderPassEndPassArgs, @@ -289,6 +299,7 @@ pub struct RenderPassSetBindGroupArgs { dynamic_offsets_data_length: usize, } +#[op] pub fn op_webgpu_render_pass_set_bind_group( state: &mut OpState, args: RenderPassSetBindGroupArgs, @@ -342,6 +353,7 @@ pub struct RenderPassPushDebugGroupArgs { group_label: String, } +#[op] pub fn op_webgpu_render_pass_push_debug_group( state: &mut OpState, args: RenderPassPushDebugGroupArgs, @@ -371,6 +383,7 @@ pub struct RenderPassPopDebugGroupArgs { render_pass_rid: ResourceId, } +#[op] pub fn op_webgpu_render_pass_pop_debug_group( state: &mut OpState, args: RenderPassPopDebugGroupArgs, @@ -394,6 +407,7 @@ pub struct RenderPassInsertDebugMarkerArgs { marker_label: String, } +#[op] pub fn op_webgpu_render_pass_insert_debug_marker( state: &mut OpState, args: RenderPassInsertDebugMarkerArgs, @@ -424,6 +438,7 @@ pub struct RenderPassSetPipelineArgs { pipeline: u32, } +#[op] pub fn op_webgpu_render_pass_set_pipeline( state: &mut OpState, args: RenderPassSetPipelineArgs, @@ -455,6 +470,7 @@ pub struct RenderPassSetIndexBufferArgs { size: Option, } +#[op] pub fn op_webgpu_render_pass_set_index_buffer( state: &mut OpState, args: RenderPassSetIndexBufferArgs, @@ -496,6 +512,7 @@ pub struct RenderPassSetVertexBufferArgs { size: Option, } +#[op] pub fn op_webgpu_render_pass_set_vertex_buffer( state: &mut OpState, args: RenderPassSetVertexBufferArgs, @@ -538,6 +555,7 @@ pub struct RenderPassDrawArgs { first_instance: u32, } +#[op] pub fn op_webgpu_render_pass_draw( state: &mut OpState, args: RenderPassDrawArgs, @@ -569,6 +587,7 @@ pub struct RenderPassDrawIndexedArgs { first_instance: u32, } +#[op] pub fn op_webgpu_render_pass_draw_indexed( state: &mut OpState, args: RenderPassDrawIndexedArgs, @@ -598,6 +617,7 @@ pub struct RenderPassDrawIndirectArgs { indirect_offset: u64, } +#[op] pub fn op_webgpu_render_pass_draw_indirect( state: &mut OpState, args: RenderPassDrawIndirectArgs, @@ -627,6 +647,7 @@ pub struct RenderPassDrawIndexedIndirectArgs { indirect_offset: u64, } +#[op] pub fn op_webgpu_render_pass_draw_indexed_indirect( state: &mut OpState, args: RenderPassDrawIndexedIndirectArgs, diff --git a/ext/webgpu/src/sampler.rs b/ext/webgpu/src/sampler.rs index c1cb0b4119..3c0c43f532 100644 --- a/ext/webgpu/src/sampler.rs +++ b/ext/webgpu/src/sampler.rs @@ -1,6 +1,7 @@ // Copyright 2018-2022 the Deno authors. All rights reserved. MIT license. use deno_core::error::AnyError; +use deno_core::op; use deno_core::ResourceId; use deno_core::{OpState, Resource}; use serde::Deserialize; @@ -32,6 +33,7 @@ pub struct CreateSamplerArgs { max_anisotropy: u8, } +#[op] pub fn op_webgpu_create_sampler( state: &mut OpState, args: CreateSamplerArgs, diff --git a/ext/webgpu/src/shader.rs b/ext/webgpu/src/shader.rs index 60290de8b0..0173fffa2b 100644 --- a/ext/webgpu/src/shader.rs +++ b/ext/webgpu/src/shader.rs @@ -1,6 +1,7 @@ // Copyright 2018-2022 the Deno authors. All rights reserved. MIT license. use deno_core::error::AnyError; +use deno_core::op; use deno_core::ResourceId; use deno_core::{OpState, Resource}; use serde::Deserialize; @@ -24,6 +25,7 @@ pub struct CreateShaderModuleArgs { _source_map: Option<()>, // not yet implemented } +#[op] pub fn op_webgpu_create_shader_module( state: &mut OpState, args: CreateShaderModuleArgs, diff --git a/ext/webgpu/src/texture.rs b/ext/webgpu/src/texture.rs index 30d440e5c6..482437478a 100644 --- a/ext/webgpu/src/texture.rs +++ b/ext/webgpu/src/texture.rs @@ -1,6 +1,7 @@ // Copyright 2018-2022 the Deno authors. All rights reserved. MIT license. use deno_core::error::AnyError; +use deno_core::op; use deno_core::ResourceId; use deno_core::{OpState, Resource}; use serde::Deserialize; @@ -34,6 +35,7 @@ pub struct CreateTextureArgs { usage: u32, } +#[op] pub fn op_webgpu_create_texture( state: &mut OpState, args: CreateTextureArgs, @@ -76,6 +78,7 @@ pub struct CreateTextureViewArgs { array_layer_count: Option, } +#[op] pub fn op_webgpu_create_texture_view( state: &mut OpState, args: CreateTextureViewArgs, diff --git a/ext/websocket/lib.rs b/ext/websocket/lib.rs index 76ca921365..d712140b54 100644 --- a/ext/websocket/lib.rs +++ b/ext/websocket/lib.rs @@ -8,8 +8,8 @@ use deno_core::futures::stream::SplitStream; use deno_core::futures::SinkExt; use deno_core::futures::StreamExt; use deno_core::include_js_files; -use deno_core::op_async; -use deno_core::op_sync; +use deno_core::op; + use deno_core::url; use deno_core::AsyncRefCell; use deno_core::ByteString; @@ -190,6 +190,7 @@ impl Resource for WsCancelResource { // This op is needed because creating a WS instance in JavaScript is a sync // operation and should throw error when permissions are not fulfilled, // but actual op that connects WS is async. +#[op] pub fn op_ws_check_permission_and_cancel_handle( state: &mut OpState, url: String, @@ -229,6 +230,7 @@ pub struct CreateResponse { extensions: String, } +#[op] pub async fn op_ws_create( state: Rc>, args: CreateArgs, @@ -378,6 +380,7 @@ pub enum SendValue { Ping, } +#[op] pub async fn op_ws_send( state: Rc>, rid: ResourceId, @@ -406,6 +409,7 @@ pub struct CloseArgs { reason: Option, } +#[op] pub async fn op_ws_close( state: Rc>, args: CloseArgs, @@ -440,6 +444,7 @@ pub enum NextEventResponse { Closed, } +#[op] pub async fn op_ws_next_event( state: Rc>, rid: ResourceId, @@ -486,14 +491,11 @@ pub fn init( "02_websocketstream.js", )) .ops(vec![ - ( - "op_ws_check_permission_and_cancel_handle", - op_sync(op_ws_check_permission_and_cancel_handle::

), - ), - ("op_ws_create", op_async(op_ws_create::

)), - ("op_ws_send", op_async(op_ws_send)), - ("op_ws_close", op_async(op_ws_close)), - ("op_ws_next_event", op_async(op_ws_next_event)), + op_ws_check_permission_and_cancel_handle::decl::

(), + op_ws_create::decl::

(), + op_ws_send::decl(), + op_ws_close::decl(), + op_ws_next_event::decl(), ]) .state(move |state| { state.put::(WsUserAgent(user_agent.clone())); diff --git a/ext/webstorage/lib.rs b/ext/webstorage/lib.rs index 0aafefe627..c51301683c 100644 --- a/ext/webstorage/lib.rs +++ b/ext/webstorage/lib.rs @@ -4,7 +4,7 @@ use deno_core::error::AnyError; use deno_core::include_js_files; -use deno_core::op_sync; +use deno_core::op; use deno_core::Extension; use deno_core::OpState; use rusqlite::params; @@ -26,16 +26,13 @@ pub fn init(origin_storage_dir: Option) -> Extension { "01_webstorage.js", )) .ops(vec![ - ("op_webstorage_length", op_sync(op_webstorage_length)), - ("op_webstorage_key", op_sync(op_webstorage_key)), - ("op_webstorage_set", op_sync(op_webstorage_set)), - ("op_webstorage_get", op_sync(op_webstorage_get)), - ("op_webstorage_remove", op_sync(op_webstorage_remove)), - ("op_webstorage_clear", op_sync(op_webstorage_clear)), - ( - "op_webstorage_iterate_keys", - op_sync(op_webstorage_iterate_keys), - ), + op_webstorage_length::decl(), + op_webstorage_key::decl(), + op_webstorage_set::decl(), + op_webstorage_get::decl(), + op_webstorage_remove::decl(), + op_webstorage_clear::decl(), + op_webstorage_iterate_keys::decl(), ]) .state(move |state| { if let Some(origin_storage_dir) = &origin_storage_dir { @@ -103,6 +100,7 @@ fn get_webstorage( Ok(conn) } +#[op] pub fn op_webstorage_length( state: &mut OpState, persistent: bool, @@ -116,6 +114,7 @@ pub fn op_webstorage_length( Ok(length) } +#[op] pub fn op_webstorage_key( state: &mut OpState, index: u32, @@ -140,6 +139,7 @@ pub struct SetArgs { key_value: String, } +#[op] pub fn op_webstorage_set( state: &mut OpState, args: SetArgs, @@ -167,6 +167,7 @@ pub fn op_webstorage_set( Ok(()) } +#[op] pub fn op_webstorage_get( state: &mut OpState, key_name: String, @@ -182,6 +183,7 @@ pub fn op_webstorage_get( Ok(val) } +#[op] pub fn op_webstorage_remove( state: &mut OpState, key_name: String, @@ -195,6 +197,7 @@ pub fn op_webstorage_remove( Ok(()) } +#[op] pub fn op_webstorage_clear( state: &mut OpState, persistent: bool, @@ -208,6 +211,7 @@ pub fn op_webstorage_clear( Ok(()) } +#[op] pub fn op_webstorage_iterate_keys( state: &mut OpState, persistent: bool, diff --git a/ops/Cargo.toml b/ops/Cargo.toml new file mode 100644 index 0000000000..aafa55cbcd --- /dev/null +++ b/ops/Cargo.toml @@ -0,0 +1,17 @@ +[package] +name = "deno_ops" +version = "0.1.1" +edition = "2021" +license = "MIT" +readme = "README.md" +description = "Proc macro for writing Deno Ops" + +[lib] +path = "./lib.rs" +proc-macro = true + +[dependencies] +proc-macro-crate = "1.1.3" +proc-macro2 = "1" +quote = "1" +syn = { version = "1", features = ["full", "extra-traits"] } diff --git a/ops/README.md b/ops/README.md new file mode 100644 index 0000000000..02ee266f71 --- /dev/null +++ b/ops/README.md @@ -0,0 +1,16 @@ +# deno_ops + +`proc_macro` for generating highly optimized V8 functions from Deno ops. + +```rust +// Declare an op. +#[op] +pub fn op_add(_: &mut OpState, a: i32, b: i32) -> Result { + Ok(a + b) +} + +// Register with an extension. +Extension::builder() + .ops(vec![op_add::decl()]) + .build(); +``` diff --git a/ops/lib.rs b/ops/lib.rs new file mode 100644 index 0000000000..d159c6c4b2 --- /dev/null +++ b/ops/lib.rs @@ -0,0 +1,264 @@ +// Copyright 2018-2022 the Deno authors. All rights reserved. MIT license. +use proc_macro::TokenStream; +use proc_macro2::Span; +use proc_macro2::TokenStream as TokenStream2; +use proc_macro_crate::crate_name; +use proc_macro_crate::FoundCrate; +use quote::quote; +use syn::Ident; + +// Identifer to the `deno_core` crate. +// +// If macro called in deno_core, `crate` is used. +// If macro called outside deno_core, `deno_core` OR the renamed +// version from Cargo.toml is used. +fn core_import() -> TokenStream2 { + let found_crate = + crate_name("deno_core").expect("deno_core not present in `Cargo.toml`"); + + match found_crate { + FoundCrate::Itself => { + // TODO(@littledivy): This won't work for `deno_core` examples + // since `crate` does not refer to `deno_core`. + // examples must re-export deno_core to make this work + // until Span inspection APIs are stabalized. + // + // https://github.com/rust-lang/rust/issues/54725 + quote!(crate) + } + FoundCrate::Name(name) => { + let ident = Ident::new(&name, Span::call_site()); + quote!(#ident) + } + } +} + +#[proc_macro_attribute] +pub fn op(_attr: TokenStream, item: TokenStream) -> TokenStream { + let func = syn::parse::(item).expect("expected a function"); + let name = &func.sig.ident; + let generics = &func.sig.generics; + let type_params = &func.sig.generics.params; + let where_clause = &func.sig.generics.where_clause; + + // Preserve the original func as op_foo::call() + let original_func = { + let mut func = func.clone(); + func.sig.ident = quote::format_ident!("call"); + func + }; + + let core = core_import(); + + let v8_body = if func.sig.asyncness.is_some() { + codegen_v8_async(&core, &func) + } else { + codegen_v8_sync(&core, &func) + }; + + // Generate wrapper + quote! { + #[allow(non_camel_case_types)] + pub struct #name; + + impl #name { + pub fn name() -> &'static str { + stringify!(#name) + } + + pub fn v8_cb #generics () -> #core::v8::FunctionCallback #where_clause { + use #core::v8::MapFnTo; + Self::v8_func::<#type_params>.map_fn_to() + } + + pub fn decl #generics () -> (&'static str, #core::v8::FunctionCallback) #where_clause { + (Self::name(), Self::v8_cb::<#type_params>()) + } + + #[inline] + #original_func + + pub fn v8_func #generics ( + scope: &mut #core::v8::HandleScope, + args: #core::v8::FunctionCallbackArguments, + mut rv: #core::v8::ReturnValue, + ) #where_clause { + #v8_body + } + } + }.into() +} + +/// Generate the body of a v8 func for an async op +fn codegen_v8_async(core: &TokenStream2, f: &syn::ItemFn) -> TokenStream2 { + let a = codegen_arg(core, &f.sig.inputs[1], "a", 2); + let b = codegen_arg(core, &f.sig.inputs[2], "b", 3); + let type_params = &f.sig.generics.params; + + quote! { + use #core::futures::FutureExt; + // SAFETY: Called from Deno.core.opAsync. Which retrieves the index using opId table. + let op_id = unsafe { + #core::v8::Local::<#core::v8::Integer>::cast(args.get(0)) + }.value() as usize; + + let promise_id = args.get(1); + let promise_id = #core::v8::Local::<#core::v8::Integer>::try_from(promise_id) + .map(|l| l.value() as #core::PromiseId) + .map_err(#core::anyhow::Error::from); + // Fail if promise id invalid (not an int) + let promise_id: #core::PromiseId = match promise_id { + Ok(promise_id) => promise_id, + Err(err) => { + #core::_ops::throw_type_error(scope, format!("invalid promise id: {}", err)); + return; + } + }; + + #a + #b + + // SAFETY: Unchecked cast to external since #core guarantees args.data() is a v8 External. + let state_refcell_raw = unsafe { + #core::v8::Local::<#core::v8::External>::cast(args.data().unwrap_unchecked()) + }.value(); + + // SAFETY: The Rc> is functionally pinned and is tied to the isolate's lifetime + let state = unsafe { + let ptr = state_refcell_raw as *const std::cell::RefCell<#core::OpState>; + // Increment so it will later be decremented/dropped by the underlaying func it is moved to + std::rc::Rc::increment_strong_count(ptr); + std::rc::Rc::from_raw(ptr) + }; + // Track async call & get copy of get_error_class_fn + let get_class = { + let state = state.borrow(); + state.tracker.track_async(op_id); + state.get_error_class_fn + }; + + #core::_ops::queue_async_op(scope, async move { + let result = Self::call::<#type_params>(state, a, b).await; + (promise_id, op_id, #core::_ops::to_op_result(get_class, result)) + }); + } +} + +/// Generate the body of a v8 func for a sync op +fn codegen_v8_sync(core: &TokenStream2, f: &syn::ItemFn) -> TokenStream2 { + let a = codegen_arg(core, &f.sig.inputs[1], "a", 1); + let b = codegen_arg(core, &f.sig.inputs[2], "b", 2); + let ret = codegen_sync_ret(core, &f.sig.output); + let type_params = &f.sig.generics.params; + + quote! { + // SAFETY: Called from Deno.core.opSync. Which retrieves the index using opId table. + let op_id = unsafe { + #core::v8::Local::<#core::v8::Integer>::cast(args.get(0)).value() + } as usize; + + #a + #b + + // SAFETY: Unchecked cast to external since #core guarantees args.data() is a v8 External. + let state_refcell_raw = unsafe { + #core::v8::Local::<#core::v8::External>::cast(args.data().unwrap_unchecked()) + }.value(); + + // SAFETY: The Rc> is functionally pinned and is tied to the isolate's lifetime + let state = unsafe { &*(state_refcell_raw as *const std::cell::RefCell<#core::OpState>) }; + + let op_state = &mut state.borrow_mut(); + let result = Self::call::<#type_params>(op_state, a, b); + + op_state.tracker.track_sync(op_id); + + #ret + } +} + +fn codegen_arg( + core: &TokenStream2, + arg: &syn::FnArg, + name: &str, + idx: i32, +) -> TokenStream2 { + let ident = quote::format_ident!("{name}"); + let pat = match arg { + syn::FnArg::Typed(pat) => &pat.pat, + _ => unreachable!(), + }; + // Fast path if arg should be skipped + if matches!(**pat, syn::Pat::Wild(_)) { + return quote! { let #ident = (); }; + } + // Otherwise deserialize it via serde_v8 + quote! { + let #ident = args.get(#idx); + let #ident = match #core::serde_v8::from_v8(scope, #ident) { + Ok(v) => v, + Err(err) => { + let msg = format!("Error parsing args: {}", #core::anyhow::Error::from(err)); + return #core::_ops::throw_type_error(scope, msg); + } + }; + } +} + +fn codegen_sync_ret( + core: &TokenStream2, + output: &syn::ReturnType, +) -> TokenStream2 { + let ret_type = match output { + // Func with no return no-ops + syn::ReturnType::Default => return quote! { let ret = (); }, + // Func with a return Result + syn::ReturnType::Type(_, ty) => ty, + }; + + // Optimize Result<(), Err> to skip serde_v8 when Ok(...) + let ok_block = if is_unit_result(&**ret_type) { + quote! {} + } else { + quote! { + let ret = #core::serde_v8::to_v8(scope, v).unwrap(); + rv.set(ret); + } + }; + + quote! { + match result { + Ok(v) => { + #ok_block + }, + Err(err) => { + let err = #core::OpError::new(op_state.get_error_class_fn, err); + rv.set(#core::serde_v8::to_v8(scope, err).unwrap()); + }, + }; + } +} + +/// Detects if a type is of the form Result<(), Err> +fn is_unit_result(ty: &syn::Type) -> bool { + let path = match ty { + syn::Type::Path(ref path) => path, + _ => return false, + }; + + let maybe_result = path.path.segments.first().expect("Invalid return type."); + if maybe_result.ident != "Result" { + return false; + } + assert!(!maybe_result.arguments.is_empty()); + + let args = match &maybe_result.arguments { + syn::PathArguments::AngleBracketed(args) => args, + _ => unreachable!(), + }; + + match args.args.first().unwrap() { + syn::GenericArgument::Type(syn::Type::Tuple(ty)) => ty.elems.is_empty(), + _ => false, + } +} diff --git a/runtime/ops/fs.rs b/runtime/ops/fs.rs index bc84cffb1c..f7f0ad33cc 100644 --- a/runtime/ops/fs.rs +++ b/runtime/ops/fs.rs @@ -8,8 +8,8 @@ use deno_core::error::bad_resource_id; use deno_core::error::custom_error; use deno_core::error::type_error; use deno_core::error::AnyError; -use deno_core::op_async; -use deno_core::op_sync; +use deno_core::op; + use deno_core::Extension; use deno_core::OpState; use deno_core::RcRef; @@ -38,59 +38,59 @@ use deno_core::error::not_supported; pub fn init() -> Extension { Extension::builder() .ops(vec![ - ("op_open_sync", op_sync(op_open_sync)), - ("op_open_async", op_async(op_open_async)), - ("op_seek_sync", op_sync(op_seek_sync)), - ("op_seek_async", op_async(op_seek_async)), - ("op_fdatasync_sync", op_sync(op_fdatasync_sync)), - ("op_fdatasync_async", op_async(op_fdatasync_async)), - ("op_fsync_sync", op_sync(op_fsync_sync)), - ("op_fsync_async", op_async(op_fsync_async)), - ("op_fstat_sync", op_sync(op_fstat_sync)), - ("op_fstat_async", op_async(op_fstat_async)), - ("op_flock_sync", op_sync(op_flock_sync)), - ("op_flock_async", op_async(op_flock_async)), - ("op_funlock_sync", op_sync(op_funlock_sync)), - ("op_funlock_async", op_async(op_funlock_async)), - ("op_umask", op_sync(op_umask)), - ("op_chdir", op_sync(op_chdir)), - ("op_mkdir_sync", op_sync(op_mkdir_sync)), - ("op_mkdir_async", op_async(op_mkdir_async)), - ("op_chmod_sync", op_sync(op_chmod_sync)), - ("op_chmod_async", op_async(op_chmod_async)), - ("op_chown_sync", op_sync(op_chown_sync)), - ("op_chown_async", op_async(op_chown_async)), - ("op_remove_sync", op_sync(op_remove_sync)), - ("op_remove_async", op_async(op_remove_async)), - ("op_copy_file_sync", op_sync(op_copy_file_sync)), - ("op_copy_file_async", op_async(op_copy_file_async)), - ("op_stat_sync", op_sync(op_stat_sync)), - ("op_stat_async", op_async(op_stat_async)), - ("op_realpath_sync", op_sync(op_realpath_sync)), - ("op_realpath_async", op_async(op_realpath_async)), - ("op_read_dir_sync", op_sync(op_read_dir_sync)), - ("op_read_dir_async", op_async(op_read_dir_async)), - ("op_rename_sync", op_sync(op_rename_sync)), - ("op_rename_async", op_async(op_rename_async)), - ("op_link_sync", op_sync(op_link_sync)), - ("op_link_async", op_async(op_link_async)), - ("op_symlink_sync", op_sync(op_symlink_sync)), - ("op_symlink_async", op_async(op_symlink_async)), - ("op_read_link_sync", op_sync(op_read_link_sync)), - ("op_read_link_async", op_async(op_read_link_async)), - ("op_ftruncate_sync", op_sync(op_ftruncate_sync)), - ("op_ftruncate_async", op_async(op_ftruncate_async)), - ("op_truncate_sync", op_sync(op_truncate_sync)), - ("op_truncate_async", op_async(op_truncate_async)), - ("op_make_temp_dir_sync", op_sync(op_make_temp_dir_sync)), - ("op_make_temp_dir_async", op_async(op_make_temp_dir_async)), - ("op_make_temp_file_sync", op_sync(op_make_temp_file_sync)), - ("op_make_temp_file_async", op_async(op_make_temp_file_async)), - ("op_cwd", op_sync(op_cwd)), - ("op_futime_sync", op_sync(op_futime_sync)), - ("op_futime_async", op_async(op_futime_async)), - ("op_utime_sync", op_sync(op_utime_sync)), - ("op_utime_async", op_async(op_utime_async)), + op_open_sync::decl(), + op_open_async::decl(), + op_seek_sync::decl(), + op_seek_async::decl(), + op_fdatasync_sync::decl(), + op_fdatasync_async::decl(), + op_fsync_sync::decl(), + op_fsync_async::decl(), + op_fstat_sync::decl(), + op_fstat_async::decl(), + op_flock_sync::decl(), + op_flock_async::decl(), + op_funlock_sync::decl(), + op_funlock_async::decl(), + op_umask::decl(), + op_chdir::decl(), + op_mkdir_sync::decl(), + op_mkdir_async::decl(), + op_chmod_sync::decl(), + op_chmod_async::decl(), + op_chown_sync::decl(), + op_chown_async::decl(), + op_remove_sync::decl(), + op_remove_async::decl(), + op_copy_file_sync::decl(), + op_copy_file_async::decl(), + op_stat_sync::decl(), + op_stat_async::decl(), + op_realpath_sync::decl(), + op_realpath_async::decl(), + op_read_dir_sync::decl(), + op_read_dir_async::decl(), + op_rename_sync::decl(), + op_rename_async::decl(), + op_link_sync::decl(), + op_link_async::decl(), + op_symlink_sync::decl(), + op_symlink_async::decl(), + op_read_link_sync::decl(), + op_read_link_async::decl(), + op_ftruncate_sync::decl(), + op_ftruncate_async::decl(), + op_truncate_sync::decl(), + op_truncate_async::decl(), + op_make_temp_dir_sync::decl(), + op_make_temp_dir_async::decl(), + op_make_temp_file_sync::decl(), + op_make_temp_file_async::decl(), + op_cwd::decl(), + op_futime_sync::decl(), + op_futime_async::decl(), + op_utime_sync::decl(), + op_utime_async::decl(), ]) .build() } @@ -157,6 +157,7 @@ fn open_helper( Ok((path, open_options)) } +#[op] fn op_open_sync( state: &mut OpState, args: OpenArgs, @@ -172,6 +173,7 @@ fn op_open_sync( Ok(rid) } +#[op] async fn op_open_async( state: Rc>, args: OpenArgs, @@ -214,6 +216,7 @@ fn seek_helper(args: SeekArgs) -> Result<(u32, SeekFrom), AnyError> { Ok((rid, seek_from)) } +#[op] fn op_seek_sync( state: &mut OpState, args: SeekArgs, @@ -229,6 +232,7 @@ fn op_seek_sync( Ok(pos) } +#[op] async fn op_seek_async( state: Rc>, args: SeekArgs, @@ -253,6 +257,7 @@ async fn op_seek_async( Ok(pos) } +#[op] fn op_fdatasync_sync( state: &mut OpState, rid: ResourceId, @@ -265,6 +270,7 @@ fn op_fdatasync_sync( Ok(()) } +#[op] async fn op_fdatasync_async( state: Rc>, rid: ResourceId, @@ -287,6 +293,7 @@ async fn op_fdatasync_async( Ok(()) } +#[op] fn op_fsync_sync( state: &mut OpState, rid: ResourceId, @@ -299,6 +306,7 @@ fn op_fsync_sync( Ok(()) } +#[op] async fn op_fsync_async( state: Rc>, rid: ResourceId, @@ -321,6 +329,7 @@ async fn op_fsync_async( Ok(()) } +#[op] fn op_fstat_sync( state: &mut OpState, rid: ResourceId, @@ -333,6 +342,7 @@ fn op_fstat_sync( Ok(get_stat(metadata)) } +#[op] async fn op_fstat_async( state: Rc>, rid: ResourceId, @@ -355,6 +365,7 @@ async fn op_fstat_async( Ok(get_stat(metadata)) } +#[op] fn op_flock_sync( state: &mut OpState, rid: ResourceId, @@ -376,6 +387,7 @@ fn op_flock_sync( }) } +#[op] async fn op_flock_async( state: Rc>, rid: ResourceId, @@ -416,6 +428,7 @@ async fn op_flock_async( .await? } +#[op] fn op_funlock_sync( state: &mut OpState, rid: ResourceId, @@ -433,6 +446,7 @@ fn op_funlock_sync( }) } +#[op] async fn op_funlock_async( state: Rc>, rid: ResourceId, @@ -469,6 +483,7 @@ async fn op_funlock_async( .await? } +#[op] fn op_umask( state: &mut OpState, mask: Option, @@ -501,6 +516,7 @@ fn op_umask( } } +#[op] fn op_chdir( state: &mut OpState, directory: String, @@ -522,6 +538,7 @@ pub struct MkdirArgs { mode: Option, } +#[op] fn op_mkdir_sync( state: &mut OpState, args: MkdirArgs, @@ -544,6 +561,7 @@ fn op_mkdir_sync( Ok(()) } +#[op] async fn op_mkdir_async( state: Rc>, args: MkdirArgs, @@ -582,6 +600,7 @@ pub struct ChmodArgs { mode: u32, } +#[op] fn op_chmod_sync( state: &mut OpState, args: ChmodArgs, @@ -611,6 +630,7 @@ fn op_chmod_sync( } } +#[op] async fn op_chmod_async( state: Rc>, args: ChmodArgs, @@ -656,6 +676,7 @@ pub struct ChownArgs { gid: Option, } +#[op] fn op_chown_sync( state: &mut OpState, args: ChownArgs, @@ -690,6 +711,7 @@ fn op_chown_sync( } } +#[op] async fn op_chown_async( state: Rc>, args: ChownArgs, @@ -738,6 +760,7 @@ pub struct RemoveArgs { recursive: bool, } +#[op] fn op_remove_sync( state: &mut OpState, args: RemoveArgs, @@ -783,6 +806,7 @@ fn op_remove_sync( Ok(()) } +#[op] async fn op_remove_async( state: Rc>, args: RemoveArgs, @@ -841,6 +865,7 @@ pub struct CopyFileArgs { to: String, } +#[op] fn op_copy_file_sync( state: &mut OpState, args: CopyFileArgs, @@ -879,6 +904,7 @@ fn op_copy_file_sync( Ok(()) } +#[op] async fn op_copy_file_async( state: Rc>, args: CopyFileArgs, @@ -1007,6 +1033,7 @@ pub struct StatArgs { lstat: bool, } +#[op] fn op_stat_sync( state: &mut OpState, args: StatArgs, @@ -1027,6 +1054,7 @@ fn op_stat_sync( Ok(get_stat(metadata)) } +#[op] async fn op_stat_async( state: Rc>, args: StatArgs, @@ -1056,6 +1084,7 @@ async fn op_stat_async( .unwrap() } +#[op] fn op_realpath_sync( state: &mut OpState, path: String, @@ -1077,6 +1106,7 @@ fn op_realpath_sync( Ok(realpath_str) } +#[op] async fn op_realpath_async( state: Rc>, path: String, @@ -1114,6 +1144,7 @@ pub struct DirEntry { is_symlink: bool, } +#[op] fn op_read_dir_sync( state: &mut OpState, path: String, @@ -1154,6 +1185,7 @@ fn op_read_dir_sync( Ok(entries) } +#[op] async fn op_read_dir_async( state: Rc>, path: String, @@ -1206,6 +1238,7 @@ pub struct RenameArgs { newpath: String, } +#[op] fn op_rename_sync( state: &mut OpState, args: RenameArgs, @@ -1234,6 +1267,7 @@ fn op_rename_sync( Ok(()) } +#[op] async fn op_rename_async( state: Rc>, args: RenameArgs, @@ -1279,6 +1313,7 @@ pub struct LinkArgs { newpath: String, } +#[op] fn op_link_sync( state: &mut OpState, args: LinkArgs, @@ -1309,6 +1344,7 @@ fn op_link_sync( Ok(()) } +#[op] async fn op_link_async( state: Rc>, args: LinkArgs, @@ -1362,6 +1398,7 @@ pub struct SymlinkOptions { _type: String, } +#[op] fn op_symlink_sync( state: &mut OpState, args: SymlinkArgs, @@ -1423,6 +1460,7 @@ fn op_symlink_sync( } } +#[op] async fn op_symlink_async( state: Rc>, args: SymlinkArgs, @@ -1487,6 +1525,7 @@ async fn op_symlink_async( .unwrap() } +#[op] fn op_read_link_sync( state: &mut OpState, path: String, @@ -1510,6 +1549,7 @@ fn op_read_link_sync( Ok(targetstr) } +#[op] async fn op_read_link_async( state: Rc>, path: String, @@ -1545,6 +1585,7 @@ pub struct FtruncateArgs { len: i32, } +#[op] fn op_ftruncate_sync( state: &mut OpState, args: FtruncateArgs, @@ -1559,6 +1600,7 @@ fn op_ftruncate_sync( Ok(()) } +#[op] async fn op_ftruncate_async( state: Rc>, args: FtruncateArgs, @@ -1591,6 +1633,7 @@ pub struct TruncateArgs { len: u64, } +#[op] fn op_truncate_sync( state: &mut OpState, args: TruncateArgs, @@ -1616,6 +1659,7 @@ fn op_truncate_sync( Ok(()) } +#[op] async fn op_truncate_async( state: Rc>, args: TruncateArgs, @@ -1699,6 +1743,7 @@ pub struct MakeTempArgs { suffix: Option, } +#[op] fn op_make_temp_dir_sync( state: &mut OpState, args: MakeTempArgs, @@ -1728,6 +1773,7 @@ fn op_make_temp_dir_sync( Ok(path_str) } +#[op] async fn op_make_temp_dir_async( state: Rc>, args: MakeTempArgs, @@ -1762,6 +1808,7 @@ async fn op_make_temp_dir_async( .unwrap() } +#[op] fn op_make_temp_file_sync( state: &mut OpState, args: MakeTempArgs, @@ -1791,6 +1838,7 @@ fn op_make_temp_file_sync( Ok(path_str) } +#[op] async fn op_make_temp_file_async( state: Rc>, args: MakeTempArgs, @@ -1833,6 +1881,7 @@ pub struct FutimeArgs { mtime: (i64, u32), } +#[op] fn op_futime_sync( state: &mut OpState, args: FutimeArgs, @@ -1856,6 +1905,7 @@ fn op_futime_sync( Ok(()) } +#[op] async fn op_futime_async( state: Rc>, args: FutimeArgs, @@ -1904,6 +1954,7 @@ pub struct UtimeArgs { mtime: (i64, u32), } +#[op] fn op_utime_sync( state: &mut OpState, args: UtimeArgs, @@ -1922,6 +1973,7 @@ fn op_utime_sync( Ok(()) } +#[op] async fn op_utime_async( state: Rc>, args: UtimeArgs, @@ -1949,6 +2001,7 @@ async fn op_utime_async( .unwrap() } +#[op] fn op_cwd(state: &mut OpState, _: (), _: ()) -> Result { let path = current_dir()?; state diff --git a/runtime/ops/fs_events.rs b/runtime/ops/fs_events.rs index 89ded2731d..8909b2636f 100644 --- a/runtime/ops/fs_events.rs +++ b/runtime/ops/fs_events.rs @@ -11,8 +11,8 @@ use deno_core::RcRef; use deno_core::Resource; use deno_core::ResourceId; -use deno_core::op_async; -use deno_core::op_sync; +use deno_core::op; + use deno_core::Extension; use notify::event::Event as NotifyEvent; use notify::Error as NotifyError; @@ -31,10 +31,7 @@ use tokio::sync::mpsc; pub fn init() -> Extension { Extension::builder() - .ops(vec![ - ("op_fs_events_open", op_sync(op_fs_events_open)), - ("op_fs_events_poll", op_async(op_fs_events_poll)), - ]) + .ops(vec![op_fs_events_open::decl(), op_fs_events_poll::decl()]) .build() } @@ -97,6 +94,7 @@ pub struct OpenArgs { paths: Vec, } +#[op] fn op_fs_events_open( state: &mut OpState, args: OpenArgs, @@ -131,6 +129,7 @@ fn op_fs_events_open( Ok(rid) } +#[op] async fn op_fs_events_poll( state: Rc>, rid: ResourceId, diff --git a/runtime/ops/http.rs b/runtime/ops/http.rs index 5b8acb881b..25f123b323 100644 --- a/runtime/ops/http.rs +++ b/runtime/ops/http.rs @@ -2,7 +2,7 @@ use std::rc::Rc; use deno_core::error::bad_resource_id; use deno_core::error::AnyError; -use deno_core::op_sync; +use deno_core::op; use deno_core::Extension; use deno_core::OpState; use deno_core::ResourceId; @@ -12,10 +12,11 @@ use deno_net::ops_tls::TlsStreamResource; pub fn init() -> Extension { Extension::builder() - .ops(vec![("op_http_start", op_sync(op_http_start))]) + .ops(vec![op_http_start::decl()]) .build() } +#[op] fn op_http_start( state: &mut OpState, tcp_stream_rid: ResourceId, diff --git a/runtime/ops/io.rs b/runtime/ops/io.rs index 61f1a2578c..35dddaac2b 100644 --- a/runtime/ops/io.rs +++ b/runtime/ops/io.rs @@ -3,7 +3,7 @@ use deno_core::error::not_supported; use deno_core::error::resource_unavailable; use deno_core::error::AnyError; -use deno_core::op_sync; +use deno_core::op; use deno_core::AsyncMutFuture; use deno_core::AsyncRefCell; use deno_core::AsyncResult; @@ -69,10 +69,7 @@ static STDERR_HANDLE: Lazy = Lazy::new(|| unsafe { pub fn init() -> Extension { Extension::builder() - .ops(vec![ - ("op_read_sync", op_sync(op_read_sync)), - ("op_write_sync", op_sync(op_write_sync)), - ]) + .ops(vec![op_read_sync::decl(), op_write_sync::decl()]) .build() } @@ -354,6 +351,7 @@ impl Resource for StdFileResource { } } +#[op] fn op_read_sync( state: &mut OpState, rid: ResourceId, @@ -368,6 +366,7 @@ fn op_read_sync( }) } +#[op] fn op_write_sync( state: &mut OpState, rid: ResourceId, diff --git a/runtime/ops/os.rs b/runtime/ops/os.rs index 405faf45ae..d9abbb2212 100644 --- a/runtime/ops/os.rs +++ b/runtime/ops/os.rs @@ -3,7 +3,7 @@ use super::utils::into_string; use crate::permissions::Permissions; use deno_core::error::{type_error, AnyError}; -use deno_core::op_sync; +use deno_core::op; use deno_core::url::Url; use deno_core::Extension; use deno_core::OpState; @@ -17,19 +17,19 @@ use std::sync::Arc; pub fn init(maybe_exit_code: Option>) -> Extension { Extension::builder() .ops(vec![ - ("op_env", op_sync(op_env)), - ("op_exec_path", op_sync(op_exec_path)), - ("op_exit", op_sync(op_exit)), - ("op_delete_env", op_sync(op_delete_env)), - ("op_get_env", op_sync(op_get_env)), - ("op_getuid", op_sync(op_getuid)), - ("op_hostname", op_sync(op_hostname)), - ("op_loadavg", op_sync(op_loadavg)), - ("op_network_interfaces", op_sync(op_network_interfaces)), - ("op_os_release", op_sync(op_os_release)), - ("op_set_env", op_sync(op_set_env)), - ("op_set_exit_code", op_sync(op_set_exit_code)), - ("op_system_memory_info", op_sync(op_system_memory_info)), + op_env::decl(), + op_exec_path::decl(), + op_exit::decl(), + op_delete_env::decl(), + op_get_env::decl(), + op_getuid::decl(), + op_hostname::decl(), + op_loadavg::decl(), + op_network_interfaces::decl(), + op_os_release::decl(), + op_set_env::decl(), + op_set_exit_code::decl(), + op_system_memory_info::decl(), ]) .state(move |state| { let exit_code = maybe_exit_code.clone().unwrap_or_default(); @@ -39,6 +39,7 @@ pub fn init(maybe_exit_code: Option>) -> Extension { .build() } +#[op] fn op_exec_path(state: &mut OpState, _: (), _: ()) -> Result { let current_exe = env::current_exe().unwrap(); state @@ -53,6 +54,7 @@ fn op_exec_path(state: &mut OpState, _: (), _: ()) -> Result { into_string(path.into_os_string()) } +#[op] fn op_set_env( state: &mut OpState, key: String, @@ -68,6 +70,7 @@ fn op_set_env( Ok(()) } +#[op] fn op_env( state: &mut OpState, _: (), @@ -77,6 +80,7 @@ fn op_env( Ok(env::vars().collect()) } +#[op] fn op_get_env( state: &mut OpState, key: String, @@ -93,6 +97,7 @@ fn op_get_env( Ok(r) } +#[op] fn op_delete_env( state: &mut OpState, key: String, @@ -106,6 +111,7 @@ fn op_delete_env( Ok(()) } +#[op] fn op_set_exit_code( state: &mut OpState, code: i32, @@ -115,11 +121,13 @@ fn op_set_exit_code( Ok(()) } +#[op] fn op_exit(state: &mut OpState, _: (), _: ()) -> Result<(), AnyError> { let code = state.borrow::>().load(Relaxed); std::process::exit(code) } +#[op] fn op_loadavg( state: &mut OpState, _: (), @@ -133,6 +141,7 @@ fn op_loadavg( } } +#[op] fn op_hostname(state: &mut OpState, _: (), _: ()) -> Result { super::check_unstable(state, "Deno.hostname"); state.borrow_mut::().env.check_all()?; @@ -140,6 +149,7 @@ fn op_hostname(state: &mut OpState, _: (), _: ()) -> Result { Ok(hostname) } +#[op] fn op_os_release( state: &mut OpState, _: (), @@ -151,6 +161,7 @@ fn op_os_release( Ok(release) } +#[op] fn op_network_interfaces( state: &mut OpState, _: (), @@ -218,6 +229,7 @@ struct MemInfo { pub swap_free: u64, } +#[op] fn op_system_memory_info( state: &mut OpState, _: (), @@ -240,6 +252,7 @@ fn op_system_memory_info( } #[cfg(not(windows))] +#[op] fn op_getuid( state: &mut OpState, _: (), @@ -251,6 +264,7 @@ fn op_getuid( } #[cfg(windows)] +#[op] fn op_getuid( state: &mut OpState, _: (), diff --git a/runtime/ops/permissions.rs b/runtime/ops/permissions.rs index da82f1fd0f..4015624390 100644 --- a/runtime/ops/permissions.rs +++ b/runtime/ops/permissions.rs @@ -4,7 +4,7 @@ use crate::permissions::Permissions; use deno_core::error::custom_error; use deno_core::error::uri_error; use deno_core::error::AnyError; -use deno_core::op_sync; +use deno_core::op; use deno_core::url; use deno_core::Extension; use deno_core::OpState; @@ -14,9 +14,9 @@ use std::path::Path; pub fn init() -> Extension { Extension::builder() .ops(vec![ - ("op_query_permission", op_sync(op_query_permission)), - ("op_revoke_permission", op_sync(op_revoke_permission)), - ("op_request_permission", op_sync(op_request_permission)), + op_query_permission::decl(), + op_revoke_permission::decl(), + op_request_permission::decl(), ]) .build() } @@ -30,6 +30,7 @@ pub struct PermissionArgs { command: Option, } +#[op] pub fn op_query_permission( state: &mut OpState, args: PermissionArgs, @@ -61,6 +62,7 @@ pub fn op_query_permission( Ok(perm.to_string()) } +#[op] pub fn op_revoke_permission( state: &mut OpState, args: PermissionArgs, @@ -92,6 +94,7 @@ pub fn op_revoke_permission( Ok(perm.to_string()) } +#[op] pub fn op_request_permission( state: &mut OpState, args: PermissionArgs, diff --git a/runtime/ops/process.rs b/runtime/ops/process.rs index eee266986f..7c45c47fc1 100644 --- a/runtime/ops/process.rs +++ b/runtime/ops/process.rs @@ -8,8 +8,8 @@ use crate::permissions::Permissions; use deno_core::error::bad_resource_id; use deno_core::error::type_error; use deno_core::error::AnyError; -use deno_core::op_async; -use deno_core::op_sync; +use deno_core::op; + use deno_core::AsyncMutFuture; use deno_core::AsyncRefCell; use deno_core::Extension; @@ -29,11 +29,7 @@ use std::os::unix::process::ExitStatusExt; pub fn init() -> Extension { Extension::builder() - .ops(vec![ - ("op_run", op_sync(op_run)), - ("op_run_status", op_async(op_run_status)), - ("op_kill", op_sync(op_kill)), - ]) + .ops(vec![op_run::decl(), op_run_status::decl(), op_kill::decl()]) .build() } @@ -102,6 +98,7 @@ struct RunInfo { stderr_rid: Option, } +#[op] fn op_run( state: &mut OpState, run_args: RunArgs, @@ -226,6 +223,7 @@ struct ProcessStatus { exit_signal: i32, } +#[op] async fn op_run_status( state: Rc>, rid: ResourceId, @@ -303,6 +301,7 @@ pub fn kill(pid: i32, signal: &str) -> Result<(), AnyError> { } } +#[op] fn op_kill( state: &mut OpState, pid: i32, diff --git a/runtime/ops/runtime.rs b/runtime/ops/runtime.rs index 19228af780..4f951383eb 100644 --- a/runtime/ops/runtime.rs +++ b/runtime/ops/runtime.rs @@ -3,14 +3,14 @@ use crate::permissions::Permissions; use deno_core::anyhow::Context; use deno_core::error::AnyError; -use deno_core::op_sync; +use deno_core::op; use deno_core::Extension; use deno_core::ModuleSpecifier; use deno_core::OpState; pub fn init(main_module: ModuleSpecifier) -> Extension { Extension::builder() - .ops(vec![("op_main_module", op_sync(op_main_module))]) + .ops(vec![op_main_module::decl()]) .state(move |state| { state.put::(main_module.clone()); Ok(()) @@ -18,6 +18,7 @@ pub fn init(main_module: ModuleSpecifier) -> Extension { .build() } +#[op] fn op_main_module( state: &mut OpState, _: (), diff --git a/runtime/ops/signal.rs b/runtime/ops/signal.rs index 9511b83e23..d9f05a7775 100644 --- a/runtime/ops/signal.rs +++ b/runtime/ops/signal.rs @@ -4,8 +4,8 @@ use deno_core::error::generic_error; #[cfg(not(target_os = "windows"))] use deno_core::error::type_error; use deno_core::error::AnyError; -use deno_core::op_async; -use deno_core::op_sync; +use deno_core::op; + use deno_core::Extension; use deno_core::OpState; use std::cell::RefCell; @@ -31,9 +31,9 @@ use tokio::signal::unix::{signal, Signal, SignalKind}; pub fn init() -> Extension { Extension::builder() .ops(vec![ - ("op_signal_bind", op_sync(op_signal_bind)), - ("op_signal_unbind", op_sync(op_signal_unbind)), - ("op_signal_poll", op_async(op_signal_poll)), + op_signal_bind::decl(), + op_signal_unbind::decl(), + op_signal_poll::decl(), ]) .build() } @@ -174,6 +174,7 @@ pub fn signal_str_to_int(s: &str) -> Result { } #[cfg(unix)] +#[op] fn op_signal_bind( state: &mut OpState, sig: String, @@ -195,6 +196,7 @@ fn op_signal_bind( } #[cfg(unix)] +#[op] async fn op_signal_poll( state: Rc>, rid: ResourceId, @@ -214,6 +216,7 @@ async fn op_signal_poll( } #[cfg(unix)] +#[op] pub fn op_signal_unbind( state: &mut OpState, rid: ResourceId, @@ -224,6 +227,7 @@ pub fn op_signal_unbind( } #[cfg(not(unix))] +#[op] pub fn op_signal_bind( _state: &mut OpState, _: (), @@ -233,6 +237,7 @@ pub fn op_signal_bind( } #[cfg(not(unix))] +#[op] fn op_signal_unbind( _state: &mut OpState, _: (), @@ -242,6 +247,7 @@ fn op_signal_unbind( } #[cfg(not(unix))] +#[op] async fn op_signal_poll( _state: Rc>, _: (), diff --git a/runtime/ops/tty.rs b/runtime/ops/tty.rs index ee6b112bc4..bbf6bd4126 100644 --- a/runtime/ops/tty.rs +++ b/runtime/ops/tty.rs @@ -5,7 +5,7 @@ use deno_core::error::bad_resource_id; use deno_core::error::not_supported; use deno_core::error::resource_unavailable; use deno_core::error::AnyError; -use deno_core::op_sync; +use deno_core::op; use deno_core::Extension; use deno_core::OpState; use deno_core::RcRef; @@ -47,9 +47,9 @@ fn get_windows_handle( pub fn init() -> Extension { Extension::builder() .ops(vec![ - ("op_set_raw", op_sync(op_set_raw)), - ("op_isatty", op_sync(op_isatty)), - ("op_console_size", op_sync(op_console_size)), + op_set_raw::decl(), + op_isatty::decl(), + op_console_size::decl(), ]) .build() } @@ -67,6 +67,7 @@ pub struct SetRawArgs { options: SetRawOptions, } +#[op] fn op_set_raw( state: &mut OpState, args: SetRawArgs, @@ -211,6 +212,7 @@ fn op_set_raw( } } +#[op] fn op_isatty( state: &mut OpState, rid: ResourceId, @@ -245,6 +247,7 @@ struct ConsoleSize { rows: u32, } +#[op] fn op_console_size( state: &mut OpState, rid: ResourceId, diff --git a/runtime/ops/web_worker.rs b/runtime/ops/web_worker.rs index e32f2371d8..3c64cf1f6d 100644 --- a/runtime/ops/web_worker.rs +++ b/runtime/ops/web_worker.rs @@ -5,8 +5,8 @@ mod sync_fetch; use crate::web_worker::WebWorkerInternalHandle; use crate::web_worker::WebWorkerType; use deno_core::error::AnyError; -use deno_core::op_async; -use deno_core::op_sync; +use deno_core::op; + use deno_core::CancelFuture; use deno_core::Extension; use deno_core::OpState; @@ -19,16 +19,17 @@ use self::sync_fetch::op_worker_sync_fetch; pub fn init() -> Extension { Extension::builder() .ops(vec![ - ("op_worker_post_message", op_sync(op_worker_post_message)), - ("op_worker_recv_message", op_async(op_worker_recv_message)), + op_worker_post_message::decl(), + op_worker_recv_message::decl(), // Notify host that guest worker closes. - ("op_worker_close", op_sync(op_worker_close)), - ("op_worker_get_type", op_sync(op_worker_get_type)), - ("op_worker_sync_fetch", op_sync(op_worker_sync_fetch)), + op_worker_close::decl(), + op_worker_get_type::decl(), + op_worker_sync_fetch::decl(), ]) .build() } +#[op] fn op_worker_post_message( state: &mut OpState, data: JsMessageData, @@ -39,6 +40,7 @@ fn op_worker_post_message( Ok(()) } +#[op] async fn op_worker_recv_message( state: Rc>, _: (), @@ -55,6 +57,7 @@ async fn op_worker_recv_message( .await? } +#[op] fn op_worker_close(state: &mut OpState, _: (), _: ()) -> Result<(), AnyError> { // Notify parent that we're finished let mut handle = state.borrow_mut::().clone(); @@ -63,6 +66,7 @@ fn op_worker_close(state: &mut OpState, _: (), _: ()) -> Result<(), AnyError> { Ok(()) } +#[op] fn op_worker_get_type( state: &mut OpState, _: (), diff --git a/runtime/ops/web_worker/sync_fetch.rs b/runtime/ops/web_worker/sync_fetch.rs index 76791ded58..464697f944 100644 --- a/runtime/ops/web_worker/sync_fetch.rs +++ b/runtime/ops/web_worker/sync_fetch.rs @@ -4,6 +4,7 @@ use crate::web_worker::WebWorkerInternalHandle; use crate::web_worker::WebWorkerType; use deno_core::error::type_error; use deno_core::error::AnyError; +use deno_core::op; use deno_core::url::Url; use deno_core::OpState; use deno_fetch::data_url::DataUrl; @@ -30,6 +31,7 @@ pub struct SyncFetchScript { script: String, } +#[op] pub fn op_worker_sync_fetch( state: &mut OpState, scripts: Vec, diff --git a/runtime/ops/worker_host.rs b/runtime/ops/worker_host.rs index 1213da6d2b..cebce81a4b 100644 --- a/runtime/ops/worker_host.rs +++ b/runtime/ops/worker_host.rs @@ -13,8 +13,8 @@ use crate::web_worker::WorkerControlEvent; use crate::web_worker::WorkerId; use deno_core::error::AnyError; use deno_core::futures::future::LocalFutureObj; -use deno_core::op_async; -use deno_core::op_sync; +use deno_core::op; + use deno_core::serde::Deserialize; use deno_core::Extension; use deno_core::ModuleSpecifier; @@ -122,14 +122,11 @@ pub fn init( Ok(()) }) .ops(vec![ - ("op_create_worker", op_sync(op_create_worker)), - ( - "op_host_terminate_worker", - op_sync(op_host_terminate_worker), - ), - ("op_host_post_message", op_sync(op_host_post_message)), - ("op_host_recv_ctrl", op_async(op_host_recv_ctrl)), - ("op_host_recv_message", op_async(op_host_recv_message)), + op_create_worker::decl(), + op_host_terminate_worker::decl(), + op_host_post_message::decl(), + op_host_recv_ctrl::decl(), + op_host_recv_message::decl(), ]) .build() } @@ -147,6 +144,7 @@ pub struct CreateWorkerArgs { } /// Create worker as the host +#[op] fn op_create_worker( state: &mut OpState, args: CreateWorkerArgs, @@ -263,6 +261,7 @@ fn op_create_worker( Ok(worker_id) } +#[op] fn op_host_terminate_worker( state: &mut OpState, id: WorkerId, @@ -317,6 +316,7 @@ fn close_channel( } /// Get control event from guest worker as host +#[op] async fn op_host_recv_ctrl( state: Rc>, id: WorkerId, @@ -348,6 +348,7 @@ async fn op_host_recv_ctrl( Ok(WorkerControlEvent::Close) } +#[op] async fn op_host_recv_message( state: Rc>, id: WorkerId, @@ -373,6 +374,7 @@ async fn op_host_recv_message( } /// Post message to guest worker as host +#[op] fn op_host_post_message( state: &mut OpState, id: WorkerId,