Browse Source

Create a unique `PromiseCapability` on each async function call (#2846)

This Pull Request changes the following:

- Creates a new `PromiseCapability` after every async function call instead of sharing the same capability for all calls of the same async function.
pull/2858/head
José Julián Espina 2 years ago
parent
commit
338f6f8176
  1. 15
      boa_engine/src/builtins/function/mod.rs
  2. 163
      boa_engine/src/vm/code_block.rs

15
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<JsObject>,
/// The promise capability record of the async function.
promise_capability: PromiseCapability,
/// The class object that this function is associated with.
class_object: Option<JsObject>,
},
@ -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);

163
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

Loading…
Cancel
Save