Skip to content

Commit

Permalink
Create a unique PromiseCapability on each async function call (#2846)
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
jedel1043 committed Apr 21, 2023
1 parent f97ad0d commit 338f6f8
Show file tree
Hide file tree
Showing 2 changed files with 82 additions and 96 deletions.
15 changes: 3 additions & 12 deletions boa_engine/src/builtins/function/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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)]
Expand Down Expand Up @@ -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>,
},
Expand Down Expand Up @@ -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);
Expand Down
163 changes: 79 additions & 84 deletions boa_engine/src/vm/code_block.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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(),
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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);

Expand All @@ -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
Expand Down

0 comments on commit 338f6f8

Please sign in to comment.