diff --git a/nova_vm/src/ecmascript/builtins/bound_function.rs b/nova_vm/src/ecmascript/builtins/bound_function.rs index 5801f5a5a..8dbe14a49 100644 --- a/nova_vm/src/ecmascript/builtins/bound_function.rs +++ b/nova_vm/src/ecmascript/builtins/bound_function.rs @@ -11,17 +11,12 @@ use crate::{ testing_and_comparison::is_constructor, }, execution::{ - Agent, JsResult, ProtoIntrinsics, + Agent, JsResult, agent::{TryResult, unwrap_try}, }, types::{ BoundFunctionHeapData, Function, FunctionInternalProperties, InternalMethods, - InternalSlots, IntoFunction, IntoValue, Object, OrdinaryObject, PropertyDescriptor, - PropertyKey, SetResult, String, TryGetResult, TryHasResult, Value, - function_create_backing_object, function_internal_define_own_property, - function_internal_delete, function_internal_get, function_internal_get_own_property, - function_internal_has_property, function_internal_own_property_keys, - function_internal_set, function_try_get, function_try_has_property, function_try_set, + IntoFunction, IntoValue, Object, OrdinaryObject, String, Value, }, }, engine::{ @@ -34,7 +29,7 @@ use crate::{ }, }; -use super::{ArgumentsList, ordinary::caches::PropertyLookupCache}; +use super::ArgumentsList; #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] #[repr(transparent)] @@ -154,17 +149,17 @@ impl<'a> FunctionInternalProperties<'a> for BoundFunction<'a> { fn get_length(self, agent: &Agent) -> u8 { agent[self].length } -} - -impl<'a> InternalSlots<'a> for BoundFunction<'a> { - const DEFAULT_PROTOTYPE: ProtoIntrinsics = ProtoIntrinsics::Function; #[inline(always)] - fn get_backing_object(self, agent: &Agent) -> Option> { + fn get_function_backing_object(self, agent: &Agent) -> Option> { agent[self].object_index.unbind() } - fn set_backing_object(self, agent: &mut Agent, backing_object: OrdinaryObject<'static>) { + fn set_function_backing_object( + self, + agent: &mut Agent, + backing_object: OrdinaryObject<'static>, + ) { assert!( agent[self] .object_index @@ -173,126 +168,6 @@ impl<'a> InternalSlots<'a> for BoundFunction<'a> { ); } - fn create_backing_object(self, agent: &mut Agent) -> OrdinaryObject<'static> { - function_create_backing_object(self, agent) - } -} - -impl<'a> InternalMethods<'a> for BoundFunction<'a> { - fn try_get_own_property<'gc>( - self, - agent: &mut Agent, - property_key: PropertyKey, - cache: Option, - gc: NoGcScope<'gc, '_>, - ) -> TryResult<'gc, Option>> { - TryResult::Continue(function_internal_get_own_property( - self, - agent, - property_key, - cache, - gc, - )) - } - - fn try_define_own_property<'gc>( - self, - agent: &mut Agent, - property_key: PropertyKey, - property_descriptor: PropertyDescriptor, - cache: Option, - gc: NoGcScope<'gc, '_>, - ) -> TryResult<'gc, bool> { - function_internal_define_own_property( - self, - agent, - property_key, - property_descriptor, - cache, - gc, - ) - } - - fn try_has_property<'gc>( - self, - agent: &mut Agent, - property_key: PropertyKey, - cache: Option, - gc: NoGcScope<'gc, '_>, - ) -> TryResult<'gc, TryHasResult<'gc>> { - function_try_has_property(self, agent, property_key, cache, gc) - } - - fn internal_has_property<'gc>( - self, - agent: &mut Agent, - property_key: PropertyKey, - gc: GcScope<'gc, '_>, - ) -> JsResult<'gc, bool> { - function_internal_has_property(self, agent, property_key, gc) - } - - fn try_get<'gc>( - self, - agent: &mut Agent, - property_key: PropertyKey, - receiver: Value, - cache: Option, - gc: NoGcScope<'gc, '_>, - ) -> TryResult<'gc, TryGetResult<'gc>> { - function_try_get(self, agent, property_key, receiver, cache, gc) - } - - fn internal_get<'gc>( - self, - agent: &mut Agent, - property_key: PropertyKey, - receiver: Value, - gc: GcScope<'gc, '_>, - ) -> JsResult<'gc, Value<'gc>> { - function_internal_get(self, agent, property_key, receiver, gc) - } - - fn try_set<'gc>( - self, - agent: &mut Agent, - property_key: PropertyKey, - value: Value, - receiver: Value, - cache: Option, - gc: NoGcScope<'gc, '_>, - ) -> TryResult<'gc, SetResult<'gc>> { - function_try_set(self, agent, property_key, value, receiver, cache, gc) - } - - fn internal_set<'gc>( - self, - agent: &mut Agent, - property_key: PropertyKey, - value: Value, - receiver: Value, - gc: GcScope<'gc, '_>, - ) -> JsResult<'gc, bool> { - function_internal_set(self, agent, property_key, value, receiver, gc) - } - - fn try_delete<'gc>( - self, - agent: &mut Agent, - property_key: PropertyKey, - gc: NoGcScope<'gc, '_>, - ) -> TryResult<'gc, bool> { - TryResult::Continue(function_internal_delete(self, agent, property_key, gc)) - } - - fn try_own_property_keys<'gc>( - self, - agent: &mut Agent, - gc: NoGcScope<'gc, '_>, - ) -> TryResult<'gc, Vec>> { - TryResult::Continue(function_internal_own_property_keys(self, agent, gc)) - } - /// ### [10.4.1.1 \[\[Call\]\] ( thisArgument, argumentsList )](https://tc39.es/ecma262/#sec-bound-function-exotic-objects-call-thisargument-argumentslist) /// /// The \[\[Call]] internal method of a bound function exotic object F @@ -300,7 +175,7 @@ impl<'a> InternalMethods<'a> for BoundFunction<'a> { /// argumentsList (a List of ECMAScript language values) and returns either /// a normal completion containing an ECMAScript language value or a throw /// completion. - fn internal_call<'gc>( + fn function_call<'gc>( self, agent: &mut Agent, _: Value, @@ -350,7 +225,7 @@ impl<'a> InternalMethods<'a> for BoundFunction<'a> { /// takes arguments argumentsList (a List of ECMAScript language values) /// and newTarget (a constructor) and returns either a normal completion /// containing an Object or a throw completion. - fn internal_construct<'gc>( + fn function_construct<'gc>( self, agent: &mut Agent, arguments_list: ArgumentsList, diff --git a/nova_vm/src/ecmascript/builtins/builtin_constructor.rs b/nova_vm/src/ecmascript/builtins/builtin_constructor.rs index 6fa30f871..9dcd7bc8f 100644 --- a/nova_vm/src/ecmascript/builtins/builtin_constructor.rs +++ b/nova_vm/src/ecmascript/builtins/builtin_constructor.rs @@ -9,8 +9,8 @@ use oxc_span::Span; use crate::{ ecmascript::{ execution::{ - Agent, Environment, ExecutionContext, JsResult, PrivateEnvironment, ProtoIntrinsics, - agent::{ExceptionType, TryResult}, + Agent, Environment, ExecutionContext, JsResult, PrivateEnvironment, + agent::ExceptionType, }, scripts_and_modules::source_code::SourceCode, syntax_directed_operations::class_definitions::{ @@ -18,13 +18,8 @@ use crate::{ }, types::{ BUILTIN_STRING_MEMORY, BuiltinConstructorHeapData, Function, - FunctionInternalProperties, InternalMethods, InternalSlots, IntoFunction, IntoObject, - IntoValue, Object, OrdinaryObject, PropertyDescriptor, PropertyKey, SetResult, String, - TryGetResult, TryHasResult, Value, function_create_backing_object, - function_internal_define_own_property, function_internal_delete, function_internal_get, - function_internal_get_own_property, function_internal_has_property, - function_internal_own_property_keys, function_internal_set, function_try_get, - function_try_has_property, function_try_set, + FunctionInternalProperties, IntoFunction, IntoObject, IntoValue, Object, + OrdinaryObject, PropertyKey, String, Value, }, }, engine::{ @@ -38,7 +33,7 @@ use crate::{ }, }; -use super::{ArgumentsList, ordinary::caches::PropertyLookupCache}; +use super::ArgumentsList; #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)] pub struct BuiltinConstructorFunction<'a>(pub(crate) BuiltinConstructorIndex<'a>); @@ -171,138 +166,18 @@ impl<'a> FunctionInternalProperties<'a> for BuiltinConstructorFunction<'a> { fn get_length(self, _: &Agent) -> u8 { unreachable!(); } -} - -impl<'a> InternalSlots<'a> for BuiltinConstructorFunction<'a> { - const DEFAULT_PROTOTYPE: ProtoIntrinsics = ProtoIntrinsics::Function; #[inline(always)] - fn get_backing_object(self, agent: &Agent) -> Option> { + fn get_function_backing_object(self, agent: &Agent) -> Option> { agent[self].object_index } - fn set_backing_object(self, agent: &mut Agent, backing_object: OrdinaryObject<'static>) { - assert!(agent[self].object_index.replace(backing_object).is_none()); - } - - fn create_backing_object(self, agent: &mut Agent) -> OrdinaryObject<'static> { - function_create_backing_object(self, agent) - } -} - -impl<'a> InternalMethods<'a> for BuiltinConstructorFunction<'a> { - fn try_get_own_property<'gc>( - self, - agent: &mut Agent, - property_key: PropertyKey, - cache: Option, - gc: NoGcScope<'gc, '_>, - ) -> TryResult<'gc, Option>> { - TryResult::Continue(function_internal_get_own_property( - self, - agent, - property_key, - cache, - gc, - )) - } - - fn try_define_own_property<'gc>( - self, - agent: &mut Agent, - property_key: PropertyKey, - property_descriptor: PropertyDescriptor, - cache: Option, - gc: NoGcScope<'gc, '_>, - ) -> TryResult<'gc, bool> { - function_internal_define_own_property( - self, - agent, - property_key, - property_descriptor, - cache, - gc, - ) - } - - fn try_has_property<'gc>( + fn set_function_backing_object( self, agent: &mut Agent, - property_key: PropertyKey, - cache: Option, - gc: NoGcScope<'gc, '_>, - ) -> TryResult<'gc, TryHasResult<'gc>> { - function_try_has_property(self, agent, property_key, cache, gc) - } - - fn internal_has_property<'gc>( - self, - agent: &mut Agent, - property_key: PropertyKey, - gc: GcScope<'gc, '_>, - ) -> JsResult<'gc, bool> { - function_internal_has_property(self, agent, property_key, gc) - } - - fn try_get<'gc>( - self, - agent: &mut Agent, - property_key: PropertyKey, - receiver: Value, - cache: Option, - gc: NoGcScope<'gc, '_>, - ) -> TryResult<'gc, TryGetResult<'gc>> { - function_try_get(self, agent, property_key, receiver, cache, gc) - } - - fn internal_get<'gc>( - self, - agent: &mut Agent, - property_key: PropertyKey, - receiver: Value, - gc: GcScope<'gc, '_>, - ) -> JsResult<'gc, Value<'gc>> { - function_internal_get(self, agent, property_key, receiver, gc) - } - - fn try_set<'gc>( - self, - agent: &mut Agent, - property_key: PropertyKey, - value: Value, - receiver: Value, - cache: Option, - gc: NoGcScope<'gc, '_>, - ) -> TryResult<'gc, SetResult<'gc>> { - function_try_set(self, agent, property_key, value, receiver, cache, gc) - } - - fn internal_set<'gc>( - self, - agent: &mut Agent, - property_key: PropertyKey, - value: Value, - receiver: Value, - gc: GcScope<'gc, '_>, - ) -> JsResult<'gc, bool> { - function_internal_set(self, agent, property_key, value, receiver, gc) - } - - fn try_delete<'gc>( - self, - agent: &mut Agent, - property_key: PropertyKey, - gc: NoGcScope<'gc, '_>, - ) -> TryResult<'gc, bool> { - TryResult::Continue(function_internal_delete(self, agent, property_key, gc)) - } - - fn try_own_property_keys<'gc>( - self, - agent: &mut Agent, - gc: NoGcScope<'gc, '_>, - ) -> TryResult<'gc, Vec>> { - TryResult::Continue(function_internal_own_property_keys(self, agent, gc)) + backing_object: OrdinaryObject<'static>, + ) { + assert!(agent[self].object_index.replace(backing_object).is_none()); } /// ### [10.3.1 \[\[Call\]\] ( thisArgument, argumentsList )](https://tc39.es/ecma262/#sec-built-in-function-objects-call-thisargument-argumentslist) @@ -312,7 +187,7 @@ impl<'a> InternalMethods<'a> for BuiltinConstructorFunction<'a> { /// (a List of ECMAScript language values) and returns either a normal /// completion containing an ECMAScript language value or a throw /// completion. - fn internal_call<'gc>( + fn function_call<'gc>( self, agent: &mut Agent, _: Value, @@ -334,7 +209,7 @@ impl<'a> InternalMethods<'a> for BuiltinConstructorFunction<'a> { /// the method is present) takes arguments argumentsList (a List of /// ECMAScript language values) and newTarget (a constructor) and returns /// either a normal completion containing an Object or a throw completion. - fn internal_construct<'gc>( + fn function_construct<'gc>( self, agent: &mut Agent, arguments_list: ArgumentsList, diff --git a/nova_vm/src/ecmascript/builtins/builtin_function.rs b/nova_vm/src/ecmascript/builtins/builtin_function.rs index 87cdf4156..e541bebc3 100644 --- a/nova_vm/src/ecmascript/builtins/builtin_function.rs +++ b/nova_vm/src/ecmascript/builtins/builtin_function.rs @@ -10,19 +10,11 @@ use std::{hint::unreachable_unchecked, ptr::NonNull}; use crate::{ ecmascript::{ - execution::{ - Agent, ExecutionContext, JsResult, ProtoIntrinsics, Realm, - agent::{ExceptionType, TryResult}, - }, + execution::{Agent, ExecutionContext, JsResult, Realm, agent::ExceptionType}, types::{ BUILTIN_STRING_MEMORY, BuiltinFunctionHeapData, Function, FunctionInternalProperties, - InternalMethods, InternalSlots, IntoFunction, IntoObject, IntoValue, Object, - OrdinaryObject, PropertyDescriptor, PropertyKey, ScopedValuesIterator, SetResult, - String, TryGetResult, TryHasResult, Value, function_create_backing_object, - function_internal_define_own_property, function_internal_delete, function_internal_get, - function_internal_get_own_property, function_internal_has_property, - function_internal_own_property_keys, function_internal_set, function_try_get, - function_try_has_property, function_try_set, + InternalSlots, IntoFunction, IntoObject, IntoValue, Object, OrdinaryObject, + PropertyKey, ScopedValuesIterator, String, Value, }, }, engine::{ @@ -36,8 +28,6 @@ use crate::{ }, }; -use super::ordinary::caches::PropertyLookupCache; - #[derive(Default)] #[repr(transparent)] pub struct ArgumentsList<'slice, 'value> { @@ -556,17 +546,17 @@ impl<'a> FunctionInternalProperties<'a> for BuiltinFunction<'a> { fn get_length(self, agent: &Agent) -> u8 { agent[self].length } -} - -impl<'a> InternalSlots<'a> for BuiltinFunction<'a> { - const DEFAULT_PROTOTYPE: ProtoIntrinsics = ProtoIntrinsics::Function; #[inline(always)] - fn get_backing_object(self, agent: &Agent) -> Option> { + fn get_function_backing_object(self, agent: &Agent) -> Option> { agent[self].object_index } - fn set_backing_object(self, agent: &mut Agent, backing_object: OrdinaryObject<'static>) { + fn set_function_backing_object( + self, + agent: &mut Agent, + backing_object: OrdinaryObject<'static>, + ) { assert!( agent[self] .object_index @@ -575,126 +565,6 @@ impl<'a> InternalSlots<'a> for BuiltinFunction<'a> { ); } - fn create_backing_object(self, agent: &mut Agent) -> OrdinaryObject<'static> { - function_create_backing_object(self, agent) - } -} - -impl<'a> InternalMethods<'a> for BuiltinFunction<'a> { - fn try_get_own_property<'gc>( - self, - agent: &mut Agent, - property_key: PropertyKey, - cache: Option, - gc: NoGcScope<'gc, '_>, - ) -> TryResult<'gc, Option>> { - TryResult::Continue(function_internal_get_own_property( - self, - agent, - property_key, - cache, - gc, - )) - } - - fn try_define_own_property<'gc>( - self, - agent: &mut Agent, - property_key: PropertyKey, - property_descriptor: PropertyDescriptor, - cache: Option, - gc: NoGcScope<'gc, '_>, - ) -> TryResult<'gc, bool> { - function_internal_define_own_property( - self, - agent, - property_key, - property_descriptor, - cache, - gc, - ) - } - - fn try_has_property<'gc>( - self, - agent: &mut Agent, - property_key: PropertyKey, - cache: Option, - gc: NoGcScope<'gc, '_>, - ) -> TryResult<'gc, TryHasResult<'gc>> { - function_try_has_property(self, agent, property_key, cache, gc) - } - - fn internal_has_property<'gc>( - self, - agent: &mut Agent, - property_key: PropertyKey, - gc: GcScope<'gc, '_>, - ) -> JsResult<'gc, bool> { - function_internal_has_property(self, agent, property_key, gc) - } - - fn try_get<'gc>( - self, - agent: &mut Agent, - property_key: PropertyKey, - receiver: Value, - cache: Option, - gc: NoGcScope<'gc, '_>, - ) -> TryResult<'gc, TryGetResult<'gc>> { - function_try_get(self, agent, property_key, receiver, cache, gc) - } - - fn internal_get<'gc>( - self, - agent: &mut Agent, - property_key: PropertyKey, - receiver: Value, - gc: GcScope<'gc, '_>, - ) -> JsResult<'gc, Value<'gc>> { - function_internal_get(self, agent, property_key, receiver, gc) - } - - fn try_set<'gc>( - self, - agent: &mut Agent, - property_key: PropertyKey, - value: Value, - receiver: Value, - cache: Option, - gc: NoGcScope<'gc, '_>, - ) -> TryResult<'gc, SetResult<'gc>> { - function_try_set(self, agent, property_key, value, receiver, cache, gc) - } - - fn internal_set<'gc>( - self, - agent: &mut Agent, - property_key: PropertyKey, - value: Value, - receiver: Value, - gc: GcScope<'gc, '_>, - ) -> JsResult<'gc, bool> { - function_internal_set(self, agent, property_key, value, receiver, gc) - } - - fn try_delete<'gc>( - self, - agent: &mut Agent, - property_key: PropertyKey, - gc: NoGcScope<'gc, '_>, - ) -> TryResult<'gc, bool> { - TryResult::Continue(function_internal_delete(self, agent, property_key, gc)) - } - - fn try_own_property_keys<'gc>( - self, - agent: &mut Agent, - gc: NoGcScope<'gc, '_>, - ) -> TryResult<'gc, Vec>> { - TryResult::Continue(function_internal_own_property_keys(self, agent, gc)) - } - /// ### [10.3.1 \[\[Call\]\] ( thisArgument, argumentsList )](https://tc39.es/ecma262/#sec-built-in-function-objects-call-thisargument-argumentslist) /// /// The [[Call]] internal method of a built-in function object F takes @@ -702,7 +572,7 @@ impl<'a> InternalMethods<'a> for BuiltinFunction<'a> { /// (a List of ECMAScript language values) and returns either a normal /// completion containing an ECMAScript language value or a throw /// completion. - fn internal_call<'gc>( + fn function_call<'gc>( self, agent: &mut Agent, this_argument: Value, @@ -719,7 +589,7 @@ impl<'a> InternalMethods<'a> for BuiltinFunction<'a> { /// the method is present) takes arguments argumentsList (a List of /// ECMAScript language values) and newTarget (a constructor) and returns /// either a normal completion containing an Object or a throw completion. - fn internal_construct<'gc>( + fn function_construct<'gc>( self, agent: &mut Agent, arguments_list: ArgumentsList, diff --git a/nova_vm/src/ecmascript/builtins/control_abstraction_objects/promise_objects/promise_abstract_operations.rs b/nova_vm/src/ecmascript/builtins/control_abstraction_objects/promise_objects/promise_abstract_operations.rs index 63e5d81e5..23f08d039 100644 --- a/nova_vm/src/ecmascript/builtins/control_abstraction_objects/promise_objects/promise_abstract_operations.rs +++ b/nova_vm/src/ecmascript/builtins/control_abstraction_objects/promise_objects/promise_abstract_operations.rs @@ -3,6 +3,7 @@ // file, You can obtain one at https://mozilla.org/MPL/2.0/. pub mod promise_capability_records; +pub(crate) mod promise_finally_functions; pub(crate) mod promise_jobs; pub(crate) mod promise_reaction_records; pub(crate) mod promise_resolving_functions; diff --git a/nova_vm/src/ecmascript/builtins/control_abstraction_objects/promise_objects/promise_abstract_operations/promise_finally_functions.rs b/nova_vm/src/ecmascript/builtins/control_abstraction_objects/promise_objects/promise_abstract_operations/promise_finally_functions.rs new file mode 100644 index 000000000..389c9fed6 --- /dev/null +++ b/nova_vm/src/ecmascript/builtins/control_abstraction_objects/promise_objects/promise_abstract_operations/promise_finally_functions.rs @@ -0,0 +1,374 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at https://mozilla.org/MPL/2.0/. + +use crate::{ + ecmascript::{ + abstract_operations::operations_on_objects::{call_function, invoke}, + builtins::{ArgumentsList, promise::Promise}, + execution::{Agent, JsResult, agent::JsError}, + types::{ + BUILTIN_STRING_MEMORY, Function, FunctionInternalProperties, IntoValue, Object, + OrdinaryObject, String, Value, + }, + }, + engine::{ + context::{Bindable, GcScope, NoGcScope, bindable_handle}, + rootable::{HeapRootData, HeapRootRef, Rootable, Scopable}, + }, + heap::{ + CompactionLists, CreateHeapData, Heap, HeapMarkAndSweep, HeapSweepWeakReference, + WorkQueues, indexes::BaseIndex, + }, +}; + +#[derive(Debug, Clone, Copy)] +enum PromiseFinallyFunctionType<'a> { + ResolveFinally { + on_finally: Function<'a>, + c: Function<'a>, + }, + RejectFinally { + on_finally: Function<'a>, + c: Function<'a>, + }, + ReturnValue { + value: Value<'a>, + }, + ThrowReason { + reason: JsError<'a>, + }, +} + +/// ### [27.2.1.3.1 Promise Finally Functions](https://tc39.es/ecma262/#sec-promise.prototype.finally) +/// +/// A promise finally function is an abstract closure +/// \[\[Promise\]\] and \[\[AlreadyResolved\]\] internal slots. +/// +/// The "length" property of a promise reject function is 1𝔽. +#[derive(Debug, Clone)] +pub struct PromiseFinallyFunctionHeapData<'a> { + backing_object: Option>, + resolve_type: PromiseFinallyFunctionType<'a>, +} + +pub(crate) type BuiltinPromiseFinallyFunctionIndex<'a> = + BaseIndex<'a, PromiseFinallyFunctionHeapData<'static>>; + +#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)] +pub struct BuiltinPromiseFinallyFunction<'a>(pub(crate) BuiltinPromiseFinallyFunctionIndex<'a>); +bindable_handle!(BuiltinPromiseFinallyFunction); + +impl<'f> BuiltinPromiseFinallyFunction<'f> { + pub(crate) fn create_finally_functions( + agent: &mut Agent, + c: Function<'f>, + on_finally: Function<'f>, + ) -> (Self, Self) { + let then_finally_closure = agent.heap.create(PromiseFinallyFunctionHeapData { + backing_object: None, + resolve_type: PromiseFinallyFunctionType::ResolveFinally { on_finally, c }, + }); + let catch_finally_closure = agent.heap.create(PromiseFinallyFunctionHeapData { + backing_object: None, + resolve_type: PromiseFinallyFunctionType::RejectFinally { on_finally, c }, + }); + (then_finally_closure, catch_finally_closure) + } + + fn get(self, agent: &Agent) -> &PromiseFinallyFunctionHeapData<'f> { + agent + .heap + .promise_finally_functions + .get(self.get_index()) + .expect("Promise.prototype.finally handler not found") + } + + fn get_mut(self, agent: &mut Agent) -> &mut PromiseFinallyFunctionHeapData<'static> { + agent + .heap + .promise_finally_functions + .get_mut(self.get_index()) + .expect("Promise.prototype.finally handler not found") + } + + pub(crate) const fn _def() -> Self { + Self(BaseIndex::from_u32_index(0)) + } + + pub(crate) const fn get_index(self) -> usize { + self.0.into_index() + } +} + +impl<'a> From> for Function<'a> { + fn from(value: BuiltinPromiseFinallyFunction<'a>) -> Self { + Self::BuiltinPromiseFinallyFunction(value) + } +} + +impl<'a> From> for Object<'a> { + fn from(value: BuiltinPromiseFinallyFunction) -> Self { + Self::BuiltinPromiseFinallyFunction(value.unbind()) + } +} + +impl<'a> From> for Value<'a> { + fn from(value: BuiltinPromiseFinallyFunction<'a>) -> Self { + Self::BuiltinPromiseFinallyFunction(value) + } +} + +impl<'a> FunctionInternalProperties<'a> for BuiltinPromiseFinallyFunction<'a> { + fn get_name(self, _: &Agent) -> String<'static> { + String::EMPTY_STRING + } + + fn get_length(self, agent: &Agent) -> u8 { + match self.get(agent).resolve_type { + PromiseFinallyFunctionType::ResolveFinally { .. } + | PromiseFinallyFunctionType::RejectFinally { .. } => 1, + PromiseFinallyFunctionType::ReturnValue { .. } + | PromiseFinallyFunctionType::ThrowReason { .. } => 0, + } + } + + #[inline(always)] + fn get_function_backing_object(self, agent: &Agent) -> Option> { + self.unbind().get(agent).backing_object + } + + fn set_function_backing_object( + self, + agent: &mut Agent, + backing_object: OrdinaryObject<'static>, + ) { + assert!( + self.get_mut(agent) + .backing_object + .replace(backing_object) + .is_none() + ); + } + + fn function_call<'gc>( + self, + agent: &mut Agent, + _this_value: Value, + arguments_list: ArgumentsList, + mut gc: GcScope<'gc, '_>, + ) -> JsResult<'gc, Value<'gc>> { + let f = self.bind(gc.nogc()); + match f.get(agent).resolve_type { + PromiseFinallyFunctionType::ResolveFinally { on_finally, c } => { + let value = arguments_list.get(0).scope(agent, gc.nogc()); + let c = c.scope(agent, gc.nogc()); + // i. Let result be ? Call(onFinally, undefined). + let result = call_function( + agent, + on_finally.unbind(), + Value::Undefined, + None, + gc.reborrow(), + ) + .unbind()? + .bind(gc.nogc()); + // SAFETY: not shared. + let _c = unsafe { c.take(agent) }.bind(gc.nogc()); + // ii. Let p be ? PromiseResolve(C, result). + let p = Promise::resolve(agent, result.unbind(), gc.reborrow()) + .unbind() + .bind(gc.nogc()); + // SAFETY: not shared. + let value = unsafe { value.take(agent) }.bind(gc.nogc()); + // iii. Let returnValue be a new Abstract Closure with no + // parameters that captures value and performs the + // following steps when called: + // iv. Let valueThunk be CreateBuiltinFunction(returnValue, 0, "", « »). + let value_thunk = agent.heap.create(PromiseFinallyFunctionHeapData { + backing_object: None, + // 1. Return NormalCompletion(value). + resolve_type: PromiseFinallyFunctionType::ReturnValue { value }, + }); + + // v. Return ? Invoke(p, "then", « valueThunk »). + invoke( + agent, + p.into_value().unbind(), + BUILTIN_STRING_MEMORY.then.to_property_key(), + Some(ArgumentsList::from_mut_value( + &mut value_thunk.into_value().unbind(), + )), + gc, + ) + } + PromiseFinallyFunctionType::RejectFinally { on_finally, c } => { + let reason = arguments_list.get(0).scope(agent, gc.nogc()); + let c = c.scope(agent, gc.nogc()); + // i. Let result be ? Call(onFinally, undefined). + let result = call_function( + agent, + on_finally.unbind(), + Value::Undefined, + None, + gc.reborrow(), + ) + .unbind()? + .bind(gc.nogc()); + // SAFETY: not shared. + let _c = unsafe { c.take(agent) }.bind(gc.nogc()); + // ii. Let p be ? PromiseResolve(C, result). + let p = Promise::resolve(agent, result.unbind(), gc.reborrow()) + .unbind() + .bind(gc.nogc()); + let reason = unsafe { reason.take(agent) }.bind(gc.nogc()); + // iii. Let throwReason be a new Abstract Closure with no parameters that captures reason and performs the following steps when called: + // iv. Let thrower be CreateBuiltinFunction(throwReason, 0, "", « »). + let thrower = agent.heap.create(PromiseFinallyFunctionHeapData { + backing_object: None, + // 1. Return ThrowCompletion(reason). + resolve_type: PromiseFinallyFunctionType::ThrowReason { + reason: JsError::new(reason), + }, + }); + // v. Return ? Invoke(p, "then", « thrower »). + invoke( + agent, + p.into_value().unbind(), + BUILTIN_STRING_MEMORY.then.to_property_key(), + Some(ArgumentsList::from_mut_value( + &mut thrower.into_value().unbind(), + )), + gc, + ) + } + PromiseFinallyFunctionType::ReturnValue { value } => { + // 1. Return NormalCompletion(value). + Ok(value.unbind().bind(gc.into_nogc())) + } + PromiseFinallyFunctionType::ThrowReason { reason } => { + // 1. Return ThrowCompletion(reason). + Err(reason.unbind().bind(gc.into_nogc())) + } + } + } +} + +impl Rootable for BuiltinPromiseFinallyFunction<'_> { + type RootRepr = HeapRootRef; + + fn to_root_repr(value: Self) -> Result { + Err(HeapRootData::BuiltinPromiseFinallyFunction(value.unbind())) + } + + fn from_root_repr(value: &Self::RootRepr) -> Result { + Err(*value) + } + + fn from_heap_ref(heap_ref: HeapRootRef) -> Self::RootRepr { + heap_ref + } + + fn from_heap_data(heap_data: HeapRootData) -> Option { + match heap_data { + HeapRootData::BuiltinPromiseFinallyFunction(d) => Some(d), + _ => None, + } + } +} + +impl<'a> CreateHeapData, BuiltinPromiseFinallyFunction<'a>> + for Heap +{ + fn create( + &mut self, + data: PromiseFinallyFunctionHeapData<'a>, + ) -> BuiltinPromiseFinallyFunction<'a> { + self.promise_finally_functions.push(data.unbind()); + self.alloc_counter += core::mem::size_of::>(); + + BuiltinPromiseFinallyFunction(BaseIndex::last_t(&self.promise_finally_functions)) + } +} + +impl HeapMarkAndSweep for BuiltinPromiseFinallyFunction<'static> { + fn mark_values(&self, queues: &mut WorkQueues) { + queues.promise_finally_functions.push(*self); + } + + fn sweep_values(&mut self, compactions: &CompactionLists) { + compactions + .promise_finally_functions + .shift_index(&mut self.0); + } +} + +impl HeapSweepWeakReference for BuiltinPromiseFinallyFunction<'static> { + fn sweep_weak_reference(self, compactions: &CompactionLists) -> Option { + compactions + .promise_finally_functions + .shift_weak_index(self.0) + .map(Self) + } +} + +// SAFETY: Property implemented as a lifetime transmute. +unsafe impl Bindable for PromiseFinallyFunctionHeapData<'_> { + type Of<'a> = PromiseFinallyFunctionHeapData<'a>; + + #[inline(always)] + fn unbind(self) -> Self::Of<'static> { + unsafe { core::mem::transmute::>(self) } + } + + #[inline(always)] + fn bind<'a>(self, _gc: NoGcScope<'a, '_>) -> Self::Of<'a> { + unsafe { core::mem::transmute::>(self) } + } +} + +impl HeapMarkAndSweep for PromiseFinallyFunctionHeapData<'static> { + fn mark_values(&self, queues: &mut WorkQueues) { + let Self { + backing_object, + resolve_type, + } = self; + backing_object.mark_values(queues); + resolve_type.mark_values(queues); + } + + fn sweep_values(&mut self, compactions: &CompactionLists) { + let Self { + backing_object, + resolve_type, + } = self; + backing_object.sweep_values(compactions); + resolve_type.sweep_values(compactions); + } +} + +impl HeapMarkAndSweep for PromiseFinallyFunctionType<'static> { + fn mark_values(&self, queues: &mut WorkQueues) { + match self { + PromiseFinallyFunctionType::ResolveFinally { on_finally, c } + | PromiseFinallyFunctionType::RejectFinally { on_finally, c } => { + on_finally.mark_values(queues); + c.mark_values(queues); + } + PromiseFinallyFunctionType::ReturnValue { value } => value.mark_values(queues), + PromiseFinallyFunctionType::ThrowReason { reason } => reason.mark_values(queues), + } + } + + fn sweep_values(&mut self, compactions: &CompactionLists) { + match self { + PromiseFinallyFunctionType::ResolveFinally { on_finally, c } + | PromiseFinallyFunctionType::RejectFinally { on_finally, c } => { + on_finally.sweep_values(compactions); + c.sweep_values(compactions); + } + PromiseFinallyFunctionType::ReturnValue { value } => value.sweep_values(compactions), + PromiseFinallyFunctionType::ThrowReason { reason } => reason.sweep_values(compactions), + } + } +} diff --git a/nova_vm/src/ecmascript/builtins/control_abstraction_objects/promise_objects/promise_abstract_operations/promise_resolving_functions.rs b/nova_vm/src/ecmascript/builtins/control_abstraction_objects/promise_objects/promise_abstract_operations/promise_resolving_functions.rs index b78b11a4f..03d98b937 100644 --- a/nova_vm/src/ecmascript/builtins/control_abstraction_objects/promise_objects/promise_abstract_operations/promise_resolving_functions.rs +++ b/nova_vm/src/ecmascript/builtins/control_abstraction_objects/promise_objects/promise_abstract_operations/promise_resolving_functions.rs @@ -7,19 +7,11 @@ use core::ops::{Index, IndexMut}; use crate::{ ecmascript::{ builtins::{ - ArgumentsList, ordinary::caches::PropertyLookupCache, + ArgumentsList, promise_objects::promise_abstract_operations::promise_capability_records::PromiseCapability, }, - execution::{Agent, JsResult, ProtoIntrinsics, agent::TryResult}, - types::{ - Function, FunctionInternalProperties, InternalMethods, InternalSlots, Object, - OrdinaryObject, PropertyDescriptor, PropertyKey, SetResult, String, TryGetResult, - TryHasResult, Value, function_create_backing_object, - function_internal_define_own_property, function_internal_delete, function_internal_get, - function_internal_get_own_property, function_internal_has_property, - function_internal_own_property_keys, function_internal_set, function_try_get, - function_try_has_property, function_try_set, - }, + execution::{Agent, JsResult}, + types::{Function, FunctionInternalProperties, Object, OrdinaryObject, String, Value}, }, engine::{ context::{Bindable, GcScope, NoGcScope}, @@ -107,141 +99,21 @@ impl<'a> FunctionInternalProperties<'a> for BuiltinPromiseResolvingFunction<'a> fn get_length(self, _: &Agent) -> u8 { 1 } -} - -impl<'a> InternalSlots<'a> for BuiltinPromiseResolvingFunction<'a> { - const DEFAULT_PROTOTYPE: ProtoIntrinsics = ProtoIntrinsics::Function; #[inline(always)] - fn get_backing_object(self, agent: &Agent) -> Option> { + fn get_function_backing_object(self, agent: &Agent) -> Option> { agent[self].object_index } - fn set_backing_object(self, agent: &mut Agent, backing_object: OrdinaryObject<'static>) { - assert!(agent[self].object_index.replace(backing_object).is_none()); - } - - fn create_backing_object(self, agent: &mut Agent) -> OrdinaryObject<'static> { - function_create_backing_object(self, agent) - } -} - -impl<'a> InternalMethods<'a> for BuiltinPromiseResolvingFunction<'a> { - fn try_get_own_property<'gc>( - self, - agent: &mut Agent, - property_key: PropertyKey, - cache: Option, - gc: NoGcScope<'gc, '_>, - ) -> TryResult<'gc, Option>> { - TryResult::Continue(function_internal_get_own_property( - self, - agent, - property_key, - cache, - gc, - )) - } - - fn try_define_own_property<'gc>( - self, - agent: &mut Agent, - property_key: PropertyKey, - property_descriptor: PropertyDescriptor, - cache: Option, - gc: NoGcScope<'gc, '_>, - ) -> TryResult<'gc, bool> { - function_internal_define_own_property( - self, - agent, - property_key, - property_descriptor, - cache, - gc, - ) - } - - fn try_has_property<'gc>( - self, - agent: &mut Agent, - property_key: PropertyKey, - cache: Option, - gc: NoGcScope<'gc, '_>, - ) -> TryResult<'gc, TryHasResult<'gc>> { - function_try_has_property(self, agent, property_key, cache, gc) - } - - fn internal_has_property<'gc>( - self, - agent: &mut Agent, - property_key: PropertyKey, - gc: GcScope<'gc, '_>, - ) -> JsResult<'gc, bool> { - function_internal_has_property(self, agent, property_key, gc) - } - - fn try_get<'gc>( + fn set_function_backing_object( self, agent: &mut Agent, - property_key: PropertyKey, - receiver: Value, - cache: Option, - gc: NoGcScope<'gc, '_>, - ) -> TryResult<'gc, TryGetResult<'gc>> { - function_try_get(self, agent, property_key, receiver, cache, gc) - } - - fn internal_get<'gc>( - self, - agent: &mut Agent, - property_key: PropertyKey, - receiver: Value, - gc: GcScope<'gc, '_>, - ) -> JsResult<'gc, Value<'gc>> { - function_internal_get(self, agent, property_key, receiver, gc) - } - - fn try_set<'gc>( - self, - agent: &mut Agent, - property_key: PropertyKey, - value: Value, - receiver: Value, - cache: Option, - gc: NoGcScope<'gc, '_>, - ) -> TryResult<'gc, SetResult<'gc>> { - function_try_set(self, agent, property_key, value, receiver, cache, gc) - } - - fn internal_set<'gc>( - self, - agent: &mut Agent, - property_key: PropertyKey, - value: Value, - receiver: Value, - gc: GcScope<'gc, '_>, - ) -> JsResult<'gc, bool> { - function_internal_set(self, agent, property_key, value, receiver, gc) - } - - fn try_delete<'gc>( - self, - agent: &mut Agent, - property_key: PropertyKey, - gc: NoGcScope<'gc, '_>, - ) -> TryResult<'gc, bool> { - TryResult::Continue(function_internal_delete(self, agent, property_key, gc)) - } - - fn try_own_property_keys<'gc>( - self, - agent: &mut Agent, - gc: NoGcScope<'gc, '_>, - ) -> TryResult<'gc, Vec>> { - TryResult::Continue(function_internal_own_property_keys(self, agent, gc)) + backing_object: OrdinaryObject<'static>, + ) { + assert!(agent[self].object_index.replace(backing_object).is_none()); } - fn internal_call<'gc>( + fn function_call<'gc>( self, agent: &mut Agent, _this_value: Value, @@ -377,13 +249,23 @@ unsafe impl Bindable for PromiseResolvingFunctionHeapData<'_> { } impl HeapMarkAndSweep for PromiseResolvingFunctionHeapData<'static> { - fn mark_values(&self, queues: &mut crate::heap::WorkQueues) { - self.object_index.mark_values(queues); - self.promise_capability.mark_values(queues); + fn mark_values(&self, queues: &mut WorkQueues) { + let Self { + object_index, + promise_capability, + resolve_type: _, + } = self; + object_index.mark_values(queues); + promise_capability.mark_values(queues); } - fn sweep_values(&mut self, compactions: &crate::heap::CompactionLists) { - self.object_index.sweep_values(compactions); - self.promise_capability.sweep_values(compactions); + fn sweep_values(&mut self, compactions: &CompactionLists) { + let Self { + object_index, + promise_capability, + resolve_type: _, + } = self; + object_index.sweep_values(compactions); + promise_capability.sweep_values(compactions); } } diff --git a/nova_vm/src/ecmascript/builtins/control_abstraction_objects/promise_objects/promise_prototype.rs b/nova_vm/src/ecmascript/builtins/control_abstraction_objects/promise_objects/promise_prototype.rs index 219728619..a1a6e7f7c 100644 --- a/nova_vm/src/ecmascript/builtins/control_abstraction_objects/promise_objects/promise_prototype.rs +++ b/nova_vm/src/ecmascript/builtins/control_abstraction_objects/promise_objects/promise_prototype.rs @@ -4,7 +4,10 @@ use crate::{ ecmascript::{ - abstract_operations::operations_on_objects::invoke, + abstract_operations::{ + operations_on_objects::{invoke, species_constructor}, + testing_and_comparison::{is_callable, is_constructor}, + }, builders::ordinary_object_builder::OrdinaryObjectBuilder, builtins::{ ArgumentsList, Behaviour, Builtin, @@ -12,14 +15,21 @@ use crate::{ Promise, data::{PromiseReactions, PromiseState}, }, + promise_objects::promise_abstract_operations::promise_finally_functions::BuiltinPromiseFinallyFunction, }, execution::{ Agent, JsResult, Realm, agent::{ExceptionType, PromiseRejectionTrackerOperation}, }, - types::{BUILTIN_STRING_MEMORY, Function, IntoValue, String, Value}, + types::{ + BUILTIN_STRING_MEMORY, Function, IntoFunction, IntoObject, IntoValue, Object, String, + Value, + }, + }, + engine::{ + context::{Bindable, GcScope, NoGcScope}, + rootable::Scopable, }, - engine::context::{Bindable, GcScope, NoGcScope}, heap::{CreateHeapData, WellKnownSymbolIndexes}, }; @@ -76,13 +86,76 @@ impl PromisePrototype { ) } + /// ### [27.2.5.3 Promise.prototype.finally ( onFinally )](https://tc39.es/ecma262/#sec-promise.prototype.finally) fn finally<'gc>( agent: &mut Agent, - _this_value: Value, - _: ArgumentsList, - gc: GcScope<'gc, '_>, + this_value: Value, + args: ArgumentsList, + mut gc: GcScope<'gc, '_>, ) -> JsResult<'gc, Value<'gc>> { - Err(agent.todo("Promise.prototype.finally", gc.into_nogc())) + let on_finally = args.get(0).bind(gc.nogc()); + // 1. Let promise be the this value. + let promise = this_value.bind(gc.nogc()); + // 2. If promise is not an Object, throw a TypeError exception. + let Ok(promise) = Object::try_from(promise) else { + return Err(agent.throw_exception_with_static_message( + ExceptionType::TypeError, + "'this' is not an Object", + gc.into_nogc(), + )); + }; + let scoped_promise = promise.scope(agent, gc.nogc()); + let scoped_on_finally = on_finally.scope(agent, gc.nogc()); + + // 3. Let C be ? SpeciesConstructor(promise, %Promise%). + let promise_intrinsic = agent + .current_realm_record() + .intrinsics() + .promise() + .bind(gc.nogc()); + let c = species_constructor( + agent, + promise.into_object().unbind(), + promise_intrinsic.into_function().unbind(), + gc.reborrow(), + ) + .unbind()? + .bind(gc.nogc()); + // 4. Assert: IsConstructor(C) is true. + debug_assert!(is_constructor(agent, c).is_some()); + + // SAFETY: not shared. + let on_finally = unsafe { scoped_on_finally.take(agent).bind(gc.nogc()) }; + // SAFETY: not shared. + let promise = unsafe { scoped_promise.take(agent).bind(gc.nogc()) }; + + // 5. If IsCallable(onFinally) is false, then + let (then_finally, catch_finally) = + if let Some(on_finally) = is_callable(on_finally, gc.nogc()) { + // 6. Else, + // a. Let thenFinallyClosure be a new Abstract Closure with... + // b. Let thenFinally be CreateBuiltinFunction(thenFinallyClosure, 1, "", « »). + // c. Let catchFinallyClosure be a new Abstract Closure with... + // d. Let catchFinally be CreateBuiltinFunction(catchFinallyClosure, 1, "", « »). + let (then_finally, catch_finally) = + BuiltinPromiseFinallyFunction::create_finally_functions(agent, c, on_finally); + (then_finally.into_value(), catch_finally.into_value()) + } else { + // a. Let thenFinally be onFinally. + // b. Let catchFinally be onFinally. + (on_finally, on_finally) + }; + // 7. Return ? Invoke(promise, "then", « thenFinally, catchFinally »). + invoke( + agent, + promise.into_value().unbind(), + BUILTIN_STRING_MEMORY.then.to_property_key(), + Some(ArgumentsList::from_mut_slice(&mut [ + then_finally.unbind(), + catch_finally.unbind(), + ])), + gc, + ) } /// ### [27.2.5.4 Promise.prototype.then ( onFulfilled, onRejected )](https://tc39.es/ecma262/#sec-promise.prototype.then) diff --git a/nova_vm/src/ecmascript/builtins/ecmascript_function.rs b/nova_vm/src/ecmascript/builtins/ecmascript_function.rs index dcd9e57ba..95f79208f 100644 --- a/nova_vm/src/ecmascript/builtins/ecmascript_function.rs +++ b/nova_vm/src/ecmascript/builtins/ecmascript_function.rs @@ -20,7 +20,7 @@ use crate::{ ThisBindingStatus, agent::{ ExceptionType::{self, SyntaxError}, - TryResult, get_active_script_or_module, + get_active_script_or_module, }, new_function_environment, }, @@ -31,13 +31,8 @@ use crate::{ }, types::{ BUILTIN_STRING_MEMORY, ECMAScriptFunctionHeapData, Function, - FunctionInternalProperties, InternalMethods, InternalSlots, IntoFunction, IntoObject, - IntoValue, Object, OrdinaryObject, PropertyDescriptor, PropertyKey, SetResult, String, - TryGetResult, TryHasResult, Value, function_create_backing_object, - function_internal_define_own_property, function_internal_delete, function_internal_get, - function_internal_get_own_property, function_internal_has_property, - function_internal_own_property_keys, function_internal_set, function_try_get, - function_try_has_property, function_try_set, + FunctionInternalProperties, InternalSlots, IntoFunction, IntoObject, IntoValue, Object, + OrdinaryObject, PropertyDescriptor, PropertyKey, String, Value, }, }, engine::{ @@ -53,10 +48,7 @@ use crate::{ use super::{ ArgumentsList, - ordinary::{ - caches::PropertyLookupCache, ordinary_create_from_constructor, - ordinary_object_create_with_intrinsics, - }, + ordinary::{ordinary_create_from_constructor, ordinary_object_create_with_intrinsics}, }; #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)] @@ -303,15 +295,25 @@ unsafe impl Bindable for ECMAScriptFunction<'_> { } } -impl<'a> InternalSlots<'a> for ECMAScriptFunction<'a> { - const DEFAULT_PROTOTYPE: ProtoIntrinsics = ProtoIntrinsics::Function; +impl<'a> FunctionInternalProperties<'a> for ECMAScriptFunction<'a> { + fn get_name(self, agent: &Agent) -> String<'static> { + agent[self].name.unwrap_or(String::EMPTY_STRING) + } + + fn get_length(self, agent: &Agent) -> u8 { + agent[self].length + } #[inline(always)] - fn get_backing_object(self, agent: &Agent) -> Option> { + fn get_function_backing_object(self, agent: &Agent) -> Option> { agent[self].object_index } - fn set_backing_object(self, agent: &mut Agent, backing_object: OrdinaryObject<'static>) { + fn set_function_backing_object( + self, + agent: &mut Agent, + backing_object: OrdinaryObject<'static>, + ) { assert!( agent[self] .object_index @@ -320,11 +322,7 @@ impl<'a> InternalSlots<'a> for ECMAScriptFunction<'a> { ); } - fn create_backing_object(self, agent: &mut Agent) -> OrdinaryObject<'static> { - function_create_backing_object(self, agent) - } - - fn internal_prototype(self, agent: &Agent) -> Option> { + fn function_prototype(self, agent: &Agent) -> Option> { if let Some(object_index) = self.get_backing_object(agent) { object_index.internal_prototype(agent) } else { @@ -344,132 +342,6 @@ impl<'a> InternalSlots<'a> for ECMAScriptFunction<'a> { Some(proto) } } -} - -impl<'a> FunctionInternalProperties<'a> for ECMAScriptFunction<'a> { - fn get_name(self, agent: &Agent) -> String<'static> { - agent[self].name.unwrap_or(String::EMPTY_STRING) - } - - fn get_length(self, agent: &Agent) -> u8 { - agent[self].length - } -} - -impl<'a> InternalMethods<'a> for ECMAScriptFunction<'a> { - fn try_get_own_property<'gc>( - self, - agent: &mut Agent, - property_key: PropertyKey, - cache: Option, - gc: NoGcScope<'gc, '_>, - ) -> TryResult<'gc, Option>> { - TryResult::Continue(function_internal_get_own_property( - self, - agent, - property_key, - cache, - gc, - )) - } - - fn try_define_own_property<'gc>( - self, - agent: &mut Agent, - property_key: PropertyKey, - property_descriptor: PropertyDescriptor, - cache: Option, - gc: NoGcScope<'gc, '_>, - ) -> TryResult<'gc, bool> { - function_internal_define_own_property( - self, - agent, - property_key, - property_descriptor, - cache, - gc, - ) - } - - fn try_has_property<'gc>( - self, - agent: &mut Agent, - property_key: PropertyKey, - cache: Option, - gc: NoGcScope<'gc, '_>, - ) -> TryResult<'gc, TryHasResult<'gc>> { - function_try_has_property(self, agent, property_key, cache, gc) - } - - fn internal_has_property<'gc>( - self, - agent: &mut Agent, - property_key: PropertyKey, - gc: GcScope<'gc, '_>, - ) -> JsResult<'gc, bool> { - function_internal_has_property(self, agent, property_key, gc) - } - - fn try_get<'gc>( - self, - agent: &mut Agent, - property_key: PropertyKey, - receiver: Value, - cache: Option, - gc: NoGcScope<'gc, '_>, - ) -> TryResult<'gc, TryGetResult<'gc>> { - function_try_get(self, agent, property_key, receiver, cache, gc) - } - - fn internal_get<'gc>( - self, - agent: &mut Agent, - property_key: PropertyKey, - receiver: Value, - gc: GcScope<'gc, '_>, - ) -> JsResult<'gc, Value<'gc>> { - function_internal_get(self, agent, property_key, receiver, gc) - } - - fn try_set<'gc>( - self, - agent: &mut Agent, - property_key: PropertyKey, - value: Value, - receiver: Value, - cache: Option, - gc: NoGcScope<'gc, '_>, - ) -> TryResult<'gc, SetResult<'gc>> { - function_try_set(self, agent, property_key, value, receiver, cache, gc) - } - - fn internal_set<'gc>( - self, - agent: &mut Agent, - property_key: PropertyKey, - value: Value, - receiver: Value, - gc: GcScope<'gc, '_>, - ) -> JsResult<'gc, bool> { - function_internal_set(self, agent, property_key, value, receiver, gc) - } - - fn try_delete<'gc>( - self, - agent: &mut Agent, - property_key: PropertyKey, - gc: NoGcScope<'gc, '_>, - ) -> TryResult<'gc, bool> { - TryResult::Continue(function_internal_delete(self, agent, property_key, gc)) - } - - fn try_own_property_keys<'gc>( - self, - agent: &mut Agent, - gc: NoGcScope<'gc, '_>, - ) -> TryResult<'gc, Vec>> { - TryResult::Continue(function_internal_own_property_keys(self, agent, gc)) - } /// ### [10.2.1 \[\[Call\]\] ( thisArgument, argumentsList )](https://tc39.es/ecma262/#sec-call) /// @@ -478,7 +350,7 @@ impl<'a> InternalMethods<'a> for ECMAScriptFunction<'a> { /// `argumentsList` (a List of ECMAScript language values) and returns /// either a normal completion containing an ECMAScript language value or a /// throw completion. - fn internal_call<'gc>( + fn function_call<'gc>( self, agent: &mut Agent, this_argument: Value, @@ -536,7 +408,7 @@ impl<'a> InternalMethods<'a> for ECMAScriptFunction<'a> { result } - fn internal_construct<'gc>( + fn function_construct<'gc>( self, agent: &mut Agent, arguments: ArgumentsList, @@ -1013,7 +885,7 @@ fn expected_arguments_count(params: &FormalParameters) -> usize { /// UNUSED. It converts F into a constructor. pub(crate) fn make_constructor<'a>( agent: &mut Agent, - function: impl IntoFunction<'a> + InternalMethods<'a>, + function: impl FunctionInternalProperties<'a>, writable_prototype: Option, prototype: Option, gc: NoGcScope, @@ -1039,6 +911,7 @@ pub(crate) fn make_constructor<'a>( Function::BuiltinGeneratorFunction | Function::BuiltinConstructorFunction(_) | Function::BuiltinPromiseResolvingFunction(_) + | Function::BuiltinPromiseFinallyFunction(_) | Function::BuiltinPromiseCollectorFunction | Function::BuiltinProxyRevokerFunction => unreachable!(), } @@ -1233,6 +1106,7 @@ pub(crate) fn set_function_name<'a>( Function::BuiltinGeneratorFunction | Function::BuiltinConstructorFunction(_) | Function::BuiltinPromiseResolvingFunction(_) + | Function::BuiltinPromiseFinallyFunction(_) | Function::BuiltinPromiseCollectorFunction | Function::BuiltinProxyRevokerFunction => unreachable!(), } diff --git a/nova_vm/src/ecmascript/builtins/fundamental_objects/function_objects/function_prototype.rs b/nova_vm/src/ecmascript/builtins/fundamental_objects/function_objects/function_prototype.rs index 55a7fb446..52cbeabfe 100644 --- a/nova_vm/src/ecmascript/builtins/fundamental_objects/function_objects/function_prototype.rs +++ b/nova_vm/src/ecmascript/builtins/fundamental_objects/function_objects/function_prototype.rs @@ -427,8 +427,10 @@ impl FunctionPrototype { // 4. If func is an Object and IsCallable(func) is true, return an // implementation-defined String source code representation of func. // The representation must have the syntax of a NativeFunction. - Function::BoundFunction(_) | Function::BuiltinPromiseResolvingFunction(_) => { - // Promise resolving functions have no initial name. + Function::BoundFunction(_) + | Function::BuiltinPromiseResolvingFunction(_) + | Function::BuiltinPromiseFinallyFunction(_) => { + // Promise resolving and finally functions have no initial name. Ok( Value::from_static_str(agent, "function () { [ native code ] }", gc.nogc()) .unbind(), diff --git a/nova_vm/src/ecmascript/builtins/shared_array_buffer/data.rs b/nova_vm/src/ecmascript/builtins/shared_array_buffer/data.rs index 271bb727b..8d8b5b5d2 100644 --- a/nova_vm/src/ecmascript/builtins/shared_array_buffer/data.rs +++ b/nova_vm/src/ecmascript/builtins/shared_array_buffer/data.rs @@ -30,10 +30,12 @@ unsafe impl Bindable for SharedArrayBufferHeapData<'_> { impl HeapMarkAndSweep for SharedArrayBufferHeapData<'static> { fn mark_values(&self, queues: &mut WorkQueues) { - self.object_index.mark_values(queues); + let Self { object_index } = self; + object_index.mark_values(queues); } fn sweep_values(&mut self, compactions: &CompactionLists) { - self.object_index.sweep_values(compactions); + let Self { object_index } = self; + object_index.sweep_values(compactions); } } diff --git a/nova_vm/src/ecmascript/execution/weak_key.rs b/nova_vm/src/ecmascript/execution/weak_key.rs index 15cdf014a..64918a41d 100644 --- a/nova_vm/src/ecmascript/execution/weak_key.rs +++ b/nova_vm/src/ecmascript/execution/weak_key.rs @@ -64,6 +64,7 @@ use crate::{ module::Module, primitive_objects::PrimitiveObject, promise::Promise, + promise_objects::promise_abstract_operations::promise_finally_functions::BuiltinPromiseFinallyFunction, proxy::Proxy, text_processing::string_objects::string_iterator_objects::StringIterator, }, @@ -73,6 +74,7 @@ use crate::{ BOUND_FUNCTION_DISCRIMINANT, BUILTIN_CONSTRUCTOR_FUNCTION_DISCRIMINANT, BUILTIN_FUNCTION_DISCRIMINANT, BUILTIN_GENERATOR_FUNCTION_DISCRIMINANT, BUILTIN_PROMISE_COLLECTOR_FUNCTION_DISCRIMINANT, + BUILTIN_PROMISE_FINALLY_FUNCTION_DISCRIMINANT, BUILTIN_PROMISE_RESOLVING_FUNCTION_DISCRIMINANT, BUILTIN_PROXY_REVOKER_FUNCTION, ECMASCRIPT_FUNCTION_DISCRIMINANT, EMBEDDER_OBJECT_DISCRIMINANT, ERROR_DISCRIMINANT, FINALIZATION_REGISTRY_DISCRIMINANT, GENERATOR_DISCRIMINANT, IntoValue, @@ -102,6 +104,8 @@ pub(crate) enum WeakKey<'a> { BUILTIN_CONSTRUCTOR_FUNCTION_DISCRIMINANT, BuiltinPromiseResolvingFunction(BuiltinPromiseResolvingFunction<'a>) = BUILTIN_PROMISE_RESOLVING_FUNCTION_DISCRIMINANT, + BuiltinPromiseFinallyFunction(BuiltinPromiseFinallyFunction<'a>) = + BUILTIN_PROMISE_FINALLY_FUNCTION_DISCRIMINANT, BuiltinPromiseCollectorFunction = BUILTIN_PROMISE_COLLECTOR_FUNCTION_DISCRIMINANT, BuiltinProxyRevokerFunction = BUILTIN_PROXY_REVOKER_FUNCTION, PrimitiveObject(PrimitiveObject<'a>) = PRIMITIVE_OBJECT_DISCRIMINANT, @@ -184,6 +188,7 @@ impl<'a> From> for Value<'a> { WeakKey::BuiltinGeneratorFunction => Self::BuiltinGeneratorFunction, WeakKey::BuiltinConstructorFunction(d) => Self::BuiltinConstructorFunction(d), WeakKey::BuiltinPromiseResolvingFunction(d) => Self::BuiltinPromiseResolvingFunction(d), + WeakKey::BuiltinPromiseFinallyFunction(d) => Self::BuiltinPromiseFinallyFunction(d), WeakKey::BuiltinPromiseCollectorFunction => Self::BuiltinPromiseCollectorFunction, WeakKey::BuiltinProxyRevokerFunction => Self::BuiltinProxyRevokerFunction, WeakKey::PrimitiveObject(d) => Self::PrimitiveObject(d), @@ -261,6 +266,7 @@ impl<'a> From> for WeakKey<'a> { Object::BuiltinGeneratorFunction => Self::BuiltinGeneratorFunction, Object::BuiltinConstructorFunction(d) => Self::BuiltinConstructorFunction(d), Object::BuiltinPromiseResolvingFunction(d) => Self::BuiltinPromiseResolvingFunction(d), + Object::BuiltinPromiseFinallyFunction(d) => Self::BuiltinPromiseFinallyFunction(d), Object::BuiltinPromiseCollectorFunction => Self::BuiltinPromiseCollectorFunction, Object::BuiltinProxyRevokerFunction => Self::BuiltinProxyRevokerFunction, Object::PrimitiveObject(d) => Self::PrimitiveObject(d), @@ -341,6 +347,7 @@ impl<'a> TryFrom> for Object<'a> { WeakKey::BuiltinPromiseResolvingFunction(d) => { Ok(Self::BuiltinPromiseResolvingFunction(d)) } + WeakKey::BuiltinPromiseFinallyFunction(d) => Ok(Self::BuiltinPromiseFinallyFunction(d)), WeakKey::BuiltinPromiseCollectorFunction => Ok(Self::BuiltinPromiseCollectorFunction), WeakKey::BuiltinProxyRevokerFunction => Ok(Self::BuiltinProxyRevokerFunction), WeakKey::PrimitiveObject(d) => Ok(Self::PrimitiveObject(d)), @@ -465,6 +472,7 @@ impl HeapMarkAndSweep for WeakKey<'static> { Self::BuiltinGeneratorFunction => {} Self::BuiltinConstructorFunction(d) => d.mark_values(queues), Self::BuiltinPromiseResolvingFunction(d) => d.mark_values(queues), + Self::BuiltinPromiseFinallyFunction(d) => d.mark_values(queues), Self::BuiltinPromiseCollectorFunction => {} Self::BuiltinProxyRevokerFunction => {} Self::PrimitiveObject(d) => d.mark_values(queues), @@ -539,6 +547,7 @@ impl HeapMarkAndSweep for WeakKey<'static> { Self::BuiltinGeneratorFunction => {} Self::BuiltinConstructorFunction(d) => d.sweep_values(compactions), Self::BuiltinPromiseResolvingFunction(d) => d.sweep_values(compactions), + Self::BuiltinPromiseFinallyFunction(d) => d.sweep_values(compactions), Self::BuiltinPromiseCollectorFunction => {} Self::BuiltinProxyRevokerFunction => {} Self::PrimitiveObject(d) => d.sweep_values(compactions), @@ -625,6 +634,9 @@ impl HeapSweepWeakReference for WeakKey<'static> { Self::BuiltinPromiseResolvingFunction(data) => data .sweep_weak_reference(compactions) .map(Self::BuiltinPromiseResolvingFunction), + Self::BuiltinPromiseFinallyFunction(data) => data + .sweep_weak_reference(compactions) + .map(Self::BuiltinPromiseFinallyFunction), Self::BuiltinPromiseCollectorFunction => Some(Self::BuiltinPromiseCollectorFunction), Self::BuiltinProxyRevokerFunction => Some(Self::BuiltinProxyRevokerFunction), Self::PrimitiveObject(data) => data diff --git a/nova_vm/src/ecmascript/types/language.rs b/nova_vm/src/ecmascript/types/language.rs index 03d73b10d..edad407af 100644 --- a/nova_vm/src/ecmascript/types/language.rs +++ b/nova_vm/src/ecmascript/types/language.rs @@ -19,11 +19,7 @@ mod value_vec; pub use bigint::{BigInt, BigIntHeapData}; pub(crate) use function::{ BoundFunctionHeapData, BuiltinConstructorHeapData, BuiltinFunctionHeapData, - ECMAScriptFunctionHeapData, FunctionInternalProperties, function_create_backing_object, - function_internal_define_own_property, function_internal_delete, function_internal_get, - function_internal_get_own_property, function_internal_has_property, - function_internal_own_property_keys, function_internal_set, function_try_get, - function_try_has_property, function_try_set, + ECMAScriptFunctionHeapData, FunctionInternalProperties, }; pub use function::{Function, IntoFunction}; pub use into_numeric::IntoNumeric; @@ -51,7 +47,7 @@ pub(crate) use value::{ ASYNC_FROM_SYNC_ITERATOR_DISCRIMINANT, ASYNC_GENERATOR_DISCRIMINANT, BIGINT_DISCRIMINANT, BOOLEAN_DISCRIMINANT, BOUND_FUNCTION_DISCRIMINANT, BUILTIN_CONSTRUCTOR_FUNCTION_DISCRIMINANT, BUILTIN_FUNCTION_DISCRIMINANT, BUILTIN_GENERATOR_FUNCTION_DISCRIMINANT, - BUILTIN_PROMISE_COLLECTOR_FUNCTION_DISCRIMINANT, + BUILTIN_PROMISE_COLLECTOR_FUNCTION_DISCRIMINANT, BUILTIN_PROMISE_FINALLY_FUNCTION_DISCRIMINANT, BUILTIN_PROMISE_RESOLVING_FUNCTION_DISCRIMINANT, BUILTIN_PROXY_REVOKER_FUNCTION, ECMASCRIPT_FUNCTION_DISCRIMINANT, EMBEDDER_OBJECT_DISCRIMINANT, ERROR_DISCRIMINANT, FINALIZATION_REGISTRY_DISCRIMINANT, FLOAT_DISCRIMINANT, GENERATOR_DISCRIMINANT, diff --git a/nova_vm/src/ecmascript/types/language/function.rs b/nova_vm/src/ecmascript/types/language/function.rs index 1f9cb8540..7ee1da8c8 100644 --- a/nova_vm/src/ecmascript/types/language/function.rs +++ b/nova_vm/src/ecmascript/types/language/function.rs @@ -12,6 +12,7 @@ use super::{ BOUND_FUNCTION_DISCRIMINANT, BUILTIN_CONSTRUCTOR_FUNCTION_DISCRIMINANT, BUILTIN_FUNCTION_DISCRIMINANT, BUILTIN_GENERATOR_FUNCTION_DISCRIMINANT, BUILTIN_PROMISE_COLLECTOR_FUNCTION_DISCRIMINANT, + BUILTIN_PROMISE_FINALLY_FUNCTION_DISCRIMINANT, BUILTIN_PROMISE_RESOLVING_FUNCTION_DISCRIMINANT, BUILTIN_PROXY_REVOKER_FUNCTION, ECMASCRIPT_FUNCTION_DISCRIMINANT, }, @@ -22,27 +23,24 @@ use crate::{ ArgumentsList, BuiltinConstructorFunction, BuiltinFunction, ECMAScriptFunction, bound_function::BoundFunction, ordinary::caches::{PropertyLookupCache, PropertyOffset}, - promise_objects::promise_abstract_operations::promise_resolving_functions::BuiltinPromiseResolvingFunction, + promise_objects::promise_abstract_operations::{ + promise_finally_functions::BuiltinPromiseFinallyFunction, + promise_resolving_functions::BuiltinPromiseResolvingFunction, + }, }, execution::{Agent, JsResult, ProtoIntrinsics, agent::TryResult}, types::PropertyDescriptor, }, engine::{ - context::{Bindable, GcScope, NoGcScope}, + context::{Bindable, GcScope, NoGcScope, bindable_handle}, rootable::{HeapRootData, HeapRootRef, Rootable}, }, heap::{CompactionLists, HeapMarkAndSweep, WorkQueues}, }; pub(crate) use data::*; +pub(crate) use into_function::FunctionInternalProperties; pub use into_function::IntoFunction; -pub(crate) use into_function::{ - FunctionInternalProperties, function_create_backing_object, - function_internal_define_own_property, function_internal_delete, function_internal_get, - function_internal_get_own_property, function_internal_has_property, - function_internal_own_property_keys, function_internal_set, function_try_get, - function_try_has_property, function_try_set, -}; /// https://tc39.es/ecma262/#function-object #[derive(Clone, Copy, PartialEq, Eq)] @@ -56,25 +54,31 @@ pub enum Function<'a> { BUILTIN_CONSTRUCTOR_FUNCTION_DISCRIMINANT, BuiltinPromiseResolvingFunction(BuiltinPromiseResolvingFunction<'a>) = BUILTIN_PROMISE_RESOLVING_FUNCTION_DISCRIMINANT, + BuiltinPromiseFinallyFunction(BuiltinPromiseFinallyFunction<'a>) = + BUILTIN_PROMISE_FINALLY_FUNCTION_DISCRIMINANT, BuiltinPromiseCollectorFunction = BUILTIN_PROMISE_COLLECTOR_FUNCTION_DISCRIMINANT, BuiltinProxyRevokerFunction = BUILTIN_PROXY_REVOKER_FUNCTION, } +bindable_handle!(Function); impl core::fmt::Debug for Function<'_> { fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { match self { - Function::BoundFunction(d) => write!(f, "BoundFunction({d:?})"), - Function::BuiltinFunction(d) => write!(f, "BuiltinFunction({d:?})"), - Function::ECMAScriptFunction(d) => write!(f, "ECMAScriptFunction({d:?})"), - Function::BuiltinGeneratorFunction => todo!(), - Function::BuiltinConstructorFunction(d) => { + Self::BoundFunction(d) => write!(f, "BoundFunction({d:?})"), + Self::BuiltinFunction(d) => write!(f, "BuiltinFunction({d:?})"), + Self::ECMAScriptFunction(d) => write!(f, "ECMAScriptFunction({d:?})"), + Self::BuiltinGeneratorFunction => todo!(), + Self::BuiltinConstructorFunction(d) => { write!(f, "BuiltinConstructorFunction({d:?})") } - Function::BuiltinPromiseResolvingFunction(d) => { + Self::BuiltinPromiseResolvingFunction(d) => { write!(f, "BuiltinPromiseResolvingFunction({d:?})") } - Function::BuiltinPromiseCollectorFunction => todo!(), - Function::BuiltinProxyRevokerFunction => todo!(), + Self::BuiltinPromiseFinallyFunction(d) => { + write!(f, "BuiltinPromiseFinallyFunction({d:?})") + } + Self::BuiltinPromiseCollectorFunction => todo!(), + Self::BuiltinProxyRevokerFunction => todo!(), } } } @@ -89,20 +93,16 @@ impl<'a> TryFrom> for Function<'a> { type Error = (); fn try_from(value: Object<'a>) -> Result { match value { - Object::BoundFunction(d) => Ok(Function::BoundFunction(d)), - Object::BuiltinFunction(d) => Ok(Function::BuiltinFunction(d)), - Object::ECMAScriptFunction(d) => Ok(Function::ECMAScriptFunction(d)), - Object::BuiltinGeneratorFunction => Ok(Function::BuiltinGeneratorFunction), - Object::BuiltinConstructorFunction(data) => { - Ok(Function::BuiltinConstructorFunction(data)) - } + Object::BoundFunction(d) => Ok(Self::BoundFunction(d)), + Object::BuiltinFunction(d) => Ok(Self::BuiltinFunction(d)), + Object::ECMAScriptFunction(d) => Ok(Self::ECMAScriptFunction(d)), + Object::BuiltinGeneratorFunction => Ok(Self::BuiltinGeneratorFunction), + Object::BuiltinConstructorFunction(data) => Ok(Self::BuiltinConstructorFunction(data)), Object::BuiltinPromiseResolvingFunction(data) => { - Ok(Function::BuiltinPromiseResolvingFunction(data)) - } - Object::BuiltinPromiseCollectorFunction => { - Ok(Function::BuiltinPromiseCollectorFunction) + Ok(Self::BuiltinPromiseResolvingFunction(data)) } - Object::BuiltinProxyRevokerFunction => Ok(Function::BuiltinProxyRevokerFunction), + Object::BuiltinPromiseCollectorFunction => Ok(Self::BuiltinPromiseCollectorFunction), + Object::BuiltinProxyRevokerFunction => Ok(Self::BuiltinProxyRevokerFunction), _ => Err(()), } } @@ -112,18 +112,16 @@ impl<'a> TryFrom> for Function<'a> { type Error = (); fn try_from(value: Value<'a>) -> Result { match value { - Value::BoundFunction(d) => Ok(Function::BoundFunction(d)), - Value::BuiltinFunction(d) => Ok(Function::BuiltinFunction(d)), - Value::ECMAScriptFunction(d) => Ok(Function::ECMAScriptFunction(d)), - Value::BuiltinGeneratorFunction => Ok(Function::BuiltinGeneratorFunction), - Value::BuiltinConstructorFunction(data) => { - Ok(Function::BuiltinConstructorFunction(data)) - } + Value::BoundFunction(d) => Ok(Self::BoundFunction(d)), + Value::BuiltinFunction(d) => Ok(Self::BuiltinFunction(d)), + Value::ECMAScriptFunction(d) => Ok(Self::ECMAScriptFunction(d)), + Value::BuiltinGeneratorFunction => Ok(Self::BuiltinGeneratorFunction), + Value::BuiltinConstructorFunction(data) => Ok(Self::BuiltinConstructorFunction(data)), Value::BuiltinPromiseResolvingFunction(data) => { - Ok(Function::BuiltinPromiseResolvingFunction(data)) + Ok(Self::BuiltinPromiseResolvingFunction(data)) } - Value::BuiltinPromiseCollectorFunction => Ok(Function::BuiltinPromiseCollectorFunction), - Value::BuiltinProxyRevokerFunction => Ok(Function::BuiltinProxyRevokerFunction), + Value::BuiltinPromiseCollectorFunction => Ok(Self::BuiltinPromiseCollectorFunction), + Value::BuiltinProxyRevokerFunction => Ok(Self::BuiltinProxyRevokerFunction), _ => Err(()), } } @@ -132,18 +130,19 @@ impl<'a> TryFrom> for Function<'a> { impl<'a> From> for Object<'a> { fn from(value: Function<'a>) -> Self { match value { - Function::BoundFunction(d) => Object::from(d), - Function::BuiltinFunction(d) => Object::from(d), - Function::ECMAScriptFunction(d) => Object::from(d), - Function::BuiltinGeneratorFunction => Object::BuiltinGeneratorFunction, - Function::BuiltinConstructorFunction(data) => { - Object::BuiltinConstructorFunction(data.unbind()) - } + Function::BoundFunction(d) => Self::BoundFunction(d), + Function::BuiltinFunction(d) => Self::BuiltinFunction(d), + Function::ECMAScriptFunction(d) => Self::ECMAScriptFunction(d), + Function::BuiltinGeneratorFunction => Self::BuiltinGeneratorFunction, + Function::BuiltinConstructorFunction(data) => Self::BuiltinConstructorFunction(data), Function::BuiltinPromiseResolvingFunction(data) => { - Object::BuiltinPromiseResolvingFunction(data.unbind()) + Self::BuiltinPromiseResolvingFunction(data) + } + Function::BuiltinPromiseFinallyFunction(data) => { + Self::BuiltinPromiseFinallyFunction(data) } - Function::BuiltinPromiseCollectorFunction => Object::BuiltinPromiseCollectorFunction, - Function::BuiltinProxyRevokerFunction => Object::BuiltinProxyRevokerFunction, + Function::BuiltinPromiseCollectorFunction => Self::BuiltinPromiseCollectorFunction, + Function::BuiltinProxyRevokerFunction => Self::BuiltinProxyRevokerFunction, } } } @@ -151,18 +150,21 @@ impl<'a> From> for Object<'a> { impl<'a> From> for Value<'a> { fn from(value: Function<'a>) -> Self { match value { - Function::BoundFunction(d) => Value::BoundFunction(d.unbind()), - Function::BuiltinFunction(d) => Value::BuiltinFunction(d.unbind()), - Function::ECMAScriptFunction(d) => Value::ECMAScriptFunction(d.unbind()), - Function::BuiltinGeneratorFunction => Value::BuiltinGeneratorFunction, + Function::BoundFunction(d) => Self::BoundFunction(d.unbind()), + Function::BuiltinFunction(d) => Self::BuiltinFunction(d.unbind()), + Function::ECMAScriptFunction(d) => Self::ECMAScriptFunction(d.unbind()), + Function::BuiltinGeneratorFunction => Self::BuiltinGeneratorFunction, Function::BuiltinConstructorFunction(data) => { - Value::BuiltinConstructorFunction(data.unbind()) + Self::BuiltinConstructorFunction(data.unbind()) } Function::BuiltinPromiseResolvingFunction(data) => { - Value::BuiltinPromiseResolvingFunction(data.unbind()) + Self::BuiltinPromiseResolvingFunction(data.unbind()) } - Function::BuiltinPromiseCollectorFunction => Value::BuiltinPromiseCollectorFunction, - Function::BuiltinProxyRevokerFunction => Value::BuiltinProxyRevokerFunction, + Function::BuiltinPromiseFinallyFunction(data) => { + Self::BuiltinPromiseFinallyFunction(data.unbind()) + } + Function::BuiltinPromiseCollectorFunction => Self::BuiltinPromiseCollectorFunction, + Function::BuiltinProxyRevokerFunction => Self::BuiltinProxyRevokerFunction, } } } @@ -174,6 +176,7 @@ impl Function<'_> { Function::BuiltinFunction(f) => f.is_constructor(agent), Function::ECMAScriptFunction(f) => f.is_constructor(agent), Function::BuiltinPromiseResolvingFunction(_) => false, + Function::BuiltinPromiseFinallyFunction(_) => false, Function::BuiltinGeneratorFunction => todo!(), Function::BuiltinConstructorFunction(_) => true, Function::BuiltinPromiseCollectorFunction => todo!(), @@ -189,26 +192,12 @@ impl Function<'_> { Function::ECMAScriptFunction(f) => f.get_name(agent).bind(gc), Function::BuiltinConstructorFunction(f) => f.get_name(agent).bind(gc), Function::BuiltinPromiseResolvingFunction(f) => f.get_name(agent).bind(gc), + Function::BuiltinPromiseFinallyFunction(f) => f.get_name(agent).bind(gc), _ => todo!(), } } } -// SAFETY: Property implemented as a lifetime transmute. -unsafe impl Bindable for Function<'_> { - type Of<'a> = Function<'a>; - - #[inline(always)] - fn unbind(self) -> Self::Of<'static> { - unsafe { core::mem::transmute::>(self) } - } - - #[inline(always)] - fn bind<'a>(self, _gc: NoGcScope<'a, '_>) -> Self::Of<'a> { - unsafe { core::mem::transmute::>(self) } - } -} - impl<'a> InternalSlots<'a> for Function<'a> { const DEFAULT_PROTOTYPE: ProtoIntrinsics = ProtoIntrinsics::Function; @@ -223,41 +212,24 @@ impl<'a> InternalSlots<'a> for Function<'a> { #[inline(always)] fn get_backing_object(self, agent: &Agent) -> Option> { match self { - Function::BoundFunction(d) => agent[d].object_index, - Function::BuiltinFunction(d) => agent[d].object_index, - Function::ECMAScriptFunction(d) => agent[d].object_index, + Function::BoundFunction(d) => d.get_backing_object(agent), + Function::BuiltinFunction(d) => d.get_backing_object(agent), + Function::ECMAScriptFunction(d) => d.get_backing_object(agent), Function::BuiltinGeneratorFunction => todo!(), - Function::BuiltinConstructorFunction(d) => agent[d].object_index, - Function::BuiltinPromiseResolvingFunction(d) => agent[d].object_index, + Function::BuiltinConstructorFunction(d) => d.get_backing_object(agent), + Function::BuiltinPromiseResolvingFunction(d) => d.get_backing_object(agent), + Function::BuiltinPromiseFinallyFunction(d) => d.get_backing_object(agent), Function::BuiltinPromiseCollectorFunction => todo!(), Function::BuiltinProxyRevokerFunction => todo!(), } } - fn internal_set_extensible(self, agent: &mut Agent, value: bool) { - if let Some(object_index) = self.get_backing_object(agent) { - object_index.internal_set_extensible(agent, value) - } else if !value { - // Create function base object and set inextensible - todo!() - } + fn internal_set_extensible(self, _: &mut Agent, _: bool) { + unreachable!() } - fn internal_set_prototype(self, agent: &mut Agent, prototype: Option) { - if let Some(object_index) = self.get_backing_object(agent) { - object_index.internal_set_prototype(agent, prototype) - } else if prototype - != Some( - agent - .current_realm_record() - .intrinsics() - .function_prototype() - .into(), - ) - { - // Create function base object with custom prototype - todo!() - } + fn internal_set_prototype(self, _: &mut Agent, _: Option) { + unreachable!() } } @@ -274,6 +246,7 @@ impl<'a> InternalMethods<'a> for Function<'a> { Function::BuiltinGeneratorFunction => todo!(), Function::BuiltinConstructorFunction(x) => x.try_get_prototype_of(agent, gc), Function::BuiltinPromiseResolvingFunction(x) => x.try_get_prototype_of(agent, gc), + Function::BuiltinPromiseFinallyFunction(x) => x.try_get_prototype_of(agent, gc), Function::BuiltinPromiseCollectorFunction => todo!(), Function::BuiltinProxyRevokerFunction => todo!(), } @@ -294,6 +267,9 @@ impl<'a> InternalMethods<'a> for Function<'a> { Function::BuiltinPromiseResolvingFunction(x) => { x.try_set_prototype_of(agent, prototype, gc) } + Function::BuiltinPromiseFinallyFunction(x) => { + x.try_set_prototype_of(agent, prototype, gc) + } Function::BuiltinPromiseCollectorFunction => todo!(), Function::BuiltinProxyRevokerFunction => todo!(), } @@ -311,6 +287,7 @@ impl<'a> InternalMethods<'a> for Function<'a> { Function::BuiltinGeneratorFunction => todo!(), Function::BuiltinConstructorFunction(x) => x.try_is_extensible(agent, gc), Function::BuiltinPromiseResolvingFunction(x) => x.try_is_extensible(agent, gc), + Function::BuiltinPromiseFinallyFunction(x) => x.try_is_extensible(agent, gc), Function::BuiltinPromiseCollectorFunction => todo!(), Function::BuiltinProxyRevokerFunction => todo!(), } @@ -328,6 +305,7 @@ impl<'a> InternalMethods<'a> for Function<'a> { Function::BuiltinGeneratorFunction => todo!(), Function::BuiltinConstructorFunction(x) => x.try_prevent_extensions(agent, gc), Function::BuiltinPromiseResolvingFunction(x) => x.try_prevent_extensions(agent, gc), + Function::BuiltinPromiseFinallyFunction(x) => x.try_prevent_extensions(agent, gc), Function::BuiltinPromiseCollectorFunction => todo!(), Function::BuiltinProxyRevokerFunction => todo!(), } @@ -353,6 +331,9 @@ impl<'a> InternalMethods<'a> for Function<'a> { Function::BuiltinPromiseResolvingFunction(x) => { x.try_get_own_property(agent, property_key, cache, gc) } + Function::BuiltinPromiseFinallyFunction(x) => { + x.try_get_own_property(agent, property_key, cache, gc) + } Function::BuiltinPromiseCollectorFunction => todo!(), Function::BuiltinProxyRevokerFunction => todo!(), } @@ -383,6 +364,9 @@ impl<'a> InternalMethods<'a> for Function<'a> { Function::BuiltinPromiseResolvingFunction(x) => { x.try_define_own_property(agent, property_key, property_descriptor, cache, gc) } + Function::BuiltinPromiseFinallyFunction(x) => { + x.try_define_own_property(agent, property_key, property_descriptor, cache, gc) + } Function::BuiltinPromiseCollectorFunction => todo!(), Function::BuiltinProxyRevokerFunction => todo!(), } @@ -406,6 +390,9 @@ impl<'a> InternalMethods<'a> for Function<'a> { Function::BuiltinPromiseResolvingFunction(x) => { x.try_has_property(agent, property_key, cache, gc) } + Function::BuiltinPromiseFinallyFunction(x) => { + x.try_has_property(agent, property_key, cache, gc) + } Function::BuiltinPromiseCollectorFunction => todo!(), Function::BuiltinProxyRevokerFunction => todo!(), } @@ -428,6 +415,9 @@ impl<'a> InternalMethods<'a> for Function<'a> { Function::BuiltinPromiseResolvingFunction(x) => { x.internal_has_property(agent, property_key, gc) } + Function::BuiltinPromiseFinallyFunction(x) => { + x.internal_has_property(agent, property_key, gc) + } Function::BuiltinPromiseCollectorFunction => todo!(), Function::BuiltinProxyRevokerFunction => todo!(), } @@ -452,6 +442,9 @@ impl<'a> InternalMethods<'a> for Function<'a> { Function::BuiltinPromiseResolvingFunction(x) => { x.try_get(agent, property_key, receiver, cache, gc) } + Function::BuiltinPromiseFinallyFunction(x) => { + x.try_get(agent, property_key, receiver, cache, gc) + } Function::BuiltinPromiseCollectorFunction => todo!(), Function::BuiltinProxyRevokerFunction => todo!(), } @@ -475,6 +468,9 @@ impl<'a> InternalMethods<'a> for Function<'a> { Function::BuiltinPromiseResolvingFunction(x) => { x.internal_get(agent, property_key, receiver, gc) } + Function::BuiltinPromiseFinallyFunction(x) => { + x.internal_get(agent, property_key, receiver, gc) + } Function::BuiltinPromiseCollectorFunction => todo!(), Function::BuiltinProxyRevokerFunction => todo!(), } @@ -506,6 +502,9 @@ impl<'a> InternalMethods<'a> for Function<'a> { Function::BuiltinPromiseResolvingFunction(x) => { x.try_set(agent, property_key, value, receiver, cache, gc) } + Function::BuiltinPromiseFinallyFunction(x) => { + x.try_set(agent, property_key, value, receiver, cache, gc) + } Function::BuiltinPromiseCollectorFunction => todo!(), Function::BuiltinProxyRevokerFunction => todo!(), } @@ -534,6 +533,9 @@ impl<'a> InternalMethods<'a> for Function<'a> { Function::BuiltinPromiseResolvingFunction(x) => { x.internal_set(agent, property_key, value, receiver, gc) } + Function::BuiltinPromiseFinallyFunction(x) => { + x.internal_set(agent, property_key, value, receiver, gc) + } Function::BuiltinPromiseCollectorFunction => todo!(), Function::BuiltinProxyRevokerFunction => todo!(), } @@ -552,6 +554,7 @@ impl<'a> InternalMethods<'a> for Function<'a> { Function::BuiltinGeneratorFunction => todo!(), Function::BuiltinConstructorFunction(x) => x.try_delete(agent, property_key, gc), Function::BuiltinPromiseResolvingFunction(x) => x.try_delete(agent, property_key, gc), + Function::BuiltinPromiseFinallyFunction(x) => x.try_delete(agent, property_key, gc), Function::BuiltinPromiseCollectorFunction => todo!(), Function::BuiltinProxyRevokerFunction => todo!(), } @@ -569,6 +572,7 @@ impl<'a> InternalMethods<'a> for Function<'a> { Function::BuiltinGeneratorFunction => todo!(), Function::BuiltinConstructorFunction(x) => x.try_own_property_keys(agent, gc), Function::BuiltinPromiseResolvingFunction(x) => x.try_own_property_keys(agent, gc), + Function::BuiltinPromiseFinallyFunction(x) => x.try_own_property_keys(agent, gc), Function::BuiltinPromiseCollectorFunction => todo!(), Function::BuiltinProxyRevokerFunction => todo!(), } @@ -591,6 +595,9 @@ impl<'a> InternalMethods<'a> for Function<'a> { Function::BuiltinPromiseResolvingFunction(f) => { f.get_own_property_at_offset(agent, offset, gc) } + Function::BuiltinPromiseFinallyFunction(f) => { + f.get_own_property_at_offset(agent, offset, gc) + } Function::BuiltinPromiseCollectorFunction => todo!(), Function::BuiltinProxyRevokerFunction => todo!(), } @@ -612,6 +619,7 @@ impl<'a> InternalMethods<'a> for Function<'a> { Function::BuiltinPromiseResolvingFunction(f) => { f.set_at_offset(agent, props, offset, gc) } + Function::BuiltinPromiseFinallyFunction(f) => f.set_at_offset(agent, props, offset, gc), Function::BuiltinPromiseCollectorFunction => todo!(), Function::BuiltinProxyRevokerFunction => todo!(), } @@ -635,6 +643,9 @@ impl<'a> InternalMethods<'a> for Function<'a> { Function::BuiltinPromiseResolvingFunction(x) => { x.internal_call(agent, this_argument, arguments, gc) } + Function::BuiltinPromiseFinallyFunction(x) => { + x.internal_call(agent, this_argument, arguments, gc) + } Function::BuiltinPromiseCollectorFunction => todo!(), Function::BuiltinProxyRevokerFunction => todo!(), } @@ -660,6 +671,9 @@ impl<'a> InternalMethods<'a> for Function<'a> { Function::BuiltinPromiseResolvingFunction(x) => { x.internal_construct(agent, arguments, new_target, gc) } + Function::BuiltinPromiseFinallyFunction(x) => { + x.internal_construct(agent, arguments, new_target, gc) + } Function::BuiltinPromiseCollectorFunction => todo!(), Function::BuiltinProxyRevokerFunction => todo!(), } @@ -675,6 +689,7 @@ impl HeapMarkAndSweep for Function<'static> { Function::BuiltinGeneratorFunction => todo!(), Function::BuiltinConstructorFunction(x) => x.mark_values(queues), Function::BuiltinPromiseResolvingFunction(x) => x.mark_values(queues), + Function::BuiltinPromiseFinallyFunction(x) => x.mark_values(queues), Function::BuiltinPromiseCollectorFunction => todo!(), Function::BuiltinProxyRevokerFunction => todo!(), } @@ -688,6 +703,7 @@ impl HeapMarkAndSweep for Function<'static> { Function::BuiltinGeneratorFunction => todo!(), Function::BuiltinConstructorFunction(x) => x.sweep_values(compactions), Function::BuiltinPromiseResolvingFunction(x) => x.sweep_values(compactions), + Function::BuiltinPromiseFinallyFunction(x) => x.sweep_values(compactions), Function::BuiltinPromiseCollectorFunction => todo!(), Function::BuiltinProxyRevokerFunction => todo!(), } @@ -726,6 +742,9 @@ impl Rootable for Function<'_> { Self::BuiltinPromiseResolvingFunction(d) => { Err(HeapRootData::BuiltinPromiseResolvingFunction(d.unbind())) } + Self::BuiltinPromiseFinallyFunction(d) => { + Err(HeapRootData::BuiltinPromiseFinallyFunction(d.unbind())) + } Self::BuiltinPromiseCollectorFunction => { Err(HeapRootData::BuiltinPromiseCollectorFunction) } diff --git a/nova_vm/src/ecmascript/types/language/function/into_function.rs b/nova_vm/src/ecmascript/types/language/function/into_function.rs index 24a25dee4..a35c88034 100644 --- a/nova_vm/src/ecmascript/types/language/function/into_function.rs +++ b/nova_vm/src/ecmascript/types/language/function/into_function.rs @@ -5,18 +5,21 @@ use super::Function; use crate::{ ecmascript::{ - builtins::ordinary::{ - caches::PropertyLookupCache, ordinary_define_own_property, ordinary_delete, - ordinary_get_own_property, ordinary_has_property, ordinary_own_property_keys, - ordinary_set, ordinary_try_get, ordinary_try_has_property, ordinary_try_set, + builtins::{ + ArgumentsList, + ordinary::{ + caches::PropertyLookupCache, ordinary_define_own_property, ordinary_delete, + ordinary_get_own_property, ordinary_has_property, ordinary_own_property_keys, + ordinary_set, ordinary_try_get, ordinary_try_has_property, ordinary_try_set, + }, }, execution::{ - Agent, JsResult, + Agent, JsResult, ProtoIntrinsics, agent::{TryResult, js_result_into_try, unwrap_try}, }, types::{ - BUILTIN_STRING_MEMORY, InternalMethods, InternalSlots, IntoValue, OrdinaryObject, - PropertyDescriptor, PropertyKey, SetCachedProps, SetResult, String, TryGetResult, + BUILTIN_STRING_MEMORY, InternalMethods, InternalSlots, IntoValue, Object, + OrdinaryObject, PropertyDescriptor, PropertyKey, SetResult, String, TryGetResult, TryHasResult, Value, language::IntoObject, }, }, @@ -45,328 +48,395 @@ where /// These are used when the function hasn't had a backing object created. pub(crate) trait FunctionInternalProperties<'a> where - Self: IntoObject<'a> + IntoFunction<'a> + InternalSlots<'a> + InternalMethods<'a>, + Self: Sized + Copy + Into> + IntoObject<'a> + IntoFunction<'a> + core::fmt::Debug, { /// Value of the 'name' property. fn get_name(self, agent: &Agent) -> String<'static>; /// Value of the 'length' property. fn get_length(self, agent: &Agent) -> u8; -} -pub(crate) fn function_create_backing_object<'a>( - func: impl FunctionInternalProperties<'a>, - agent: &mut Agent, -) -> OrdinaryObject<'static> { - assert!(func.get_backing_object(agent).is_none()); - let prototype = func.internal_prototype(agent).unwrap(); - let length_entry = ObjectEntry { - key: BUILTIN_STRING_MEMORY.length.into(), - value: ObjectEntryPropertyDescriptor::Data { - value: func.get_length(agent).into(), - writable: false, - enumerable: false, - configurable: true, - }, - }; - let name_entry = ObjectEntry { - key: BUILTIN_STRING_MEMORY.name.into(), - value: ObjectEntryPropertyDescriptor::Data { - value: func.get_name(agent).into_value(), - writable: false, - enumerable: false, - configurable: true, - }, - }; - let backing_object = - OrdinaryObject::create_object(agent, Some(prototype), &[length_entry, name_entry]); - func.set_backing_object(agent, backing_object); - backing_object -} + fn get_function_backing_object(self, agent: &Agent) -> Option>; + + fn set_function_backing_object( + self, + agent: &mut Agent, + backing_object: OrdinaryObject<'static>, + ); -pub(crate) fn function_set_cached<'a, 'gc>( - func: impl FunctionInternalProperties<'a>, - agent: &mut Agent, - props: &SetCachedProps, - gc: NoGcScope<'gc, '_>, -) -> TryResult<'gc, SetResult<'gc>> { - let bo = func.get_backing_object(agent); - if bo.is_none() - && (props.p == BUILTIN_STRING_MEMORY.length.into() - || props.p == BUILTIN_STRING_MEMORY.name.into()) - { - SetResult::Unwritable.into() - } else { - let shape = if let Some(bo) = bo { - bo.object_shape(agent) + // #### \[\[Prototype\]\] + fn function_prototype(self, agent: &Agent) -> Option> { + if let Some(backing_object) = self.get_backing_object(agent) { + backing_object.internal_prototype(agent) } else { - func.object_shape(agent) - }; - shape.set_cached(agent, func.into_object(), props, gc) + Some( + agent + .current_realm_record() + .intrinsics() + .get_intrinsic_default_proto(Self::DEFAULT_PROTOTYPE), + ) + } } -} -pub(crate) fn function_internal_get_own_property<'a, 'gc>( - func: impl FunctionInternalProperties<'a>, - agent: &mut Agent, - property_key: PropertyKey, - cache: Option, - gc: NoGcScope<'gc, '_>, -) -> Option> { - if let Some(backing_object) = func.get_backing_object(agent) { - ordinary_get_own_property( - agent, - func.into_object().bind(gc), - backing_object, - property_key, - cache, - gc, - ) - } else if property_key == BUILTIN_STRING_MEMORY.length.into() { - Some(PropertyDescriptor { - value: Some(func.get_length(agent).into()), - writable: Some(false), - enumerable: Some(false), - configurable: Some(true), - ..Default::default() - }) - } else if property_key == BUILTIN_STRING_MEMORY.name.into() { - Some(PropertyDescriptor { - value: Some(func.get_name(agent).into_value().bind(gc)), - writable: Some(false), - enumerable: Some(false), - configurable: Some(true), - ..Default::default() - }) - } else { - None + #[allow(unused_variables)] + fn function_call<'gc>( + self, + agent: &mut Agent, + this_value: Value, + arguments_list: ArgumentsList, + gc: GcScope<'gc, '_>, + ) -> JsResult<'gc, Value<'gc>>; + + #[allow(unused_variables)] + fn function_construct<'gc>( + self, + agent: &mut Agent, + arguments_list: ArgumentsList, + new_target: Function, + gc: GcScope<'gc, '_>, + ) -> JsResult<'gc, Object<'gc>> { + unreachable!() } } -pub(crate) fn function_internal_define_own_property<'a, 'gc>( - func: impl FunctionInternalProperties<'a>, - agent: &mut Agent, - property_key: PropertyKey, - property_descriptor: PropertyDescriptor, - cache: Option, - gc: NoGcScope<'gc, '_>, -) -> TryResult<'gc, bool> { - let backing_object = func - .get_backing_object(agent) - .unwrap_or_else(|| func.create_backing_object(agent)); - js_result_into_try(ordinary_define_own_property( - agent, - func.into_object(), - backing_object, - property_key, - property_descriptor, - cache, - gc, - )) -} +impl<'a, T: 'a + FunctionInternalProperties<'a>> InternalSlots<'a> for T { + const DEFAULT_PROTOTYPE: ProtoIntrinsics = ProtoIntrinsics::Function; -pub(crate) fn function_try_has_property<'a, 'gc>( - func: impl FunctionInternalProperties<'a>, - agent: &mut Agent, - property_key: PropertyKey, - cache: Option, - gc: NoGcScope<'gc, '_>, -) -> TryResult<'gc, TryHasResult<'gc>> { - let backing_object = func.get_backing_object(agent); + fn get_backing_object(self, agent: &Agent) -> Option> { + self.get_function_backing_object(agent) + } - if backing_object.is_none() - && (property_key == BUILTIN_STRING_MEMORY.length.into() - || property_key == BUILTIN_STRING_MEMORY.name.into()) - { - let index = if property_key == BUILTIN_STRING_MEMORY.length.into() { - 0 - } else { - 1 + fn set_backing_object(self, agent: &mut Agent, backing_object: OrdinaryObject<'static>) { + self.set_function_backing_object(agent, backing_object) + } + + fn create_backing_object(self, agent: &mut Agent) -> OrdinaryObject<'static> { + assert!(self.get_backing_object(agent).is_none()); + let prototype = self.internal_prototype(agent).unwrap(); + let length_entry = ObjectEntry { + key: BUILTIN_STRING_MEMORY.length.into(), + value: ObjectEntryPropertyDescriptor::Data { + value: self.get_length(agent).into(), + writable: false, + enumerable: false, + configurable: true, + }, }; - TryHasResult::Custom(index, func.into_object().bind(gc)).into() - } else { - ordinary_try_has_property( - agent, - func.into_object(), - backing_object, - property_key, - cache, - gc, - ) + let name_entry = ObjectEntry { + key: BUILTIN_STRING_MEMORY.name.into(), + value: ObjectEntryPropertyDescriptor::Data { + value: self.get_name(agent).into_value(), + writable: false, + enumerable: false, + configurable: true, + }, + }; + let backing_object = + OrdinaryObject::create_object(agent, Some(prototype), &[length_entry, name_entry]); + self.set_backing_object(agent, backing_object); + backing_object + } + + fn internal_prototype(self, agent: &Agent) -> Option> { + self.function_prototype(agent) } } -pub(crate) fn function_internal_has_property<'a, 'gc>( - func: impl FunctionInternalProperties<'a>, - agent: &mut Agent, - property_key: PropertyKey, - gc: GcScope<'gc, '_>, -) -> JsResult<'gc, bool> { - let property_key = property_key.bind(gc.nogc()); - if let Some(backing_object) = func.get_backing_object(agent) { - ordinary_has_property( - agent, - func.into_object(), - backing_object, - property_key.unbind(), - gc, - ) - } else if property_key == BUILTIN_STRING_MEMORY.length.into() - || property_key == BUILTIN_STRING_MEMORY.name.into() - { - Ok(true) - } else { - let parent = unwrap_try(func.try_get_prototype_of(agent, gc.nogc())); - if let Some(parent) = parent { - parent - .unbind() - .internal_has_property(agent, property_key.unbind(), gc) +impl<'a, T: 'a + FunctionInternalProperties<'a>> InternalMethods<'a> for T { + fn try_get_own_property<'gc>( + self, + agent: &mut Agent, + property_key: PropertyKey, + cache: Option, + gc: NoGcScope<'gc, '_>, + ) -> TryResult<'gc, Option>> { + if let Some(backing_object) = self.get_backing_object(agent) { + TryResult::Continue(ordinary_get_own_property( + agent, + self.into_object().bind(gc), + backing_object, + property_key, + cache, + gc, + )) + } else if property_key == BUILTIN_STRING_MEMORY.length.into() { + TryResult::Continue(Some(PropertyDescriptor { + value: Some(self.get_length(agent).into()), + writable: Some(false), + enumerable: Some(false), + configurable: Some(true), + ..Default::default() + })) + } else if property_key == BUILTIN_STRING_MEMORY.name.into() { + TryResult::Continue(Some(PropertyDescriptor { + value: Some(self.get_name(agent).into_value().bind(gc)), + writable: Some(false), + enumerable: Some(false), + configurable: Some(true), + ..Default::default() + })) } else { - Ok(false) + TryResult::Continue(None) } } -} -pub(crate) fn function_try_get<'gc, 'a>( - func: impl FunctionInternalProperties<'a>, - agent: &mut Agent, - property_key: PropertyKey, - receiver: Value, - cache: Option, - gc: NoGcScope<'gc, '_>, -) -> TryResult<'gc, TryGetResult<'gc>> { - let backing_object = func.get_backing_object(agent); - // if let Some(backing_object) = func.get_backing_object(agent) { - if backing_object.is_none() && property_key == BUILTIN_STRING_MEMORY.length.into() { - TryGetResult::Value(func.get_length(agent).into()).into() - } else if backing_object.is_none() && property_key == BUILTIN_STRING_MEMORY.name.into() { - TryGetResult::Value(func.get_name(agent).into_value()).into() - } else { - ordinary_try_get( + fn try_define_own_property<'gc>( + self, + agent: &mut Agent, + property_key: PropertyKey, + property_descriptor: PropertyDescriptor, + cache: Option, + gc: NoGcScope<'gc, '_>, + ) -> TryResult<'gc, bool> { + let backing_object = self + .get_backing_object(agent) + .unwrap_or_else(|| self.create_backing_object(agent)); + js_result_into_try(ordinary_define_own_property( agent, - func.into_object(), + self.into_object(), backing_object, property_key, - receiver, + property_descriptor, cache, gc, - ) + )) } -} -pub(crate) fn function_internal_get<'gc, 'a>( - func: impl FunctionInternalProperties<'a>, - agent: &mut Agent, - property_key: PropertyKey, - receiver: Value, - gc: GcScope<'gc, '_>, -) -> JsResult<'gc, Value<'gc>> { - let property_key = property_key.bind(gc.nogc()); - if let Some(backing_object) = func.get_backing_object(agent) { - backing_object.internal_get(agent, property_key.unbind(), receiver, gc) - } else if property_key == BUILTIN_STRING_MEMORY.length.into() { - Ok(func.get_length(agent).into()) - } else if property_key == BUILTIN_STRING_MEMORY.name.into() { - Ok(func.get_name(agent).into_value().bind(gc.into_nogc())) - } else { - // Note: Getting a function's prototype never calls JavaScript. - let parent = unwrap_try(func.try_get_prototype_of(agent, gc.nogc())); - if let Some(parent) = parent { - parent - .unbind() - .internal_get(agent, property_key.unbind(), receiver, gc) + fn try_has_property<'gc>( + self, + agent: &mut Agent, + property_key: PropertyKey, + cache: Option, + gc: NoGcScope<'gc, '_>, + ) -> TryResult<'gc, TryHasResult<'gc>> { + let backing_object = self.get_backing_object(agent); + + if backing_object.is_none() + && (property_key == BUILTIN_STRING_MEMORY.length.into() + || property_key == BUILTIN_STRING_MEMORY.name.into()) + { + let index = if property_key == BUILTIN_STRING_MEMORY.length.into() { + 0 + } else { + 1 + }; + TryHasResult::Custom(index, self.into_object().bind(gc)).into() } else { - Ok(Value::Undefined) + ordinary_try_has_property( + agent, + self.into_object(), + backing_object, + property_key, + cache, + gc, + ) } } -} -pub(crate) fn function_try_set<'gc, 'a>( - func: impl FunctionInternalProperties<'a>, - agent: &mut Agent, - property_key: PropertyKey, - value: Value, - receiver: Value, - cache: Option, - gc: NoGcScope<'gc, '_>, -) -> TryResult<'gc, SetResult<'gc>> { - if func.get_backing_object(agent).is_some() { - ordinary_try_set(agent, func, property_key, value, receiver, cache, gc) - } else if property_key == BUILTIN_STRING_MEMORY.length.into() - || property_key == BUILTIN_STRING_MEMORY.name.into() - { - // length and name are not writable - SetResult::Unwritable.into() - } else { - ordinary_try_set(agent, func, property_key, value, receiver, cache, gc) + fn internal_has_property<'gc>( + self, + agent: &mut Agent, + property_key: PropertyKey, + gc: GcScope<'gc, '_>, + ) -> JsResult<'gc, bool> { + let property_key = property_key.bind(gc.nogc()); + if let Some(backing_object) = self.get_backing_object(agent) { + ordinary_has_property( + agent, + self.into_object(), + backing_object, + property_key.unbind(), + gc, + ) + } else if property_key == BUILTIN_STRING_MEMORY.length.into() + || property_key == BUILTIN_STRING_MEMORY.name.into() + { + Ok(true) + } else { + let parent = unwrap_try(self.try_get_prototype_of(agent, gc.nogc())); + if let Some(parent) = parent { + parent + .unbind() + .internal_has_property(agent, property_key.unbind(), gc) + } else { + Ok(false) + } + } } -} -pub(crate) fn function_internal_set<'a, 'gc>( - func: impl FunctionInternalProperties<'a>, - agent: &mut Agent, - property_key: PropertyKey, - value: Value, - receiver: Value, - gc: GcScope<'gc, '_>, -) -> JsResult<'gc, bool> { - let property_key = property_key.bind(gc.nogc()); - if func.get_backing_object(agent).is_some() { - ordinary_set( - agent, - func.into_object(), - property_key.unbind(), - value, - receiver, - gc, - ) - } else if property_key == BUILTIN_STRING_MEMORY.length.into() - || property_key == BUILTIN_STRING_MEMORY.name.into() - { - // length and name are not writable - Ok(false) - } else { - ordinary_set( - agent, - func.into_object(), - property_key.unbind(), - value, - receiver, - gc, - ) + fn try_get<'gc>( + self, + agent: &mut Agent, + property_key: PropertyKey, + receiver: Value, + cache: Option, + gc: NoGcScope<'gc, '_>, + ) -> TryResult<'gc, TryGetResult<'gc>> { + let backing_object = self.get_backing_object(agent); + // if let Some(backing_object) = self.get_backing_object(agent) { + if backing_object.is_none() && property_key == BUILTIN_STRING_MEMORY.length.into() { + TryGetResult::Value(self.get_length(agent).into()).into() + } else if backing_object.is_none() && property_key == BUILTIN_STRING_MEMORY.name.into() { + TryGetResult::Value(self.get_name(agent).into_value()).into() + } else { + ordinary_try_get( + agent, + self.into_object(), + backing_object, + property_key, + receiver, + cache, + gc, + ) + } } -} -pub(crate) fn function_internal_delete<'a>( - func: impl FunctionInternalProperties<'a>, - agent: &mut Agent, - property_key: PropertyKey, - gc: NoGcScope, -) -> bool { - if let Some(backing_object) = func.get_backing_object(agent) { - ordinary_delete(agent, func.into_object(), backing_object, property_key, gc) - } else if property_key == BUILTIN_STRING_MEMORY.length.into() - || property_key == BUILTIN_STRING_MEMORY.name.into() - { - let backing_object = func.create_backing_object(agent); - ordinary_delete(agent, func.into_object(), backing_object, property_key, gc) - } else { - // Non-existing property - true + fn internal_get<'gc>( + self, + agent: &mut Agent, + property_key: PropertyKey, + receiver: Value, + gc: GcScope<'gc, '_>, + ) -> JsResult<'gc, Value<'gc>> { + let property_key = property_key.bind(gc.nogc()); + if let Some(backing_object) = self.get_backing_object(agent) { + backing_object.internal_get(agent, property_key.unbind(), receiver, gc) + } else if property_key == BUILTIN_STRING_MEMORY.length.into() { + Ok(self.get_length(agent).into()) + } else if property_key == BUILTIN_STRING_MEMORY.name.into() { + Ok(self.get_name(agent).into_value().bind(gc.into_nogc())) + } else { + // Note: Getting a function's prototype never calls JavaScript. + let parent = unwrap_try(self.try_get_prototype_of(agent, gc.nogc())); + if let Some(parent) = parent { + parent + .unbind() + .internal_get(agent, property_key.unbind(), receiver, gc) + } else { + Ok(Value::Undefined) + } + } + } + + fn try_set<'gc>( + self, + agent: &mut Agent, + property_key: PropertyKey, + value: Value, + receiver: Value, + cache: Option, + gc: NoGcScope<'gc, '_>, + ) -> TryResult<'gc, SetResult<'gc>> { + if self.get_backing_object(agent).is_some() { + ordinary_try_set(agent, self, property_key, value, receiver, cache, gc) + } else if property_key == BUILTIN_STRING_MEMORY.length.into() + || property_key == BUILTIN_STRING_MEMORY.name.into() + { + // length and name are not writable + SetResult::Unwritable.into() + } else { + ordinary_try_set(agent, self, property_key, value, receiver, cache, gc) + } + } + + fn internal_set<'gc>( + self, + agent: &mut Agent, + property_key: PropertyKey, + value: Value, + receiver: Value, + gc: GcScope<'gc, '_>, + ) -> JsResult<'gc, bool> { + let property_key = property_key.bind(gc.nogc()); + if self.get_backing_object(agent).is_some() { + ordinary_set( + agent, + self.into_object(), + property_key.unbind(), + value, + receiver, + gc, + ) + } else if property_key == BUILTIN_STRING_MEMORY.length.into() + || property_key == BUILTIN_STRING_MEMORY.name.into() + { + // length and name are not writable + Ok(false) + } else { + ordinary_set( + agent, + self.into_object(), + property_key.unbind(), + value, + receiver, + gc, + ) + } + } + + fn try_delete<'gc>( + self, + agent: &mut Agent, + property_key: PropertyKey, + gc: NoGcScope<'gc, '_>, + ) -> TryResult<'gc, bool> { + if let Some(backing_object) = self.get_backing_object(agent) { + TryResult::Continue(ordinary_delete( + agent, + self.into_object(), + backing_object, + property_key, + gc, + )) + } else if property_key == BUILTIN_STRING_MEMORY.length.into() + || property_key == BUILTIN_STRING_MEMORY.name.into() + { + let backing_object = self.create_backing_object(agent); + TryResult::Continue(ordinary_delete( + agent, + self.into_object(), + backing_object, + property_key, + gc, + )) + } else { + // Non-existing property + TryResult::Continue(true) + } + } + + fn try_own_property_keys<'gc>( + self, + agent: &mut Agent, + gc: NoGcScope<'gc, '_>, + ) -> TryResult<'gc, Vec>> { + if let Some(backing_object) = self.get_backing_object(agent) { + TryResult::Continue(ordinary_own_property_keys(agent, backing_object, gc)) + } else { + TryResult::Continue(vec![ + BUILTIN_STRING_MEMORY.length.into(), + BUILTIN_STRING_MEMORY.name.into(), + ]) + } + } + + fn internal_call<'gc>( + self, + agent: &mut Agent, + this_value: Value, + arguments_list: ArgumentsList, + gc: GcScope<'gc, '_>, + ) -> JsResult<'gc, Value<'gc>> { + self.function_call(agent, this_value, arguments_list, gc) } -} -pub(crate) fn function_internal_own_property_keys<'a, 'b>( - func: impl FunctionInternalProperties<'a>, - agent: &mut Agent, - gc: NoGcScope<'b, '_>, -) -> Vec> { - if let Some(backing_object) = func.get_backing_object(agent) { - ordinary_own_property_keys(agent, backing_object, gc) - } else { - vec![ - BUILTIN_STRING_MEMORY.length.into(), - BUILTIN_STRING_MEMORY.name.into(), - ] + fn internal_construct<'gc>( + self, + agent: &mut Agent, + arguments_list: ArgumentsList, + new_target: Function, + gc: GcScope<'gc, '_>, + ) -> JsResult<'gc, Object<'gc>> { + self.function_construct(agent, arguments_list, new_target, gc) } } diff --git a/nova_vm/src/ecmascript/types/language/object.rs b/nova_vm/src/ecmascript/types/language/object.rs index 8796709cd..dcf78196d 100644 --- a/nova_vm/src/ecmascript/types/language/object.rs +++ b/nova_vm/src/ecmascript/types/language/object.rs @@ -41,6 +41,7 @@ use super::{ BOUND_FUNCTION_DISCRIMINANT, BUILTIN_CONSTRUCTOR_FUNCTION_DISCRIMINANT, BUILTIN_FUNCTION_DISCRIMINANT, BUILTIN_GENERATOR_FUNCTION_DISCRIMINANT, BUILTIN_PROMISE_COLLECTOR_FUNCTION_DISCRIMINANT, + BUILTIN_PROMISE_FINALLY_FUNCTION_DISCRIMINANT, BUILTIN_PROMISE_RESOLVING_FUNCTION_DISCRIMINANT, BUILTIN_PROXY_REVOKER_FUNCTION, ECMASCRIPT_FUNCTION_DISCRIMINANT, EMBEDDER_OBJECT_DISCRIMINANT, ERROR_DISCRIMINANT, FINALIZATION_REGISTRY_DISCRIMINANT, GENERATOR_DISCRIMINANT, MAP_DISCRIMINANT, @@ -95,6 +96,7 @@ use crate::{ }, primitive_objects::PrimitiveObject, promise::Promise, + promise_objects::promise_abstract_operations::promise_finally_functions::BuiltinPromiseFinallyFunction, proxy::Proxy, text_processing::string_objects::string_iterator_objects::StringIterator, }, @@ -141,6 +143,8 @@ pub enum Object<'a> { BUILTIN_CONSTRUCTOR_FUNCTION_DISCRIMINANT, BuiltinPromiseResolvingFunction(BuiltinPromiseResolvingFunction<'a>) = BUILTIN_PROMISE_RESOLVING_FUNCTION_DISCRIMINANT, + BuiltinPromiseFinallyFunction(BuiltinPromiseFinallyFunction<'a>) = + BUILTIN_PROMISE_FINALLY_FUNCTION_DISCRIMINANT, BuiltinPromiseCollectorFunction = BUILTIN_PROMISE_COLLECTOR_FUNCTION_DISCRIMINANT, BuiltinProxyRevokerFunction = BUILTIN_PROXY_REVOKER_FUNCTION, PrimitiveObject(PrimitiveObject<'a>) = PRIMITIVE_OBJECT_DISCRIMINANT, @@ -699,6 +703,9 @@ impl<'a> From> for Value<'a> { Object::BuiltinPromiseResolvingFunction(data) => { Value::BuiltinPromiseResolvingFunction(data.unbind()) } + Object::BuiltinPromiseFinallyFunction(data) => { + Value::BuiltinPromiseFinallyFunction(data.unbind()) + } Object::BuiltinPromiseCollectorFunction => Value::BuiltinPromiseCollectorFunction, Object::BuiltinProxyRevokerFunction => Value::BuiltinProxyRevokerFunction, Object::PrimitiveObject(data) => Value::PrimitiveObject(data.unbind()), @@ -793,6 +800,9 @@ impl<'a> TryFrom> for Object<'a> { Value::BuiltinPromiseResolvingFunction(data) => { Ok(Object::BuiltinPromiseResolvingFunction(data)) } + Value::BuiltinPromiseFinallyFunction(data) => { + Ok(Object::BuiltinPromiseFinallyFunction(data)) + } Value::BuiltinPromiseCollectorFunction => Ok(Object::BuiltinPromiseCollectorFunction), Value::BuiltinProxyRevokerFunction => Ok(Object::BuiltinProxyRevokerFunction), Value::PrimitiveObject(data) => Ok(Object::PrimitiveObject(data)), @@ -872,6 +882,7 @@ impl Hash for Object<'_> { Object::BuiltinGeneratorFunction => {} Object::BuiltinConstructorFunction(data) => data.get_index().hash(state), Object::BuiltinPromiseResolvingFunction(data) => data.get_index().hash(state), + Object::BuiltinPromiseFinallyFunction(data) => data.get_index().hash(state), Object::BuiltinPromiseCollectorFunction => {} Object::BuiltinProxyRevokerFunction => {} Object::PrimitiveObject(data) => data.get_index().hash(state), @@ -954,6 +965,7 @@ impl<'a> InternalSlots<'a> for Object<'a> { Object::BuiltinGeneratorFunction => todo!(), Object::BuiltinConstructorFunction(data) => data.get_backing_object(agent), Object::BuiltinPromiseResolvingFunction(data) => data.get_backing_object(agent), + Object::BuiltinPromiseFinallyFunction(data) => data.get_backing_object(agent), Object::BuiltinPromiseCollectorFunction => todo!(), Object::BuiltinProxyRevokerFunction => todo!(), Object::PrimitiveObject(data) => data.get_backing_object(agent), @@ -1044,6 +1056,7 @@ impl<'a> InternalSlots<'a> for Object<'a> { Object::BuiltinPromiseResolvingFunction(data) => { data.get_or_create_backing_object(agent) } + Object::BuiltinPromiseFinallyFunction(data) => data.get_or_create_backing_object(agent), Object::BuiltinPromiseCollectorFunction => todo!(), Object::BuiltinProxyRevokerFunction => todo!(), Object::PrimitiveObject(data) => data.get_or_create_backing_object(agent), @@ -1142,6 +1155,7 @@ impl<'a> InternalSlots<'a> for Object<'a> { Object::BuiltinGeneratorFunction => todo!(), Object::BuiltinConstructorFunction(data) => data.object_shape(agent), Object::BuiltinPromiseResolvingFunction(data) => data.object_shape(agent), + Object::BuiltinPromiseFinallyFunction(data) => data.object_shape(agent), Object::BuiltinPromiseCollectorFunction => todo!(), Object::BuiltinProxyRevokerFunction => todo!(), Object::PrimitiveObject(data) => data.object_shape(agent), @@ -1218,6 +1232,7 @@ impl<'a> InternalSlots<'a> for Object<'a> { Object::BuiltinGeneratorFunction => todo!(), Object::BuiltinConstructorFunction(data) => data.internal_extensible(agent), Object::BuiltinPromiseResolvingFunction(data) => data.internal_extensible(agent), + Object::BuiltinPromiseFinallyFunction(data) => data.internal_extensible(agent), Object::BuiltinPromiseCollectorFunction => todo!(), Object::BuiltinProxyRevokerFunction => todo!(), Object::PrimitiveObject(data) => data.internal_extensible(agent), @@ -1300,6 +1315,9 @@ impl<'a> InternalSlots<'a> for Object<'a> { Object::BuiltinPromiseResolvingFunction(data) => { data.internal_set_extensible(agent, value) } + Object::BuiltinPromiseFinallyFunction(data) => { + data.internal_set_extensible(agent, value) + } Object::BuiltinPromiseCollectorFunction => todo!(), Object::BuiltinProxyRevokerFunction => todo!(), Object::PrimitiveObject(data) => data.internal_set_extensible(agent, value), @@ -1398,6 +1416,7 @@ impl<'a> InternalSlots<'a> for Object<'a> { Object::BuiltinGeneratorFunction => todo!(), Object::BuiltinConstructorFunction(data) => data.internal_prototype(agent), Object::BuiltinPromiseResolvingFunction(data) => data.internal_prototype(agent), + Object::BuiltinPromiseFinallyFunction(data) => data.internal_prototype(agent), Object::BuiltinPromiseCollectorFunction => todo!(), Object::BuiltinProxyRevokerFunction => todo!(), Object::PrimitiveObject(data) => data.internal_prototype(agent), @@ -1482,6 +1501,9 @@ impl<'a> InternalSlots<'a> for Object<'a> { Object::BuiltinPromiseResolvingFunction(data) => { data.internal_set_prototype(agent, prototype) } + Object::BuiltinPromiseFinallyFunction(data) => { + data.internal_set_prototype(agent, prototype) + } Object::BuiltinPromiseCollectorFunction => todo!(), Object::BuiltinProxyRevokerFunction => todo!(), Object::PrimitiveObject(data) => data.internal_set_prototype(agent, prototype), @@ -1586,6 +1608,7 @@ impl<'a> InternalMethods<'a> for Object<'a> { Object::BuiltinGeneratorFunction => todo!(), Object::BuiltinConstructorFunction(data) => data.try_get_prototype_of(agent, gc), Object::BuiltinPromiseResolvingFunction(data) => data.try_get_prototype_of(agent, gc), + Object::BuiltinPromiseFinallyFunction(data) => data.try_get_prototype_of(agent, gc), Object::BuiltinPromiseCollectorFunction => todo!(), Object::BuiltinProxyRevokerFunction => todo!(), Object::PrimitiveObject(data) => data.try_get_prototype_of(agent, gc), @@ -1688,6 +1711,9 @@ impl<'a> InternalMethods<'a> for Object<'a> { Object::BuiltinPromiseResolvingFunction(data) => { data.internal_get_prototype_of(agent, gc) } + Object::BuiltinPromiseFinallyFunction(data) => { + data.internal_get_prototype_of(agent, gc) + } Object::BuiltinPromiseCollectorFunction => todo!(), Object::BuiltinProxyRevokerFunction => todo!(), Object::PrimitiveObject(data) => data.internal_get_prototype_of(agent, gc), @@ -1795,6 +1821,9 @@ impl<'a> InternalMethods<'a> for Object<'a> { Object::BuiltinPromiseResolvingFunction(data) => { data.try_set_prototype_of(agent, prototype, gc) } + Object::BuiltinPromiseFinallyFunction(data) => { + data.try_set_prototype_of(agent, prototype, gc) + } Object::BuiltinPromiseCollectorFunction => todo!(), Object::BuiltinProxyRevokerFunction => todo!(), Object::PrimitiveObject(data) => data.try_set_prototype_of(agent, prototype, gc), @@ -1904,6 +1933,9 @@ impl<'a> InternalMethods<'a> for Object<'a> { Object::BuiltinPromiseResolvingFunction(data) => { data.internal_set_prototype_of(agent, prototype, gc) } + Object::BuiltinPromiseFinallyFunction(data) => { + data.internal_set_prototype_of(agent, prototype, gc) + } Object::BuiltinPromiseCollectorFunction => todo!(), Object::BuiltinProxyRevokerFunction => todo!(), Object::PrimitiveObject(data) => data.internal_set_prototype_of(agent, prototype, gc), @@ -2008,6 +2040,7 @@ impl<'a> InternalMethods<'a> for Object<'a> { Object::BuiltinGeneratorFunction => todo!(), Object::BuiltinConstructorFunction(data) => data.try_is_extensible(agent, gc), Object::BuiltinPromiseResolvingFunction(data) => data.try_is_extensible(agent, gc), + Object::BuiltinPromiseFinallyFunction(data) => data.try_is_extensible(agent, gc), Object::BuiltinPromiseCollectorFunction => todo!(), Object::BuiltinProxyRevokerFunction => todo!(), Object::PrimitiveObject(data) => data.try_is_extensible(agent, gc), @@ -2098,6 +2131,7 @@ impl<'a> InternalMethods<'a> for Object<'a> { Object::BuiltinGeneratorFunction => todo!(), Object::BuiltinConstructorFunction(data) => data.internal_is_extensible(agent, gc), Object::BuiltinPromiseResolvingFunction(data) => data.internal_is_extensible(agent, gc), + Object::BuiltinPromiseFinallyFunction(data) => data.internal_is_extensible(agent, gc), Object::BuiltinPromiseCollectorFunction => todo!(), Object::BuiltinProxyRevokerFunction => todo!(), Object::PrimitiveObject(data) => data.internal_is_extensible(agent, gc), @@ -2200,6 +2234,7 @@ impl<'a> InternalMethods<'a> for Object<'a> { Object::BuiltinGeneratorFunction => todo!(), Object::BuiltinConstructorFunction(data) => data.try_prevent_extensions(agent, gc), Object::BuiltinPromiseResolvingFunction(data) => data.try_prevent_extensions(agent, gc), + Object::BuiltinPromiseFinallyFunction(data) => data.try_prevent_extensions(agent, gc), Object::BuiltinPromiseCollectorFunction => todo!(), Object::BuiltinProxyRevokerFunction => todo!(), Object::PrimitiveObject(data) => data.try_prevent_extensions(agent, gc), @@ -2304,6 +2339,9 @@ impl<'a> InternalMethods<'a> for Object<'a> { Object::BuiltinPromiseResolvingFunction(data) => { data.internal_prevent_extensions(agent, gc) } + Object::BuiltinPromiseFinallyFunction(data) => { + data.internal_prevent_extensions(agent, gc) + } Object::BuiltinPromiseCollectorFunction => todo!(), Object::BuiltinProxyRevokerFunction => todo!(), Object::PrimitiveObject(data) => data.internal_prevent_extensions(agent, gc), @@ -2418,6 +2456,9 @@ impl<'a> InternalMethods<'a> for Object<'a> { Object::BuiltinPromiseResolvingFunction(data) => { data.try_get_own_property(agent, property_key, cache, gc) } + Object::BuiltinPromiseFinallyFunction(data) => { + data.try_get_own_property(agent, property_key, cache, gc) + } Object::BuiltinPromiseCollectorFunction => todo!(), Object::BuiltinProxyRevokerFunction => todo!(), Object::PrimitiveObject(data) => { @@ -2545,6 +2586,9 @@ impl<'a> InternalMethods<'a> for Object<'a> { Object::BuiltinPromiseResolvingFunction(data) => { data.internal_get_own_property(agent, property_key, gc) } + Object::BuiltinPromiseFinallyFunction(data) => { + data.internal_get_own_property(agent, property_key, gc) + } Object::BuiltinPromiseCollectorFunction => todo!(), Object::BuiltinProxyRevokerFunction => todo!(), Object::PrimitiveObject(data) => { @@ -2675,6 +2719,9 @@ impl<'a> InternalMethods<'a> for Object<'a> { Object::BuiltinPromiseResolvingFunction(data) => { data.try_define_own_property(agent, property_key, property_descriptor, cache, gc) } + Object::BuiltinPromiseFinallyFunction(data) => { + data.try_define_own_property(agent, property_key, property_descriptor, cache, gc) + } Object::BuiltinPromiseCollectorFunction => todo!(), Object::BuiltinProxyRevokerFunction => todo!(), Object::PrimitiveObject(data) => { @@ -2879,6 +2926,9 @@ impl<'a> InternalMethods<'a> for Object<'a> { Object::BuiltinPromiseResolvingFunction(data) => { data.internal_define_own_property(agent, property_key, property_descriptor, gc) } + Object::BuiltinPromiseFinallyFunction(data) => { + data.internal_define_own_property(agent, property_key, property_descriptor, gc) + } Object::BuiltinPromiseCollectorFunction => todo!(), Object::BuiltinProxyRevokerFunction => todo!(), Object::PrimitiveObject(data) => { @@ -3035,6 +3085,9 @@ impl<'a> InternalMethods<'a> for Object<'a> { Object::BuiltinPromiseResolvingFunction(data) => { data.try_has_property(agent, property_key, cache, gc) } + Object::BuiltinPromiseFinallyFunction(data) => { + data.try_has_property(agent, property_key, cache, gc) + } Object::BuiltinPromiseCollectorFunction => todo!(), Object::BuiltinProxyRevokerFunction => todo!(), Object::PrimitiveObject(data) => data.try_has_property(agent, property_key, cache, gc), @@ -3146,6 +3199,9 @@ impl<'a> InternalMethods<'a> for Object<'a> { Object::BuiltinPromiseResolvingFunction(data) => { data.internal_has_property(agent, property_key, gc) } + Object::BuiltinPromiseFinallyFunction(data) => { + data.internal_has_property(agent, property_key, gc) + } Object::BuiltinPromiseCollectorFunction => todo!(), Object::BuiltinProxyRevokerFunction => todo!(), Object::PrimitiveObject(data) => data.internal_has_property(agent, property_key, gc), @@ -3259,6 +3315,9 @@ impl<'a> InternalMethods<'a> for Object<'a> { Object::BuiltinPromiseResolvingFunction(data) => { data.try_get(agent, property_key, receiver, cache, gc) } + Object::BuiltinPromiseFinallyFunction(data) => { + data.try_get(agent, property_key, receiver, cache, gc) + } Object::BuiltinPromiseCollectorFunction => todo!(), Object::BuiltinProxyRevokerFunction => todo!(), Object::PrimitiveObject(data) => data.try_get(agent, property_key, receiver, cache, gc), @@ -3377,6 +3436,9 @@ impl<'a> InternalMethods<'a> for Object<'a> { Object::BuiltinPromiseResolvingFunction(data) => { data.internal_get(agent, property_key, receiver, gc) } + Object::BuiltinPromiseFinallyFunction(data) => { + data.internal_get(agent, property_key, receiver, gc) + } Object::BuiltinPromiseCollectorFunction => todo!(), Object::BuiltinProxyRevokerFunction => todo!(), Object::PrimitiveObject(data) => data.internal_get(agent, property_key, receiver, gc), @@ -3497,6 +3559,9 @@ impl<'a> InternalMethods<'a> for Object<'a> { Object::BuiltinPromiseResolvingFunction(data) => { data.try_set(agent, property_key, value, receiver, cache, gc) } + Object::BuiltinPromiseFinallyFunction(data) => { + data.try_set(agent, property_key, value, receiver, cache, gc) + } Object::BuiltinPromiseCollectorFunction => todo!(), Object::BuiltinProxyRevokerFunction => todo!(), Object::PrimitiveObject(data) => { @@ -3691,6 +3756,9 @@ impl<'a> InternalMethods<'a> for Object<'a> { Object::BuiltinPromiseResolvingFunction(data) => { data.internal_set(agent, property_key, value, receiver, gc) } + Object::BuiltinPromiseFinallyFunction(data) => { + data.internal_set(agent, property_key, value, receiver, gc) + } Object::BuiltinPromiseCollectorFunction => todo!(), Object::BuiltinProxyRevokerFunction => todo!(), Object::PrimitiveObject(data) => { @@ -3838,6 +3906,7 @@ impl<'a> InternalMethods<'a> for Object<'a> { Object::BuiltinPromiseResolvingFunction(data) => { data.try_delete(agent, property_key, gc) } + Object::BuiltinPromiseFinallyFunction(data) => data.try_delete(agent, property_key, gc), Object::BuiltinPromiseCollectorFunction => todo!(), Object::BuiltinProxyRevokerFunction => todo!(), Object::PrimitiveObject(data) => data.try_delete(agent, property_key, gc), @@ -3945,6 +4014,9 @@ impl<'a> InternalMethods<'a> for Object<'a> { Object::BuiltinPromiseResolvingFunction(data) => { data.internal_delete(agent, property_key, gc) } + Object::BuiltinPromiseFinallyFunction(data) => { + data.internal_delete(agent, property_key, gc) + } Object::BuiltinPromiseCollectorFunction => todo!(), Object::BuiltinProxyRevokerFunction => todo!(), Object::PrimitiveObject(data) => data.internal_delete(agent, property_key, gc), @@ -4047,6 +4119,7 @@ impl<'a> InternalMethods<'a> for Object<'a> { Object::BuiltinGeneratorFunction => todo!(), Object::BuiltinConstructorFunction(data) => data.try_own_property_keys(agent, gc), Object::BuiltinPromiseResolvingFunction(data) => data.try_own_property_keys(agent, gc), + Object::BuiltinPromiseFinallyFunction(data) => data.try_own_property_keys(agent, gc), Object::BuiltinPromiseCollectorFunction => todo!(), Object::BuiltinProxyRevokerFunction => todo!(), Object::PrimitiveObject(data) => data.try_own_property_keys(agent, gc), @@ -4149,6 +4222,9 @@ impl<'a> InternalMethods<'a> for Object<'a> { Object::BuiltinPromiseResolvingFunction(data) => { data.internal_own_property_keys(agent, gc) } + Object::BuiltinPromiseFinallyFunction(data) => { + data.internal_own_property_keys(agent, gc) + } Object::BuiltinPromiseCollectorFunction => todo!(), Object::BuiltinProxyRevokerFunction => todo!(), Object::PrimitiveObject(data) => data.internal_own_property_keys(agent, gc), @@ -4256,6 +4332,9 @@ impl<'a> InternalMethods<'a> for Object<'a> { Object::BuiltinPromiseResolvingFunction(data) => { data.get_own_property_at_offset(agent, offset, gc) } + Object::BuiltinPromiseFinallyFunction(data) => { + data.get_own_property_at_offset(agent, offset, gc) + } Object::BuiltinPromiseCollectorFunction => todo!(), Object::BuiltinProxyRevokerFunction => todo!(), Object::PrimitiveObject(data) => data.get_own_property_at_offset(agent, offset, gc), @@ -4366,6 +4445,9 @@ impl<'a> InternalMethods<'a> for Object<'a> { Object::BuiltinPromiseResolvingFunction(data) => { data.set_at_offset(agent, props, offset, gc) } + Object::BuiltinPromiseFinallyFunction(data) => { + data.set_at_offset(agent, props, offset, gc) + } Object::BuiltinPromiseCollectorFunction => todo!(), Object::BuiltinProxyRevokerFunction => todo!(), Object::PrimitiveObject(data) => data.set_at_offset(agent, props, offset, gc), @@ -4505,6 +4587,7 @@ impl HeapMarkAndSweep for Object<'static> { Self::BuiltinGeneratorFunction => todo!(), Self::BuiltinConstructorFunction(data) => data.mark_values(queues), Self::BuiltinPromiseResolvingFunction(data) => data.mark_values(queues), + Self::BuiltinPromiseFinallyFunction(data) => data.mark_values(queues), Self::BuiltinPromiseCollectorFunction => todo!(), Self::BuiltinProxyRevokerFunction => todo!(), Self::PrimitiveObject(data) => data.mark_values(queues), @@ -4573,6 +4656,7 @@ impl HeapMarkAndSweep for Object<'static> { Self::BuiltinGeneratorFunction => todo!(), Self::BuiltinConstructorFunction(data) => data.sweep_values(compactions), Self::BuiltinPromiseResolvingFunction(data) => data.sweep_values(compactions), + Self::BuiltinPromiseFinallyFunction(data) => data.sweep_values(compactions), Self::BuiltinPromiseCollectorFunction => todo!(), Self::BuiltinProxyRevokerFunction => todo!(), Self::PrimitiveObject(data) => data.sweep_values(compactions), @@ -4659,6 +4743,9 @@ impl HeapSweepWeakReference for Object<'static> { Self::BuiltinPromiseResolvingFunction(data) => data .sweep_weak_reference(compactions) .map(Self::BuiltinPromiseResolvingFunction), + Self::BuiltinPromiseFinallyFunction(data) => data + .sweep_weak_reference(compactions) + .map(Self::BuiltinPromiseFinallyFunction), Self::BuiltinPromiseCollectorFunction => Some(Self::BuiltinPromiseCollectorFunction), Self::BuiltinProxyRevokerFunction => Some(Self::BuiltinProxyRevokerFunction), Self::PrimitiveObject(data) => data @@ -4808,6 +4895,9 @@ impl TryFrom for Object<'_> { builtin_promise_resolving_function, )) } + HeapRootData::BuiltinPromiseFinallyFunction(builtin_promise_finally_function) => Ok( + Self::BuiltinPromiseFinallyFunction(builtin_promise_finally_function), + ), HeapRootData::BuiltinPromiseCollectorFunction => { Ok(Self::BuiltinPromiseCollectorFunction) } diff --git a/nova_vm/src/ecmascript/types/language/object/internal_methods.rs b/nova_vm/src/ecmascript/types/language/object/internal_methods.rs index 003c2bd0c..ebd2aa7ae 100644 --- a/nova_vm/src/ecmascript/types/language/object/internal_methods.rs +++ b/nova_vm/src/ecmascript/types/language/object/internal_methods.rs @@ -546,23 +546,25 @@ where } /// ## \[\[Call\]\] + #[allow(unused_variables)] fn internal_call<'gc>( self, - _agent: &mut Agent, - _this_value: Value, - _arguments_list: ArgumentsList, - _gc: GcScope<'gc, '_>, + agent: &mut Agent, + this_value: Value, + arguments_list: ArgumentsList, + gc: GcScope<'gc, '_>, ) -> JsResult<'gc, Value<'gc>> { unreachable!() } /// ## \[\[Construct\]\] + #[allow(unused_variables)] fn internal_construct<'gc>( self, - _agent: &mut Agent, - _arguments_list: ArgumentsList, - _new_target: Function, - _gc: GcScope<'gc, '_>, + agent: &mut Agent, + arguments_list: ArgumentsList, + new_target: Function, + gc: GcScope<'gc, '_>, ) -> JsResult<'gc, Object<'gc>> { unreachable!() } diff --git a/nova_vm/src/ecmascript/types/language/value.rs b/nova_vm/src/ecmascript/types/language/value.rs index bb755525a..af2c38f35 100644 --- a/nova_vm/src/ecmascript/types/language/value.rs +++ b/nova_vm/src/ecmascript/types/language/value.rs @@ -42,6 +42,7 @@ use crate::{ module::Module, primitive_objects::PrimitiveObject, promise::Promise, + promise_objects::promise_abstract_operations::promise_finally_functions::BuiltinPromiseFinallyFunction, proxy::Proxy, text_processing::string_objects::string_iterator_objects::StringIterator, }, @@ -140,6 +141,7 @@ pub enum Value<'a> { /// [ClassDefinitionEvaluation](https://tc39.es/ecma262/#sec-runtime-semantics-classdefinitionevaluation). BuiltinConstructorFunction(BuiltinConstructorFunction<'a>), BuiltinPromiseResolvingFunction(BuiltinPromiseResolvingFunction<'a>), + BuiltinPromiseFinallyFunction(BuiltinPromiseFinallyFunction<'a>), BuiltinPromiseCollectorFunction, BuiltinProxyRevokerFunction, @@ -285,6 +287,9 @@ pub(crate) const BUILTIN_CONSTRUCTOR_FUNCTION_DISCRIMINANT: u8 = value_discrimin pub(crate) const BUILTIN_PROMISE_RESOLVING_FUNCTION_DISCRIMINANT: u8 = value_discriminant( Value::BuiltinPromiseResolvingFunction(BuiltinPromiseResolvingFunction::_def()), ); +pub(crate) const BUILTIN_PROMISE_FINALLY_FUNCTION_DISCRIMINANT: u8 = value_discriminant( + Value::BuiltinPromiseFinallyFunction(BuiltinPromiseFinallyFunction::_def()), +); pub(crate) const BUILTIN_PROMISE_COLLECTOR_FUNCTION_DISCRIMINANT: u8 = value_discriminant(Value::BuiltinPromiseCollectorFunction); pub(crate) const BUILTIN_PROXY_REVOKER_FUNCTION: u8 = @@ -707,6 +712,10 @@ impl<'a> Value<'a> { discriminant.hash(hasher); data.get_index().hash(hasher); } + Value::BuiltinPromiseFinallyFunction(data) => { + discriminant.hash(hasher); + data.get_index().hash(hasher); + } Value::BuiltinPromiseCollectorFunction => todo!(), Value::BuiltinProxyRevokerFunction => todo!(), Value::PrimitiveObject(data) => { @@ -941,6 +950,10 @@ impl<'a> Value<'a> { discriminant.hash(hasher); data.get_index().hash(hasher); } + Value::BuiltinPromiseFinallyFunction(data) => { + discriminant.hash(hasher); + data.get_index().hash(hasher); + } Value::BuiltinPromiseCollectorFunction => todo!(), Value::BuiltinProxyRevokerFunction => todo!(), Value::PrimitiveObject(data) => { @@ -1253,6 +1266,11 @@ impl Rootable for Value<'_> { builtin_promise_resolving_function.unbind(), )) } + Self::BuiltinPromiseFinallyFunction(builtin_promise_finally_function) => { + Err(HeapRootData::BuiltinPromiseFinallyFunction( + builtin_promise_finally_function.unbind(), + )) + } Self::BuiltinPromiseCollectorFunction => { Err(HeapRootData::BuiltinPromiseCollectorFunction) } @@ -1391,6 +1409,9 @@ impl Rootable for Value<'_> { builtin_promise_resolving_function, )) } + HeapRootData::BuiltinPromiseFinallyFunction(builtin_promise_finally_function) => Some( + Self::BuiltinPromiseFinallyFunction(builtin_promise_finally_function), + ), HeapRootData::BuiltinPromiseCollectorFunction => { Some(Self::BuiltinPromiseCollectorFunction) } @@ -1574,6 +1595,7 @@ impl HeapMarkAndSweep for Value<'static> { Value::BuiltinGeneratorFunction => todo!(), Value::BuiltinConstructorFunction(data) => data.mark_values(queues), Value::BuiltinPromiseResolvingFunction(data) => data.mark_values(queues), + Value::BuiltinPromiseFinallyFunction(data) => data.mark_values(queues), Value::BuiltinPromiseCollectorFunction => todo!(), Value::BuiltinProxyRevokerFunction => todo!(), Value::AsyncFromSyncIterator => todo!(), @@ -1661,6 +1683,7 @@ impl HeapMarkAndSweep for Value<'static> { Value::BuiltinGeneratorFunction => todo!(), Value::BuiltinConstructorFunction(data) => data.sweep_values(compactions), Value::BuiltinPromiseResolvingFunction(data) => data.sweep_values(compactions), + Value::BuiltinPromiseFinallyFunction(data) => data.sweep_values(compactions), Value::BuiltinPromiseCollectorFunction => todo!(), Value::BuiltinProxyRevokerFunction => todo!(), Value::AsyncFromSyncIterator => todo!(), @@ -1685,6 +1708,7 @@ fn map_object_to_static_string_repr(value: Value) -> String<'static> { | Object::BuiltinGeneratorFunction | Object::BuiltinConstructorFunction(_) | Object::BuiltinPromiseResolvingFunction(_) + | Object::BuiltinPromiseFinallyFunction(_) | Object::BuiltinPromiseCollectorFunction | Object::BuiltinProxyRevokerFunction => BUILTIN_STRING_MEMORY._object_Function_, Object::Arguments(_) => BUILTIN_STRING_MEMORY._object_Arguments_, diff --git a/nova_vm/src/engine/bytecode/vm.rs b/nova_vm/src/engine/bytecode/vm.rs index 13aa0bf98..bde8e7947 100644 --- a/nova_vm/src/engine/bytecode/vm.rs +++ b/nova_vm/src/engine/bytecode/vm.rs @@ -3443,6 +3443,7 @@ fn typeof_operator(agent: &Agent, val: Value, gc: NoGcScope) -> String<'static> Value::BuiltinGeneratorFunction | Value::BuiltinConstructorFunction(_) | Value::BuiltinPromiseResolvingFunction(_) | + Value::BuiltinPromiseFinallyFunction(_) | Value::BuiltinPromiseCollectorFunction | Value::BuiltinProxyRevokerFunction => BUILTIN_STRING_MEMORY.function, Value::Proxy(proxy) => { diff --git a/nova_vm/src/engine/rootable.rs b/nova_vm/src/engine/rootable.rs index 576ea5d38..cae241072 100644 --- a/nova_vm/src/engine/rootable.rs +++ b/nova_vm/src/engine/rootable.rs @@ -66,6 +66,7 @@ use crate::{ primitive_objects::PrimitiveObject, promise::Promise, promise_objects::promise_abstract_operations::{ + promise_finally_functions::BuiltinPromiseFinallyFunction, promise_reaction_records::PromiseReaction, promise_resolving_functions::BuiltinPromiseResolvingFunction, }, @@ -87,6 +88,7 @@ use crate::{ BUILTIN_CONSTRUCTOR_FUNCTION_DISCRIMINANT, BUILTIN_FUNCTION_DISCRIMINANT, BUILTIN_GENERATOR_FUNCTION_DISCRIMINANT, BUILTIN_PROMISE_COLLECTOR_FUNCTION_DISCRIMINANT, + BUILTIN_PROMISE_FINALLY_FUNCTION_DISCRIMINANT, BUILTIN_PROMISE_RESOLVING_FUNCTION_DISCRIMINANT, BUILTIN_PROXY_REVOKER_FUNCTION, ECMASCRIPT_FUNCTION_DISCRIMINANT, EMBEDDER_OBJECT_DISCRIMINANT, ERROR_DISCRIMINANT, FINALIZATION_REGISTRY_DISCRIMINANT, GENERATOR_DISCRIMINANT, HeapNumber, HeapString, @@ -137,6 +139,7 @@ pub mod private { primitive_objects::PrimitiveObject, promise::Promise, promise_objects::promise_abstract_operations::{ + promise_finally_functions::BuiltinPromiseFinallyFunction, promise_reaction_records::PromiseReaction, promise_resolving_functions::BuiltinPromiseResolvingFunction, }, @@ -179,6 +182,7 @@ pub mod private { impl RootableSealed for BuiltinConstructorFunction<'_> {} impl RootableSealed for BuiltinFunction<'_> {} impl RootableSealed for BuiltinPromiseResolvingFunction<'_> {} + impl RootableSealed for BuiltinPromiseFinallyFunction<'_> {} #[cfg(feature = "array-buffer")] impl RootableSealed for DataView<'_> {} #[cfg(feature = "date")] @@ -465,6 +469,8 @@ pub enum HeapRootData { BUILTIN_CONSTRUCTOR_FUNCTION_DISCRIMINANT, BuiltinPromiseResolvingFunction(BuiltinPromiseResolvingFunction<'static>) = BUILTIN_PROMISE_RESOLVING_FUNCTION_DISCRIMINANT, + BuiltinPromiseFinallyFunction(BuiltinPromiseFinallyFunction<'static>) = + BUILTIN_PROMISE_FINALLY_FUNCTION_DISCRIMINANT, BuiltinPromiseCollectorFunction = BUILTIN_PROMISE_COLLECTOR_FUNCTION_DISCRIMINANT, BuiltinProxyRevokerFunction = BUILTIN_PROXY_REVOKER_FUNCTION, PrimitiveObject(PrimitiveObject<'static>), @@ -567,6 +573,7 @@ impl From> for HeapRootData { Object::BuiltinPromiseResolvingFunction(builtin_promise_resolving_function) => { Self::BuiltinPromiseResolvingFunction(builtin_promise_resolving_function) } + Object::BuiltinPromiseFinallyFunction(f) => Self::BuiltinPromiseFinallyFunction(f), Object::BuiltinPromiseCollectorFunction => Self::BuiltinPromiseCollectorFunction, Object::BuiltinProxyRevokerFunction => Self::BuiltinProxyRevokerFunction, Object::PrimitiveObject(primitive_object) => Self::PrimitiveObject(primitive_object), @@ -676,6 +683,9 @@ impl HeapMarkAndSweep for HeapRootData { HeapRootData::BuiltinPromiseResolvingFunction(builtin_promise_resolving_function) => { builtin_promise_resolving_function.mark_values(queues) } + HeapRootData::BuiltinPromiseFinallyFunction(builtin_promise_finally_function) => { + builtin_promise_finally_function.mark_values(queues) + } HeapRootData::BuiltinPromiseCollectorFunction => todo!(), HeapRootData::BuiltinProxyRevokerFunction => todo!(), HeapRootData::PrimitiveObject(primitive_object) => primitive_object.mark_values(queues), @@ -795,6 +805,9 @@ impl HeapMarkAndSweep for HeapRootData { HeapRootData::BuiltinPromiseResolvingFunction(builtin_promise_resolving_function) => { builtin_promise_resolving_function.sweep_values(compactions) } + HeapRootData::BuiltinPromiseFinallyFunction(builtin_promise_finally_function) => { + builtin_promise_finally_function.sweep_values(compactions); + } HeapRootData::BuiltinPromiseCollectorFunction => todo!(), HeapRootData::BuiltinProxyRevokerFunction => todo!(), HeapRootData::PrimitiveObject(primitive_object) => { diff --git a/nova_vm/src/heap.rs b/nova_vm/src/heap.rs index 77c966b42..684990e3b 100644 --- a/nova_vm/src/heap.rs +++ b/nova_vm/src/heap.rs @@ -80,6 +80,7 @@ use crate::{ }, primitive_objects::PrimitiveObjectHeapData, promise::data::PromiseHeapData, + promise_objects::promise_abstract_operations::promise_finally_functions::PromiseFinallyFunctionHeapData, proxy::data::ProxyHeapData, text_processing::string_objects::string_iterator_objects::StringIteratorHeapData, }, @@ -167,6 +168,7 @@ pub struct Heap { pub primitive_objects: Vec>>, pub promise_reaction_records: Vec>>, pub promise_resolving_functions: Vec>>, + pub promise_finally_functions: Vec>, pub promises: Vec>>, pub proxys: Vec>>, pub realms: Vec>>, @@ -312,6 +314,7 @@ impl Heap { primitive_objects: Vec::with_capacity(0), promise_reaction_records: Vec::with_capacity(0), promise_resolving_functions: Vec::with_capacity(0), + promise_finally_functions: Vec::with_capacity(0), promises: Vec::with_capacity(0), proxys: Vec::with_capacity(0), realms: Vec::with_capacity(1), diff --git a/nova_vm/src/heap/heap_bits.rs b/nova_vm/src/heap/heap_bits.rs index 79cbb0d9a..71cc06731 100644 --- a/nova_vm/src/heap/heap_bits.rs +++ b/nova_vm/src/heap/heap_bits.rs @@ -50,6 +50,7 @@ use crate::ecmascript::{ ordinary::{caches::PropertyLookupCache, shape::ObjectShape}, primitive_objects::PrimitiveObject, promise::Promise, + promise_objects::promise_abstract_operations::promise_finally_functions::BuiltinPromiseFinallyFunction, proxy::Proxy, text_processing::string_objects::string_iterator_objects::StringIterator, }, @@ -125,6 +126,7 @@ pub struct HeapBits { pub private_environments: Box<[bool]>, pub promise_reaction_records: Box<[bool]>, pub promise_resolving_functions: Box<[bool]>, + pub promise_finally_functions: Box<[bool]>, pub promises: Box<[bool]>, pub proxys: Box<[bool]>, pub realms: Box<[bool]>, @@ -208,6 +210,7 @@ pub(crate) struct WorkQueues { pub promises: Vec>, pub promise_reaction_records: Vec>, pub promise_resolving_functions: Vec>, + pub promise_finally_functions: Vec>, pub proxys: Vec>, pub realms: Vec>, #[cfg(feature = "regexp")] @@ -288,6 +291,7 @@ impl HeapBits { let primitive_objects = vec![false; heap.primitive_objects.len()]; let promise_reaction_records = vec![false; heap.promise_reaction_records.len()]; let promise_resolving_functions = vec![false; heap.promise_resolving_functions.len()]; + let promise_finally_functions = vec![false; heap.promise_finally_functions.len()]; let private_environments = vec![false; heap.environments.private.len()]; let promises = vec![false; heap.promises.len()]; let proxys = vec![false; heap.proxys.len()]; @@ -367,6 +371,7 @@ impl HeapBits { primitive_objects: primitive_objects.into_boxed_slice(), promise_reaction_records: promise_reaction_records.into_boxed_slice(), promise_resolving_functions: promise_resolving_functions.into_boxed_slice(), + promise_finally_functions: promise_finally_functions.into_boxed_slice(), private_environments: private_environments.into_boxed_slice(), promises: promises.into_boxed_slice(), proxys: proxys.into_boxed_slice(), @@ -455,6 +460,7 @@ impl WorkQueues { promise_resolving_functions: Vec::with_capacity( heap.promise_resolving_functions.len() / 4, ), + promise_finally_functions: Vec::with_capacity(heap.promise_finally_functions.len() / 4), promises: Vec::with_capacity(heap.promises.len() / 4), proxys: Vec::with_capacity(heap.proxys.len() / 4), realms: Vec::with_capacity(heap.realms.len() / 4), @@ -541,6 +547,7 @@ impl WorkQueues { promises, promise_reaction_records, promise_resolving_functions, + promise_finally_functions, proxys, realms, #[cfg(feature = "regexp")] @@ -639,6 +646,7 @@ impl WorkQueues { && private_environments.is_empty() && promise_reaction_records.is_empty() && promise_resolving_functions.is_empty() + && promise_finally_functions.is_empty() && promises.is_empty() && proxys.is_empty() && realms.is_empty() @@ -984,6 +992,7 @@ pub(crate) struct CompactionLists { pub private_environments: CompactionList, pub promise_reaction_records: CompactionList, pub promise_resolving_functions: CompactionList, + pub promise_finally_functions: CompactionList, pub promises: CompactionList, pub proxys: CompactionList, pub realms: CompactionList, @@ -1080,6 +1089,9 @@ impl CompactionLists { promise_resolving_functions: CompactionList::from_mark_bits( &bits.promise_resolving_functions, ), + promise_finally_functions: CompactionList::from_mark_bits( + &bits.promise_finally_functions, + ), promises: CompactionList::from_mark_bits(&bits.promises), #[cfg(feature = "regexp")] regexps: CompactionList::from_mark_bits(&bits.regexps), diff --git a/nova_vm/src/heap/heap_gc.rs b/nova_vm/src/heap/heap_gc.rs index d2edf82bd..312580b3e 100644 --- a/nova_vm/src/heap/heap_gc.rs +++ b/nova_vm/src/heap/heap_gc.rs @@ -57,6 +57,7 @@ use crate::{ ordinary::{caches::PropertyLookupCache, shape::ObjectShape}, primitive_objects::PrimitiveObject, promise::Promise, + promise_objects::promise_abstract_operations::promise_finally_functions::BuiltinPromiseFinallyFunction, proxy::Proxy, text_processing::string_objects::string_iterator_objects::StringIterator, }, @@ -158,6 +159,7 @@ pub fn heap_gc(agent: &mut Agent, root_realms: &mut [Option>], gc primitive_objects, promise_reaction_records, promise_resolving_functions, + promise_finally_functions, promises, proxys, realms, @@ -669,6 +671,22 @@ pub fn heap_gc(agent: &mut Agent, root_realms: &mut [Option>], gc .mark_values(&mut queues); } }); + let mut promise_finally_function_marks: Box<[BuiltinPromiseFinallyFunction]> = + queues.promise_finally_functions.drain(..).collect(); + promise_finally_function_marks.sort(); + promise_finally_function_marks.iter().for_each(|&idx| { + let index = idx.get_index(); + if let Some(marked) = bits.promise_finally_functions.get_mut(index) { + if *marked { + // Already marked, ignore + return; + } + *marked = true; + promise_finally_functions + .get(index) + .mark_values(&mut queues); + } + }); let mut proxy_marks: Box<[Proxy]> = queues.proxys.drain(..).collect(); proxy_marks.sort(); proxy_marks.iter().for_each(|&idx| { @@ -1289,6 +1307,7 @@ fn sweep( primitive_objects, promise_reaction_records, promise_resolving_functions, + promise_finally_functions, promises, proxys, realms, @@ -1714,6 +1733,15 @@ fn sweep( ); }); } + if !promise_finally_functions.is_empty() { + s.spawn(|| { + sweep_heap_vector_values( + promise_finally_functions, + &compactions, + &bits.promise_finally_functions, + ); + }); + } if !promises.is_empty() { s.spawn(|| { sweep_heap_vector_values(promises, &compactions, &bits.promises); diff --git a/nova_vm/src/heap/indexes.rs b/nova_vm/src/heap/indexes.rs index 621b5f971..5fa22bb77 100644 --- a/nova_vm/src/heap/indexes.rs +++ b/nova_vm/src/heap/indexes.rs @@ -174,6 +174,14 @@ impl BaseIndex<'_, T> { assert!(!vec.is_empty()); Self::from_usize(vec.len()) } + + pub(crate) fn last_t(vec: &[T]) -> Self + where + T: Sized, + { + assert!(!vec.is_empty()); + Self::from_usize(vec.len()) + } } impl Default for BaseIndex<'_, T> { diff --git a/tests/expectations.json b/tests/expectations.json index 1c292c10d..e10c67ffe 100644 --- a/tests/expectations.json +++ b/tests/expectations.json @@ -1624,28 +1624,16 @@ "built-ins/Promise/get-prototype-abrupt-executor-not-callable.js": "FAIL", "built-ins/Promise/get-prototype-abrupt.js": "FAIL", "built-ins/Promise/proto-from-ctor-realm.js": "FAIL", - "built-ins/Promise/prototype/finally/invokes-then-with-function.js": "FAIL", - "built-ins/Promise/prototype/finally/invokes-then-with-non-function.js": "FAIL", "built-ins/Promise/prototype/finally/rejected-observable-then-calls-PromiseResolve.js": "FAIL", - "built-ins/Promise/prototype/finally/rejected-observable-then-calls-argument.js": "FAIL", "built-ins/Promise/prototype/finally/rejected-observable-then-calls.js": "FAIL", "built-ins/Promise/prototype/finally/rejection-reason-no-fulfill.js": "FAIL", "built-ins/Promise/prototype/finally/rejection-reason-override-with-throw.js": "FAIL", "built-ins/Promise/prototype/finally/resolution-value-no-override.js": "FAIL", "built-ins/Promise/prototype/finally/resolved-observable-then-calls-PromiseResolve.js": "FAIL", - "built-ins/Promise/prototype/finally/resolved-observable-then-calls-argument.js": "FAIL", "built-ins/Promise/prototype/finally/resolved-observable-then-calls.js": "FAIL", "built-ins/Promise/prototype/finally/species-constructor.js": "FAIL", "built-ins/Promise/prototype/finally/subclass-reject-count.js": "FAIL", "built-ins/Promise/prototype/finally/subclass-resolve-count.js": "FAIL", - "built-ins/Promise/prototype/finally/subclass-species-constructor-reject-count.js": "FAIL", - "built-ins/Promise/prototype/finally/subclass-species-constructor-resolve-count.js": "FAIL", - "built-ins/Promise/prototype/finally/this-value-non-object.js": "FAIL", - "built-ins/Promise/prototype/finally/this-value-proxy.js": "FAIL", - "built-ins/Promise/prototype/finally/this-value-then-not-callable.js": "FAIL", - "built-ins/Promise/prototype/finally/this-value-then-poisoned.js": "FAIL", - "built-ins/Promise/prototype/finally/this-value-then-throws.js": "FAIL", - "built-ins/Promise/prototype/finally/this-value-thenable.js": "FAIL", "built-ins/Promise/prototype/then/capability-executor-called-twice.js": "FAIL", "built-ins/Promise/prototype/then/capability-executor-not-callable.js": "FAIL", "built-ins/Promise/prototype/then/ctor-access-count.js": "FAIL", diff --git a/tests/metrics.json b/tests/metrics.json index 642248022..a320dc648 100644 --- a/tests/metrics.json +++ b/tests/metrics.json @@ -1,8 +1,8 @@ { "results": { "crash": 103, - "fail": 9013, - "pass": 38130, + "fail": 9001, + "pass": 38142, "skip": 3310, "timeout": 8, "unresolved": 30