2021-06-19 21:45:00 +01:00
/*
2023-04-13 00:47:15 +02:00
* Copyright ( c ) 2020 - 2023 , Linus Groh < linusg @ serenityos . org >
2021-06-19 21:45:00 +01:00
*
* SPDX - License - Identifier : BSD - 2 - Clause
*/
# pragma once
2022-11-14 18:20:59 +00:00
# include <AK/Concepts.h>
2021-06-19 21:45:00 +01:00
# include <AK/Forward.h>
2021-12-21 21:27:14 +01:00
# include <LibCrypto/Forward.h>
2024-12-26 14:32:52 +01:00
# include <LibGC/RootVector.h>
2025-07-19 13:49:30 -07:00
# include <LibJS/Export.h>
2021-06-19 21:45:00 +01:00
# include <LibJS/Forward.h>
2022-02-14 01:17:07 -08:00
# include <LibJS/Runtime/CanonicalIndex.h>
2025-01-16 16:51:26 -05:00
# include <LibJS/Runtime/Environment.h>
2022-01-23 02:06:51 -07:00
# include <LibJS/Runtime/FunctionObject.h>
2021-06-19 22:34:48 +01:00
# include <LibJS/Runtime/GlobalObject.h>
2023-07-19 06:54:48 -04:00
# include <LibJS/Runtime/Iterator.h>
2024-07-09 15:24:28 -04:00
# include <LibJS/Runtime/KeyedCollections.h>
2021-10-11 20:29:31 +02:00
# include <LibJS/Runtime/PrivateEnvironment.h>
2024-11-03 20:18:56 +13:00
# include <LibJS/Runtime/VM.h>
2021-06-19 21:45:00 +01:00
# include <LibJS/Runtime/Value.h>
namespace JS {
2025-07-19 10:41:08 -07:00
GC : : Ref < DeclarativeEnvironment > new_declarative_environment ( Environment & ) ;
2025-07-19 13:49:30 -07:00
JS_API GC : : Ref < ObjectEnvironment > new_object_environment ( Object & , bool is_with_environment , Environment * ) ;
2025-07-19 10:41:08 -07:00
GC : : Ref < FunctionEnvironment > new_function_environment ( ECMAScriptFunctionObject & , Object * new_target ) ;
GC : : Ref < PrivateEnvironment > new_private_environment ( VM & vm , PrivateEnvironment * outer ) ;
GC : : Ref < Environment > get_this_environment ( VM & ) ;
2025-08-03 14:05:09 -07:00
JS_API bool can_be_held_weakly ( Value ) ;
2025-07-19 10:41:08 -07:00
Object * get_super_constructor ( VM & ) ;
ThrowCompletionOr < Value > require_object_coercible ( VM & , Value ) ;
2025-07-19 13:49:30 -07:00
JS_API ThrowCompletionOr < Value > call_impl ( VM & , Value function , Value this_value , ReadonlySpan < Value > arguments = { } ) ;
JS_API ThrowCompletionOr < Value > call_impl ( VM & , FunctionObject & function , Value this_value , ReadonlySpan < Value > arguments = { } ) ;
JS_API ThrowCompletionOr < GC : : Ref < Object > > construct_impl ( VM & , FunctionObject & , ReadonlySpan < Value > arguments = { } , FunctionObject * new_target = nullptr ) ;
JS_API ThrowCompletionOr < size_t > length_of_array_like ( VM & , Object const & ) ;
2025-07-19 10:41:08 -07:00
ThrowCompletionOr < GC : : RootVector < Value > > create_list_from_array_like ( VM & , Value , Function < ThrowCompletionOr < void > ( Value ) > = { } ) ;
ThrowCompletionOr < FunctionObject * > species_constructor ( VM & , Object const & , FunctionObject & default_constructor ) ;
2025-07-19 13:49:30 -07:00
JS_API ThrowCompletionOr < Realm * > get_function_realm ( VM & , FunctionObject const & ) ;
2025-08-02 19:27:29 -04:00
ThrowCompletionOr < void > initialize_bound_name ( VM & , Utf16FlyString const & , Value , Environment * ) ;
2025-09-15 16:43:27 +02:00
bool is_compatible_property_descriptor ( bool extensible , PropertyDescriptor & , Optional < PropertyDescriptor > const & current ) ;
bool validate_and_apply_property_descriptor ( Object * , PropertyKey const & , bool extensible , PropertyDescriptor & , Optional < PropertyDescriptor > const & current ) ;
2025-07-19 13:49:30 -07:00
JS_API ThrowCompletionOr < Object * > get_prototype_from_constructor ( VM & , FunctionObject const & constructor , GC : : Ref < Object > ( Intrinsics : : * intrinsic_default_prototype ) ( ) ) ;
2025-07-19 10:41:08 -07:00
Object * create_unmapped_arguments_object ( VM & , ReadonlySpan < Value > arguments ) ;
Object * create_mapped_arguments_object ( VM & , FunctionObject & , NonnullRefPtr < FunctionParameters const > const & , ReadonlySpan < Value > arguments , Environment & ) ;
2022-02-14 01:17:07 -08:00
2025-01-16 16:51:26 -05:00
// 2.1.1 DisposeCapability Records, https://tc39.es/proposal-explicit-resource-management/#sec-disposecapability-records
2025-07-19 13:49:30 -07:00
struct JS_API DisposeCapability {
2025-01-16 16:51:26 -05:00
void visit_edges ( GC : : Cell : : Visitor & ) const ;
Vector < DisposableResource > disposable_resource_stack ; // [[DisposableResourceStack]]
} ;
// 2.1.2 DisposableResource Records, https://tc39.es/proposal-explicit-resource-management/#sec-disposableresource-records
2022-12-20 22:09:57 +01:00
struct DisposableResource {
2025-01-16 16:51:26 -05:00
void visit_edges ( GC : : Cell : : Visitor & ) const ;
GC : : Ptr < Object > resource_value ; // [[ResourceValue]]
Environment : : InitializeBindingHint hint ; // [[Hint]]
GC : : Ptr < FunctionObject > dispose_method ; // [[DisposeMethod]]
2022-12-20 22:09:57 +01:00
} ;
2025-01-16 16:51:26 -05:00
2025-07-19 13:49:30 -07:00
JS_API DisposeCapability new_dispose_capability ( ) ;
JS_API ThrowCompletionOr < void > add_disposable_resource ( VM & , DisposeCapability & , Value , Environment : : InitializeBindingHint , GC : : Ptr < FunctionObject > = { } ) ;
2025-07-19 10:41:08 -07:00
ThrowCompletionOr < DisposableResource > create_disposable_resource ( VM & , Value , Environment : : InitializeBindingHint , GC : : Ptr < FunctionObject > = { } ) ;
ThrowCompletionOr < GC : : Ptr < FunctionObject > > get_dispose_method ( VM & , Value , Environment : : InitializeBindingHint ) ;
Completion dispose ( VM & , Value , Environment : : InitializeBindingHint , GC : : Ptr < FunctionObject > method ) ;
Completion dispose_resources ( VM & , DisposeCapability & , Completion ) ;
2022-12-20 22:09:57 +01:00
2025-07-19 10:41:08 -07:00
ThrowCompletionOr < Value > perform_import_call ( VM & , Value specifier , Value options_value ) ;
2023-06-24 15:22:16 +02:00
2022-02-14 01:17:07 -08:00
enum class CanonicalIndexMode {
DetectNumericRoundtrip ,
IgnoreNumericRoundtrip ,
} ;
2025-07-19 10:41:08 -07:00
[ [ nodiscard ] ] CanonicalIndex canonical_numeric_index_string ( PropertyKey const & , CanonicalIndexMode needs_numeric ) ;
ThrowCompletionOr < String > get_substitution ( VM & , Utf16View const & matched , Utf16View const & str , size_t position , Span < Value > captures , Value named_captures , Value replacement ) ;
2021-06-19 21:45:00 +01:00
2021-06-19 20:13:53 -07:00
enum class CallerMode {
Strict ,
NonStrict
} ;
2024-11-03 20:18:56 +13:00
2025-07-19 10:41:08 -07:00
ThrowCompletionOr < Value > perform_eval ( VM & , Value , CallerMode , EvalMode ) ;
2021-06-19 20:13:53 -07:00
2025-07-19 10:41:08 -07:00
ThrowCompletionOr < void > eval_declaration_instantiation ( VM & vm , Program const & program , Environment * variable_environment , Environment * lexical_environment , PrivateEnvironment * private_environment , bool strict ) ;
2021-09-22 12:44:56 +02:00
2021-12-21 08:27:04 -05:00
// 7.3.14 Call ( F, V [ , argumentsList ] ), https://tc39.es/ecma262/#sec-call
2023-11-27 12:56:20 +01:00
ALWAYS_INLINE ThrowCompletionOr < Value > call ( VM & vm , Value function , Value this_value , ReadonlySpan < Value > arguments_list )
LibJS: Implement [[Call]] and [[Construct]] internal slots properly
This patch implements:
- Spec compliant [[Call]] and [[Construct]] internal slots, as virtual
FunctionObject::internal_{call,construct}(). These effectively replace
the old virtual FunctionObject::{call,construct}(), but with several
advantages:
- Clear and consistent naming, following the object internal methods
- Use of completions
- internal_construct() returns an Object, and not Value! This has been
a source of confusion for a long time, since in the spec there's
always an Object returned but the Value return type in LibJS meant
that this could not be fully trusted and something could screw you
over.
- Arguments are passed explicitly in form of a MarkedValueList,
allowing manipulation (BoundFunction). We still put them on the
execution context as a lot of code depends on it (VM::arguments()),
but not from the Call() / Construct() AOs anymore, which now allows
for bypassing them and invoking [[Call]] / [[Construct]] directly.
Nothing but Call() / Construct() themselves do that at the moment,
but future additions to ECMA262 or already existing web specs might.
- Spec compliant, standalone Call() and Construct() AOs: currently the
closest we have is VM::{call,construct}(), but those try to cater to
all the different function object subclasses at once, resulting in a
horrible mess and calling AOs with functions they should never be
called with; most prominently PrepareForOrdinaryCall and
OrdinaryCallBindThis, which are only for ECMAScriptFunctionObject.
As a result this also contains an implicit optimization: we no longer
need to create a new function environment for NativeFunctions - which,
worth mentioning, is what started this whole crusade in the first place
:^)
2021-10-08 20:37:21 +01:00
{
2023-11-27 12:56:20 +01:00
return call_impl ( vm , function , this_value , arguments_list ) ;
LibJS: Implement [[Call]] and [[Construct]] internal slots properly
This patch implements:
- Spec compliant [[Call]] and [[Construct]] internal slots, as virtual
FunctionObject::internal_{call,construct}(). These effectively replace
the old virtual FunctionObject::{call,construct}(), but with several
advantages:
- Clear and consistent naming, following the object internal methods
- Use of completions
- internal_construct() returns an Object, and not Value! This has been
a source of confusion for a long time, since in the spec there's
always an Object returned but the Value return type in LibJS meant
that this could not be fully trusted and something could screw you
over.
- Arguments are passed explicitly in form of a MarkedValueList,
allowing manipulation (BoundFunction). We still put them on the
execution context as a lot of code depends on it (VM::arguments()),
but not from the Call() / Construct() AOs anymore, which now allows
for bypassing them and invoking [[Call]] / [[Construct]] directly.
Nothing but Call() / Construct() themselves do that at the moment,
but future additions to ECMA262 or already existing web specs might.
- Spec compliant, standalone Call() and Construct() AOs: currently the
closest we have is VM::{call,construct}(), but those try to cater to
all the different function object subclasses at once, resulting in a
horrible mess and calling AOs with functions they should never be
called with; most prominently PrepareForOrdinaryCall and
OrdinaryCallBindThis, which are only for ECMAScriptFunctionObject.
As a result this also contains an implicit optimization: we no longer
need to create a new function environment for NativeFunctions - which,
worth mentioning, is what started this whole crusade in the first place
:^)
2021-10-08 20:37:21 +01:00
}
2023-11-27 12:56:20 +01:00
ALWAYS_INLINE ThrowCompletionOr < Value > call ( VM & vm , Value function , Value this_value , Span < Value > arguments_list )
2022-01-23 02:06:51 -07:00
{
2023-11-27 12:56:20 +01:00
return call_impl ( vm , function , this_value , static_cast < ReadonlySpan < Value > > ( arguments_list ) ) ;
2022-01-23 02:06:51 -07:00
}
LibJS: Implement [[Call]] and [[Construct]] internal slots properly
This patch implements:
- Spec compliant [[Call]] and [[Construct]] internal slots, as virtual
FunctionObject::internal_{call,construct}(). These effectively replace
the old virtual FunctionObject::{call,construct}(), but with several
advantages:
- Clear and consistent naming, following the object internal methods
- Use of completions
- internal_construct() returns an Object, and not Value! This has been
a source of confusion for a long time, since in the spec there's
always an Object returned but the Value return type in LibJS meant
that this could not be fully trusted and something could screw you
over.
- Arguments are passed explicitly in form of a MarkedValueList,
allowing manipulation (BoundFunction). We still put them on the
execution context as a lot of code depends on it (VM::arguments()),
but not from the Call() / Construct() AOs anymore, which now allows
for bypassing them and invoking [[Call]] / [[Construct]] directly.
Nothing but Call() / Construct() themselves do that at the moment,
but future additions to ECMA262 or already existing web specs might.
- Spec compliant, standalone Call() and Construct() AOs: currently the
closest we have is VM::{call,construct}(), but those try to cater to
all the different function object subclasses at once, resulting in a
horrible mess and calling AOs with functions they should never be
called with; most prominently PrepareForOrdinaryCall and
OrdinaryCallBindThis, which are only for ECMAScriptFunctionObject.
As a result this also contains an implicit optimization: we no longer
need to create a new function environment for NativeFunctions - which,
worth mentioning, is what started this whole crusade in the first place
:^)
2021-10-08 20:37:21 +01:00
template < typename . . . Args >
2022-08-21 19:24:32 +01:00
ALWAYS_INLINE ThrowCompletionOr < Value > call ( VM & vm , Value function , Value this_value , Args & & . . . args )
LibJS: Implement [[Call]] and [[Construct]] internal slots properly
This patch implements:
- Spec compliant [[Call]] and [[Construct]] internal slots, as virtual
FunctionObject::internal_{call,construct}(). These effectively replace
the old virtual FunctionObject::{call,construct}(), but with several
advantages:
- Clear and consistent naming, following the object internal methods
- Use of completions
- internal_construct() returns an Object, and not Value! This has been
a source of confusion for a long time, since in the spec there's
always an Object returned but the Value return type in LibJS meant
that this could not be fully trusted and something could screw you
over.
- Arguments are passed explicitly in form of a MarkedValueList,
allowing manipulation (BoundFunction). We still put them on the
execution context as a lot of code depends on it (VM::arguments()),
but not from the Call() / Construct() AOs anymore, which now allows
for bypassing them and invoking [[Call]] / [[Construct]] directly.
Nothing but Call() / Construct() themselves do that at the moment,
but future additions to ECMA262 or already existing web specs might.
- Spec compliant, standalone Call() and Construct() AOs: currently the
closest we have is VM::{call,construct}(), but those try to cater to
all the different function object subclasses at once, resulting in a
horrible mess and calling AOs with functions they should never be
called with; most prominently PrepareForOrdinaryCall and
OrdinaryCallBindThis, which are only for ECMAScriptFunctionObject.
As a result this also contains an implicit optimization: we no longer
need to create a new function environment for NativeFunctions - which,
worth mentioning, is what started this whole crusade in the first place
:^)
2021-10-08 20:37:21 +01:00
{
2023-11-27 12:56:20 +01:00
constexpr auto argument_count = sizeof . . . ( Args ) ;
if constexpr ( argument_count > 0 ) {
AK : : Array < Value , argument_count > arguments { forward < Args > ( args ) . . . } ;
return call_impl ( vm , function , this_value , static_cast < ReadonlySpan < Value > > ( arguments . span ( ) ) ) ;
LibJS: Implement [[Call]] and [[Construct]] internal slots properly
This patch implements:
- Spec compliant [[Call]] and [[Construct]] internal slots, as virtual
FunctionObject::internal_{call,construct}(). These effectively replace
the old virtual FunctionObject::{call,construct}(), but with several
advantages:
- Clear and consistent naming, following the object internal methods
- Use of completions
- internal_construct() returns an Object, and not Value! This has been
a source of confusion for a long time, since in the spec there's
always an Object returned but the Value return type in LibJS meant
that this could not be fully trusted and something could screw you
over.
- Arguments are passed explicitly in form of a MarkedValueList,
allowing manipulation (BoundFunction). We still put them on the
execution context as a lot of code depends on it (VM::arguments()),
but not from the Call() / Construct() AOs anymore, which now allows
for bypassing them and invoking [[Call]] / [[Construct]] directly.
Nothing but Call() / Construct() themselves do that at the moment,
but future additions to ECMA262 or already existing web specs might.
- Spec compliant, standalone Call() and Construct() AOs: currently the
closest we have is VM::{call,construct}(), but those try to cater to
all the different function object subclasses at once, resulting in a
horrible mess and calling AOs with functions they should never be
called with; most prominently PrepareForOrdinaryCall and
OrdinaryCallBindThis, which are only for ECMAScriptFunctionObject.
As a result this also contains an implicit optimization: we no longer
need to create a new function environment for NativeFunctions - which,
worth mentioning, is what started this whole crusade in the first place
:^)
2021-10-08 20:37:21 +01:00
}
2022-08-21 19:24:32 +01:00
return call_impl ( vm , function , this_value ) ;
LibJS: Implement [[Call]] and [[Construct]] internal slots properly
This patch implements:
- Spec compliant [[Call]] and [[Construct]] internal slots, as virtual
FunctionObject::internal_{call,construct}(). These effectively replace
the old virtual FunctionObject::{call,construct}(), but with several
advantages:
- Clear and consistent naming, following the object internal methods
- Use of completions
- internal_construct() returns an Object, and not Value! This has been
a source of confusion for a long time, since in the spec there's
always an Object returned but the Value return type in LibJS meant
that this could not be fully trusted and something could screw you
over.
- Arguments are passed explicitly in form of a MarkedValueList,
allowing manipulation (BoundFunction). We still put them on the
execution context as a lot of code depends on it (VM::arguments()),
but not from the Call() / Construct() AOs anymore, which now allows
for bypassing them and invoking [[Call]] / [[Construct]] directly.
Nothing but Call() / Construct() themselves do that at the moment,
but future additions to ECMA262 or already existing web specs might.
- Spec compliant, standalone Call() and Construct() AOs: currently the
closest we have is VM::{call,construct}(), but those try to cater to
all the different function object subclasses at once, resulting in a
horrible mess and calling AOs with functions they should never be
called with; most prominently PrepareForOrdinaryCall and
OrdinaryCallBindThis, which are only for ECMAScriptFunctionObject.
As a result this also contains an implicit optimization: we no longer
need to create a new function environment for NativeFunctions - which,
worth mentioning, is what started this whole crusade in the first place
:^)
2021-10-08 20:37:21 +01:00
}
2023-11-27 12:56:20 +01:00
ALWAYS_INLINE ThrowCompletionOr < Value > call ( VM & vm , FunctionObject & function , Value this_value , ReadonlySpan < Value > arguments_list )
2022-01-23 02:06:51 -07:00
{
2023-11-27 12:56:20 +01:00
return call_impl ( vm , function , this_value , arguments_list ) ;
2022-01-23 02:06:51 -07:00
}
2023-11-27 12:56:20 +01:00
ALWAYS_INLINE ThrowCompletionOr < Value > call ( VM & vm , FunctionObject & function , Value this_value , Span < Value > arguments_list )
2022-01-23 02:06:51 -07:00
{
2023-11-27 12:56:20 +01:00
return call_impl ( vm , function , this_value , static_cast < ReadonlySpan < Value > > ( arguments_list ) ) ;
2022-01-23 02:06:51 -07:00
}
template < typename . . . Args >
2022-08-21 19:24:32 +01:00
ALWAYS_INLINE ThrowCompletionOr < Value > call ( VM & vm , FunctionObject & function , Value this_value , Args & & . . . args )
2022-01-23 02:06:51 -07:00
{
2023-11-27 12:56:20 +01:00
constexpr auto argument_count = sizeof . . . ( Args ) ;
if constexpr ( argument_count > 0 ) {
AK : : Array < Value , argument_count > arguments { forward < Args > ( args ) . . . } ;
return call_impl ( vm , function , this_value , static_cast < ReadonlySpan < Value > > ( arguments . span ( ) ) ) ;
2022-01-23 02:06:51 -07:00
}
2022-08-21 19:24:32 +01:00
return call_impl ( vm , function , this_value ) ;
2022-01-23 02:06:51 -07:00
}
2022-01-25 15:04:45 -05:00
// 7.3.15 Construct ( F [ , argumentsList [ , newTarget ] ] ), https://tc39.es/ecma262/#sec-construct
template < typename . . . Args >
2024-11-15 04:01:23 +13:00
ALWAYS_INLINE ThrowCompletionOr < GC : : Ref < Object > > construct ( VM & vm , FunctionObject & function , Args & & . . . args )
2022-01-25 15:04:45 -05:00
{
2023-11-27 12:56:20 +01:00
constexpr auto argument_count = sizeof . . . ( Args ) ;
if constexpr ( argument_count > 0 ) {
AK : : Array < Value , argument_count > arguments { forward < Args > ( args ) . . . } ;
return construct_impl ( vm , function , static_cast < ReadonlySpan < Value > > ( arguments . span ( ) ) ) ;
2022-01-25 15:04:45 -05:00
}
2022-08-21 19:24:32 +01:00
return construct_impl ( vm , function ) ;
2022-01-25 15:04:45 -05:00
}
2024-11-15 04:01:23 +13:00
ALWAYS_INLINE ThrowCompletionOr < GC : : Ref < Object > > construct ( VM & vm , FunctionObject & function , ReadonlySpan < Value > arguments_list , FunctionObject * new_target = nullptr )
2022-01-25 15:04:45 -05:00
{
2023-11-27 12:56:20 +01:00
return construct_impl ( vm , function , arguments_list , new_target ) ;
2022-01-25 15:04:45 -05:00
}
2024-11-15 04:01:23 +13:00
ALWAYS_INLINE ThrowCompletionOr < GC : : Ref < Object > > construct ( VM & vm , FunctionObject & function , Span < Value > arguments_list , FunctionObject * new_target = nullptr )
2022-01-25 15:04:45 -05:00
{
2023-11-27 12:56:20 +01:00
return construct_impl ( vm , function , static_cast < ReadonlySpan < Value > > ( arguments_list ) , new_target ) ;
2022-01-25 15:04:45 -05:00
}
2021-06-19 22:34:48 +01:00
// 10.1.13 OrdinaryCreateFromConstructor ( constructor, intrinsicDefaultProto [ , internalSlotsList ] ), https://tc39.es/ecma262/#sec-ordinarycreatefromconstructor
template < typename T , typename . . . Args >
2025-10-15 11:26:58 +02:00
ALWAYS_INLINE ThrowCompletionOr < GC : : Ref < T > > ordinary_create_from_constructor ( VM & vm , Realm & realm , FunctionObject const & constructor , GC : : Ref < Object > ( Intrinsics : : * intrinsic_default_prototype ) ( ) , Args & & . . . args )
2021-06-19 22:34:48 +01:00
{
2022-08-21 19:24:32 +01:00
auto * prototype = TRY ( get_prototype_from_constructor ( vm , constructor , intrinsic_default_prototype ) ) ;
2024-11-14 05:50:17 +13:00
return realm . create < T > ( forward < Args > ( args ) . . . , * prototype ) ;
2021-06-19 22:34:48 +01:00
}
2025-10-15 11:26:58 +02:00
// 10.1.13 OrdinaryCreateFromConstructor ( constructor, intrinsicDefaultProto [ , internalSlotsList ] ), https://tc39.es/ecma262/#sec-ordinarycreatefromconstructor
template < typename T , typename . . . Args >
ALWAYS_INLINE ThrowCompletionOr < GC : : Ref < T > > ordinary_create_from_constructor ( VM & vm , FunctionObject const & constructor , GC : : Ref < Object > ( Intrinsics : : * intrinsic_default_prototype ) ( ) , Args & & . . . args )
{
return ordinary_create_from_constructor < T > ( vm , * vm . current_realm ( ) , constructor , intrinsic_default_prototype , forward < Args > ( args ) . . . ) ;
}
2023-12-26 08:55:15 -05:00
// 7.3.35 AddValueToKeyedGroup ( groups, key, value ), https://tc39.es/ecma262/#sec-add-value-to-keyed-group
2023-07-11 16:23:00 +02:00
template < typename GroupsType , typename KeyType >
void add_value_to_keyed_group ( VM & vm , GroupsType & groups , KeyType key , Value value )
{
// 1. For each Record { [[Key]], [[Elements]] } g of groups, do
// a. If SameValue(g.[[Key]], key) is true, then
// NOTE: This is performed in KeyedGroupTraits::equals for groupToMap and Traits<JS::PropertyKey>::equals for group.
auto existing_elements_iterator = groups . find ( key ) ;
if ( existing_elements_iterator ! = groups . end ( ) ) {
// i. Assert: exactly one element of groups meets this criteria.
// NOTE: This is done on insertion into the hash map, as only `set` tells us if we overrode an entry.
// ii. Append value as the last element of g.[[Elements]].
existing_elements_iterator - > value . append ( value ) ;
// iii. Return unused.
return ;
}
// 2. Let group be the Record { [[Key]]: key, [[Elements]]: « value » }.
2024-12-26 14:32:52 +01:00
GC : : RootVector < Value > new_elements { vm . heap ( ) } ;
2023-07-11 16:23:00 +02:00
new_elements . append ( value ) ;
// 3. Append group as the last element of groups.
auto result = groups . set ( key , move ( new_elements ) ) ;
VERIFY ( result = = AK : : HashSetResult : : InsertedNewEntry ) ;
// 4. Return unused.
}
2023-12-26 08:55:15 -05:00
// 7.3.36 GroupBy ( items, callbackfn, keyCoercion ), https://tc39.es/ecma262/#sec-groupby
2023-07-11 16:23:00 +02:00
template < typename GroupsType , typename KeyType >
ThrowCompletionOr < GroupsType > group_by ( VM & vm , Value items , Value callback_function )
{
// 1. Perform ? RequireObjectCoercible(items).
TRY ( require_object_coercible ( vm , items ) ) ;
// 2. If IsCallable(callbackfn) is false, throw a TypeError exception.
if ( ! callback_function . is_function ( ) )
2023-08-09 08:49:02 +02:00
return vm . throw_completion < TypeError > ( ErrorType : : NotAFunction , callback_function . to_string_without_side_effects ( ) ) ;
2023-07-11 16:23:00 +02:00
// 3. Let groups be a new empty List.
GroupsType groups ;
2023-12-26 08:55:15 -05:00
// 4. Let iteratorRecord be ? GetIterator(items, sync).
2023-07-18 14:52:21 -04:00
auto iterator_record = TRY ( get_iterator ( vm , items , IteratorHint : : Sync ) ) ;
2023-07-11 16:23:00 +02:00
// 5. Let k be 0.
u64 k = 0 ;
// 6. Repeat,
while ( true ) {
// a. If k ≥ 2^53 - 1, then
if ( k > = MAX_ARRAY_LIKE_INDEX ) {
// i. Let error be ThrowCompletion(a newly created TypeError object).
auto error = vm . throw_completion < TypeError > ( ErrorType : : ArrayMaxSize ) ;
// ii. Return ? IteratorClose(iteratorRecord, error).
return iterator_close ( vm , iterator_record , move ( error ) ) ;
}
2024-02-01 14:53:28 -05:00
// b. Let next be ? IteratorStepValue(iteratorRecord).
auto next = TRY ( iterator_step_value ( vm , iterator_record ) ) ;
2023-07-11 16:23:00 +02:00
2024-02-01 14:53:28 -05:00
// c. If next is DONE, then
if ( ! next . has_value ( ) ) {
2023-07-11 16:23:00 +02:00
// i. Return groups.
return ThrowCompletionOr < GroupsType > { move ( groups ) } ;
}
2024-02-01 14:53:28 -05:00
// d. Let value be next.
auto value = next . release_value ( ) ;
2023-07-11 16:23:00 +02:00
// e. Let key be Completion(Call(callbackfn, undefined, « value, 𝔽 (k) »)).
// f. IfAbruptCloseIterator(key, iteratorRecord).
2025-04-28 18:22:32 -04:00
auto key = TRY_OR_CLOSE_ITERATOR ( vm , iterator_record , call ( vm , callback_function , js_undefined ( ) , value , Value ( k ) ) ) ;
2023-07-11 16:23:00 +02:00
// g. If keyCoercion is property, then
if constexpr ( IsSame < KeyType , PropertyKey > ) {
// i. Set key to Completion(ToPropertyKey(key)).
// ii. IfAbruptCloseIterator(key, iteratorRecord).
2025-04-28 18:22:32 -04:00
auto property_key = TRY_OR_CLOSE_ITERATOR ( vm , iterator_record , key . to_property_key ( vm ) ) ;
2023-07-11 16:23:00 +02:00
2025-04-28 18:22:32 -04:00
add_value_to_keyed_group ( vm , groups , move ( property_key ) , value ) ;
2023-07-11 16:23:00 +02:00
}
// h. Else,
else {
// i. Assert: keyCoercion is zero.
static_assert ( IsSame < KeyType , void > ) ;
2024-07-09 15:24:28 -04:00
// ii. Set key to CanonicalizeKeyedCollectionKey(key).
2025-04-28 18:22:32 -04:00
key = canonicalize_keyed_collection_key ( key ) ;
2023-07-11 16:23:00 +02:00
2025-04-28 18:22:32 -04:00
add_value_to_keyed_group ( vm , groups , make_root ( key ) , value ) ;
2023-07-11 16:23:00 +02:00
}
// i. Perform AddValueToKeyedGroup(groups, key, value).
// NOTE: This is dependent on the `key_coercion` template parameter and thus done separately in the branches above.
// j. Set k to k + 1.
+ + k ;
}
}
2021-11-07 20:48:38 +00:00
// x modulo y, https://tc39.es/ecma262/#eqn-modulo
2022-11-14 18:20:59 +00:00
template < Arithmetic T , Arithmetic U >
2022-10-17 00:06:11 +02:00
auto modulo ( T x , U y )
2021-11-07 20:48:38 +00:00
{
// The notation “x modulo y” (y must be finite and non-zero) computes a value k of the same sign as y (or zero) such that abs(k) < abs(y) and x - k = q × y for some integer q.
VERIFY ( y ! = 0 ) ;
2021-12-21 21:22:38 +01:00
if constexpr ( IsFloatingPoint < T > | | IsFloatingPoint < U > ) {
if constexpr ( IsFloatingPoint < U > )
VERIFY ( isfinite ( y ) ) ;
2024-01-02 19:24:36 +13:00
auto r = fmod ( x , y ) ;
return r < 0 ? r + y : r ;
2021-11-07 20:48:38 +00:00
} else {
return ( ( x % y ) + y ) % y ;
}
}
2021-12-21 21:27:14 +01:00
auto modulo ( Crypto : : BigInteger auto const & x , Crypto : : BigInteger auto const & y )
{
2022-07-16 12:43:23 -04:00
VERIFY ( ! y . is_zero ( ) ) ;
2021-12-21 21:27:14 +01:00
auto result = x . divided_by ( y ) . remainder ;
if ( result . is_negative ( ) )
result = result . plus ( y ) ;
return result ;
}
2024-01-08 19:20:31 +13:00
// remainder(x, y), https://tc39.es/proposal-temporal/#eqn-remainder
template < Arithmetic T , Arithmetic U >
auto remainder ( T x , U y )
{
// The mathematical function remainder(x, y) produces the mathematical value whose sign is the sign of x and whose magnitude is abs(x) modulo y.
VERIFY ( y ! = 0 ) ;
if constexpr ( IsFloatingPoint < T > | | IsFloatingPoint < U > ) {
if constexpr ( IsFloatingPoint < U > )
VERIFY ( isfinite ( y ) ) ;
return fmod ( x , y ) ;
} else {
return x % y ;
}
}
auto remainder ( Crypto : : BigInteger auto const & x , Crypto : : BigInteger auto const & y )
{
VERIFY ( ! y . is_zero ( ) ) ;
return x . divided_by ( y ) . remainder ;
}
2025-02-28 12:15:49 -05:00
// 14.3 The Year-Week Record Specification Type, https://tc39.es/proposal-temporal/#sec-year-week-record-specification-type
struct YearWeek {
Optional < u8 > week ;
Optional < i32 > year ;
} ;
2025-02-28 12:22:27 -05:00
// 14.5.1.1 ToIntegerIfIntegral ( argument ), https://tc39.es/proposal-temporal/#sec-tointegerifintegral
template < typename . . . Args >
2025-08-07 19:31:52 -04:00
ThrowCompletionOr < double > to_integer_if_integral ( VM & vm , Value argument , ErrorType const & error_type , Args & & . . . args )
2025-02-28 12:22:27 -05:00
{
// 1. Let number be ? ToNumber(argument).
auto number = TRY ( argument . to_number ( vm ) ) ;
// 2. If number is not an integral Number, throw a RangeError exception.
if ( ! number . is_integral_number ( ) )
return vm . throw_completion < RangeError > ( error_type , forward < Args > ( args ) . . . ) ;
// 3. Return ℝ (number).
return number . as_double ( ) ;
}
2025-02-28 12:15:49 -05:00
enum class OptionType {
Boolean ,
String ,
} ;
struct Required { } ;
using OptionDefault = Variant < Required , Empty , bool , StringView , double > ;
2025-07-19 10:41:08 -07:00
ThrowCompletionOr < GC : : Ref < Object > > get_options_object ( VM & , Value options ) ;
ThrowCompletionOr < Value > get_option ( VM & , Object const & options , PropertyKey const & property , OptionType type , ReadonlySpan < StringView > values , OptionDefault const & ) ;
2025-02-28 12:15:49 -05:00
template < size_t Size >
ThrowCompletionOr < Value > get_option ( VM & vm , Object const & options , PropertyKey const & property , OptionType type , StringView const ( & values ) [ Size ] , OptionDefault const & default_ )
{
return get_option ( vm , options , property , type , ReadonlySpan < StringView > { values } , default_ ) ;
}
// https://tc39.es/proposal-temporal/#table-temporal-rounding-modes
enum class RoundingMode {
Ceil ,
Floor ,
Expand ,
Trunc ,
HalfCeil ,
HalfFloor ,
HalfExpand ,
HalfTrunc ,
HalfEven ,
} ;
2025-07-19 10:41:08 -07:00
ThrowCompletionOr < RoundingMode > get_rounding_mode_option ( VM & , Object const & options , RoundingMode fallback ) ;
ThrowCompletionOr < u64 > get_rounding_increment_option ( VM & , Object const & options ) ;
2025-02-28 12:15:49 -05:00
2025-07-19 10:41:08 -07:00
Crypto : : SignedBigInteger big_floor ( Crypto : : SignedBigInteger const & numerator , Crypto : : UnsignedBigInteger const & denominator ) ;
2025-02-28 12:15:49 -05:00
2021-06-19 21:45:00 +01:00
}