From 4db650ddd57b85475d71c0b9fc84d37becab9d6a Mon Sep 17 00:00:00 2001 From: Divy Srivastava Date: Fri, 22 Jul 2022 19:06:32 +0530 Subject: [PATCH] Revert "feat(ops): V8 Fast Calls (#15122)" (#15276) This reverts commit 03dc3b8972f460e40d0b75fc3207cae9fe4f60da. --- Cargo.lock | 23 -- cli/bench/deno_common.js | 25 +-- core/01_core.js | 4 +- core/bindings.rs | 80 ++----- core/extensions.rs | 9 +- core/lib.rs | 3 - core/ops_builtin.rs | 8 +- core/runtime.rs | 19 +- ext/net/lib.rs | 4 +- ext/web/02_timers.js | 4 +- ext/web/timers.rs | 2 +- ops/Cargo.toml | 4 - ops/README.md | 28 --- ops/lib.rs | 250 +--------------------- ops/tests/compile_fail/unsupported.rs | 27 --- ops/tests/compile_fail/unsupported.stderr | 31 --- ops/tests/mod.rs | 5 - 17 files changed, 32 insertions(+), 494 deletions(-) delete mode 100644 ops/tests/compile_fail/unsupported.rs delete mode 100644 ops/tests/compile_fail/unsupported.stderr delete mode 100644 ops/tests/mod.rs diff --git a/Cargo.lock b/Cargo.lock index 7489f9ba18..c3e84f40ba 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1118,14 +1118,12 @@ dependencies = [ name = "deno_ops" version = "0.22.0" dependencies = [ - "deno_core", "once_cell", "proc-macro-crate", "proc-macro2 1.0.39", "quote 1.0.18", "regex", "syn 1.0.96", - "trybuild", ] [[package]] @@ -1899,12 +1897,6 @@ dependencies = [ "polyval", ] -[[package]] -name = "glob" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b919933a397b79c37e33b77bb2aa3dc8eb6e165ad809e58ff75bc7db2e34574" - [[package]] name = "glow" version = "0.11.2" @@ -4961,21 +4953,6 @@ version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "59547bce71d9c38b83d9c0e92b6066c4253371f15005def0c30d9657f50c7642" -[[package]] -name = "trybuild" -version = "1.0.63" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "764b9e244b482a9b81bde596aa37aa6f1347bf8007adab25e59f901b32b4e0a0" -dependencies = [ - "glob", - "once_cell", - "serde", - "serde_derive", - "serde_json", - "termcolor", - "toml", -] - [[package]] name = "tungstenite" version = "0.16.0" diff --git a/cli/bench/deno_common.js b/cli/bench/deno_common.js index c02a6c883d..c31ccd981c 100644 --- a/cli/bench/deno_common.js +++ b/cli/bench/deno_common.js @@ -5,31 +5,8 @@ Deno.bench("date_now", { n: 5e5 }, () => { Date.now(); }); -// Fast API calls -{ - // deno-lint-ignore camelcase - const { op_add } = Deno.core.ops; - // deno-lint-ignore no-inner-declarations - function add(a, b) { - return op_add.call(a, b); - } - // deno-lint-ignore no-inner-declarations - function addJS(a, b) { - return a + b; - } - Deno.bench("op_add", { n: 1e7 }, () => add(1, 2)); - Deno.bench("add_js", { n: 1e7 }, () => addJS(1, 2)); -} - -// deno-lint-ignore camelcase -const { op_void_sync } = Deno.core.ops; -function sync() { - return op_void_sync.call(); -} -sync(); // Warmup -console.log(sync()); // Void ops measure op-overhead -Deno.bench("op_void_sync", { n: 1e7 }, () => sync()); +Deno.bench("op_void_sync", { n: 1e7 }, () => Deno.core.opSync("op_void_sync")); Deno.bench( "op_void_async", diff --git a/core/01_core.js b/core/01_core.js index 354540fb72..21376b695b 100644 --- a/core/01_core.js +++ b/core/01_core.js @@ -147,7 +147,7 @@ function opAsync(opName, ...args) { const promiseId = nextPromiseId++; - const maybeError = ops[opName].call(promiseId, ...args); + const maybeError = ops[opName](promiseId, ...args); // Handle sync error (e.g: error parsing args) if (maybeError) return unwrapOpResult(maybeError); let p = PromisePrototypeThen(setPromise(promiseId), unwrapOpResult); @@ -167,7 +167,7 @@ } function opSync(opName, ...args) { - return unwrapOpResult(ops[opName].call(...args)); + return unwrapOpResult(ops[opName](...args)); } function refOp(promiseId) { diff --git a/core/bindings.rs b/core/bindings.rs index afbbcee4ee..6fa9f745b0 100644 --- a/core/bindings.rs +++ b/core/bindings.rs @@ -9,36 +9,17 @@ use crate::modules::ModuleMap; use crate::ops::OpCtx; use crate::JsRuntime; use log::debug; +use once_cell::sync::Lazy; use std::option::Option; use std::os::raw::c_void; -use v8::fast_api::FastFunction; use v8::MapFnTo; -pub fn external_references(ops: &[OpCtx]) -> v8::ExternalReferences { - let mut references = vec![ - v8::ExternalReference { +pub static EXTERNAL_REFERENCES: Lazy = + Lazy::new(|| { + v8::ExternalReferences::new(&[v8::ExternalReference { function: call_console.map_fn_to(), - }, - v8::ExternalReference { - pointer: ops as *const _ as _, - }, - ]; - - for ctx in ops { - let ctx_ptr = ctx as *const OpCtx as _; - references.push(v8::ExternalReference { pointer: ctx_ptr }); - references.push(v8::ExternalReference { - function: ctx.decl.v8_fn_ptr, - }); - if let Some(fast_fn) = &ctx.decl.fast_fn { - references.push(v8::ExternalReference { - pointer: fast_fn.function() as _, - }); - } - } - - v8::ExternalReferences::new(&references) -} + }]) + }); // TODO(nayeemrmn): Move to runtime and/or make `pub(crate)`. pub fn script_origin<'a>( @@ -101,8 +82,7 @@ pub fn initialize_context<'s>( // Grab the Deno.core.ops object & init it let ops_obj = JsRuntime::grab_global::(scope, "Deno.core.ops") .expect("Deno.core.ops to exist"); - initialize_ops(scope, ops_obj, op_ctxs, snapshot_loaded); - + initialize_ops(scope, ops_obj, op_ctxs); return scope.escape(context); } @@ -114,8 +94,7 @@ pub fn initialize_context<'s>( // Bind functions to Deno.core.ops.* let ops_obj = JsRuntime::ensure_objs(scope, global, "Deno.core.ops").unwrap(); - - initialize_ops(scope, ops_obj, op_ctxs, snapshot_loaded); + initialize_ops(scope, ops_obj, op_ctxs); scope.escape(context) } @@ -123,32 +102,10 @@ fn initialize_ops( scope: &mut v8::HandleScope, ops_obj: v8::Local, op_ctxs: &[OpCtx], - snapshot_loaded: bool, ) { for ctx in op_ctxs { let ctx_ptr = ctx as *const OpCtx as *const c_void; - - let object_template = v8::ObjectTemplate::new(scope); - assert!(object_template.set_internal_field_count( - (crate::runtime::V8_WRAPPER_OBJECT_INDEX + 1) as usize - )); - - let method_obj = object_template.new_instance(scope).unwrap(); - method_obj.set_aligned_pointer_in_internal_field( - crate::runtime::V8_WRAPPER_OBJECT_INDEX, - ctx_ptr, - ); - set_func_raw( - scope, - method_obj, - "call", - ctx.decl.v8_fn_ptr, - ctx_ptr, - &ctx.decl.fast_fn, - snapshot_loaded, - ); - let method_key = v8::String::new(scope, ctx.decl.name).unwrap(); - ops_obj.set(scope, method_key.into(), method_obj.into()); + set_func_raw(scope, ops_obj, ctx.decl.name, ctx.decl.v8_fn_ptr, ctx_ptr); } } @@ -172,24 +129,13 @@ pub fn set_func_raw( name: &'static str, callback: v8::FunctionCallback, external_data: *const c_void, - fast_function: &Option>, - snapshot_loaded: bool, ) { let key = v8::String::new(scope, name).unwrap(); let external = v8::External::new(scope, external_data as *mut c_void); - let builder = - v8::FunctionTemplate::builder_raw(callback).data(external.into()); - let templ = if let Some(fast_function) = fast_function { - if !snapshot_loaded { - builder.build(scope) - } else { - // TODO(@littledivy): Support fast api overloads in ops. - builder.build_fast(scope, &**fast_function, None) - } - } else { - builder.build(scope) - }; - let val = templ.get_function(scope).unwrap(); + let val = v8::Function::builder_raw(callback) + .data(external.into()) + .build(scope) + .unwrap(); val.set_name(key); obj.set(scope, key.into(), val.into()); } diff --git a/core/extensions.rs b/core/extensions.rs index 39b4471bf9..ce69578752 100644 --- a/core/extensions.rs +++ b/core/extensions.rs @@ -2,7 +2,6 @@ use crate::OpState; use anyhow::Error; use std::{cell::RefCell, rc::Rc, task::Context}; -use v8::fast_api::FastFunction; pub type SourcePair = (&'static str, &'static str); pub type OpFnRef = v8::FunctionCallback; @@ -10,16 +9,14 @@ pub type OpMiddlewareFn = dyn Fn(OpDecl) -> OpDecl; pub type OpStateFn = dyn Fn(&mut OpState) -> Result<(), Error>; pub type OpEventLoopFn = dyn Fn(Rc>, &mut Context) -> bool; -pub trait FastFunctionSignature {} - +#[derive(Clone, Copy)] pub struct OpDecl { pub name: &'static str, pub v8_fn_ptr: OpFnRef, pub enabled: bool, - pub is_async: bool, + pub is_async: bool, // TODO(@AaronO): enum sync/async/fast ? pub is_unstable: bool, pub is_v8: bool, - pub fast_fn: Option>, } impl OpDecl { @@ -35,7 +32,7 @@ impl OpDecl { #[derive(Default)] pub struct Extension { js_files: Option>, - pub ops: Option>, + ops: Option>, opstate_fn: Option>, middleware_fn: Option>, event_loop_middleware: Option>, diff --git a/core/lib.rs b/core/lib.rs index a77705ff35..ab22392c49 100644 --- a/core/lib.rs +++ b/core/lib.rs @@ -113,12 +113,9 @@ pub fn v8_version() -> &'static str { pub mod _ops { pub use super::bindings::throw_type_error; pub use super::error_codes::get_error_code; - pub use super::extensions::FastFunctionSignature; pub use super::ops::to_op_result; pub use super::ops::OpCtx; pub use super::runtime::queue_async_op; - pub use super::runtime::V8_WRAPPER_OBJECT_INDEX; - pub use super::runtime::V8_WRAPPER_TYPE_INDEX; } /// A helper macro that will return a call site in Rust code. Should be diff --git a/core/ops_builtin.rs b/core/ops_builtin.rs index 2e911e4150..a42c0bae88 100644 --- a/core/ops_builtin.rs +++ b/core/ops_builtin.rs @@ -31,7 +31,6 @@ pub(crate) fn init_builtins() -> Extension { op_wasm_streaming_set_url::decl(), op_void_sync::decl(), op_void_async::decl(), - op_add::decl(), // // TODO(@AaronO): track IO metrics for builtin streams op_read::decl(), op_write::decl(), @@ -55,12 +54,7 @@ pub fn op_resources(state: &mut OpState) -> Vec<(ResourceId, String)> { .collect() } -#[op(fast)] -fn op_add(a: i32, b: i32) -> i32 { - a + b -} - -#[op(fast)] +#[op] pub fn op_void_sync() {} #[op] diff --git a/core/runtime.rs b/core/runtime.rs index caadd00897..64e7f635c0 100644 --- a/core/runtime.rs +++ b/core/runtime.rs @@ -230,7 +230,6 @@ fn v8_init( " --harmony-import-assertions", " --no-validate-asm", " --turbo_fast_api_calls", - " --allow-natives-syntax", ); if predictable { @@ -243,9 +242,6 @@ fn v8_init( } } -pub const V8_WRAPPER_TYPE_INDEX: i32 = 0; -pub const V8_WRAPPER_OBJECT_INDEX: i32 = 1; - #[derive(Default)] pub struct RuntimeOptions { /// Source map reference for errors. @@ -321,6 +317,7 @@ impl JsRuntime { 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 op_ctxs = ops .into_iter() @@ -333,13 +330,12 @@ impl JsRuntime { .collect::>() .into_boxed_slice(); - let refs = bindings::external_references(&op_ctxs); - 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(refs)); + let mut creator = + v8::SnapshotCreator::new(Some(&bindings::EXTERNAL_REFERENCES)); // SAFETY: `get_owned_isolate` is unsafe because it may only be called // once. This is the only place we call this function, so this call is // safe. @@ -356,13 +352,8 @@ impl JsRuntime { let mut params = options .create_params .take() - .unwrap_or_else(|| { - v8::Isolate::create_params().embedder_wrapper_type_info_offsets( - V8_WRAPPER_TYPE_INDEX, - V8_WRAPPER_OBJECT_INDEX, - ) - }) - .external_references(&**refs); + .unwrap_or_else(v8::Isolate::create_params) + .external_references(&**bindings::EXTERNAL_REFERENCES); let snapshot_loaded = if let Some(snapshot) = options.startup_snapshot { params = match snapshot { Snapshot::Static(data) => params.snapshot_blob(data), diff --git a/ext/net/lib.rs b/ext/net/lib.rs index 2491700607..c95348020b 100644 --- a/ext/net/lib.rs +++ b/ext/net/lib.rs @@ -81,8 +81,6 @@ pub fn init( unstable: bool, unsafely_ignore_certificate_errors: Option>, ) -> Extension { - let mut ops = ops::init::

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

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

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

()[..]].concat()) .state(move |state| { state.put(DefaultTlsOptions { root_cert_store: root_cert_store.clone(), diff --git a/ext/web/02_timers.js b/ext/web/02_timers.js index 1a456f9bb1..a4ce33a184 100644 --- a/ext/web/02_timers.js +++ b/ext/web/02_timers.js @@ -23,11 +23,9 @@ const { webidl } = window.__bootstrap; const { reportException } = window.__bootstrap.event; const { assert } = window.__bootstrap.infra; - // deno-lint-ignore camelcase - const { op_now } = Deno.core.ops; function opNow() { - return op_now.call(); + return core.opSync("op_now"); } // --------------------------------------------------------------------------- diff --git a/ext/web/timers.rs b/ext/web/timers.rs index ebef717ba9..f57baa559d 100644 --- a/ext/web/timers.rs +++ b/ext/web/timers.rs @@ -28,7 +28,7 @@ pub type StartTime = Instant; // If the High precision flag is not set, the // nanoseconds are rounded on 2ms. #[op] -pub fn op_now(state: &mut OpState) -> f64 +pub fn op_now(state: &mut OpState, _argument: ()) -> f64 where TP: TimersPermission + 'static, { diff --git a/ops/Cargo.toml b/ops/Cargo.toml index 9628ca91f7..e0453b9e2e 100644 --- a/ops/Cargo.toml +++ b/ops/Cargo.toml @@ -17,7 +17,3 @@ proc-macro2 = "1" quote = "1" regex = "1.5.6" syn = { version = "1", features = ["full", "extra-traits"] } - -[dev-dependencies] -deno_core = { path = "../core" } -trybuild = "1.0.61" diff --git a/ops/README.md b/ops/README.md index 7b61704b5b..02ee266f71 100644 --- a/ops/README.md +++ b/ops/README.md @@ -14,31 +14,3 @@ Extension::builder() .ops(vec![op_add::decl()]) .build(); ``` - -## Peformance - -The macro can optimize away code, short circuit fast paths and generate a Fast -API impl. - -Cases where code is optimized away: - -- `-> ()` skips serde_v8 and `rv.set` calls. -- `-> Result<(), E>` skips serde_v8 and `rv.set` calls for `Ok()` branch. -- `-> ResourceId` or `-> [int]` types will use specialized method like - `v8::ReturnValue::set_uint32`. A fast path for SMI. -- `-> Result` or `-> Result<[int], E>` types will be optimized - like above for the `Ok()` branch. - -### Fast calls - -The macro will infer and try to auto generate V8 fast API call trait impl for -`sync` ops with: - -- arguments: integers / `&mut OpState` -- return_type: integers - -The `#[op(fast)]` attribute can be used to enforce fast call generation at -compile time. - -Trait gen for `async` ops & a ZeroCopyBuf equivalent type is planned and will be -added soon. diff --git a/ops/lib.rs b/ops/lib.rs index bd40630ab0..df8abf61ea 100644 --- a/ops/lib.rs +++ b/ops/lib.rs @@ -1,13 +1,10 @@ // Copyright 2018-2022 the Deno authors. All rights reserved. MIT license. - -use core::panic; use once_cell::sync::Lazy; 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::format_ident; use quote::quote; use quote::ToTokens; use regex::Regex; @@ -17,9 +14,6 @@ use syn::FnArg; use syn::GenericParam; use syn::Ident; -#[cfg(test)] -mod tests; - // Identifier to the `deno_core` crate. // // If macro called in deno_core, `crate` is used. @@ -50,7 +44,6 @@ fn core_import() -> TokenStream2 { struct MacroArgs { is_unstable: bool, is_v8: bool, - must_be_fast: bool, } impl syn::parse::Parse for MacroArgs { @@ -62,7 +55,7 @@ impl syn::parse::Parse for MacroArgs { let vars: Vec<_> = vars.iter().map(Ident::to_string).collect(); let vars: Vec<_> = vars.iter().map(String::as_str).collect(); for var in vars.iter() { - if !["unstable", "v8", "fast"].contains(var) { + if !["unstable", "v8"].contains(var) { return Err(syn::Error::new( input.span(), "Ops expect #[op] or #[op(unstable)]", @@ -72,7 +65,6 @@ impl syn::parse::Parse for MacroArgs { Ok(Self { is_unstable: vars.contains(&"unstable"), is_v8: vars.contains(&"v8"), - must_be_fast: vars.contains(&"fast"), }) } } @@ -80,11 +72,7 @@ impl syn::parse::Parse for MacroArgs { #[proc_macro_attribute] pub fn op(attr: TokenStream, item: TokenStream) -> TokenStream { let margs = syn::parse_macro_input!(attr as MacroArgs); - let MacroArgs { - is_unstable, - is_v8, - must_be_fast, - } = margs; + let MacroArgs { is_unstable, is_v8 } = margs; let func = syn::parse::(item).expect("expected a function"); let name = &func.sig.ident; let mut generics = func.sig.generics.clone(); @@ -114,8 +102,6 @@ pub fn op(attr: TokenStream, item: TokenStream) -> TokenStream { } else { codegen_v8_sync(&core, &func, margs) }; - let (fast_impl, fast_field) = - codegen_fast_impl(&core, &func, name, is_async, must_be_fast); let docline = format!("Use `{name}::decl()` to get an op-declaration"); // Generate wrapper @@ -143,7 +129,6 @@ pub fn op(attr: TokenStream, item: TokenStream) -> TokenStream { name: Self::name(), v8_fn_ptr: Self::v8_fn_ptr::<#type_params>(), enabled: true, - fast_fn: #fast_field, is_async: #is_async, is_unstable: #is_unstable, is_v8: #is_v8, @@ -162,8 +147,6 @@ pub fn op(attr: TokenStream, item: TokenStream) -> TokenStream { #v8_body } } - - #fast_impl }.into() } @@ -277,114 +260,6 @@ fn opstate_arg(arg: &FnArg) -> Option { } } -fn codegen_fast_impl( - core: &TokenStream2, - f: &syn::ItemFn, - name: &syn::Ident, - is_async: bool, - must_be_fast: bool, -) -> (TokenStream2, TokenStream2) { - let fast_info = can_be_fast_api(core, f); - if must_be_fast && fast_info.is_none() { - panic!("op cannot be a fast api. enforced by #[op(fast)]") - } - if must_be_fast && is_async { - panic!("async op cannot be a fast api. enforced by #[op(fast)]") - } - if !is_async { - if let Some(FastApiSyn { - args, - ret, - use_recv, - }) = fast_info - { - let inputs = &f - .sig - .inputs - .iter() - .skip(if use_recv { 1 } else { 0 }) - .collect::>(); - let input_idents = f - .sig - .inputs - .iter() - .map(|a| match a { - FnArg::Receiver(_) => unreachable!(), - FnArg::Typed(t) => match &*t.pat { - syn::Pat::Ident(i) => format_ident!("{}", i.ident), - _ => unreachable!(), - }, - }) - .collect::>(); - let generics = &f.sig.generics; - let (impl_generics, ty_generics, where_clause) = - generics.split_for_impl(); - let type_params = exclude_lifetime_params(&f.sig.generics.params); - let (trampoline, raw_block) = if is_async { - // TODO(@littledivy): Fast async calls. - ( - quote! { - fn func(recv: #core::v8::Local<#core::v8::Object>, __promise_id: u32, #(#inputs),*) { - let op_ctx = recv.get_aligned_pointer_from_internal_field(#core::_ops::V8_WRAPPER_OBJECT_INDEX); - let op_id = op_ctx.op_id; - #core::_ops::queue_async_op(scope, async move { - let result = Self::call(#args); - (__promise_id, __op_id, #core::_ops::OpResult::Ok(result)) - }); - } - func as *const _ - }, - quote! {}, - ) - } else { - let output = &f.sig.output; - let func_name = format_ident!("func_{}", name); - let recv_decl = if use_recv { - quote! { - let ptr = unsafe { recv.get_aligned_pointer_from_internal_field(#core::_ops::V8_WRAPPER_OBJECT_INDEX) }; - let op_ctx = unsafe { &*(ptr as *const #core::_ops::OpCtx) }; - let state = &mut op_ctx.state.borrow_mut(); - } - } else { - quote!() - }; - - ( - quote! { - fn #func_name #generics (recv: #core::v8::Local<#core::v8::Object>, #(#inputs),*) #output #where_clause { - #recv_decl - #name::call::<#type_params>(#(#input_idents),*) - } - }, - quote! { - #func_name #ty_generics as *const _ - }, - ) - }; - return ( - quote! { - #trampoline - impl #impl_generics #core::v8::fast_api::FastFunction for #name #ty_generics { - fn function(&self) -> *const ::std::ffi::c_void { - #raw_block - } - fn args(&self) -> &'static [#core::v8::fast_api::Type] { - &[ #args ] - } - fn return_type(&self) -> #core::v8::fast_api::CType { - #ret - } - } - }, - quote! { Some(Box::new(#name #ty_generics)) }, - ); - } - } - - // Default impl to satisfy generic bounds for non-fast ops - (quote! {}, quote! { None }) -} - /// Generate the body of a v8 func for a sync op fn codegen_v8_sync( core: &TokenStream2, @@ -402,6 +277,7 @@ fn codegen_v8_sync( .collect::>(); let rust_i0 = special_args.len(); let args_head = special_args.into_iter().collect::(); + let (arg_decls, args_tail) = codegen_args(core, f, rust_i0, 0); let ret = codegen_sync_ret(core, &f.sig.output); let type_params = exclude_lifetime_params(&f.sig.generics.params); @@ -424,124 +300,6 @@ fn codegen_v8_sync( } } -struct FastApiSyn { - args: TokenStream2, - ret: TokenStream2, - use_recv: bool, -} - -fn can_be_fast_api(core: &TokenStream2, f: &syn::ItemFn) -> Option { - // TODO(@littledivy): Support generics - if !f.sig.generics.params.is_empty() { - return None; - } - - let inputs = &f.sig.inputs; - let ret = match &f.sig.output { - syn::ReturnType::Default => quote!(#core::v8::fast_api::CType::Void), - syn::ReturnType::Type(_, ty) => match is_fast_scalar(core, ty, true) { - Some(ret) => ret, - None => return None, - }, - }; - - let mut use_recv = false; - let mut args = vec![quote! { #core::v8::fast_api::Type::V8Value }]; - for (pos, input) in inputs.iter().enumerate() { - if pos == 0 && is_mut_ref_opstate(input) { - use_recv = true; - continue; - } - - let ty = match input { - syn::FnArg::Typed(pat) => &pat.ty, - _ => unreachable!(), - }; - - match is_fast_scalar(core, ty, false) { - None => match is_fast_arg_sequence(core, ty) { - Some(arg) => { - args.push(arg); - } - // early return, this function cannot be a fast call. - None => return None, - }, - Some(arg) => { - args.push(arg); - } - } - } - - let args = args - .iter() - .map(|arg| format!("{}", arg)) - .collect::>() - .join(", "); - Some(FastApiSyn { - args: args.parse().unwrap(), - ret, - use_recv, - }) -} - -// A v8::Local or FastApiTypedArray -fn is_fast_arg_sequence( - core: &TokenStream2, - ty: impl ToTokens, -) -> Option { - // TODO(@littledivy): Make `v8::` parts optional. - if is_fast_typed_array(&ty) { - return Some( - quote! { #core::v8::fast_api::Type::TypedArray(#core::v8::fast_api::CType::Uint32) }, - ); - } - if is_local_array(&ty) { - return Some( - quote! { #core::v8::fast_api::Type::Sequence(#core::v8::fast_api::CType::Void) }, - ); - } - None -} - -fn is_local_array(arg: impl ToTokens) -> bool { - static RE: Lazy = - Lazy::new(|| Regex::new(r"^v8::Local$").unwrap()); - RE.is_match(&tokens(arg)) -} - -fn is_fast_typed_array(arg: impl ToTokens) -> bool { - static RE: Lazy = Lazy::new(|| { - Regex::new(r#": (?:deno_core :: )?FastApiTypedArray$"#).unwrap() - }); - RE.is_match(&tokens(arg)) -} - -fn is_fast_scalar( - core: &TokenStream2, - ty: impl ToTokens, - is_ret: bool, -) -> Option { - let cty = if is_ret { - quote! { CType } - } else { - quote! { Type } - }; - if is_resource_id(&ty) { - return Some(quote! { #core::v8::fast_api::#cty::Uint32 }); - } - if is_void(&ty) { - return Some(quote! { #core::v8::fast_api::#cty::Void }); - } - // TODO(@littledivy): Support u8, i8, u16, i16 by casting. - match tokens(&ty).as_str() { - "u32" => Some(quote! { #core::v8::fast_api::#cty::Uint32 }), - "i32" => Some(quote! { #core::v8::fast_api::#cty::Int32 }), - "f32" => Some(quote! { #core::v8::fast_api::#cty::Float32 }), - "f64" => Some(quote! { #core::v8::fast_api::#cty::Float64 }), - _ => None, - } -} - fn codegen_args( core: &TokenStream2, f: &syn::ItemFn, @@ -685,7 +443,7 @@ fn is_resource_id(arg: impl ToTokens) -> bool { RE.is_match(&tokens(arg)) } -fn is_mut_ref_opstate(arg: impl ToTokens) -> bool { +fn is_mut_ref_opstate(arg: &syn::FnArg) -> bool { static RE: Lazy = Lazy::new(|| Regex::new(r#": & mut (?:deno_core :: )?OpState$"#).unwrap()); RE.is_match(&tokens(arg)) diff --git a/ops/tests/compile_fail/unsupported.rs b/ops/tests/compile_fail/unsupported.rs deleted file mode 100644 index 1c4d6407ad..0000000000 --- a/ops/tests/compile_fail/unsupported.rs +++ /dev/null @@ -1,27 +0,0 @@ -// Copyright 2019-2020 the Deno authors. All rights reserved. MIT license. - -use deno_ops::op; - -#[op(fast)] -fn op_result_return(a: i32, b: i32) -> Result<(), ()> { - a + b -} - -#[op(fast)] -fn op_u8_arg(a: u8, b: u8) { - // -} - -#[op(fast)] -fn op_u16_arg(a: u16, b: u16) { - // -} - -#[op(fast)] -async fn op_async_fn(a: i32, b: i32) -> i32 { - a + b -} - -fn main() { - // pass -} diff --git a/ops/tests/compile_fail/unsupported.stderr b/ops/tests/compile_fail/unsupported.stderr deleted file mode 100644 index 68c9f7f162..0000000000 --- a/ops/tests/compile_fail/unsupported.stderr +++ /dev/null @@ -1,31 +0,0 @@ -error: custom attribute panicked - --> tests/compile_fail/unsupported.rs:5:1 - | -5 | #[op(fast)] - | ^^^^^^^^^^^ - | - = help: message: op cannot be a fast api. enforced by #[op(fast)] - -error: custom attribute panicked - --> tests/compile_fail/unsupported.rs:10:1 - | -10 | #[op(fast)] - | ^^^^^^^^^^^ - | - = help: message: op cannot be a fast api. enforced by #[op(fast)] - -error: custom attribute panicked - --> tests/compile_fail/unsupported.rs:15:1 - | -15 | #[op(fast)] - | ^^^^^^^^^^^ - | - = help: message: op cannot be a fast api. enforced by #[op(fast)] - -error: custom attribute panicked - --> tests/compile_fail/unsupported.rs:20:1 - | -20 | #[op(fast)] - | ^^^^^^^^^^^ - | - = help: message: async op cannot be a fast api. enforced by #[op(fast)] diff --git a/ops/tests/mod.rs b/ops/tests/mod.rs deleted file mode 100644 index 522647f51e..0000000000 --- a/ops/tests/mod.rs +++ /dev/null @@ -1,5 +0,0 @@ -#[test] -fn op_macro() { - let t = trybuild::TestCases::new(); - t.compile_fail("tests/compile_fail/*.rs"); -}