Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement [[HostDefined]] field on Realms #2952

Merged
merged 1 commit into from
Sep 27, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 12 additions & 10 deletions boa_cli/src/debug/limits.rs
Original file line number Diff line number Diff line change
Expand Up @@ -32,22 +32,24 @@ fn set_recursion(_: &JsValue, args: &[JsValue], context: &mut Context<'_>) -> Js
}

pub(super) fn create_object(context: &mut Context<'_>) -> JsObject {
let get_loop = FunctionObjectBuilder::new(context, NativeFunction::from_fn_ptr(get_loop))
.name("get loop")
.length(0)
.build();
let set_loop = FunctionObjectBuilder::new(context, NativeFunction::from_fn_ptr(set_loop))
.name("set loop")
.length(1)
.build();
let get_loop =
FunctionObjectBuilder::new(context.realm(), NativeFunction::from_fn_ptr(get_loop))
.name("get loop")
.length(0)
.build();
let set_loop =
FunctionObjectBuilder::new(context.realm(), NativeFunction::from_fn_ptr(set_loop))
.name("set loop")
.length(1)
.build();

let get_recursion =
FunctionObjectBuilder::new(context, NativeFunction::from_fn_ptr(get_recursion))
FunctionObjectBuilder::new(context.realm(), NativeFunction::from_fn_ptr(get_recursion))
.name("get recursion")
.length(0)
.build();
let set_recursion =
FunctionObjectBuilder::new(context, NativeFunction::from_fn_ptr(set_recursion))
FunctionObjectBuilder::new(context.realm(), NativeFunction::from_fn_ptr(set_recursion))
.name("set recursion")
.length(1)
.build();
Expand Down
28 changes: 16 additions & 12 deletions boa_cli/src/debug/optimizer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -44,24 +44,28 @@ fn set_statistics(_: &JsValue, args: &[JsValue], context: &mut Context<'_>) -> J
}

pub(super) fn create_object(context: &mut Context<'_>) -> JsObject {
let get_constant_folding =
FunctionObjectBuilder::new(context, NativeFunction::from_fn_ptr(get_constant_folding))
.name("get constantFolding")
.length(0)
.build();
let set_constant_folding =
FunctionObjectBuilder::new(context, NativeFunction::from_fn_ptr(set_constant_folding))
.name("set constantFolding")
.length(1)
.build();
let get_constant_folding = FunctionObjectBuilder::new(
context.realm(),
NativeFunction::from_fn_ptr(get_constant_folding),
)
.name("get constantFolding")
HalidOdat marked this conversation as resolved.
Show resolved Hide resolved
.length(0)
.build();
let set_constant_folding = FunctionObjectBuilder::new(
context.realm(),
NativeFunction::from_fn_ptr(set_constant_folding),
)
.name("set constantFolding")
.length(1)
.build();

let get_statistics =
FunctionObjectBuilder::new(context, NativeFunction::from_fn_ptr(get_statistics))
FunctionObjectBuilder::new(context.realm(), NativeFunction::from_fn_ptr(get_statistics))
.name("get statistics")
.length(0)
.build();
let set_statistics =
FunctionObjectBuilder::new(context, NativeFunction::from_fn_ptr(set_statistics))
FunctionObjectBuilder::new(context.realm(), NativeFunction::from_fn_ptr(set_statistics))
.name("set statistics")
.length(1)
.build();
Expand Down
4 changes: 2 additions & 2 deletions boa_engine/src/builtins/async_generator/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -550,7 +550,7 @@ impl AsyncGenerator {
// 7. Let fulfilledClosure be a new Abstract Closure with parameters (value) that captures generator and performs the following steps when called:
// 8. Let onFulfilled be CreateBuiltinFunction(fulfilledClosure, 1, "", « »).
let on_fulfilled = FunctionObjectBuilder::new(
context,
context.realm(),
NativeFunction::from_copy_closure_with_captures(
|_this, args, generator, context| {
let next = {
Expand Down Expand Up @@ -588,7 +588,7 @@ impl AsyncGenerator {
// 9. Let rejectedClosure be a new Abstract Closure with parameters (reason) that captures generator and performs the following steps when called:
// 10. Let onRejected be CreateBuiltinFunction(rejectedClosure, 1, "", « »).
let on_rejected = FunctionObjectBuilder::new(
context,
context.realm(),
NativeFunction::from_copy_closure_with_captures(
|_this, args, generator, context| {
let mut generator_borrow_mut = generator.borrow_mut();
Expand Down
2 changes: 1 addition & 1 deletion boa_engine/src/builtins/function/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -145,7 +145,7 @@ fn closure_capture_clone() {
.unwrap();

let func = FunctionObjectBuilder::new(
ctx,
ctx.realm(),
NativeFunction::from_copy_closure_with_captures(
|_, _, captures, context| {
let (string, object) = &captures;
Expand Down
2 changes: 1 addition & 1 deletion boa_engine/src/builtins/intl/collator/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -441,7 +441,7 @@ impl Collator {
f
} else {
let bound_compare = FunctionObjectBuilder::new(
context,
context.realm(),
// 10.3.3.1. Collator Compare Functions
// https://tc39.es/ecma402/#sec-collator-compare-functions
NativeFunction::from_copy_closure_with_captures(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -319,7 +319,7 @@ impl AsyncFromSyncIterator {
// that captures done and performs the following steps when called:
// 9. Let onFulfilled be CreateBuiltinFunction(unwrap, 1, "", « »).
let on_fulfilled = FunctionObjectBuilder::new(
context,
context.realm(),
NativeFunction::from_copy_closure(move |_this, args, context| {
// a. Return CreateIterResultObject(value, done).
Ok(create_iter_result_object(
Expand Down
2 changes: 1 addition & 1 deletion boa_engine/src/builtins/object/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1281,7 +1281,7 @@ impl Object {
// 4. Let closure be a new Abstract Closure with parameters (key, value) that captures
// obj and performs the following steps when called:
let closure = FunctionObjectBuilder::new(
context,
context.realm(),
NativeFunction::from_copy_closure_with_captures(
|_, args, obj, context| {
let key = args.get_or_undefined(0);
Expand Down
22 changes: 11 additions & 11 deletions boa_engine/src/builtins/promise/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -229,7 +229,7 @@ impl PromiseCapability {
// 4. Let executorClosure be a new Abstract Closure with parameters (resolve, reject) that captures promiseCapability and performs the following steps when called:
// 5. Let executor be CreateBuiltinFunction(executorClosure, 2, "", « »).
let executor = FunctionObjectBuilder::new(
context,
context.realm(),
NativeFunction::from_copy_closure_with_captures(
|_this, args: &[JsValue], captures, _| {
let mut promise_capability = captures.borrow_mut();
Expand Down Expand Up @@ -595,7 +595,7 @@ impl Promise {
// p. Set onFulfilled.[[Capability]] to resultCapability.
// q. Set onFulfilled.[[RemainingElements]] to remainingElementsCount.
let on_fulfilled = FunctionObjectBuilder::new(
context,
context.realm(),
NativeFunction::from_copy_closure_with_captures(
|_, args, captures, context| {
// https://tc39.es/ecma262/#sec-promise.all-resolve-element-functions
Expand Down Expand Up @@ -820,7 +820,7 @@ impl Promise {
// q. Set onFulfilled.[[Capability]] to resultCapability.
// r. Set onFulfilled.[[RemainingElements]] to remainingElementsCount.
let on_fulfilled = FunctionObjectBuilder::new(
context,
context.realm(),
NativeFunction::from_copy_closure_with_captures(
|_, args, captures, context| {
// https://tc39.es/ecma262/#sec-promise.allsettled-resolve-element-functions
Expand Down Expand Up @@ -906,7 +906,7 @@ impl Promise {
// y. Set onRejected.[[Capability]] to resultCapability.
// z. Set onRejected.[[RemainingElements]] to remainingElementsCount.
let on_rejected = FunctionObjectBuilder::new(
context,
context.realm(),
NativeFunction::from_copy_closure_with_captures(
|_, args, captures, context| {
// https://tc39.es/ecma262/#sec-promise.allsettled-reject-element-functions
Expand Down Expand Up @@ -1149,7 +1149,7 @@ impl Promise {
// p. Set onRejected.[[Capability]] to resultCapability.
// q. Set onRejected.[[RemainingElements]] to remainingElementsCount.
let on_rejected = FunctionObjectBuilder::new(
context,
context.realm(),
NativeFunction::from_copy_closure_with_captures(
|_, args, captures, context| {
// https://tc39.es/ecma262/#sec-promise.any-reject-element-functions
Expand Down Expand Up @@ -1567,7 +1567,7 @@ impl Promise {

// a. Let thenFinallyClosure be a new Abstract Closure with parameters (value) that captures onFinally and C and performs the following steps when called:
let then_finally_closure = FunctionObjectBuilder::new(
context,
context.realm(),
NativeFunction::from_copy_closure_with_captures(
|_this, args, captures, context| {
/// Capture object for the abstract `returnValue` closure.
Expand All @@ -1588,7 +1588,7 @@ impl Promise {

// iii. Let returnValue be a new Abstract Closure with no parameters that captures value and performs the following steps when called:
let return_value = FunctionObjectBuilder::new(
context,
context.realm(),
NativeFunction::from_copy_closure_with_captures(
|_this, _args, captures, _context| {
// 1. Return value.
Expand Down Expand Up @@ -1618,7 +1618,7 @@ impl Promise {

// c. Let catchFinallyClosure be a new Abstract Closure with parameters (reason) that captures onFinally and C and performs the following steps when called:
let catch_finally_closure = FunctionObjectBuilder::new(
context,
context.realm(),
NativeFunction::from_copy_closure_with_captures(
|_this, args, captures, context| {
/// Capture object for the abstract `throwReason` closure.
Expand All @@ -1639,7 +1639,7 @@ impl Promise {

// iii. Let throwReason be a new Abstract Closure with no parameters that captures reason and performs the following steps when called:
let throw_reason = FunctionObjectBuilder::new(
context,
context.realm(),
NativeFunction::from_copy_closure_with_captures(
|_this, _args, captures, _context| {
// 1. Return ThrowCompletion(reason).
Expand Down Expand Up @@ -2020,7 +2020,7 @@ impl Promise {
// 3. Let lengthResolve be the number of non-optional parameters of the function definition in Promise Resolve Functions.
// 4. Let resolve be CreateBuiltinFunction(stepsResolve, lengthResolve, "", « [[Promise]], [[AlreadyResolved]] »).
let resolve = FunctionObjectBuilder::new(
context,
context.realm(),
NativeFunction::from_copy_closure_with_captures(
|_this, args, captures, context| {
// https://tc39.es/ecma262/#sec-promise-resolve-functions
Expand Down Expand Up @@ -2119,7 +2119,7 @@ impl Promise {
// 8. Let lengthReject be the number of non-optional parameters of the function definition in Promise Reject Functions.
// 9. Let reject be CreateBuiltinFunction(stepsReject, lengthReject, "", « [[Promise]], [[AlreadyResolved]] »).
let reject = FunctionObjectBuilder::new(
context,
context.realm(),
NativeFunction::from_copy_closure_with_captures(
|_this, args, captures, context| {
// https://tc39.es/ecma262/#sec-promise-reject-functions
Expand Down
2 changes: 1 addition & 1 deletion boa_engine/src/builtins/proxy/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -143,7 +143,7 @@ impl Proxy {
// 3. Let revoker be ! CreateBuiltinFunction(revokerClosure, 0, "", « [[RevocableProxy]] »).
// 4. Set revoker.[[RevocableProxy]] to p.
FunctionObjectBuilder::new(
context,
context.realm(),
NativeFunction::from_copy_closure_with_captures(
|_, _, revocable_proxy, _| {
// a. Let F be the active function object.
Expand Down
4 changes: 2 additions & 2 deletions boa_engine/src/context/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -256,7 +256,7 @@ impl<'host> Context<'host> {
length: usize,
body: NativeFunction,
) -> JsResult<()> {
let function = FunctionObjectBuilder::new(self, body)
let function = FunctionObjectBuilder::new(&self.realm, body)
.name(name)
.length(length)
.constructor(true)
Expand Down Expand Up @@ -289,7 +289,7 @@ impl<'host> Context<'host> {
length: usize,
body: NativeFunction,
) -> JsResult<()> {
let function = FunctionObjectBuilder::new(self, body)
let function = FunctionObjectBuilder::new(&self.realm, body)
.name(name)
.length(length)
.constructor(false)
Expand Down
127 changes: 127 additions & 0 deletions boa_engine/src/host_defined.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,127 @@
use std::any::TypeId;

use boa_gc::{GcRef, GcRefCell, GcRefMut};
use boa_macros::{Finalize, Trace};
use rustc_hash::FxHashMap;

use crate::object::NativeObject;

/// Map used to store the host defined objects.
#[doc(hidden)]
type HostDefinedMap = FxHashMap<TypeId, Box<dyn NativeObject>>;

/// This represents a `ECMASCript` specification \[`HostDefined`\] field.
///
/// This allows storing types which are mapped by their [`TypeId`].
#[derive(Default, Trace, Finalize)]
#[allow(missing_debug_implementations)]
pub struct HostDefined {
state: GcRefCell<HostDefinedMap>,
}

impl HostDefined {
/// Insert a type into the [`HostDefined`].
///
/// # Panics
///
/// Panics if [`HostDefined`] field is borrowed.
#[track_caller]
pub fn insert_default<T: NativeObject + Default>(&self) -> Option<Box<dyn NativeObject>> {
self.state
.borrow_mut()
.insert(TypeId::of::<T>(), Box::<T>::default())
}

/// Insert a type into the [`HostDefined`].
///
/// # Panics
///
/// Panics if [`HostDefined`] field is borrowed.
#[track_caller]
pub fn insert<T: NativeObject>(&self, value: T) -> Option<Box<dyn NativeObject>> {
self.state
.borrow_mut()
.insert(TypeId::of::<T>(), Box::new(value))
}

/// Check if the [`HostDefined`] has type T.
///
/// # Panics
///
/// Panics if [`HostDefined`] field is borrowed mutably.
#[track_caller]
pub fn has<T: NativeObject>(&self) -> bool {
self.state.borrow().contains_key(&TypeId::of::<T>())
}

/// Remove type T from [`HostDefined`], if it exists.
///
/// Returns [`Some`] with the object if it exits, [`None`] otherwise.
///
/// # Panics
///
/// Panics if [`HostDefined`] field is borrowed.
#[track_caller]
pub fn remove<T: NativeObject>(&self) -> Option<Box<dyn NativeObject>> {
self.state.borrow_mut().remove(&TypeId::of::<T>())
}

/// Get type T from [`HostDefined`], if it exits.
///
/// # Panics
///
/// Panics if [`HostDefined`] field is borrowed.
#[track_caller]
pub fn get<T: NativeObject>(&self) -> Option<GcRef<'_, T>> {
let state = self.state.borrow();

state
.get(&TypeId::of::<T>())
.map(Box::as_ref)
.and_then(<dyn NativeObject>::downcast_ref::<T>)?;

Some(GcRef::map(state, |state| {
state
.get(&TypeId::of::<T>())
.map(Box::as_ref)
.and_then(<dyn NativeObject>::downcast_ref::<T>)
.expect("Should not fail")
}))
}

/// Get type T from [`HostDefined`], if it exits.
///
/// # Panics
///
/// Panics if [`HostDefined`] field is borrowed.
#[track_caller]
pub fn get_mut<T: NativeObject>(&self) -> Option<GcRefMut<'_, HostDefinedMap, T>> {
let mut state = self.state.borrow_mut();

state
.get_mut(&TypeId::of::<T>())
.map(Box::as_mut)
.and_then(<dyn NativeObject>::downcast_mut::<T>)?;

Some(GcRefMut::map(
state,
|state: &mut FxHashMap<TypeId, Box<dyn NativeObject>>| {
state
.get_mut(&TypeId::of::<T>())
.map(Box::as_mut)
.and_then(<dyn NativeObject>::downcast_mut::<T>)
.expect("Should not fail")
},
))
}

/// Clears all the objects.
///
/// # Panics
///
/// Panics if [`HostDefined`] field is borrowed.
#[track_caller]
pub fn clear(&self) {
self.state.borrow_mut().clear();
}
}
Loading