From 115cc1e6ae00cfd9283c1549060892e0c00dcbc4 Mon Sep 17 00:00:00 2001 From: Divy Srivastava Date: Thu, 27 Oct 2022 07:58:27 -0700 Subject: [PATCH] Revert "perf(core): generate inlined wrappers for async ops (#16428)" (#16443) --- bench_util/js_runtime.rs | 5 +- cli/bench/async_ops.js | 5 +- cli/tests/unit/metrics_test.ts | 2 +- core/01_core.js | 88 +++++--------------- core/bindings.rs | 92 +------------------- core/examples/http_bench_json_ops.js | 4 +- core/extensions.rs | 3 - core/runtime.rs | 56 ++++++------- ops/lib.rs | 120 ++++++++++++--------------- runtime/js/99_main.js | 2 - 10 files changed, 112 insertions(+), 265 deletions(-) diff --git a/bench_util/js_runtime.rs b/bench_util/js_runtime.rs index f87fa3b03a..06dd79fae4 100644 --- a/bench_util/js_runtime.rs +++ b/bench_util/js_runtime.rs @@ -63,6 +63,7 @@ pub fn bench_js_sync_with( let code = v8::String::new(scope, looped_src.as_ref()).unwrap(); let script = v8::Script::compile(scope, code, None).unwrap(); + // Run once if profiling, otherwise regular bench loop if is_profiling() { script.run(scope).unwrap(); @@ -101,9 +102,7 @@ pub fn bench_js_async_with( }; let looped = loop_code(inner_iters, src); let src = looped.as_ref(); - runtime - .execute_script("init", "Deno.core.initializeAsyncOps();") - .unwrap(); + if is_profiling() { for _ in 0..opts.profiling_outer { tokio_runtime.block_on(inner_async(src, &mut runtime)); diff --git a/cli/bench/async_ops.js b/cli/bench/async_ops.js index 2647accbdd..ac4eb68589 100644 --- a/cli/bench/async_ops.js +++ b/cli/bench/async_ops.js @@ -5,7 +5,7 @@ let [total, count] = typeof Deno !== "undefined" : [process.argv[2], process.argv[3]]; total = total ? parseInt(total, 0) : 50; -count = count ? parseInt(count, 10) : 1000000; +count = count ? parseInt(count, 10) : 100000; async function bench(fun) { const start = Date.now(); @@ -16,5 +16,4 @@ async function bench(fun) { if (--total) queueMicrotask(() => bench(fun)); } -const { ops } = Deno.core; -bench(() => ops.op_void_async()); +bench(() => Deno.core.opAsync("op_void_async")); diff --git a/cli/tests/unit/metrics_test.ts b/cli/tests/unit/metrics_test.ts index 7f78d4578b..82ff7ddd06 100644 --- a/cli/tests/unit/metrics_test.ts +++ b/cli/tests/unit/metrics_test.ts @@ -84,6 +84,6 @@ Deno.test(function opNamesMatch() { // @ts-ignore: Deno.core allowed Deno.core.opNames().sort(), // @ts-ignore: Deno.core allowed - Object.keys(Deno.core.ops).sort().filter((name) => name !== "asyncOpsInfo"), + Object.keys(Deno.core.ops).sort(), ); }); diff --git a/core/01_core.js b/core/01_core.js index 5df11c382c..7bee019d9f 100644 --- a/core/01_core.js +++ b/core/01_core.js @@ -28,7 +28,7 @@ SymbolFor, setQueueMicrotask, } = window.__bootstrap.primordials; - const { ops } = window.Deno.core; + const ops = window.Deno.core.ops; const errorMap = {}; // Builtin v8 / JS errors @@ -159,63 +159,21 @@ return res; } - function rollPromiseId() { - return nextPromiseId++; - } - - // Generate async op wrappers. See core/bindings.rs - function initializeAsyncOps() { - function genAsyncOp(op, name, args) { - return new Function( - "setPromise", - "getPromise", - "promiseIdSymbol", - "rollPromiseId", - "handleOpCallTracing", - "op", - "unwrapOpResult", - "PromisePrototypeThen", - ` - return function ${name}(${args}) { - const id = rollPromiseId(); - let promise = PromisePrototypeThen(setPromise(id), unwrapOpResult); - try { - op(id, ${args}); - } catch (err) { - // Cleanup the just-created promise - getPromise(id); - // Rethrow the error - throw err; - } - handleOpCallTracing("${name}", id, promise); - promise[promiseIdSymbol] = id; - return promise; - } - `, - )( - setPromise, - getPromise, - promiseIdSymbol, - rollPromiseId, - handleOpCallTracing, - op, - unwrapOpResult, - PromisePrototypeThen, - ); + function opAsync(opName, ...args) { + const promiseId = nextPromiseId++; + let p = setPromise(promiseId); + try { + ops[opName](promiseId, ...args); + } catch (err) { + // Cleanup the just-created promise + getPromise(promiseId); + // Rethrow the error + throw err; } - - // { : , ... } - for (const ele of Object.entries(ops.asyncOpsInfo())) { - if (!ele) continue; - const [name, argc] = ele; - const op = ops[name]; - const args = Array.from({ length: argc }, (_, i) => `arg${i}`).join(", "); - ops[name] = genAsyncOp(op, name, args); - } - } - - function handleOpCallTracing(opName, promiseId, p) { + p = PromisePrototypeThen(p, unwrapOpResult); if (opCallTracingEnabled) { + // Capture a stack trace by creating a new `Error` object. We remove the + // first 6 characters (the `Error\n` prefix) to get just the stack trace. const stack = StringPrototypeSlice(new Error().stack, 6); MapPrototypeSet(opCallTraces, promiseId, { opName, stack }); p = PromisePrototypeFinally( @@ -223,10 +181,9 @@ () => MapPrototypeDelete(opCallTraces, promiseId), ); } - } - - function opAsync(opName, ...args) { - return ops[opName](...args); + // Save the id on the promise so it can later be ref'ed or unref'ed + p[promiseIdSymbol] = promiseId; + return p; } function refOp(promiseId) { @@ -346,7 +303,6 @@ // Extra Deno.core.* exports const core = ObjectAssign(globalThis.Deno.core, { opAsync, - initializeAsyncOps, resources, metrics, registerErrorBuilder, @@ -366,11 +322,11 @@ setPromiseHooks, close: (rid) => ops.op_close(rid), tryClose: (rid) => ops.op_try_close(rid), - read: (rid, buffer) => ops.op_read(rid, buffer), - readAll: (rid) => ops.op_read_all(rid), - write: (rid, buffer) => ops.op_write(rid, buffer), - writeAll: (rid, buffer) => ops.op_write_all(rid, buffer), - shutdown: (rid) => ops.op_shutdown(rid), + read: opAsync.bind(null, "op_read"), + readAll: opAsync.bind(null, "op_read_all"), + write: opAsync.bind(null, "op_write"), + writeAll: opAsync.bind(null, "op_write_all"), + shutdown: opAsync.bind(null, "op_shutdown"), print: (msg, isErr) => ops.op_print(msg, isErr), setMacrotaskCallback: (fn) => ops.op_set_macrotask_callback(fn), setNextTickCallback: (fn) => ops.op_set_next_tick_callback(fn), diff --git a/core/bindings.rs b/core/bindings.rs index 60d15f745a..741ab63365 100644 --- a/core/bindings.rs +++ b/core/bindings.rs @@ -97,7 +97,6 @@ pub fn initialize_context<'s>( scope: &mut v8::HandleScope<'s, ()>, op_ctxs: &[OpCtx], snapshot_loaded: bool, - will_snapshot: bool, ) -> v8::Local<'s, v8::Context> { let scope = &mut v8::EscapableHandleScope::new(scope); @@ -117,9 +116,7 @@ pub fn initialize_context<'s>( 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); - if !will_snapshot { - initialize_async_ops_info(scope, ops_obj, op_ctxs); - } + return scope.escape(context); } @@ -131,10 +128,8 @@ pub fn initialize_context<'s>( // Bind functions to Deno.core.ops.* let ops_obj = JsRuntime::ensure_objs(scope, global, "Deno.core.ops").unwrap(); - if !will_snapshot { - initialize_async_ops_info(scope, ops_obj, op_ctxs); - } - initialize_ops(scope, ops_obj, op_ctxs, !will_snapshot); + + initialize_ops(scope, ops_obj, op_ctxs, snapshot_loaded); scope.escape(context) } @@ -595,84 +590,3 @@ pub fn throw_type_error(scope: &mut v8::HandleScope, message: impl AsRef) { let exception = v8::Exception::type_error(scope, message); scope.throw_exception(exception); } - -struct AsyncOpsInfo { - ptr: *const OpCtx, - len: usize, -} - -impl<'s> IntoIterator for &'s AsyncOpsInfo { - type Item = &'s OpCtx; - type IntoIter = AsyncOpsInfoIterator<'s>; - - fn into_iter(self) -> Self::IntoIter { - AsyncOpsInfoIterator { - // SAFETY: OpCtx slice is valid for the lifetime of the Isolate - info: unsafe { std::slice::from_raw_parts(self.ptr, self.len) }, - index: 0, - } - } -} - -struct AsyncOpsInfoIterator<'s> { - info: &'s [OpCtx], - index: usize, -} - -impl<'s> Iterator for AsyncOpsInfoIterator<'s> { - type Item = &'s OpCtx; - - fn next(&mut self) -> Option { - loop { - match self.info.get(self.index) { - Some(ctx) if ctx.decl.is_async => { - self.index += 1; - return Some(ctx); - } - Some(_) => { - self.index += 1; - } - None => return None, - } - } - } -} - -fn async_ops_info( - scope: &mut v8::HandleScope, - args: v8::FunctionCallbackArguments, - mut rv: v8::ReturnValue, -) { - let async_op_names = v8::Object::new(scope); - let external: v8::Local = args.data().try_into().unwrap(); - let info: &AsyncOpsInfo = - // SAFETY: external is guaranteed to be a valid pointer to AsyncOpsInfo - unsafe { &*(external.value() as *const AsyncOpsInfo) }; - for ctx in info { - let name = v8::String::new(scope, ctx.decl.name).unwrap(); - let argc = v8::Integer::new(scope, ctx.decl.argc as i32); - async_op_names.set(scope, name.into(), argc.into()); - } - rv.set(async_op_names.into()); -} - -fn initialize_async_ops_info( - scope: &mut v8::HandleScope, - ops_obj: v8::Local, - op_ctxs: &[OpCtx], -) { - let key = v8::String::new(scope, "asyncOpsInfo").unwrap(); - let external = v8::External::new( - scope, - Box::into_raw(Box::new(AsyncOpsInfo { - ptr: op_ctxs as *const [OpCtx] as _, - len: op_ctxs.len(), - })) as *mut c_void, - ); - let val = v8::Function::builder(async_ops_info) - .data(external.into()) - .build(scope) - .unwrap(); - val.set_name(key); - ops_obj.set(scope, key.into(), val.into()); -} diff --git a/core/examples/http_bench_json_ops.js b/core/examples/http_bench_json_ops.js index 261d91559e..883ef1752d 100644 --- a/core/examples/http_bench_json_ops.js +++ b/core/examples/http_bench_json_ops.js @@ -2,8 +2,6 @@ // This is not a real HTTP server. We read blindly one time into 'requestBuf', // then write this fixed 'responseBuf'. The point of this benchmark is to // exercise the event loop in a simple yet semi-realistic way. -Deno.core.initializeAsyncOps(); - const requestBuf = new Uint8Array(64 * 1024); const responseBuf = new Uint8Array( "HTTP/1.1 200 OK\r\nContent-Length: 12\r\n\r\nHello World\n" @@ -18,7 +16,7 @@ function listen() { /** Accepts a connection, returns rid. */ function accept(serverRid) { - return Deno.core.ops.op_accept(serverRid); + return Deno.core.opAsync("op_accept", serverRid); } async function serve(rid) { diff --git a/core/extensions.rs b/core/extensions.rs index 7b9ab59087..846770d1fb 100644 --- a/core/extensions.rs +++ b/core/extensions.rs @@ -16,9 +16,6 @@ pub struct OpDecl { pub enabled: bool, pub is_async: bool, pub is_unstable: bool, - /// V8 argument count. Used as an optimization - /// hint by `core.initalizeAsyncOps`. - pub argc: usize, pub is_v8: bool, pub fast_fn: Option>, } diff --git a/core/runtime.rs b/core/runtime.rs index 294982b7c7..e574bf9d38 100644 --- a/core/runtime.rs +++ b/core/runtime.rs @@ -384,8 +384,7 @@ impl JsRuntime { isolate_ptr.read() }; let scope = &mut v8::HandleScope::new(&mut isolate); - let context = - bindings::initialize_context(scope, &op_ctxs, false, true); + let context = bindings::initialize_context(scope, &op_ctxs, false); global_context = v8::Global::new(scope, context); scope.set_default_context(context); } @@ -423,7 +422,7 @@ impl JsRuntime { }; let scope = &mut v8::HandleScope::new(&mut isolate); let context = - bindings::initialize_context(scope, &op_ctxs, snapshot_loaded, false); + bindings::initialize_context(scope, &op_ctxs, snapshot_loaded); global_context = v8::Global::new(scope, context); } @@ -551,7 +550,6 @@ impl JsRuntime { scope, &self.state.borrow().op_ctxs, self.built_from_snapshot, - false, ); JsRealm::new(v8::Global::new(scope, context)) }; @@ -2245,7 +2243,6 @@ pub mod tests { #[derive(Copy, Clone)] enum Mode { Async, - AsyncDeferred, AsyncZeroCopy(bool), } @@ -2254,28 +2251,20 @@ pub mod tests { dispatch_count: Arc, } - #[op] + #[op(deferred)] async fn op_test( rc_op_state: Rc>, control: u8, buf: Option, ) -> Result { - #![allow(clippy::await_holding_refcell_ref)] // False positive. let op_state_ = rc_op_state.borrow(); let test_state = op_state_.borrow::(); test_state.dispatch_count.fetch_add(1, Ordering::Relaxed); - let mode = test_state.mode; - drop(op_state_); - match mode { + match test_state.mode { Mode::Async => { assert_eq!(control, 42); Ok(43) } - Mode::AsyncDeferred => { - tokio::task::yield_now().await; - assert_eq!(control, 42); - Ok(43) - } Mode::AsyncZeroCopy(has_buffer) => { assert_eq!(buf.is_some(), has_buffer); if let Some(buf) = buf { @@ -2325,15 +2314,14 @@ pub mod tests { #[test] fn test_ref_unref_ops() { - let (mut runtime, _dispatch_count) = setup(Mode::AsyncDeferred); + let (mut runtime, _dispatch_count) = setup(Mode::Async); runtime .execute_script( "filename.js", r#" - Deno.core.initializeAsyncOps(); var promiseIdSymbol = Symbol.for("Deno.core.internalPromiseId"); - var p1 = Deno.core.ops.op_test(42); - var p2 = Deno.core.ops.op_test(42); + var p1 = Deno.core.opAsync("op_test", 42); + var p2 = Deno.core.opAsync("op_test", 42); "#, ) .unwrap(); @@ -2386,7 +2374,6 @@ pub mod tests { "filename.js", r#" let control = 42; - Deno.core.initializeAsyncOps(); Deno.core.opAsync("op_test", control); async function main() { Deno.core.opAsync("op_test", control); @@ -2405,7 +2392,6 @@ pub mod tests { .execute_script( "filename.js", r#" - Deno.core.initializeAsyncOps(); const p = Deno.core.opAsync("op_test", 42); if (p[Symbol.for("Deno.core.internalPromiseId")] == undefined) { throw new Error("missing id on returned promise"); @@ -2422,7 +2408,6 @@ pub mod tests { .execute_script( "filename.js", r#" - Deno.core.initializeAsyncOps(); Deno.core.opAsync("op_test"); "#, ) @@ -2437,7 +2422,6 @@ pub mod tests { .execute_script( "filename.js", r#" - Deno.core.initializeAsyncOps(); let zero_copy_a = new Uint8Array([0]); Deno.core.opAsync("op_test", null, zero_copy_a); "#, @@ -3037,6 +3021,7 @@ pub mod tests { function main() { console.log("asdf); } + main(); "#, ); @@ -3056,16 +3041,18 @@ function assert(cond) { throw Error("assert"); } } + function main() { assert(false); } + main(); "#, ); let expected_error = r#"Error: assert at assert (error_stack.js:4:11) - at main (error_stack.js:8:3) - at error_stack.js:10:1"#; + at main (error_stack.js:9:3) + at error_stack.js:12:1"#; assert_eq!(result.unwrap_err().to_string(), expected_error); } @@ -3083,6 +3070,7 @@ main(); throw new Error("async"); }); })(); + try { await p; } catch (error) { @@ -3095,7 +3083,7 @@ main(); let expected_error = r#"Error: async at error_async_stack.js:5:13 at async error_async_stack.js:4:5 - at async error_async_stack.js:9:5"#; + at async error_async_stack.js:10:5"#; match runtime.poll_event_loop(cx, false) { Poll::Ready(Err(e)) => { @@ -3188,6 +3176,7 @@ function assertEquals(a, b) { const sab = new SharedArrayBuffer(16); const i32a = new Int32Array(sab); globalThis.resolved = false; + (function() { const result = Atomics.waitAsync(i32a, 0, 0); result.value.then( @@ -3195,6 +3184,7 @@ globalThis.resolved = false; () => { assertUnreachable(); }); })(); + const notify_return_value = Atomics.notify(i32a, 0, 1); assertEquals(1, notify_return_value); "#, @@ -3304,7 +3294,7 @@ assertEquals(1, notify_return_value); runtime .execute_script( "op_async_borrow.js", - "Deno.core.initializeAsyncOps(); Deno.core.ops.op_async_borrow()", + "Deno.core.opAsync('op_async_borrow')", ) .unwrap(); runtime.run_event_loop(false).await.unwrap(); @@ -3378,8 +3368,7 @@ Deno.core.ops.op_sync_serialize_object_with_numbers_as_keys({ .execute_script( "op_async_serialize_object_with_numbers_as_keys.js", r#" -Deno.core.initializeAsyncOps(); -Deno.core.ops.op_async_serialize_object_with_numbers_as_keys({ +Deno.core.opAsync('op_async_serialize_object_with_numbers_as_keys', { lines: { 100: { unit: "m" @@ -3417,7 +3406,6 @@ Deno.core.ops.op_async_serialize_object_with_numbers_as_keys({ .execute_script( "macrotasks_and_nextticks.js", r#" - Deno.core.initializeAsyncOps(); (async function () { const results = []; Deno.core.ops.op_set_macrotask_callback(() => { @@ -3428,6 +3416,7 @@ Deno.core.ops.op_async_serialize_object_with_numbers_as_keys({ results.push("nextTick"); Deno.core.ops.op_set_has_tick_scheduled(false); }); + Deno.core.ops.op_set_has_tick_scheduled(true); await Deno.core.opAsync('op_async_sleep'); if (results[0] != "nextTick") { @@ -3638,6 +3627,7 @@ Deno.core.ops.op_async_serialize_object_with_numbers_as_keys({ Deno.core.ops.op_store_pending_promise_exception(promise); Deno.core.ops.op_promise_reject(); }); + new Promise((_, reject) => reject(Error("reject"))); "#, ) @@ -3655,6 +3645,7 @@ Deno.core.ops.op_async_serialize_object_with_numbers_as_keys({ prev(...args); }); } + new Promise((_, reject) => reject(Error("reject"))); "#, ) @@ -3704,6 +3695,7 @@ Deno.core.ops.op_async_serialize_object_with_numbers_as_keys({ Deno.core.ops.op_set_promise_reject_callback((type, promise, reason) => { Deno.core.ops.op_promise_reject(); }); + throw new Error('top level throw'); "#; @@ -3834,6 +3826,8 @@ Deno.core.ops.op_async_serialize_object_with_numbers_as_keys({ const a1b = a1.subarray(0, 3); const a2 = new Uint8Array([5,10,15]); const a2b = a2.subarray(0, 3); + + if (!(a1.length > 0 && a1b.length > 0)) { throw new Error("a1 & a1b should have a length"); } @@ -3844,6 +3838,7 @@ Deno.core.ops.op_async_serialize_object_with_numbers_as_keys({ if (a1.length > 0 || a1b.length > 0) { throw new Error("expecting a1 & a1b to be detached"); } + const a3 = Deno.core.ops.op_boomerang(a2b); if (a3.byteLength != 3) { throw new Error(`Expected a3.byteLength === 3, got ${a3.byteLength}`); @@ -3854,6 +3849,7 @@ Deno.core.ops.op_async_serialize_object_with_numbers_as_keys({ if (a2.byteLength > 0 || a2b.byteLength > 0) { throw new Error("expecting a2 & a2b to be detached, a3 re-attached"); } + const wmem = new WebAssembly.Memory({ initial: 1, maximum: 2 }); const w32 = new Uint32Array(wmem.buffer); w32[0] = 1; w32[1] = 2; w32[2] = 3; diff --git a/ops/lib.rs b/ops/lib.rs index 44f7832803..8cd85f4f33 100644 --- a/ops/lib.rs +++ b/ops/lib.rs @@ -118,7 +118,7 @@ pub fn op(attr: TokenStream, item: TokenStream) -> TokenStream { let (has_fallible_fast_call, fast_impl, fast_field) = codegen_fast_impl(&core, &func, name, is_async, must_be_fast); - let (v8_body, argc) = if is_async { + let v8_body = if is_async { codegen_v8_async(&core, &func, margs, asyncness, deferred) } else { codegen_v8_sync(&core, &func, margs, has_fallible_fast_call) @@ -154,7 +154,6 @@ pub fn op(attr: TokenStream, item: TokenStream) -> TokenStream { is_async: #is_async, is_unstable: #is_unstable, is_v8: #is_v8, - argc: #argc, } } @@ -182,7 +181,7 @@ fn codegen_v8_async( margs: MacroArgs, asyncness: bool, deferred: bool, -) -> (TokenStream2, usize) { +) -> TokenStream2 { let MacroArgs { is_v8, .. } = margs; let special_args = f .sig @@ -195,7 +194,7 @@ fn codegen_v8_async( let rust_i0 = special_args.len(); let args_head = special_args.into_iter().collect::(); - let (arg_decls, args_tail, argc) = codegen_args(core, f, rust_i0, 1); + let (arg_decls, args_tail) = codegen_args(core, f, rust_i0, 1); let type_params = exclude_lifetime_params(&f.sig.generics.params); let (pre_result, mut result_fut) = match asyncness { @@ -226,47 +225,44 @@ fn codegen_v8_async( false => quote! { let result = Ok(result); }, }; - ( - quote! { - use #core::futures::FutureExt; - // SAFETY: #core guarantees args.data() is a v8 External pointing to an OpCtx for the isolates lifetime - let ctx = unsafe { - &*(#core::v8::Local::<#core::v8::External>::cast(args.data()).value() - as *const #core::_ops::OpCtx) - }; - let op_id = ctx.id; + quote! { + use #core::futures::FutureExt; + // SAFETY: #core guarantees args.data() is a v8 External pointing to an OpCtx for the isolates lifetime + let ctx = unsafe { + &*(#core::v8::Local::<#core::v8::External>::cast(args.data()).value() + as *const #core::_ops::OpCtx) + }; + let op_id = ctx.id; - let promise_id = args.get(0); - 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; - } - }; + let promise_id = args.get(0); + 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; + } + }; - #arg_decls + #arg_decls - // Track async call & get copy of get_error_class_fn - let get_class = { - let state = ::std::cell::RefCell::borrow(&ctx.state); - state.tracker.track_async(op_id); - state.get_error_class_fn - }; + // Track async call & get copy of get_error_class_fn + let get_class = { + let state = ::std::cell::RefCell::borrow(&ctx.state); + state.tracker.track_async(op_id); + state.get_error_class_fn + }; - #pre_result - #core::_ops::queue_async_op(ctx, scope, #deferred, async move { - let result = #result_fut - #result_wrapper - (promise_id, op_id, #core::_ops::to_op_result(get_class, result)) - }); - }, - argc, - ) + #pre_result + #core::_ops::queue_async_op(ctx, scope, #deferred, async move { + let result = #result_fut + #result_wrapper + (promise_id, op_id, #core::_ops::to_op_result(get_class, result)) + }); + } } fn scope_arg(arg: &FnArg) -> Option { @@ -520,7 +516,7 @@ fn codegen_v8_sync( f: &syn::ItemFn, margs: MacroArgs, has_fallible_fast_call: bool, -) -> (TokenStream2, usize) { +) -> TokenStream2 { let MacroArgs { is_v8, .. } = margs; let special_args = f .sig @@ -532,7 +528,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, argc) = codegen_args(core, f, rust_i0, 0); + 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); @@ -551,27 +547,24 @@ fn codegen_v8_sync( quote! {} }; - ( - quote! { - // SAFETY: #core guarantees args.data() is a v8 External pointing to an OpCtx for the isolates lifetime - let ctx = unsafe { - &*(#core::v8::Local::<#core::v8::External>::cast(args.data()).value() - as *const #core::_ops::OpCtx) - }; + quote! { + // SAFETY: #core guarantees args.data() is a v8 External pointing to an OpCtx for the isolates lifetime + let ctx = unsafe { + &*(#core::v8::Local::<#core::v8::External>::cast(args.data()).value() + as *const #core::_ops::OpCtx) + }; - #fast_error_handler - #arg_decls + #fast_error_handler + #arg_decls - let result = Self::call::<#type_params>(#args_head #args_tail); + let result = Self::call::<#type_params>(#args_head #args_tail); - // use RefCell::borrow instead of state.borrow to avoid clash with std::borrow::Borrow - let op_state = ::std::cell::RefCell::borrow(&*ctx.state); - op_state.tracker.track_sync(ctx.id); + // use RefCell::borrow instead of state.borrow to avoid clash with std::borrow::Borrow + let op_state = ::std::cell::RefCell::borrow(&*ctx.state); + op_state.tracker.track_sync(ctx.id); - #ret - }, - argc, - ) + #ret + } } struct FastApiSyn { @@ -810,15 +803,12 @@ fn is_fast_scalar( } } -/// (full declarations, idents, v8 argument count) -type ArgumentDecl = (TokenStream2, TokenStream2, usize); - fn codegen_args( core: &TokenStream2, f: &syn::ItemFn, rust_i0: usize, // Index of first generic arg in rust v8_i0: usize, // Index of first generic arg in v8/js -) -> ArgumentDecl { +) -> (TokenStream2, TokenStream2) { let inputs = &f.sig.inputs.iter().skip(rust_i0).enumerate(); let ident_seq: TokenStream2 = inputs .clone() @@ -833,7 +823,7 @@ fn codegen_args( codegen_arg(core, arg, format!("arg_{i}").as_ref(), v8_i0 + i) }) .collect(); - (decls, ident_seq, inputs.len()) + (decls, ident_seq) } fn codegen_arg( diff --git a/runtime/js/99_main.js b/runtime/js/99_main.js index ef99969b22..afacd9b34a 100644 --- a/runtime/js/99_main.js +++ b/runtime/js/99_main.js @@ -692,7 +692,6 @@ delete Intl.v8BreakIterator; throw new Error("Worker runtime already bootstrapped"); } - core.initializeAsyncOps(); performance.setTimeOrigin(DateNow()); net.setup(runtimeOptions.unstableFlag); @@ -792,7 +791,6 @@ delete Intl.v8BreakIterator; throw new Error("Worker runtime already bootstrapped"); } - core.initializeAsyncOps(); performance.setTimeOrigin(DateNow()); net.setup(runtimeOptions.unstableFlag);