From f4a2b747ecc2d5ad98f01987baa94cabbc99aa4b Mon Sep 17 00:00:00 2001 From: jedel1043 Date: Wed, 19 Apr 2023 12:57:58 -0600 Subject: [PATCH] Create a unique `PromiseCapability` on each async function call --- boa_engine/src/builtins/function/mod.rs | 15 +-- boa_engine/src/vm/code_block.rs | 163 ++++++++++++------------ 2 files changed, 82 insertions(+), 96 deletions(-) diff --git a/boa_engine/src/builtins/function/mod.rs b/boa_engine/src/builtins/function/mod.rs index 9c249e458bc..ef0eae5360b 100644 --- a/boa_engine/src/builtins/function/mod.rs +++ b/boa_engine/src/builtins/function/mod.rs @@ -42,7 +42,7 @@ use thin_vec::ThinVec; use std::{fmt, io::Read}; -use super::{promise::PromiseCapability, BuiltInBuilder, BuiltInConstructor, IntrinsicObject}; +use super::{BuiltInBuilder, BuiltInConstructor, IntrinsicObject}; pub(crate) mod arguments; #[cfg(test)] @@ -189,9 +189,6 @@ pub(crate) enum FunctionKind { /// The `[[HomeObject]]` internal slot. home_object: Option, - /// The promise capability record of the async function. - promise_capability: PromiseCapability, - /// The class object that this function is associated with. class_object: Option, }, @@ -270,14 +267,8 @@ unsafe impl Trace for FunctionKind { } mark(class_object); } - Self::Async { code, environments, home_object, promise_capability, class_object } => { - mark(code); - mark(environments); - mark(home_object); - mark(promise_capability); - mark(class_object); - } - Self::Generator { code, environments, home_object, class_object} + Self::Async { code, environments, home_object, class_object } + | Self::Generator { code, environments, home_object, class_object} | Self::AsyncGenerator { code, environments, home_object, class_object} => { mark(code); mark(environments); diff --git a/boa_engine/src/vm/code_block.rs b/boa_engine/src/vm/code_block.rs index 076edb71a83..6c4b73112b2 100644 --- a/boa_engine/src/vm/code_block.rs +++ b/boa_engine/src/vm/code_block.rs @@ -608,18 +608,11 @@ pub(crate) fn create_function_object( .build(); let function = if r#async { - let promise_capability = PromiseCapability::new( - &context.intrinsics().constructors().promise().constructor(), - context, - ) - .expect("cannot fail per spec"); - Function::new( FunctionKind::Async { code, environments: context.vm.environments.clone(), home_object: None, - promise_capability, class_object: None, }, context.realm().clone(), @@ -835,90 +828,92 @@ impl JsObject { let context = &mut ContextCleanupGuard::new(context, realm, active_function); - let (code, mut environments, class_object, promise_cap, async_, gen) = - match function_object.kind() { - FunctionKind::Native { - function, - constructor, - } => { - let function = function.clone(); - let constructor = *constructor; - drop(object); - - return if constructor.is_some() { - function.call(&JsValue::undefined(), args, context) - } else { - function.call(this, args, context) - } - .map_err(|err| err.inject_realm(context.realm().clone())); + let (code, mut environments, class_object, async_, gen) = match function_object.kind() { + FunctionKind::Native { + function, + constructor, + } => { + let function = function.clone(); + let constructor = *constructor; + drop(object); + + return if constructor.is_some() { + function.call(&JsValue::undefined(), args, context) + } else { + function.call(this, args, context) } - FunctionKind::Ordinary { - code, - environments, - class_object, - .. - } => { - let code = code.clone(); - if code.is_class_constructor { - return Err(JsNativeError::typ() - .with_message("class constructor cannot be invoked without 'new'") - .with_realm(context.realm().clone()) - .into()); - } - ( - code, - environments.clone(), - class_object.clone(), - None, - false, - false, - ) + .map_err(|err| err.inject_realm(context.realm().clone())); + } + FunctionKind::Ordinary { + code, + environments, + class_object, + .. + } => { + let code = code.clone(); + if code.is_class_constructor { + return Err(JsNativeError::typ() + .with_message("class constructor cannot be invoked without 'new'") + .with_realm(context.realm().clone()) + .into()); } - - FunctionKind::Async { + ( code, - environments, - promise_capability, - class_object, - .. - } => ( - code.clone(), environments.clone(), class_object.clone(), - Some(promise_capability.clone()), - true, false, - ), - FunctionKind::Generator { - code, - environments, - class_object, - .. - } => ( - code.clone(), - environments.clone(), - class_object.clone(), - None, false, - true, - ), - FunctionKind::AsyncGenerator { - code, - environments, - class_object, - .. - } => ( - code.clone(), - environments.clone(), - class_object.clone(), - None, - true, - true, - ), - }; + ) + } + + FunctionKind::Async { + code, + environments, + class_object, + .. + } => ( + code.clone(), + environments.clone(), + class_object.clone(), + true, + false, + ), + FunctionKind::Generator { + code, + environments, + class_object, + .. + } => ( + code.clone(), + environments.clone(), + class_object.clone(), + false, + true, + ), + FunctionKind::AsyncGenerator { + code, + environments, + class_object, + .. + } => ( + code.clone(), + environments.clone(), + class_object.clone(), + true, + true, + ), + }; drop(object); + let promise_capability = (async_ && !gen).then(|| { + PromiseCapability::new( + &context.intrinsics().constructors().promise().constructor(), + context, + ) + .expect("cannot fail per spec") + }); + std::mem::swap(&mut environments, &mut context.vm.environments); let lexical_this_mode = code.this_mode == ThisMode::Lexical; @@ -1023,7 +1018,7 @@ impl JsObject { let mut frame = CallFrame::new(code) .with_param_count(param_count) .with_arg_count(arg_count); - frame.promise_capability = promise_cap.clone(); + frame.promise_capability = promise_capability.clone(); context.vm.push_frame(frame); @@ -1036,8 +1031,8 @@ impl JsObject { std::mem::swap(&mut environments, &mut context.vm.environments); std::mem::swap(&mut context.vm.stack, &mut stack); - if let Some(promise_cap) = promise_cap { - Ok(promise_cap.promise().clone().into()) + if let Some(promise_capability) = promise_capability { + Ok(promise_capability.promise().clone().into()) } else if gen { result?; let proto = this_function_object