diff --git a/core/lib.rs b/core/lib.rs index 70dadfc6a8..cb16c26548 100644 --- a/core/lib.rs +++ b/core/lib.rs @@ -89,11 +89,8 @@ pub use crate::modules::ModuleType; pub use crate::modules::NoopModuleLoader; pub use crate::modules::ResolutionKind; pub use crate::normalize_path::normalize_path; -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::OpResult; pub use crate::ops::OpState; @@ -135,6 +132,10 @@ pub mod _ops { pub use super::ops::to_op_result; pub use super::ops::OpCtx; pub use super::ops::OpResult; + pub use super::runtime::map_async_op1; + pub use super::runtime::map_async_op2; + pub use super::runtime::map_async_op3; + pub use super::runtime::map_async_op4; pub use super::runtime::queue_async_op; pub use super::runtime::queue_fast_async_op; pub use super::runtime::V8_WRAPPER_OBJECT_INDEX; diff --git a/core/ops.rs b/core/ops.rs index cceeb56547..b7dcc26638 100644 --- a/core/ops.rs +++ b/core/ops.rs @@ -8,12 +8,10 @@ use crate::runtime::JsRuntimeState; use crate::OpDecl; use crate::OpsTracker; use anyhow::Error; -use futures::future::maybe_done; -use futures::future::FusedFuture; use futures::future::MaybeDone; -use futures::ready; -use futures::task::noop_waker; use futures::Future; +use futures::FutureExt; +use pin_project::pin_project; use serde::Serialize; use std::cell::RefCell; use std::ops::Deref; @@ -22,91 +20,78 @@ use std::pin::Pin; use std::ptr::NonNull; use std::rc::Rc; use std::rc::Weak; -use std::task::Context; -use std::task::Poll; use v8::fast_api::CFunctionInfo; use v8::fast_api::CTypeInfo; -/// Wrapper around a Future, which causes that Future to be polled immediately. -/// -/// 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. -pub struct OpCall(MaybeDone>>>); +pub type RealmIdx = u16; +pub type PromiseId = i32; +pub type OpId = u16; -pub enum EagerPollResult { - Ready(T), - Pending(OpCall), +#[pin_project] +pub struct OpCall { + realm_idx: RealmIdx, + promise_id: PromiseId, + op_id: OpId, + /// Future is not necessarily Unpin, so we need to pin_project. + #[pin] + fut: MaybeDone>>>, } -impl OpCall { - /// Wraps a future, and polls the inner future immediately. - /// This should be the default choice for ops. - pub fn eager(fut: impl Future + 'static) -> EagerPollResult { - let boxed = Box::pin(fut) as Pin>>; - let mut inner = maybe_done(boxed); - let waker = noop_waker(); - let mut cx = Context::from_waker(&waker); - let mut pinned = Pin::new(&mut inner); - let poll = pinned.as_mut().poll(&mut cx); - match poll { - Poll::Ready(_) => EagerPollResult::Ready(pinned.take_output().unwrap()), - _ => EagerPollResult::Pending(Self(inner)), - } - } - +impl OpCall { /// Wraps a future; the inner future is polled the usual way (lazily). - pub fn lazy(fut: impl Future + 'static) -> Self { - let boxed = Box::pin(fut) as Pin>>; - let inner = maybe_done(boxed); - Self(inner) + pub fn pending( + op_ctx: &OpCtx, + promise_id: PromiseId, + fut: Pin + 'static>>, + ) -> Self { + Self { + realm_idx: op_ctx.realm_idx, + op_id: op_ctx.id, + promise_id, + fut: MaybeDone::Future(fut), + } } /// Create a future by specifying its output. This is basically the same as /// `async { value }` or `futures::future::ready(value)`. - pub fn ready(value: T) -> Self { - Self(MaybeDone::Done(value)) + pub fn ready(op_ctx: &OpCtx, promise_id: PromiseId, value: OpResult) -> Self { + Self { + realm_idx: op_ctx.realm_idx, + op_id: op_ctx.id, + promise_id, + fut: MaybeDone::Done(value), + } } } -impl Future for OpCall { - type Output = T; +impl Future for OpCall { + type Output = (RealmIdx, PromiseId, OpId, OpResult); fn poll( self: std::pin::Pin<&mut Self>, cx: &mut std::task::Context<'_>, ) -> std::task::Poll { - // TODO(piscisaureus): safety comment - #[allow(clippy::undocumented_unsafe_blocks)] - let inner = unsafe { &mut self.get_unchecked_mut().0 }; - let mut pinned = Pin::new(inner); - ready!(pinned.as_mut().poll(cx)); - Poll::Ready(pinned.as_mut().take_output().unwrap()) + let realm_idx = self.realm_idx; + let promise_id = self.promise_id; + let op_id = self.op_id; + let fut = &mut *self.project().fut; + match fut { + MaybeDone::Done(_) => { + // Let's avoid using take_output as it keeps our Pin::box + let res = std::mem::replace(fut, MaybeDone::Gone); + let MaybeDone::Done(res) = res + else { + unreachable!() + }; + std::task::Poll::Ready(res) + } + MaybeDone::Future(f) => f.poll_unpin(cx), + MaybeDone::Gone => std::task::Poll::Pending, + } + .map(move |res| (realm_idx, promise_id, op_id, res)) } } -impl FusedFuture for OpCall -where - F: Future, -{ - fn is_terminated(&self) -> bool { - self.0.is_terminated() - } -} - -pub type RealmIdx = usize; -pub type PromiseId = i32; -pub type OpAsyncFuture = OpCall<(PromiseId, OpId, OpResult)>; -pub type OpFn = - fn(&mut v8::HandleScope, v8::FunctionCallbackArguments, v8::ReturnValue); -pub type OpId = usize; - -pub enum Op { - Sync(OpResult), - Async(OpAsyncFuture), - NotFound, -} - pub enum OpResult { Ok(serde_v8::SerializablePkg), Err(OpError), diff --git a/core/ops_metrics.rs b/core/ops_metrics.rs index c0b8abb519..b25368bd01 100644 --- a/core/ops_metrics.rs +++ b/core/ops_metrics.rs @@ -63,7 +63,7 @@ impl OpsTracker { #[inline] fn metrics_mut(&self, id: OpId) -> RefMut { - RefMut::map(self.ops.borrow_mut(), |ops| &mut ops[id]) + RefMut::map(self.ops.borrow_mut(), |ops| &mut ops[id as usize]) } #[inline] diff --git a/core/runtime.rs b/core/runtime.rs index 6820df6bca..3723a917ac 100644 --- a/core/runtime.rs +++ b/core/runtime.rs @@ -35,8 +35,10 @@ use futures::channel::oneshot; use futures::future::poll_fn; use futures::future::Future; use futures::future::FutureExt; +use futures::future::MaybeDone; use futures::stream::FuturesUnordered; use futures::stream::StreamExt; +use futures::task::noop_waker; use futures::task::AtomicWaker; use smallvec::SmallVec; use std::any::Any; @@ -45,6 +47,7 @@ use std::collections::HashMap; use std::collections::VecDeque; use std::ffi::c_void; use std::option::Option; +use std::pin::Pin; use std::rc::Rc; use std::sync::Arc; use std::sync::Mutex; @@ -53,8 +56,6 @@ use std::task::Context; use std::task::Poll; use v8::OwnedIsolate; -type PendingOpFuture = OpCall<(RealmIdx, PromiseId, OpId, OpResult)>; - pub enum Snapshot { Static(&'static [u8]), JustCreated(v8::StartupData), @@ -165,7 +166,7 @@ pub struct JsRuntimeState { dyn_module_evaluate_idle_counter: u32, pub(crate) source_map_getter: Option>>, pub(crate) source_map_cache: Rc>, - pub(crate) pending_ops: FuturesUnordered, + pub(crate) pending_ops: FuturesUnordered, pub(crate) have_unpolled_ops: bool, pub(crate) op_state: Rc>, pub(crate) shared_array_buffer_store: Option, @@ -360,7 +361,7 @@ impl JsRuntime { .into_iter() .enumerate() .map(|(id, decl)| { - OpCtx::new(id, 0, Rc::new(decl), op_state.clone(), weak.clone()) + OpCtx::new(id as u16, 0, Rc::new(decl), op_state.clone(), weak.clone()) }) .collect::>() .into_boxed_slice(); @@ -610,7 +611,7 @@ impl JsRuntime { /// constructed. pub fn create_realm(&mut self) -> Result { let realm = { - let realm_idx = self.state.borrow().known_realms.len(); + let realm_idx = self.state.borrow().known_realms.len() as u16; let op_ctxs: Box<[OpCtx]> = self .global_realm() @@ -2231,7 +2232,7 @@ impl JsRuntime { { let (realm_idx, promise_id, op_id, resp) = item; state.op_state.borrow().tracker.track_async_completed(op_id); - responses_per_realm[realm_idx].push((promise_id, resp)); + responses_per_realm[realm_idx as usize].push((promise_id, resp)); } } @@ -2335,7 +2336,7 @@ impl JsRuntime { { let (realm_idx, promise_id, op_id, mut resp) = item; debug_assert_eq!( - state.known_realms[realm_idx], + state.known_realms[realm_idx as usize], state.global_realm.as_ref().unwrap().context() ); realm_state.unrefed_ops.remove(&promise_id); @@ -2382,27 +2383,106 @@ impl JsRuntime { } #[inline] -pub fn queue_fast_async_op( +pub fn queue_fast_async_op( ctx: &OpCtx, - op: impl Future + 'static, + promise_id: PromiseId, + op: impl Future> + 'static, ) { let runtime_state = match ctx.runtime_state.upgrade() { Some(rc_state) => rc_state, // atleast 1 Rc is held by the JsRuntime. None => unreachable!(), }; - + let get_class = { + let state = RefCell::borrow(&ctx.state); + state.tracker.track_async(ctx.id); + state.get_error_class_fn + }; + let fut = op + .map(|result| crate::_ops::to_op_result(get_class, result)) + .boxed_local(); let mut state = runtime_state.borrow_mut(); - state.pending_ops.push(OpCall::lazy(op)); + state + .pending_ops + .push(OpCall::pending(ctx, promise_id, fut)); state.have_unpolled_ops = true; } #[inline] +pub fn map_async_op1( + ctx: &OpCtx, + op: impl Future> + 'static, +) -> MaybeDone>>> { + let get_class = { + let state = RefCell::borrow(&ctx.state); + state.tracker.track_async(ctx.id); + state.get_error_class_fn + }; + + let fut = op + .map(|result| crate::_ops::to_op_result(get_class, result)) + .boxed_local(); + MaybeDone::Future(fut) +} + +#[inline] +pub fn map_async_op2( + ctx: &OpCtx, + op: impl Future + 'static, +) -> MaybeDone>>> { + let state = RefCell::borrow(&ctx.state); + state.tracker.track_async(ctx.id); + + let fut = op.map(|result| OpResult::Ok(result.into())).boxed_local(); + MaybeDone::Future(fut) +} + +#[inline] +pub fn map_async_op3( + ctx: &OpCtx, + op: Result> + 'static, Error>, +) -> MaybeDone>>> { + let get_class = { + let state = RefCell::borrow(&ctx.state); + state.tracker.track_async(ctx.id); + state.get_error_class_fn + }; + + match op { + Err(err) => MaybeDone::Done(OpResult::Err(OpError::new(get_class, err))), + Ok(fut) => MaybeDone::Future( + fut + .map(|result| crate::_ops::to_op_result(get_class, result)) + .boxed_local(), + ), + } +} + +#[inline] +pub fn map_async_op4( + ctx: &OpCtx, + op: Result + 'static, Error>, +) -> MaybeDone>>> { + let get_class = { + let state = RefCell::borrow(&ctx.state); + state.tracker.track_async(ctx.id); + state.get_error_class_fn + }; + + match op { + Err(err) => MaybeDone::Done(OpResult::Err(OpError::new(get_class, err))), + Ok(fut) => MaybeDone::Future( + fut.map(|result| OpResult::Ok(result.into())).boxed_local(), + ), + } +} + pub fn queue_async_op<'s>( ctx: &OpCtx, scope: &'s mut v8::HandleScope, deferred: bool, - op: impl Future + 'static, + promise_id: PromiseId, + mut op: MaybeDone>>>, ) -> Option> { let runtime_state = match ctx.runtime_state.upgrade() { Some(rc_state) => rc_state, @@ -2415,32 +2495,40 @@ pub fn queue_async_op<'s>( // deno_core doesn't currently support such exposure, even though embedders // can cause them, so we panic in debug mode (since the check is expensive). debug_assert_eq!( - runtime_state.borrow().known_realms[ctx.realm_idx].to_local(scope), + runtime_state.borrow().known_realms[ctx.realm_idx as usize].to_local(scope), Some(scope.get_current_context()) ); - match OpCall::eager(op) { - // If the result is ready we'll just return it straight to the caller, so - // we don't have to invoke a JS callback to respond. // This works under the - // assumption that `()` return value is serialized as `null`. - EagerPollResult::Ready((_, _, op_id, mut resp)) if !deferred => { - let resp = resp.to_v8(scope).unwrap(); - ctx.state.borrow_mut().tracker.track_async_completed(op_id); - return Some(resp); - } - EagerPollResult::Ready(op) => { - let ready = OpCall::ready(op); - let mut state = runtime_state.borrow_mut(); - state.pending_ops.push(ready); - state.have_unpolled_ops = true; - } - EagerPollResult::Pending(op) => { - let mut state = runtime_state.borrow_mut(); - state.pending_ops.push(op); - state.have_unpolled_ops = true; - } - } + // All ops are polled immediately + let waker = noop_waker(); + let mut cx = Context::from_waker(&waker); + // Note that MaybeDone returns () from the future + let op_call = match op.poll_unpin(&mut cx) { + Poll::Pending => { + let MaybeDone::Future(fut) = op else { + unreachable!() + }; + OpCall::pending(ctx, promise_id, fut) + } + Poll::Ready(_) => { + let mut op_result = Pin::new(&mut op).take_output().unwrap(); + // If the op is ready and is not marked as deferred we can immediately return + // the result. + if !deferred { + ctx.state.borrow_mut().tracker.track_async_completed(ctx.id); + return Some(op_result.to_v8(scope).unwrap()); + } + + OpCall::ready(ctx, promise_id, op_result) + } + }; + + // Otherwise we will push it to the `pending_ops` and let it be polled again + // or resolved on the next tick of the event loop. + let mut state = runtime_state.borrow_mut(); + state.pending_ops.push(op_call); + state.have_unpolled_ops = true; None } diff --git a/ops/fast_call.rs b/ops/fast_call.rs index 2485b6083c..ebbb1927bc 100644 --- a/ops/fast_call.rs +++ b/ops/fast_call.rs @@ -245,41 +245,16 @@ pub(crate) fn generate( } if optimizer.is_async { - // Referenced variables are declared in parent block. - let track_async = q!({ - let __op_id = __ctx.id; - let __state = ::std::cell::RefCell::borrow(&__ctx.state); - __state.tracker.track_async(__op_id); - }); - - output_transforms.push_tokens(&track_async); - let queue_future = if optimizer.returns_result { q!({ - let realm_idx = __ctx.realm_idx; - let __get_class = __state.get_error_class_fn; - let result = _ops::queue_fast_async_op(__ctx, async move { - let result = result.await; - ( - realm_idx, - __promise_id, - __op_id, - _ops::to_op_result(__get_class, result), - ) - }); + let result = _ops::queue_fast_async_op(__ctx, __promise_id, result); }) } else { q!({ - let realm_idx = __ctx.realm_idx; - let result = _ops::queue_fast_async_op(__ctx, async move { - let result = result.await; - ( - realm_idx, - __promise_id, - __op_id, - _ops::OpResult::Ok(result.into()), - ) - }); + let result = + _ops::queue_fast_async_op(__ctx, __promise_id, async move { + Ok(result.await) + }); }) }; diff --git a/ops/lib.rs b/ops/lib.rs index 7bf9620917..5a192537fd 100644 --- a/ops/lib.rs +++ b/ops/lib.rs @@ -258,32 +258,55 @@ fn codegen_v8_async( let (arg_decls, args_tail, _) = codegen_args(core, f, rust_i0, 1, asyncness); let type_params = exclude_lifetime_params(&f.sig.generics.params); - let (pre_result, mut result_fut) = match asyncness { - true => ( - quote! {}, - quote! { Self::call::<#type_params>(#args_head #args_tail).await; }, - ), - false => ( - quote! { let result_fut = Self::call::<#type_params>(#args_head #args_tail); }, - quote! { result_fut.await; }, - ), - }; - let result_wrapper = match is_result(&f.sig.output) { - true => { - // Support `Result> + 'static, AnyError>` - if !asyncness { - result_fut = quote! { result_fut; }; - quote! { - let result = match result { - Ok(fut) => fut.await, - Err(e) => return (realm_idx, promise_id, op_id, #core::_ops::to_op_result::<()>(get_class, Err(e))), - }; - } - } else { - quote! {} + let wrapper = match (asyncness, is_result(&f.sig.output)) { + (true, true) => { + quote! { + let fut = #core::_ops::map_async_op1(ctx, Self::call::<#type_params>(#args_head #args_tail)); + let maybe_response = #core::_ops::queue_async_op( + ctx, + scope, + #deferred, + promise_id, + fut, + ); + } + } + (true, false) => { + quote! { + let fut = #core::_ops::map_async_op2(ctx, Self::call::<#type_params>(#args_head #args_tail)); + let maybe_response = #core::_ops::queue_async_op( + ctx, + scope, + #deferred, + promise_id, + fut, + ); + } + } + (false, true) => { + quote! { + let fut = #core::_ops::map_async_op3(ctx, Self::call::<#type_params>(#args_head #args_tail)); + let maybe_response = #core::_ops::queue_async_op( + ctx, + scope, + #deferred, + promise_id, + fut, + ); + } + } + (false, false) => { + quote! { + let fut = #core::_ops::map_async_op4(ctx, Self::call::<#type_params>(#args_head #args_tail)); + let maybe_response = #core::_ops::queue_async_op( + ctx, + scope, + #deferred, + promise_id, + fut, + ); } } - false => quote! { let result = Ok(result); }, }; quote! { @@ -293,8 +316,6 @@ fn codegen_v8_async( &*(#core::v8::Local::<#core::v8::External>::cast(args.data()).value() as *const #core::_ops::OpCtx) }; - let op_id = ctx.id; - let realm_idx = ctx.realm_idx; let promise_id = args.get(0); let promise_id = #core::v8::Local::<#core::v8::Integer>::try_from(promise_id) @@ -310,20 +331,7 @@ fn codegen_v8_async( }; #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 - }; - - #pre_result - let maybe_response = #core::_ops::queue_async_op(ctx, scope, #deferred, async move { - let result = #result_fut - #result_wrapper - (realm_idx, promise_id, op_id, #core::_ops::to_op_result(get_class, result)) - }); + #wrapper if let Some(response) = maybe_response { rv.set(response); diff --git a/ops/optimizer_tests/async_nop.out b/ops/optimizer_tests/async_nop.out index 7782b5970d..d267338258 100644 --- a/ops/optimizer_tests/async_nop.out +++ b/ops/optimizer_tests/async_nop.out @@ -56,8 +56,6 @@ impl op_void_async { &*(deno_core::v8::Local::::cast(args.data()).value() as *const deno_core::_ops::OpCtx) }; - let op_id = ctx.id; - let realm_idx = ctx.realm_idx; let promise_id = args.get(0); let promise_id = deno_core::v8::Local::< deno_core::v8::Integer, @@ -74,25 +72,13 @@ impl op_void_async { return; } }; - let get_class = { - let state = ::std::cell::RefCell::borrow(&ctx.state); - state.tracker.track_async(op_id); - state.get_error_class_fn - }; + let fut = deno_core::_ops::map_async_op2(ctx, Self::call()); let maybe_response = deno_core::_ops::queue_async_op( ctx, scope, false, - async move { - let result = Self::call().await; - let result = Ok(result); - ( - realm_idx, - promise_id, - op_id, - deno_core::_ops::to_op_result(get_class, result), - ) - }, + promise_id, + fut, ); if let Some(response) = maybe_response { rv.set(response); @@ -116,16 +102,10 @@ fn op_void_async_fast_fn<'scope>( }; let op_state = __ctx.state.clone(); let result = op_void_async::call(); - let __op_id = __ctx.id; - let __state = ::std::cell::RefCell::borrow(&__ctx.state); - __state.tracker.track_async(__op_id); - let realm_idx = __ctx.realm_idx; let result = _ops::queue_fast_async_op( __ctx, - async move { - let result = result.await; - (realm_idx, __promise_id, __op_id, _ops::OpResult::Ok(result.into())) - }, + __promise_id, + async move { Ok(result.await) }, ); result } diff --git a/ops/optimizer_tests/async_result.out b/ops/optimizer_tests/async_result.out index c3bb433f1a..4494bf22ae 100644 --- a/ops/optimizer_tests/async_result.out +++ b/ops/optimizer_tests/async_result.out @@ -56,8 +56,6 @@ impl op_async_result { &*(deno_core::v8::Local::::cast(args.data()).value() as *const deno_core::_ops::OpCtx) }; - let op_id = ctx.id; - let realm_idx = ctx.realm_idx; let promise_id = args.get(0); let promise_id = deno_core::v8::Local::< deno_core::v8::Integer, @@ -85,24 +83,16 @@ impl op_async_result { return deno_core::_ops::throw_type_error(scope, msg); } }; - let get_class = { - let state = ::std::cell::RefCell::borrow(&ctx.state); - state.tracker.track_async(op_id); - state.get_error_class_fn - }; + let fut = deno_core::_ops::map_async_op1( + ctx, + Self::call(ctx.state.clone(), arg_0), + ); let maybe_response = deno_core::_ops::queue_async_op( ctx, scope, false, - async move { - let result = Self::call(ctx.state.clone(), arg_0).await; - ( - realm_idx, - promise_id, - op_id, - deno_core::_ops::to_op_result(get_class, result), - ) - }, + promise_id, + fut, ); if let Some(response) = maybe_response { rv.set(response); @@ -127,16 +117,5 @@ fn op_async_result_fast_fn<'scope>( }; let state = __ctx.state.clone(); let result = op_async_result::call(state, rid); - let __op_id = __ctx.id; - let __state = ::std::cell::RefCell::borrow(&__ctx.state); - __state.tracker.track_async(__op_id); - let realm_idx = __ctx.realm_idx; - let __get_class = __state.get_error_class_fn; - let result = _ops::queue_fast_async_op( - __ctx, - async move { - let result = result.await; - (realm_idx, __promise_id, __op_id, _ops::to_op_result(__get_class, result)) - }, - ); + let result = _ops::queue_fast_async_op(__ctx, __promise_id, result); } diff --git a/ops/optimizer_tests/issue16934.out b/ops/optimizer_tests/issue16934.out index 68f59ef438..e92510038c 100644 --- a/ops/optimizer_tests/issue16934.out +++ b/ops/optimizer_tests/issue16934.out @@ -50,8 +50,6 @@ impl send_stdin { &*(deno_core::v8::Local::::cast(args.data()).value() as *const deno_core::_ops::OpCtx) }; - let op_id = ctx.id; - let realm_idx = ctx.realm_idx; let promise_id = args.get(0); let promise_id = deno_core::v8::Local::< deno_core::v8::Integer, @@ -79,28 +77,19 @@ impl send_stdin { ); } }; - let get_class = { - let state = ::std::cell::RefCell::borrow(&ctx.state); - state.tracker.track_async(op_id); - state.get_error_class_fn - }; + let fut = deno_core::_ops::map_async_op1( + ctx, + Self::call( + compile_error!("mutable opstate is not supported in async ops"), + arg_0, + ), + ); let maybe_response = deno_core::_ops::queue_async_op( ctx, scope, false, - async move { - let result = Self::call( - compile_error!("mutable opstate is not supported in async ops"), - arg_0, - ) - .await; - ( - realm_idx, - promise_id, - op_id, - deno_core::_ops::to_op_result(get_class, result), - ) - }, + promise_id, + fut, ); if let Some(response) = maybe_response { rv.set(response); diff --git a/ops/optimizer_tests/issue16934_fast.out b/ops/optimizer_tests/issue16934_fast.out index 7a4a39f348..2a16d1b626 100644 --- a/ops/optimizer_tests/issue16934_fast.out +++ b/ops/optimizer_tests/issue16934_fast.out @@ -48,8 +48,6 @@ impl send_stdin { &*(deno_core::v8::Local::::cast(args.data()).value() as *const deno_core::_ops::OpCtx) }; - let op_id = ctx.id; - let realm_idx = ctx.realm_idx; let promise_id = args.get(0); let promise_id = deno_core::v8::Local::< deno_core::v8::Integer, @@ -77,28 +75,19 @@ impl send_stdin { return deno_core::_ops::throw_type_error(scope, msg); } }; - let get_class = { - let state = ::std::cell::RefCell::borrow(&ctx.state); - state.tracker.track_async(op_id); - state.get_error_class_fn - }; + let fut = deno_core::_ops::map_async_op1( + ctx, + Self::call( + compile_error!("mutable opstate is not supported in async ops"), + arg_0, + ), + ); let maybe_response = deno_core::_ops::queue_async_op( ctx, scope, false, - async move { - let result = Self::call( - compile_error!("mutable opstate is not supported in async ops"), - arg_0, - ) - .await; - ( - realm_idx, - promise_id, - op_id, - deno_core::_ops::to_op_result(get_class, result), - ) - }, + promise_id, + fut, ); if let Some(response) = maybe_response { rv.set(response);