2020-03-13 10:08:52 +01:00
/*
2021-05-29 12:38:28 +02:00
* Copyright ( c ) 2020 , Stephan Unverwerth < s . unverwerth @ serenityos . org >
2023-03-01 14:52:31 +00:00
* Copyright ( c ) 2020 - 2023 , Linus Groh < linusg @ serenityos . org >
2025-04-08 00:45:27 +02:00
* Copyright ( c ) 2023 - 2025 , Andreas Kling < andreas @ ladybird . org >
2023-07-16 18:04:01 +12:00
* Copyright ( c ) 2023 , Shannon Booth < shannon @ serenityos . org >
2020-03-13 10:08:52 +01:00
*
2021-04-22 01:24:48 -07:00
* SPDX - License - Identifier : BSD - 2 - Clause
2020-03-13 10:08:52 +01:00
*/
2021-06-07 15:17:37 +02:00
# include <AK/Debug.h>
2020-04-04 14:34:27 +01:00
# include <AK/Function.h>
2020-03-18 11:23:53 +01:00
# include <LibJS/AST.h>
2021-06-09 06:49:58 +04:30
# include <LibJS/Bytecode/BasicBlock.h>
2021-06-05 15:53:36 +02:00
# include <LibJS/Bytecode/Generator.h>
# include <LibJS/Bytecode/Interpreter.h>
2021-09-22 12:44:56 +02:00
# include <LibJS/Runtime/AbstractOperations.h>
2020-05-04 16:05:13 +01:00
# include <LibJS/Runtime/Array.h>
2021-11-11 00:46:07 +03:30
# include <LibJS/Runtime/AsyncFunctionDriverWrapper.h>
2023-07-14 21:57:49 +01:00
# include <LibJS/Runtime/AsyncGenerator.h>
2021-09-24 22:40:38 +02:00
# include <LibJS/Runtime/ECMAScriptFunctionObject.h>
2020-04-04 14:34:27 +01:00
# include <LibJS/Runtime/Error.h>
2021-11-09 20:39:22 +02:00
# include <LibJS/Runtime/ExecutionContext.h>
2021-07-01 12:24:46 +02:00
# include <LibJS/Runtime/FunctionEnvironment.h>
2021-06-11 01:38:30 +04:30
# include <LibJS/Runtime/GeneratorObject.h>
2023-08-07 19:59:00 +02:00
# include <LibJS/Runtime/GlobalEnvironment.h>
2020-04-17 19:59:32 +02:00
# include <LibJS/Runtime/GlobalObject.h>
2021-06-11 01:38:30 +04:30
# include <LibJS/Runtime/NativeFunction.h>
2022-10-02 10:59:22 +01:00
# include <LibJS/Runtime/PromiseCapability.h>
2021-11-09 20:39:22 +02:00
# include <LibJS/Runtime/PromiseConstructor.h>
2020-03-16 14:20:30 +01:00
# include <LibJS/Runtime/Value.h>
2025-09-13 20:50:09 +02:00
# include <LibJS/Runtime/ValueInlines.h>
2020-03-13 10:08:52 +01:00
namespace JS {
2024-11-15 04:01:23 +13:00
GC_DEFINE_ALLOCATOR ( ECMAScriptFunctionObject ) ;
2023-11-19 09:45:05 +01:00
2025-08-02 19:27:29 -04:00
GC : : Ref < ECMAScriptFunctionObject > ECMAScriptFunctionObject : : create ( Realm & realm , Utf16FlyString name , ByteString source_text , Statement const & ecmascript_code , NonnullRefPtr < FunctionParameters const > parameters , i32 function_length , Vector < LocalVariable > local_variables_names , Environment * parent_environment , PrivateEnvironment * private_environment , FunctionKind kind , bool is_strict , FunctionParsingInsights parsing_insights , bool is_arrow_function , Variant < PropertyKey , PrivateName , Empty > class_field_initializer_name )
2020-04-17 19:59:32 +02:00
{
2021-06-15 00:04:08 -07:00
Object * prototype = nullptr ;
switch ( kind ) {
2022-01-15 00:30:02 +01:00
case FunctionKind : : Normal :
2022-08-27 00:54:55 +01:00
prototype = realm . intrinsics ( ) . function_prototype ( ) ;
2021-06-15 00:04:08 -07:00
break ;
case FunctionKind : : Generator :
2022-08-27 00:54:55 +01:00
prototype = realm . intrinsics ( ) . generator_function_prototype ( ) ;
2021-06-15 00:04:08 -07:00
break ;
2021-11-09 20:39:22 +02:00
case FunctionKind : : Async :
2022-08-27 00:54:55 +01:00
prototype = realm . intrinsics ( ) . async_function_prototype ( ) ;
2021-11-09 20:39:22 +02:00
break ;
2021-11-15 01:53:24 +01:00
case FunctionKind : : AsyncGenerator :
2022-08-27 00:54:55 +01:00
prototype = realm . intrinsics ( ) . async_generator_function_prototype ( ) ;
2021-11-15 01:53:24 +01:00
break ;
2021-06-15 00:04:08 -07:00
}
2025-04-08 00:45:27 +02:00
auto shared_data = adopt_ref ( * new SharedFunctionInstanceData (
realm . vm ( ) ,
kind ,
move ( name ) ,
function_length ,
* parameters ,
ecmascript_code ,
source_text ,
is_strict ,
is_arrow_function ,
parsing_insights ,
move ( local_variables_names ) ) ) ;
shared_data - > m_class_field_initializer_name = move ( class_field_initializer_name ) ;
return realm . create < ECMAScriptFunctionObject > (
move ( shared_data ) ,
parent_environment ,
private_environment ,
* prototype ) ;
2020-04-17 19:59:32 +02:00
}
2025-08-02 19:27:29 -04:00
GC : : Ref < ECMAScriptFunctionObject > ECMAScriptFunctionObject : : create ( Realm & realm , Utf16FlyString name , Object & prototype , ByteString source_text , Statement const & ecmascript_code , NonnullRefPtr < FunctionParameters const > parameters , i32 function_length , Vector < LocalVariable > local_variables_names , Environment * parent_environment , PrivateEnvironment * private_environment , FunctionKind kind , bool is_strict , FunctionParsingInsights parsing_insights , bool is_arrow_function , Variant < PropertyKey , PrivateName , Empty > class_field_initializer_name )
2022-01-15 17:18:12 +01:00
{
2025-04-08 00:45:27 +02:00
auto shared_data = adopt_ref ( * new SharedFunctionInstanceData (
realm . vm ( ) ,
kind ,
move ( name ) ,
function_length ,
* parameters ,
ecmascript_code ,
source_text ,
is_strict ,
is_arrow_function ,
parsing_insights ,
move ( local_variables_names ) ) ) ;
shared_data - > m_class_field_initializer_name = move ( class_field_initializer_name ) ;
return realm . create < ECMAScriptFunctionObject > (
move ( shared_data ) ,
parent_environment ,
private_environment ,
prototype ) ;
2022-01-15 17:18:12 +01:00
}
2025-04-07 21:08:55 +02:00
GC : : Ref < ECMAScriptFunctionObject > ECMAScriptFunctionObject : : create_from_function_node (
FunctionNode const & function_node ,
2025-08-02 19:27:29 -04:00
Utf16FlyString name ,
2025-04-07 21:08:55 +02:00
GC : : Ref < Realm > realm ,
GC : : Ptr < Environment > parent_environment ,
GC : : Ptr < PrivateEnvironment > private_environment )
{
GC : : Ptr < Object > prototype = nullptr ;
switch ( function_node . kind ( ) ) {
case FunctionKind : : Normal :
prototype = realm - > intrinsics ( ) . function_prototype ( ) ;
break ;
case FunctionKind : : Generator :
prototype = realm - > intrinsics ( ) . generator_function_prototype ( ) ;
break ;
case FunctionKind : : Async :
prototype = realm - > intrinsics ( ) . async_function_prototype ( ) ;
break ;
case FunctionKind : : AsyncGenerator :
prototype = realm - > intrinsics ( ) . async_generator_function_prototype ( ) ;
break ;
}
2025-04-08 00:45:27 +02:00
RefPtr < SharedFunctionInstanceData > shared_data = function_node . shared_data ( ) ;
if ( ! shared_data ) {
shared_data = adopt_ref ( * new SharedFunctionInstanceData ( realm - > vm ( ) ,
function_node . kind ( ) ,
move ( name ) ,
function_node . function_length ( ) ,
function_node . parameters ( ) ,
* function_node . body_ptr ( ) ,
function_node . source_text ( ) ,
function_node . is_strict_mode ( ) ,
function_node . is_arrow_function ( ) ,
function_node . parsing_insights ( ) ,
function_node . local_variables_names ( ) ) ) ;
function_node . set_shared_data ( shared_data ) ;
}
return realm - > create < ECMAScriptFunctionObject > (
shared_data . release_nonnull ( ) ,
2025-04-07 21:08:55 +02:00
parent_environment ,
private_environment ,
2025-04-08 00:45:27 +02:00
* prototype ) ;
2025-04-07 21:08:55 +02:00
}
2025-04-08 00:45:27 +02:00
SharedFunctionInstanceData : : SharedFunctionInstanceData (
VM & vm ,
FunctionKind kind ,
2025-08-02 19:27:29 -04:00
Utf16FlyString name ,
2025-04-08 00:45:27 +02:00
i32 function_length ,
NonnullRefPtr < FunctionParameters const > formal_parameters ,
NonnullRefPtr < Statement const > ecmascript_code ,
ByteString source_text ,
bool strict ,
bool is_arrow_function ,
FunctionParsingInsights const & parsing_insights ,
2025-05-05 21:53:19 +03:00
Vector < LocalVariable > local_variables_names )
2025-04-08 00:45:27 +02:00
: m_formal_parameters ( move ( formal_parameters ) )
, m_ecmascript_code ( move ( ecmascript_code ) )
2022-01-31 13:19:06 +01:00
, m_name ( move ( name ) )
2022-01-18 23:47:11 +00:00
, m_source_text ( move ( source_text ) )
2025-04-08 00:45:27 +02:00
, m_local_variables_names ( move ( local_variables_names ) )
, m_function_length ( function_length )
, m_kind ( kind )
2022-01-31 13:19:06 +01:00
, m_strict ( strict )
2024-05-22 11:04:50 +01:00
, m_might_need_arguments_object ( parsing_insights . might_need_arguments_object )
, m_contains_direct_call_to_eval ( parsing_insights . contains_direct_call_to_eval )
2020-05-30 00:10:42 -05:00
, m_is_arrow_function ( is_arrow_function )
2025-04-08 00:45:27 +02:00
, m_uses_this ( parsing_insights . uses_this )
2020-03-13 10:08:52 +01:00
{
2021-06-25 20:53:17 +02:00
if ( m_is_arrow_function )
2021-09-24 23:19:36 +02:00
m_this_mode = ThisMode : : Lexical ;
2021-09-24 23:10:21 +02:00
else if ( m_strict )
2021-09-24 23:19:36 +02:00
m_this_mode = ThisMode : : Strict ;
2021-06-25 20:53:17 +02:00
else
2021-09-24 23:19:36 +02:00
m_this_mode = ThisMode : : Global ;
2021-06-28 11:18:32 +02:00
// 15.1.3 Static Semantics: IsSimpleParameterList, https://tc39.es/ecma262/#sec-static-semantics-issimpleparameterlist
2025-03-27 12:59:50 +00:00
m_has_simple_parameter_list = all_of ( m_formal_parameters - > parameters ( ) , [ & ] ( auto & parameter ) {
2021-06-28 11:18:32 +02:00
if ( parameter . is_rest )
return false ;
if ( parameter . default_value )
return false ;
2023-07-06 17:49:38 +02:00
if ( ! parameter . binding . template has < NonnullRefPtr < Identifier const > > ( ) )
2021-06-28 11:18:32 +02:00
return false ;
return true ;
2021-09-25 00:10:09 +02:00
} ) ;
2023-09-19 02:46:28 +02:00
// NOTE: The following steps are from FunctionDeclarationInstantiation that could be executed once
// and then reused in all subsequent function instantiations.
// 2. Let code be func.[[ECMAScriptCode]].
ScopeNode const * scope_body = nullptr ;
if ( is < ScopeNode > ( * m_ecmascript_code ) )
scope_body = static_cast < ScopeNode const * > ( m_ecmascript_code . ptr ( ) ) ;
// 3. Let strict be func.[[Strict]].
// 4. Let formals be func.[[FormalParameters]].
2025-04-08 00:45:27 +02:00
auto const & formals = * m_formal_parameters ;
2023-09-19 02:46:28 +02:00
// 5. Let parameterNames be the BoundNames of formals.
// 6. If parameterNames has any duplicate entries, let hasDuplicates be true. Otherwise, let hasDuplicates be false.
2024-01-21 16:30:25 +01:00
size_t parameters_in_environment = 0 ;
2023-09-19 02:46:28 +02:00
// NOTE: This loop performs step 5, 6, and 8.
2025-04-08 00:45:27 +02:00
for ( auto const & parameter : formals . parameters ( ) ) {
2023-09-19 02:46:28 +02:00
if ( parameter . default_value )
m_has_parameter_expressions = true ;
parameter . binding . visit (
[ & ] ( Identifier const & identifier ) {
2025-08-06 11:12:58 -04:00
if ( m_parameter_names . set ( identifier . string ( ) , identifier . is_local ( ) ? ParameterIsLocal : : Yes : ParameterIsLocal : : No ) ! = AK : : HashSetResult : : InsertedNewEntry )
2023-09-19 02:46:28 +02:00
m_has_duplicates = true ;
2024-01-21 16:30:25 +01:00
else if ( ! identifier . is_local ( ) )
+ + parameters_in_environment ;
2023-09-19 02:46:28 +02:00
} ,
[ & ] ( NonnullRefPtr < BindingPattern const > const & pattern ) {
if ( pattern - > contains_expression ( ) )
m_has_parameter_expressions = true ;
// NOTE: Nothing in the callback throws an exception.
MUST ( pattern - > for_each_bound_identifier ( [ & ] ( auto & identifier ) {
2025-08-06 11:12:58 -04:00
if ( m_parameter_names . set ( identifier . string ( ) , identifier . is_local ( ) ? ParameterIsLocal : : Yes : ParameterIsLocal : : No ) ! = AK : : HashSetResult : : InsertedNewEntry )
2023-09-19 02:46:28 +02:00
m_has_duplicates = true ;
2024-01-21 16:30:25 +01:00
else if ( ! identifier . is_local ( ) )
+ + parameters_in_environment ;
2023-09-19 02:46:28 +02:00
} ) ) ;
} ) ;
}
// 15. Let argumentsObjectNeeded be true.
m_arguments_object_needed = m_might_need_arguments_object ;
// 16. If func.[[ThisMode]] is lexical, then
2025-04-08 00:45:27 +02:00
if ( m_this_mode = = ThisMode : : Lexical ) {
2023-09-19 02:46:28 +02:00
// a. NOTE: Arrow functions never have an arguments object.
// b. Set argumentsObjectNeeded to false.
m_arguments_object_needed = false ;
}
// 17. Else if parameterNames contains "arguments", then
2025-04-08 00:45:27 +02:00
else if ( m_parameter_names . contains ( vm . names . arguments . as_string ( ) ) ) {
2023-09-19 02:46:28 +02:00
// a. Set argumentsObjectNeeded to false.
m_arguments_object_needed = false ;
}
2025-08-02 19:27:29 -04:00
HashTable < Utf16FlyString > function_names ;
2023-09-19 02:46:28 +02:00
// 18. Else if hasParameterExpressions is false, then
// a. If functionNames contains "arguments" or lexicalNames contains "arguments", then
// i. Set argumentsObjectNeeded to false.
// NOTE: The block below is a combination of step 14 and step 18.
if ( scope_body ) {
// NOTE: Nothing in the callback throws an exception.
MUST ( scope_body - > for_each_var_function_declaration_in_reverse_order ( [ & ] ( FunctionDeclaration const & function ) {
2025-08-06 11:12:58 -04:00
if ( function_names . set ( function . name ( ) ) = = AK : : HashSetResult : : InsertedNewEntry )
2023-09-19 02:46:28 +02:00
m_functions_to_initialize . append ( function ) ;
} ) ) ;
2025-04-08 00:45:27 +02:00
auto const & arguments_name = vm . names . arguments . as_string ( ) ;
2023-09-19 02:46:28 +02:00
if ( ! m_has_parameter_expressions & & function_names . contains ( arguments_name ) )
m_arguments_object_needed = false ;
if ( ! m_has_parameter_expressions & & m_arguments_object_needed ) {
// NOTE: Nothing in the callback throws an exception.
MUST ( scope_body - > for_each_lexically_declared_identifier ( [ & ] ( auto const & identifier ) {
if ( identifier . string ( ) = = arguments_name )
m_arguments_object_needed = false ;
} ) ) ;
}
} else {
m_arguments_object_needed = false ;
}
2023-09-20 01:32:07 +02:00
size_t * environment_size = nullptr ;
size_t parameter_environment_bindings_count = 0 ;
// 19. If strict is true or hasParameterExpressions is false, then
2025-04-08 00:45:27 +02:00
if ( strict | | ! m_has_parameter_expressions ) {
2023-09-20 01:32:07 +02:00
// a. NOTE: Only a single Environment Record is needed for the parameters, since calls to eval in strict mode code cannot create new bindings which are visible outside of the eval.
// b. Let env be the LexicalEnvironment of calleeContext
// NOTE: Here we are only interested in the size of the environment.
environment_size = & m_function_environment_bindings_count ;
}
// 20. Else,
else {
// a. NOTE: A separate Environment Record is needed to ensure that bindings created by direct eval calls in the formal parameter list are outside the environment where parameters are declared.
// b. Let calleeEnv be the LexicalEnvironment of calleeContext.
// c. Let env be NewDeclarativeEnvironment(calleeEnv).
environment_size = & parameter_environment_bindings_count ;
}
2024-01-21 16:30:25 +01:00
* environment_size + = parameters_in_environment ;
2023-09-20 01:32:07 +02:00
2025-08-02 19:27:29 -04:00
HashMap < Utf16FlyString , ParameterIsLocal > parameter_bindings ;
2023-09-19 02:46:28 +02:00
2025-05-05 21:53:19 +03:00
auto arguments_object_needs_binding = m_arguments_object_needed & & ! m_local_variables_names . first_matching ( [ ] ( auto const & local ) { return local . declaration_kind = = LocalVariable : : DeclarationKind : : ArgumentsObject ; } ) . has_value ( ) ;
2024-05-21 14:27:15 +01:00
2023-09-19 02:46:28 +02:00
// 22. If argumentsObjectNeeded is true, then
if ( m_arguments_object_needed ) {
// f. Let parameterBindings be the list-concatenation of parameterNames and « "arguments" ».
parameter_bindings = m_parameter_names ;
2025-04-08 00:45:27 +02:00
parameter_bindings . set ( vm . names . arguments . as_string ( ) , ParameterIsLocal : : No ) ;
2023-09-20 01:32:07 +02:00
2024-05-21 14:27:15 +01:00
if ( arguments_object_needs_binding )
( * environment_size ) + + ;
2023-09-19 02:46:28 +02:00
} else {
parameter_bindings = m_parameter_names ;
// a. Let parameterBindings be parameterNames.
}
2025-08-02 19:27:29 -04:00
HashMap < Utf16FlyString , ParameterIsLocal > instantiated_var_names ;
2023-09-19 02:46:28 +02:00
2023-09-20 01:32:07 +02:00
size_t * var_environment_size = nullptr ;
2023-09-19 02:46:28 +02:00
// 27. If hasParameterExpressions is false, then
if ( ! m_has_parameter_expressions ) {
// b. Let instantiatedVarNames be a copy of the List parameterBindings.
instantiated_var_names = parameter_bindings ;
if ( scope_body ) {
// c. For each element n of varNames, do
2025-08-02 19:27:29 -04:00
MUST ( scope_body - > for_each_var_declared_identifier ( [ & ] ( Identifier const & id ) {
2023-09-19 02:46:28 +02:00
// i. If instantiatedVarNames does not contain n, then
2025-08-06 11:12:58 -04:00
if ( instantiated_var_names . set ( id . string ( ) , id . is_local ( ) ? ParameterIsLocal : : Yes : ParameterIsLocal : : No ) = = AK : : HashSetResult : : InsertedNewEntry ) {
2023-09-19 02:46:28 +02:00
// 1. Append n to instantiatedVarNames.
// Following steps will be executed in function_declaration_instantiation:
// 2. Perform ! env.CreateMutableBinding(n, false).
// 3. Perform ! env.InitializeBinding(n, undefined).
m_var_names_to_initialize_binding . append ( {
. identifier = id ,
2025-03-27 17:07:40 +00:00
// NOTE: We don't have to set parameter_binding or function_name here
// since those are only relevant in the hasParameterExpressions==true path.
2023-09-19 02:46:28 +02:00
} ) ;
2023-09-20 01:32:07 +02:00
if ( ! id . is_local ( ) )
( * environment_size ) + + ;
2023-09-19 02:46:28 +02:00
}
} ) ) ;
}
2023-09-20 01:32:07 +02:00
// d. Let varEnv be env
var_environment_size = environment_size ;
2023-09-19 02:46:28 +02:00
} else {
2023-09-20 01:32:07 +02:00
// a. NOTE: A separate Environment Record is needed to ensure that closures created by expressions in the formal parameter list do not have visibility of declarations in the function body.
// b. Let varEnv be NewDeclarativeEnvironment(env).
// NOTE: Here we are only interested in the size of the environment.
var_environment_size = & m_var_environment_bindings_count ;
2023-09-19 02:46:28 +02:00
// 28. Else,
// NOTE: Steps a, b, c and d are executed in function_declaration_instantiation.
// e. For each element n of varNames, do
if ( scope_body ) {
2025-08-02 19:27:29 -04:00
MUST ( scope_body - > for_each_var_declared_identifier ( [ & ] ( Identifier const & id ) {
2025-08-06 11:12:58 -04:00
auto const & name = id . string ( ) ;
2025-08-02 19:27:29 -04:00
2023-09-19 02:46:28 +02:00
// 1. Append n to instantiatedVarNames.
// Following steps will be executed in function_declaration_instantiation:
// 2. Perform ! env.CreateMutableBinding(n, false).
// 3. Perform ! env.InitializeBinding(n, undefined).
2025-08-02 19:27:29 -04:00
if ( instantiated_var_names . set ( name , id . is_local ( ) ? ParameterIsLocal : : Yes : ParameterIsLocal : : No ) = = AK : : HashSetResult : : InsertedNewEntry ) {
2023-09-19 02:46:28 +02:00
m_var_names_to_initialize_binding . append ( {
. identifier = id ,
2025-08-02 19:27:29 -04:00
. parameter_binding = parameter_bindings . contains ( name ) ,
. function_name = function_names . contains ( name ) ,
2023-09-19 02:46:28 +02:00
} ) ;
2023-09-20 01:32:07 +02:00
if ( ! id . is_local ( ) )
( * var_environment_size ) + + ;
2023-09-19 02:46:28 +02:00
}
} ) ) ;
}
}
2023-09-20 01:32:07 +02:00
// 29. NOTE: Annex B.3.2.1 adds additional steps at this point.
// B.3.2.1 Changes to FunctionDeclarationInstantiation, https://tc39.es/ecma262/#sec-web-compat-functiondeclarationinstantiation
2023-09-19 02:46:28 +02:00
if ( ! m_strict & & scope_body ) {
MUST ( scope_body - > for_each_function_hoistable_with_annexB_extension ( [ & ] ( FunctionDeclaration & function_declaration ) {
2025-08-06 11:12:58 -04:00
auto function_name = function_declaration . name ( ) ;
2023-09-19 02:46:28 +02:00
if ( parameter_bindings . contains ( function_name ) )
return ;
2025-04-08 00:45:27 +02:00
if ( ! instantiated_var_names . contains ( function_name ) & & function_name ! = vm . names . arguments . as_string ( ) ) {
2023-09-19 02:46:28 +02:00
m_function_names_to_initialize_binding . append ( function_name ) ;
2024-01-21 16:06:18 +01:00
instantiated_var_names . set ( function_name , ParameterIsLocal : : No ) ;
2023-09-20 01:32:07 +02:00
( * var_environment_size ) + + ;
2023-09-19 02:46:28 +02:00
}
function_declaration . set_should_do_additional_annexB_steps ( ) ;
} ) ) ;
}
2023-09-20 01:32:07 +02:00
size_t * lex_environment_size = nullptr ;
// 30. If strict is false, then
if ( ! m_strict ) {
2024-05-04 22:36:56 +02:00
bool can_elide_declarative_environment = ! m_contains_direct_call_to_eval & & ( ! scope_body | | ! scope_body - > has_non_local_lexical_declarations ( ) ) ;
2023-09-20 01:32:07 +02:00
if ( can_elide_declarative_environment ) {
lex_environment_size = var_environment_size ;
} else {
// a. Let lexEnv be NewDeclarativeEnvironment(varEnv).
lex_environment_size = & m_lex_environment_bindings_count ;
}
} else {
// a. let lexEnv be varEnv.
// NOTE: Here we are only interested in the size of the environment.
lex_environment_size = var_environment_size ;
}
if ( scope_body ) {
MUST ( scope_body - > for_each_lexically_declared_identifier ( [ & ] ( auto const & id ) {
if ( ! id . is_local ( ) )
( * lex_environment_size ) + + ;
} ) ) ;
}
2024-05-03 22:54:12 +02:00
2024-05-22 11:04:50 +01:00
m_function_environment_needed = arguments_object_needs_binding | | m_function_environment_bindings_count > 0 | | m_var_environment_bindings_count > 0 | | m_lex_environment_bindings_count > 0 | | parsing_insights . uses_this_from_environment | | m_contains_direct_call_to_eval ;
2025-04-08 00:45:27 +02:00
}
ECMAScriptFunctionObject : : ECMAScriptFunctionObject (
NonnullRefPtr < SharedFunctionInstanceData > shared_data ,
Environment * parent_environment ,
PrivateEnvironment * private_environment ,
Object & prototype )
: FunctionObject ( prototype )
, m_shared_data ( move ( shared_data ) )
, m_environment ( parent_environment )
, m_private_environment ( private_environment )
{
if ( ! is_arrow_function ( ) & & kind ( ) = = FunctionKind : : Normal )
2025-04-11 18:55:01 +02:00
unsafe_set_shape ( realm ( ) - > intrinsics ( ) . normal_function_shape ( ) ) ;
2025-04-08 00:45:27 +02:00
// 15. Set F.[[ScriptOrModule]] to GetActiveScriptOrModule().
m_script_or_module = vm ( ) . get_active_script_or_module ( ) ;
2020-06-20 17:11:11 +02:00
}
2023-08-07 08:41:28 +02:00
void ECMAScriptFunctionObject : : initialize ( Realm & realm )
2020-06-20 17:11:11 +02:00
{
2020-10-13 23:49:19 +02:00
auto & vm = this - > vm ( ) ;
2023-08-07 08:41:28 +02:00
Base : : initialize ( realm ) ;
2021-10-15 15:05:02 +02:00
// Note: The ordering of these properties must be: length, name, prototype which is the order
// they are defined in the spec: https://tc39.es/ecma262/#sec-function-instances .
// This is observable through something like: https://tc39.es/ecma262/#sec-ordinaryownpropertykeys
// which must give the properties in chronological order which in this case is the order they
// are defined in the spec.
2025-04-08 00:45:27 +02:00
m_name_string = PrimitiveString : : create ( vm , name ( ) ) ;
2023-11-27 13:38:19 +01:00
2025-04-08 00:45:27 +02:00
if ( ! is_arrow_function ( ) & & kind ( ) = = FunctionKind : : Normal ) {
put_direct ( realm . intrinsics ( ) . normal_function_length_offset ( ) , Value ( function_length ( ) ) ) ;
2025-03-25 20:08:38 +00:00
put_direct ( realm . intrinsics ( ) . normal_function_name_offset ( ) , m_name_string ) ;
auto prototype = Object : : create_with_premade_shape ( realm . intrinsics ( ) . normal_function_prototype_shape ( ) ) ;
prototype - > put_direct ( realm . intrinsics ( ) . normal_function_prototype_constructor_offset ( ) , this ) ;
put_direct ( realm . intrinsics ( ) . normal_function_prototype_offset ( ) , prototype ) ;
} else {
2025-09-15 16:43:27 +02:00
PropertyDescriptor length_descriptor { . value = Value ( function_length ( ) ) , . writable = false , . enumerable = false , . configurable = true } ;
MUST ( define_property_or_throw ( vm . names . length , length_descriptor ) ) ;
PropertyDescriptor name_descriptor { . value = m_name_string , . writable = false , . enumerable = false , . configurable = true } ;
MUST ( define_property_or_throw ( vm . names . name , name_descriptor ) ) ;
2025-03-25 20:08:38 +00:00
2025-04-08 00:45:27 +02:00
if ( ! is_arrow_function ( ) ) {
2025-03-25 20:08:38 +00:00
Object * prototype = nullptr ;
2025-04-08 00:45:27 +02:00
switch ( kind ( ) ) {
2025-03-25 20:08:38 +00:00
case FunctionKind : : Normal :
VERIFY_NOT_REACHED ( ) ;
break ;
case FunctionKind : : Generator :
// prototype is "g1.prototype" in figure-2 (https://tc39.es/ecma262/img/figure-2.png)
prototype = Object : : create_prototype ( realm , realm . intrinsics ( ) . generator_function_prototype_prototype ( ) ) ;
break ;
case FunctionKind : : Async :
break ;
case FunctionKind : : AsyncGenerator :
prototype = Object : : create_prototype ( realm , realm . intrinsics ( ) . async_generator_function_prototype_prototype ( ) ) ;
break ;
}
// 27.7.4 AsyncFunction Instances, https://tc39.es/ecma262/#sec-async-function-instances
// AsyncFunction instances do not have a prototype property as they are not constructible.
2025-04-08 00:45:27 +02:00
if ( kind ( ) ! = FunctionKind : : Async )
2025-03-25 20:08:38 +00:00
define_direct_property ( vm . names . prototype , prototype , Attribute : : Writable ) ;
2021-06-15 00:04:08 -07:00
}
2020-06-08 13:24:15 -05:00
}
2020-03-13 10:08:52 +01:00
}
2025-04-27 11:53:11 +02:00
ThrowCompletionOr < void > ECMAScriptFunctionObject : : get_stack_frame_size ( size_t & registers_and_constants_and_locals_count , size_t & argument_count )
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
{
2025-04-22 21:49:41 +02:00
if ( ! m_bytecode_executable ) {
if ( ! ecmascript_code ( ) . bytecode_executable ( ) ) {
if ( is_module_wrapper ( ) ) {
2025-04-27 11:53:11 +02:00
const_cast < Statement & > ( ecmascript_code ( ) ) . set_bytecode_executable ( TRY ( Bytecode : : compile ( vm ( ) , ecmascript_code ( ) , kind ( ) , name ( ) ) ) ) ;
2025-04-22 21:49:41 +02:00
} else {
2025-04-27 11:53:11 +02:00
const_cast < Statement & > ( ecmascript_code ( ) ) . set_bytecode_executable ( TRY ( Bytecode : : compile ( vm ( ) , * this ) ) ) ;
2025-04-22 21:49:41 +02:00
}
}
m_bytecode_executable = ecmascript_code ( ) . bytecode_executable ( ) ;
}
2025-04-27 11:53:11 +02:00
registers_and_constants_and_locals_count = m_bytecode_executable - > number_of_registers + m_bytecode_executable - > constants . size ( ) + m_bytecode_executable - > local_variable_names . size ( ) ;
argument_count = max ( argument_count , formal_parameters ( ) . size ( ) ) ;
return { } ;
}
2025-04-22 21:49:41 +02:00
2025-04-27 11:53:11 +02:00
// 10.2.1 [[Call]] ( thisArgument, argumentsList ), https://tc39.es/ecma262/#sec-ecmascript-function-objects-call-thisargument-argumentslist
2025-04-28 01:54:11 +02:00
FLATTEN ThrowCompletionOr < Value > ECMAScriptFunctionObject : : internal_call ( ExecutionContext & callee_context , Value this_argument )
2025-04-27 11:53:11 +02:00
{
auto & vm = this - > vm ( ) ;
2025-04-28 01:53:44 +02:00
ASSERT ( m_bytecode_executable ) ;
2025-04-27 11:53:11 +02:00
// 1. Let callerContext be the running execution context.
// NOTE: No-op, kept by the VM in its execution context stack.
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
// 2. Let calleeContext be PrepareForOrdinaryCall(F, undefined).
2025-04-28 21:12:10 +02:00
prepare_for_ordinary_call ( vm , callee_context , nullptr ) ;
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
// 3. Assert: calleeContext is now the running execution context.
2025-04-28 01:53:44 +02:00
ASSERT ( & vm . running_execution_context ( ) = = & callee_context ) ;
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
// 4. If F.[[IsClassConstructor]] is true, then
2025-04-28 02:04:54 +02:00
if ( is_class_constructor ( ) ) [[unlikely]] {
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
// a. Let error be a newly created TypeError object.
// b. NOTE: error is created in calleeContext with F's associated Realm Record.
2025-04-08 00:45:27 +02:00
auto throw_completion = vm . throw_completion < TypeError > ( ErrorType : : ClassConstructorWithoutNew , name ( ) ) ;
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
// c. Remove calleeContext from the execution context stack and restore callerContext as the running execution context.
vm . pop_execution_context ( ) ;
// d. Return ThrowCompletion(error).
return throw_completion ;
}
// 5. Perform OrdinaryCallBindThis(F, calleeContext, thisArgument).
2025-04-08 00:45:27 +02:00
if ( uses_this ( ) )
2025-04-28 01:37:16 +02:00
ordinary_call_bind_this ( vm , callee_context , this_argument ) ;
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-05-02 20:54:39 +02:00
// 6. Let result be Completion(OrdinaryCallEvaluateBody(F, argumentsList)).
2025-04-28 01:37:16 +02:00
auto result = ordinary_call_evaluate_body ( vm ) ;
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
// 7. Remove calleeContext from the execution context stack and restore callerContext as the running execution context.
vm . pop_execution_context ( ) ;
2022-05-02 20:54:39 +02:00
// 8. If result.[[Type]] is return, return result.[[Value]].
2025-01-02 02:16:33 +13:00
// 9. Assert: result is a throw completion.
// 10. Return ? result.
2025-04-28 02:11:57 +02:00
return result ;
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
}
// 10.2.2 [[Construct]] ( argumentsList, newTarget ), https://tc39.es/ecma262/#sec-ecmascript-function-objects-construct-argumentslist-newtarget
2025-08-30 10:36:32 +02:00
ThrowCompletionOr < GC : : Ref < Object > > ECMAScriptFunctionObject : : internal_construct ( ExecutionContext & callee_context , FunctionObject & new_target )
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
{
auto & vm = this - > vm ( ) ;
2025-08-30 10:36:32 +02:00
ASSERT ( m_bytecode_executable ) ;
2025-03-18 00:13:20 +13: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
// 1. Let callerContext be the running execution context.
// NOTE: No-op, kept by the VM in its execution context stack.
// 2. Let kind be F.[[ConstructorKind]].
2025-04-08 00:45:27 +02:00
auto kind = constructor_kind ( ) ;
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
2024-11-15 04:01:23 +13:00
GC : : Ptr < Object > this_argument ;
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
// 3. If kind is base, then
if ( kind = = ConstructorKind : : Base ) {
// a. Let thisArgument be ? OrdinaryCreateFromConstructor(newTarget, "%Object.prototype%").
2022-12-14 12:17:58 +01:00
this_argument = TRY ( ordinary_create_from_constructor < Object > ( vm , new_target , & Intrinsics : : object_prototype , ConstructWithPrototypeTag : : Tag ) ) ;
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
}
// 4. Let calleeContext be PrepareForOrdinaryCall(F, newTarget).
2025-08-30 10:36:32 +02:00
prepare_for_ordinary_call ( vm , callee_context , & new_target ) ;
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
// 5. Assert: calleeContext is now the running execution context.
2025-08-30 10:36:32 +02:00
VERIFY ( & vm . running_execution_context ( ) = = & callee_context ) ;
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
// 6. If kind is base, then
if ( kind = = ConstructorKind : : Base ) {
// a. Perform OrdinaryCallBindThis(F, calleeContext, thisArgument).
2025-04-08 00:45:27 +02:00
if ( uses_this ( ) )
2025-08-30 10:36:32 +02:00
ordinary_call_bind_this ( vm , callee_context , this_argument ) ;
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-05-02 20:54:39 +02:00
// b. Let initializeResult be Completion(InitializeInstanceElements(thisArgument, F)).
2022-12-07 00:22:23 +00:00
auto initialize_result = this_argument - > initialize_instance_elements ( * this ) ;
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
// c. If initializeResult is an abrupt completion, then
if ( initialize_result . is_throw_completion ( ) ) {
// i. Remove calleeContext from the execution context stack and restore callerContext as the running execution context.
vm . pop_execution_context ( ) ;
2022-05-02 20:54:39 +02:00
// ii. Return ? initializeResult.
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
return initialize_result . throw_completion ( ) ;
}
}
// 7. Let constructorEnv be the LexicalEnvironment of calleeContext.
2025-08-30 10:36:32 +02:00
auto constructor_env = callee_context . lexical_environment ;
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-05-02 20:54:39 +02:00
// 8. Let result be Completion(OrdinaryCallEvaluateBody(F, argumentsList)).
2025-04-28 01:37:16 +02:00
auto result = ordinary_call_evaluate_body ( vm ) ;
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
// 9. Remove calleeContext from the execution context stack and restore callerContext as the running execution context.
vm . pop_execution_context ( ) ;
2025-01-02 02:16:33 +13:00
// 10. If result is a throw completion, then
2025-04-28 02:11:57 +02:00
if ( result . is_error ( ) ) {
2025-01-02 02:16:33 +13:00
// a. Return ? result.
return result . release_error ( ) ;
}
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
2025-01-02 02:16:33 +13:00
// 11. Assert: result is a return completion.
2025-04-28 02:11:57 +02:00
// NOTE: We already checked !is_error() above.
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
2025-01-02 02:16:33 +13:00
// 12. If Type(result.[[Value]]) is Object, return result.[[Value]].
2025-04-04 18:11:45 +02:00
if ( result . value ( ) . is_object ( ) )
2025-04-28 02:11:57 +02:00
return GC : : Ref < Object > { const_cast < Object & > ( result . value ( ) . as_object ( ) ) } ;
2025-01-02 02:16:33 +13:00
// 13. If kind is base, return thisArgument.
if ( kind = = ConstructorKind : : Base )
return * this_argument ;
// 14. If result.[[Value]] is not undefined, throw a TypeError exception.
2025-04-04 18:11:45 +02:00
if ( ! result . value ( ) . is_undefined ( ) )
2025-01-02 02:16:33 +13:00
return vm . throw_completion < TypeError > ( ErrorType : : DerivedConstructorReturningInvalidValue ) ;
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
2025-01-02 02:16:33 +13:00
// 15. Let thisBinding be ? constructorEnv.GetThisBinding().
2022-08-21 15:12:43 +01:00
auto this_binding = TRY ( constructor_env - > get_this_binding ( vm ) ) ;
2022-05-02 20:54:39 +02:00
2025-01-02 02:16:33 +13:00
// 16. Assert: Type(thisBinding) is Object.
2022-05-02 20:54:39 +02:00
VERIFY ( this_binding . is_object ( ) ) ;
2025-01-02 02:16:33 +13:00
// 17. Return thisBinding.
2022-12-14 18:49:48 +00:00
return this_binding . as_object ( ) ;
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
}
2021-09-24 22:40:38 +02:00
void ECMAScriptFunctionObject : : visit_edges ( Visitor & visitor )
2020-04-15 21:58:22 +02:00
{
2021-06-27 21:48:34 +02:00
Base : : visit_edges ( visitor ) ;
2021-06-25 21:22:37 +02:00
visitor . visit ( m_environment ) ;
2021-12-08 10:14:36 +01:00
visitor . visit ( m_private_environment ) ;
2021-09-24 23:49:24 +02:00
visitor . visit ( m_home_object ) ;
2024-04-01 10:33:56 +02:00
visitor . visit ( m_name_string ) ;
2021-09-25 00:01:09 +02:00
2023-11-27 13:23:59 +01:00
visitor . visit ( m_bytecode_executable ) ;
2025-04-08 13:39:07 +02:00
if ( m_class_data ) {
for ( auto & field : m_class_data - > fields ) {
field . initializer . visit (
[ & visitor ] ( GC : : Ref < ECMAScriptFunctionObject > & initializer ) {
visitor . visit ( initializer ) ;
} ,
[ & visitor ] ( Value initializer ) {
visitor . visit ( initializer ) ;
} ,
[ ] ( Empty ) { } ) ;
if ( auto * property_key_ptr = field . name . get_pointer < PropertyKey > ( ) ; property_key_ptr & & property_key_ptr - > is_symbol ( ) )
visitor . visit ( property_key_ptr - > as_symbol ( ) ) ;
}
2022-09-05 14:31:25 +02:00
2025-04-08 13:39:07 +02:00
for ( auto & private_element : m_class_data - > private_methods )
visitor . visit ( private_element . value ) ;
}
2023-12-09 11:05:25 +01:00
2022-09-05 14:31:25 +02:00
m_script_or_module . visit (
[ ] ( Empty ) { } ,
[ & ] ( auto & script_or_module ) {
2023-11-19 16:18:00 +13:00
visitor . visit ( script_or_module ) ;
2022-09-05 14:31:25 +02:00
} ) ;
2020-04-15 21:58:22 +02:00
}
2021-12-29 10:33:46 +01:00
// 10.2.7 MakeMethod ( F, homeObject ), https://tc39.es/ecma262/#sec-makemethod
void ECMAScriptFunctionObject : : make_method ( Object & home_object )
{
// 1. Set F.[[HomeObject]] to homeObject.
m_home_object = & home_object ;
2022-05-02 20:54:39 +02:00
// 2. Return unused.
2021-12-29 10:33:46 +01:00
}
2021-10-08 21:14:22 +01:00
// 10.2.1.1 PrepareForOrdinaryCall ( F, newTarget ), https://tc39.es/ecma262/#sec-prepareforordinarycall
2025-04-28 21:12:10 +02:00
void ECMAScriptFunctionObject : : prepare_for_ordinary_call ( VM & vm , ExecutionContext & callee_context , Object * new_target )
2021-10-08 21:14:22 +01:00
{
// Non-standard
2025-04-08 00:45:27 +02:00
callee_context . is_strict_mode = is_strict_mode ( ) ;
2021-10-08 21:14:22 +01:00
// 1. Let callerContext be the running execution context.
// 2. Let calleeContext be a new ECMAScript code execution context.
// 3. Set the Function of calleeContext to F.
callee_context . function = this ;
2023-11-27 13:38:19 +01:00
callee_context . function_name = m_name_string ;
2021-10-08 21:14:22 +01:00
// 4. Let calleeRealm be F.[[Realm]].
// 5. Set the Realm of calleeContext to calleeRealm.
2025-04-11 18:55:01 +02:00
callee_context . realm = realm ( ) ;
2021-10-08 21:14:22 +01:00
// 6. Set the ScriptOrModule of calleeContext to F.[[ScriptOrModule]].
2022-01-17 14:48:22 +01:00
callee_context . script_or_module = m_script_or_module ;
2021-10-08 21:14:22 +01:00
2025-04-08 00:45:27 +02:00
if ( function_environment_needed ( ) ) {
2024-05-03 22:54:12 +02:00
// 7. Let localEnv be NewFunctionEnvironment(F, newTarget).
auto local_environment = new_function_environment ( * this , new_target ) ;
2025-04-08 00:45:27 +02:00
local_environment - > ensure_capacity ( shared_data ( ) . m_function_environment_bindings_count ) ;
2021-10-08 21:14:22 +01:00
2024-05-03 22:54:12 +02:00
// 8. Set the LexicalEnvironment of calleeContext to localEnv.
callee_context . lexical_environment = local_environment ;
2021-10-08 21:14:22 +01:00
2024-05-03 22:54:12 +02:00
// 9. Set the VariableEnvironment of calleeContext to localEnv.
callee_context . variable_environment = local_environment ;
} else {
callee_context . lexical_environment = environment ( ) ;
callee_context . variable_environment = environment ( ) ;
}
2021-10-08 21:14:22 +01:00
// 10. Set the PrivateEnvironment of calleeContext to F.[[PrivateEnvironment]].
2021-10-11 20:29:31 +02:00
callee_context . private_environment = m_private_environment ;
2021-10-08 21:14:22 +01:00
// 11. If callerContext is not already suspended, suspend callerContext.
// 12. Push calleeContext onto the execution context stack; calleeContext is now the running execution context.
2025-04-28 21:12:10 +02:00
// NOTE: We don't check for stack overflow here. The bytecode interpreter will do it anyway
// when entering the function we're about to call.
vm . push_execution_context ( callee_context ) ;
2021-10-08 21:14:22 +01:00
// 13. NOTE: Any exception objects produced after this point are associated with calleeRealm.
2022-04-11 21:32:37 +01:00
// 14. Return calleeContext.
// NOTE: See the comment after step 2 above about how contexts are allocated on the C++ stack.
2021-10-08 21:14:22 +01:00
}
2021-10-08 21:15:53 +01:00
// 10.2.1.2 OrdinaryCallBindThis ( F, calleeContext, thisArgument ), https://tc39.es/ecma262/#sec-ordinarycallbindthis
2025-04-28 01:37:16 +02:00
void ECMAScriptFunctionObject : : ordinary_call_bind_this ( VM & vm , ExecutionContext & callee_context , Value this_argument )
2021-10-08 21:15:53 +01:00
{
// 1. Let thisMode be F.[[ThisMode]].
2022-05-02 20:54:39 +02:00
// If thisMode is lexical, return unused.
2025-04-08 00:45:27 +02:00
if ( this_mode ( ) = = ThisMode : : Lexical )
2021-10-08 21:15:53 +01:00
return ;
// 3. Let calleeRealm be F.[[Realm]].
2025-04-11 18:55:01 +02:00
auto callee_realm = realm ( ) ;
2021-10-08 21:15:53 +01:00
// 4. Let localEnv be the LexicalEnvironment of calleeContext.
2023-02-26 16:09:02 -07:00
auto local_env = callee_context . lexical_environment ;
2021-10-08 21:15:53 +01:00
Value this_value ;
// 5. If thisMode is strict, let thisValue be thisArgument.
2025-04-08 00:45:27 +02:00
if ( this_mode ( ) = = ThisMode : : Strict ) {
2021-10-08 21:15:53 +01:00
this_value = this_argument ;
}
// 6. Else,
else {
// a. If thisArgument is undefined or null, then
if ( this_argument . is_nullish ( ) ) {
// i. Let globalEnv be calleeRealm.[[GlobalEnv]].
// ii. Assert: globalEnv is a global Environment Record.
auto & global_env = callee_realm - > global_environment ( ) ;
// iii. Let thisValue be globalEnv.[[GlobalThisValue]].
this_value = & global_env . global_this_value ( ) ;
}
// b. Else,
else {
// i. Let thisValue be ! ToObject(thisArgument).
2022-08-21 14:00:56 +01:00
this_value = MUST ( this_argument . to_object ( vm ) ) ;
2021-10-08 21:15:53 +01:00
// ii. NOTE: ToObject produces wrapper objects using calleeRealm.
2022-08-21 14:00:56 +01:00
VERIFY ( vm . current_realm ( ) = = callee_realm ) ;
2021-10-08 21:15:53 +01:00
}
}
// 7. Assert: localEnv is a function Environment Record.
// 8. Assert: The next step never returns an abrupt completion because localEnv.[[ThisBindingStatus]] is not initialized.
2022-05-02 20:54:39 +02:00
// 9. Perform ! localEnv.BindThisValue(thisValue).
2024-05-21 16:51:21 +01:00
callee_context . this_value = this_value ;
2025-04-08 00:45:27 +02:00
if ( function_environment_needed ( ) )
2025-01-21 09:12:05 -05:00
MUST ( as < FunctionEnvironment > ( * local_env ) . bind_this_value ( vm , this_value ) ) ;
2022-05-02 20:54:39 +02:00
// 10. Return unused.
2021-10-08 21:15:53 +01:00
}
2021-11-09 20:39:22 +02:00
// 27.7.5.1 AsyncFunctionStart ( promiseCapability, asyncFunctionBody ), https://tc39.es/ecma262/#sec-async-functions-abstract-operations-async-function-start
2023-07-16 17:54:26 +12:00
template < typename T >
void async_function_start ( VM & vm , PromiseCapability const & promise_capability , T const & async_function_body )
2021-11-09 20:39:22 +02:00
{
// 1. Let runningContext be the running execution context.
auto & running_context = vm . running_execution_context ( ) ;
// 2. Let asyncContext be a copy of runningContext.
auto async_context = running_context . copy ( ) ;
// 3. NOTE: Copying the execution state is required for AsyncBlockStart to resume its execution. It is ill-defined to resume a currently executing context.
2022-05-02 20:54:39 +02:00
// 4. Perform AsyncBlockStart(promiseCapability, asyncFunctionBody, asyncContext).
2023-11-27 16:45:45 +01:00
async_block_start ( vm , async_function_body , promise_capability , * async_context ) ;
2022-05-02 20:54:39 +02:00
// 5. Return unused.
2021-11-09 20:39:22 +02:00
}
// 27.7.5.2 AsyncBlockStart ( promiseCapability, asyncBody, asyncContext ), https://tc39.es/ecma262/#sec-asyncblockstart
2023-07-16 17:54:26 +12:00
template < typename T >
void async_block_start ( VM & vm , T const & async_body , PromiseCapability const & promise_capability , ExecutionContext & async_context )
2021-11-09 20:39:22 +02:00
{
2022-08-16 00:20:49 +01:00
auto & realm = * vm . current_realm ( ) ;
2024-12-02 17:12:08 +01:00
// 1. Let runningContext be the running execution context.
2021-11-09 20:39:22 +02:00
auto & running_context = vm . running_execution_context ( ) ;
2024-12-02 17:12:08 +01:00
// 2. Let closure be a new Abstract Closure with no parameters that captures promiseCapability and asyncBody and performs the following steps when called:
2025-08-02 19:27:29 -04:00
auto closure = NativeFunction : : create ( realm , { } , [ & async_body , & promise_capability ] ( auto & vm ) - > ThrowCompletionOr < Value > {
2023-06-22 15:59:18 +02:00
Completion result ;
2023-07-16 18:04:01 +12:00
2024-12-02 17:12:08 +01:00
// a. Let acAsyncContext be the running execution context.
// b. If asyncBody is a Parse Node, then
2024-11-15 04:01:23 +13:00
if constexpr ( ! IsSame < T , GC : : Function < Completion ( ) > > ) {
2024-12-02 17:12:08 +01:00
// i. Let result be Completion(Evaluation of asyncBody).
2025-08-02 19:27:29 -04:00
auto maybe_executable = Bytecode : : compile ( vm , async_body , FunctionKind : : Async , " AsyncBlockStart " _utf16_fly_string ) ;
2023-08-07 19:59:00 +02:00
if ( maybe_executable . is_error ( ) )
result = maybe_executable . release_error ( ) ;
else
2024-05-06 06:44:08 +02:00
result = vm . bytecode_interpreter ( ) . run_executable ( * maybe_executable . value ( ) , { } ) . value ;
2023-07-16 18:04:01 +12:00
}
2024-12-02 17:12:08 +01:00
// c. Else,
2023-07-16 18:04:01 +12:00
else {
// i. Assert: asyncBody is an Abstract Closure with no parameters.
// ii. Let result be asyncBody().
2024-10-31 06:21:59 +13:00
result = async_body . function ( ) ( ) ;
2023-06-22 15:59:18 +02:00
}
2024-12-02 17:12:08 +01:00
// d. Assert: If we return here, the async function either threw an exception or performed an implicit or explicit return; all awaiting is done.
// e. Remove acAsyncContext from the execution context stack and restore the execution context that is at the top of the execution context stack as the running execution context.
2021-11-09 20:39:22 +02:00
vm . pop_execution_context ( ) ;
2024-12-02 17:12:08 +01:00
// f. If result is a normal completion, then
LibJS: Replace the custom unwind mechanism with completions :^)
This includes:
- Parsing proper LabelledStatements with try_parse_labelled_statement()
- Removing LabelableStatement
- Implementing the LoopEvaluation semantics via loop_evaluation() in
each IterationStatement subclass; and IterationStatement evaluation
via {For,ForIn,ForOf,ForAwaitOf,While,DoWhile}Statement::execute()
- Updating ReturnStatement, BreakStatement and ContinueStatement to
return the appropriate completion types
- Basically reimplementing TryStatement and SwitchStatement according to
the spec, using completions
- Honoring result completion types in AsyncBlockStart and
OrdinaryCallEvaluateBody
- Removing any uses of the VM unwind mechanism - most importantly,
VM::throw_exception() now exclusively sets an exception and no longer
triggers any unwinding mechanism.
However, we already did a good job updating all of LibWeb and userland
applications to not use it, and the few remaining uses elsewhere don't
rely on unwinding AFAICT.
2022-01-05 19:11:16 +01:00
if ( result . type ( ) = = Completion : : Type : : Normal ) {
2021-11-09 20:39:22 +02:00
// i. Perform ! Call(promiseCapability.[[Resolve]], undefined, « undefined »).
2022-10-02 12:11:30 +01:00
MUST ( call ( vm , * promise_capability . resolve ( ) , js_undefined ( ) , js_undefined ( ) ) ) ;
2021-11-09 20:39:22 +02:00
}
2024-12-02 17:12:08 +01:00
// g. Else if result is a return completion, then
LibJS: Replace the custom unwind mechanism with completions :^)
This includes:
- Parsing proper LabelledStatements with try_parse_labelled_statement()
- Removing LabelableStatement
- Implementing the LoopEvaluation semantics via loop_evaluation() in
each IterationStatement subclass; and IterationStatement evaluation
via {For,ForIn,ForOf,ForAwaitOf,While,DoWhile}Statement::execute()
- Updating ReturnStatement, BreakStatement and ContinueStatement to
return the appropriate completion types
- Basically reimplementing TryStatement and SwitchStatement according to
the spec, using completions
- Honoring result completion types in AsyncBlockStart and
OrdinaryCallEvaluateBody
- Removing any uses of the VM unwind mechanism - most importantly,
VM::throw_exception() now exclusively sets an exception and no longer
triggers any unwinding mechanism.
However, we already did a good job updating all of LibWeb and userland
applications to not use it, and the few remaining uses elsewhere don't
rely on unwinding AFAICT.
2022-01-05 19:11:16 +01:00
else if ( result . type ( ) = = Completion : : Type : : Return ) {
2021-11-09 20:39:22 +02:00
// i. Perform ! Call(promiseCapability.[[Resolve]], undefined, « result.[[Value]] »).
2025-04-04 18:11:45 +02:00
MUST ( call ( vm , * promise_capability . resolve ( ) , js_undefined ( ) , result . value ( ) ) ) ;
2021-11-09 20:39:22 +02:00
}
2024-12-02 17:12:08 +01:00
// h. Else,
2021-11-09 20:39:22 +02:00
else {
2024-12-02 17:12:08 +01:00
// i. Assert: result is a throw completion.
LibJS: Replace the custom unwind mechanism with completions :^)
This includes:
- Parsing proper LabelledStatements with try_parse_labelled_statement()
- Removing LabelableStatement
- Implementing the LoopEvaluation semantics via loop_evaluation() in
each IterationStatement subclass; and IterationStatement evaluation
via {For,ForIn,ForOf,ForAwaitOf,While,DoWhile}Statement::execute()
- Updating ReturnStatement, BreakStatement and ContinueStatement to
return the appropriate completion types
- Basically reimplementing TryStatement and SwitchStatement according to
the spec, using completions
- Honoring result completion types in AsyncBlockStart and
OrdinaryCallEvaluateBody
- Removing any uses of the VM unwind mechanism - most importantly,
VM::throw_exception() now exclusively sets an exception and no longer
triggers any unwinding mechanism.
However, we already did a good job updating all of LibWeb and userland
applications to not use it, and the few remaining uses elsewhere don't
rely on unwinding AFAICT.
2022-01-05 19:11:16 +01:00
VERIFY ( result . type ( ) = = Completion : : Type : : Throw ) ;
2021-11-09 20:39:22 +02:00
// ii. Perform ! Call(promiseCapability.[[Reject]], undefined, « result.[[Value]] »).
2025-04-04 18:11:45 +02:00
MUST ( call ( vm , * promise_capability . reject ( ) , js_undefined ( ) , result . value ( ) ) ) ;
2021-11-09 20:39:22 +02:00
}
2024-12-02 17:12:08 +01:00
// i. Return unused.
2022-05-02 20:54:39 +02:00
// NOTE: We don't support returning an empty/optional/unused value here.
2021-11-09 20:39:22 +02:00
return js_undefined ( ) ;
} ) ;
2024-12-02 17:12:08 +01:00
// 3. Set the code evaluation state of asyncContext such that when evaluation is resumed for that execution context, closure will be called with no arguments.
2021-11-09 20:39:22 +02:00
// 4. Push asyncContext onto the execution context stack; asyncContext is now the running execution context.
2022-08-21 20:38:35 +01:00
auto push_result = vm . push_execution_context ( async_context , { } ) ;
2021-11-14 12:20:49 +00:00
if ( push_result . is_error ( ) )
return ;
2021-11-09 20:39:22 +02:00
// 5. Resume the suspended evaluation of asyncContext. Let result be the value returned by the resumed computation.
2025-04-04 23:16:34 +02:00
auto result = call ( vm , * closure , * async_context . this_value ) ;
2021-11-09 20:39:22 +02:00
// 6. Assert: When we return here, asyncContext has already been removed from the execution context stack and runningContext is the currently running execution context.
VERIFY ( & vm . running_execution_context ( ) = = & running_context ) ;
2024-12-02 17:12:08 +01:00
// 7. Assert: result is a normal completion with a value of unused. The possible sources of this value are Await or, if the async function doesn't await anything, step 2.i above.
2021-11-09 20:39:22 +02:00
VERIFY ( result . has_value ( ) & & result . value ( ) . is_undefined ( ) ) ;
2022-05-02 20:54:39 +02:00
// 8. Return unused.
2021-11-09 20:39:22 +02:00
}
2023-08-07 19:59:00 +02:00
template void async_block_start ( VM & , NonnullRefPtr < Statement const > const & async_body , PromiseCapability const & , ExecutionContext & ) ;
template void async_function_start ( VM & , PromiseCapability const & , NonnullRefPtr < Statement const > const & async_function_body ) ;
2023-07-16 17:54:26 +12:00
2024-11-15 04:01:23 +13:00
template void async_block_start ( VM & , GC : : Function < Completion ( ) > const & async_body , PromiseCapability const & , ExecutionContext & ) ;
template void async_function_start ( VM & , PromiseCapability const & , GC : : Function < Completion ( ) > const & async_function_body ) ;
2023-07-16 18:04:01 +12: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
// 10.2.1.4 OrdinaryCallEvaluateBody ( F, argumentsList ), https://tc39.es/ecma262/#sec-ordinarycallevaluatebody
LibJS: Replace the custom unwind mechanism with completions :^)
This includes:
- Parsing proper LabelledStatements with try_parse_labelled_statement()
- Removing LabelableStatement
- Implementing the LoopEvaluation semantics via loop_evaluation() in
each IterationStatement subclass; and IterationStatement evaluation
via {For,ForIn,ForOf,ForAwaitOf,While,DoWhile}Statement::execute()
- Updating ReturnStatement, BreakStatement and ContinueStatement to
return the appropriate completion types
- Basically reimplementing TryStatement and SwitchStatement according to
the spec, using completions
- Honoring result completion types in AsyncBlockStart and
OrdinaryCallEvaluateBody
- Removing any uses of the VM unwind mechanism - most importantly,
VM::throw_exception() now exclusively sets an exception and no longer
triggers any unwinding mechanism.
However, we already did a good job updating all of LibWeb and userland
applications to not use it, and the few remaining uses elsewhere don't
rely on unwinding AFAICT.
2022-01-05 19:11:16 +01:00
// 15.8.4 Runtime Semantics: EvaluateAsyncFunctionBody, https://tc39.es/ecma262/#sec-runtime-semantics-evaluatefunctionbody
2025-04-28 02:11:57 +02:00
ThrowCompletionOr < Value > ECMAScriptFunctionObject : : ordinary_call_evaluate_body ( VM & vm )
2020-03-13 10:08:52 +01:00
{
2024-05-06 06:44:08 +02:00
auto result_and_frame = vm . bytecode_interpreter ( ) . run_executable ( * m_bytecode_executable , { } ) ;
2021-05-29 16:03:19 +04:30
2025-04-28 21:25:02 +02:00
if ( result_and_frame . value . is_error ( ) ) [[unlikely]] {
2023-08-07 19:59:00 +02:00
return result_and_frame . value . release_error ( ) ;
2025-04-28 21:25:02 +02:00
}
2020-10-04 13:54:44 +02:00
2023-08-07 19:59:00 +02:00
auto result = result_and_frame . value . release_value ( ) ;
2022-12-20 22:09:57 +01:00
2023-08-07 19:59:00 +02:00
// NOTE: Running the bytecode should eventually return a completion.
// Until it does, we assume "return" and include the undefined fallback from the call site.
2025-04-08 00:45:27 +02:00
if ( kind ( ) = = FunctionKind : : Normal )
2025-04-28 02:11:57 +02:00
return result ;
2022-12-20 22:09:57 +01:00
2025-04-28 21:25:28 +02:00
auto & realm = * vm . current_realm ( ) ;
2025-04-08 00:45:27 +02:00
if ( kind ( ) = = FunctionKind : : AsyncGenerator ) {
2024-05-01 19:33:49 +02:00
auto async_generator_object = TRY ( AsyncGenerator : : create ( realm , result , this , vm . running_execution_context ( ) . copy ( ) ) ) ;
2025-04-28 02:11:57 +02:00
return async_generator_object ;
2023-08-07 19:59:00 +02:00
}
2021-11-09 20:39:22 +02:00
2024-05-01 19:33:49 +02:00
auto generator_object = TRY ( GeneratorObject : : create ( realm , result , this , vm . running_execution_context ( ) . copy ( ) ) ) ;
2021-11-09 20:39:22 +02:00
2023-08-07 19:59:00 +02:00
// NOTE: Async functions are entirely transformed to generator functions, and wrapped in a custom driver that returns a promise
// See AwaitExpression::generate_bytecode() for the transformation.
2025-04-08 00:45:27 +02:00
if ( kind ( ) = = FunctionKind : : Async )
2025-04-28 02:11:57 +02:00
return AsyncFunctionDriverWrapper : : create ( realm , generator_object ) ;
2021-11-09 20:39:22 +02:00
2025-04-08 00:45:27 +02:00
VERIFY ( kind ( ) = = FunctionKind : : Generator ) ;
2025-04-28 02:11:57 +02:00
return generator_object ;
2020-04-01 18:31:24 +01:00
}
2025-08-02 19:27:29 -04:00
void ECMAScriptFunctionObject : : set_name ( Utf16FlyString const & name )
2020-04-04 14:34:27 +01:00
{
2021-07-05 18:02:27 +03:00
auto & vm = this - > vm ( ) ;
2025-04-08 00:45:27 +02:00
const_cast < SharedFunctionInstanceData & > ( shared_data ( ) ) . m_name = name ;
m_name_string = PrimitiveString : : create ( vm , name ) ;
2025-09-15 16:43:27 +02:00
PropertyDescriptor descriptor { . value = m_name_string , . writable = false , . enumerable = false , . configurable = true } ;
MUST ( define_property_or_throw ( vm . names . name , descriptor ) ) ;
2020-04-04 14:34:27 +01:00
}
2025-04-08 13:39:07 +02:00
ECMAScriptFunctionObject : : ClassData & ECMAScriptFunctionObject : : ensure_class_data ( ) const
{
if ( ! m_class_data )
m_class_data = make < ClassData > ( ) ;
return * m_class_data ;
}
2020-03-13 10:08:52 +01:00
}