diff --git a/Libraries/LibJS/AST.cpp b/Libraries/LibJS/AST.cpp index 6806c3321a5..7664b483cdb 100644 --- a/Libraries/LibJS/AST.cpp +++ b/Libraries/LibJS/AST.cpp @@ -105,8 +105,7 @@ Value FunctionExpression::instantiate_ordinary_function_expression(VM& vm, FlySt auto private_environment = vm.running_execution_context().private_environment; - auto closure = ECMAScriptFunctionObject::create(realm, used_name, source_text(), body(), parameters(), function_length(), local_variables_names(), environment, private_environment, kind(), is_strict_mode(), - parsing_insights(), is_arrow_function()); + auto closure = ECMAScriptFunctionObject::create_from_function_node(*this, used_name, realm, environment, private_environment); // FIXME: 6. Perform SetFunctionName(closure, name). // FIXME: 7. Perform MakeConstructor(closure). @@ -151,8 +150,12 @@ ThrowCompletionOr ClassMethod::class_element_evaluatio { auto property_key_or_private_name = TRY(class_key_to_property_name(vm, *m_key, property_key)); - auto& method_function = *ECMAScriptFunctionObject::create(*vm.current_realm(), m_function->name(), m_function->source_text(), m_function->body(), m_function->parameters(), m_function->function_length(), m_function->local_variables_names(), vm.lexical_environment(), vm.running_execution_context().private_environment, m_function->kind(), m_function->is_strict_mode(), - m_function->parsing_insights(), m_function->is_arrow_function()); + auto& method_function = *ECMAScriptFunctionObject::create_from_function_node( + *m_function, + m_function->name(), + *vm.current_realm(), + vm.lexical_environment(), + vm.running_execution_context().private_environment); auto method_value = Value(&method_function); method_function.make_method(target); @@ -346,20 +349,12 @@ ThrowCompletionOr ClassExpression::create_class_const // FIXME: Step 14.a is done in the parser. By using a synthetic super(...args) which does not call @@iterator of %Array.prototype% auto const& constructor = *m_constructor; - auto class_constructor = ECMAScriptFunctionObject::create( - realm, + auto class_constructor = ECMAScriptFunctionObject::create_from_function_node( + constructor, constructor.name(), - constructor.source_text(), - constructor.body(), - constructor.parameters(), - constructor.function_length(), - constructor.local_variables_names(), + realm, vm.lexical_environment(), - vm.running_execution_context().private_environment, - constructor.kind(), - constructor.is_strict_mode(), - constructor.parsing_insights(), - constructor.is_arrow_function()); + vm.running_execution_context().private_environment); class_constructor->set_name(class_name); class_constructor->set_home_object(prototype); @@ -1634,8 +1629,12 @@ void ScopeNode::block_declaration_instantiation(VM& vm, Environment* environment auto& function_declaration = static_cast(declaration); // ii. Let fo be InstantiateFunctionObject of d with arguments env and privateEnv. - auto function = ECMAScriptFunctionObject::create(realm, function_declaration.name(), function_declaration.source_text(), function_declaration.body(), function_declaration.parameters(), function_declaration.function_length(), function_declaration.local_variables_names(), environment, private_environment, function_declaration.kind(), function_declaration.is_strict_mode(), - function_declaration.parsing_insights()); + auto function = ECMAScriptFunctionObject::create_from_function_node( + function_declaration, + function_declaration.name(), + realm, + environment, + private_environment); // iii. Perform ! env.InitializeBinding(fn, fo). NOTE: This step is replaced in section B.3.2.6. if (function_declaration.name_identifier()->is_local()) { @@ -1842,8 +1841,12 @@ ThrowCompletionOr Program::global_declaration_instantiation(VM& vm, Global for (auto& declaration : functions_to_initialize.in_reverse()) { // a. Let fn be the sole element of the BoundNames of f. // b. Let fo be InstantiateFunctionObject of f with arguments env and privateEnv. - auto function = ECMAScriptFunctionObject::create(realm, declaration.name(), declaration.source_text(), declaration.body(), declaration.parameters(), declaration.function_length(), declaration.local_variables_names(), &global_environment, private_environment, declaration.kind(), declaration.is_strict_mode(), - declaration.parsing_insights()); + auto function = ECMAScriptFunctionObject::create_from_function_node( + declaration, + declaration.name(), + realm, + &global_environment, + private_environment); // c. Perform ? env.CreateGlobalFunctionBinding(fn, fo, false). TRY(global_environment.create_global_function_binding(declaration.name(), function, false)); diff --git a/Libraries/LibJS/Bytecode/Interpreter.cpp b/Libraries/LibJS/Bytecode/Interpreter.cpp index acca02a86b1..4fe3eca2589 100644 --- a/Libraries/LibJS/Bytecode/Interpreter.cpp +++ b/Libraries/LibJS/Bytecode/Interpreter.cpp @@ -1305,8 +1305,12 @@ inline Value new_function(VM& vm, FunctionNode const& function_node, Optional eval_declaration_instantiation(VM& vm, Program const& pr for (auto& declaration : functions_to_initialize.in_reverse()) { // a. Let fn be the sole element of the BoundNames of f. // b. Let fo be InstantiateFunctionObject of f with arguments lexEnv and privateEnv. - auto function = ECMAScriptFunctionObject::create(realm, declaration.name(), declaration.source_text(), declaration.body(), declaration.parameters(), declaration.function_length(), declaration.local_variables_names(), lexical_environment, private_environment, declaration.kind(), declaration.is_strict_mode(), - declaration.parsing_insights()); + auto function = ECMAScriptFunctionObject::create_from_function_node( + declaration, + declaration.name(), + realm, + lexical_environment, + private_environment); // c. If varEnv is a global Environment Record, then if (global_var_environment) { diff --git a/Libraries/LibJS/Runtime/ECMAScriptFunctionObject.cpp b/Libraries/LibJS/Runtime/ECMAScriptFunctionObject.cpp index 013b81a2610..96e4df787e5 100644 --- a/Libraries/LibJS/Runtime/ECMAScriptFunctionObject.cpp +++ b/Libraries/LibJS/Runtime/ECMAScriptFunctionObject.cpp @@ -58,6 +58,47 @@ GC::Ref ECMAScriptFunctionObject::create(Realm& realm, return realm.create(move(name), move(source_text), ecmascript_code, move(parameters), m_function_length, move(local_variables_names), parent_environment, private_environment, prototype, kind, is_strict, parsing_insights, is_arrow_function, move(class_field_initializer_name)); } +GC::Ref ECMAScriptFunctionObject::create_from_function_node( + FunctionNode const& function_node, + FlyString name, + GC::Ref realm, + GC::Ptr parent_environment, + GC::Ptr private_environment) +{ + GC::Ptr 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; + } + + return create( + *realm, + move(name), + *prototype, + function_node.source_text(), + *function_node.body_ptr(), + function_node.parameters(), + function_node.function_length(), + function_node.local_variables_names(), + parent_environment, + private_environment, + function_node.kind(), + function_node.is_strict_mode(), + function_node.parsing_insights(), + function_node.is_arrow_function(), + Variant {}); +} + ECMAScriptFunctionObject::ECMAScriptFunctionObject(FlyString name, ByteString source_text, Statement const& ecmascript_code, NonnullRefPtr formal_parameters, i32 function_length, Vector local_variables_names, Environment* parent_environment, PrivateEnvironment* private_environment, Object& prototype, FunctionKind kind, bool strict, FunctionParsingInsights parsing_insights, bool is_arrow_function, Variant class_field_initializer_name) : FunctionObject(prototype) , m_name(move(name)) diff --git a/Libraries/LibJS/Runtime/ECMAScriptFunctionObject.h b/Libraries/LibJS/Runtime/ECMAScriptFunctionObject.h index d9142ba6a8b..949be80fabf 100644 --- a/Libraries/LibJS/Runtime/ECMAScriptFunctionObject.h +++ b/Libraries/LibJS/Runtime/ECMAScriptFunctionObject.h @@ -42,6 +42,13 @@ public: static GC::Ref create(Realm&, FlyString name, ByteString source_text, Statement const& ecmascript_code, NonnullRefPtr parameters, i32 m_function_length, Vector local_variables_names, Environment* parent_environment, PrivateEnvironment* private_environment, FunctionKind, bool is_strict, FunctionParsingInsights, bool is_arrow_function = false, Variant class_field_initializer_name = {}); static GC::Ref create(Realm&, FlyString name, Object& prototype, ByteString source_text, Statement const& ecmascript_code, NonnullRefPtr parameters, i32 m_function_length, Vector local_variables_names, Environment* parent_environment, PrivateEnvironment* private_environment, FunctionKind, bool is_strict, FunctionParsingInsights, bool is_arrow_function = false, Variant class_field_initializer_name = {}); + [[nodiscard]] static GC::Ref create_from_function_node( + FunctionNode const&, + FlyString name, + GC::Ref, + GC::Ptr parent_environment, + GC::Ptr); + virtual void initialize(Realm&) override; virtual ~ECMAScriptFunctionObject() override = default; diff --git a/Libraries/LibJS/SourceTextModule.cpp b/Libraries/LibJS/SourceTextModule.cpp index d15a6c970e3..855271fd945 100644 --- a/Libraries/LibJS/SourceTextModule.cpp +++ b/Libraries/LibJS/SourceTextModule.cpp @@ -500,8 +500,12 @@ ThrowCompletionOr SourceTextModule::initialize_environment(VM& vm) FlyString function_name = function_declaration.name(); if (function_name == ExportStatement::local_name_for_default) function_name = "default"_fly_string; - auto function = ECMAScriptFunctionObject::create(realm(), function_name, function_declaration.source_text(), function_declaration.body(), function_declaration.parameters(), function_declaration.function_length(), function_declaration.local_variables_names(), environment, private_environment, function_declaration.kind(), function_declaration.is_strict_mode(), - function_declaration.parsing_insights()); + auto function = ECMAScriptFunctionObject::create_from_function_node( + function_declaration, + function_name, + realm(), + environment, + private_environment); // 2. Perform ! env.InitializeBinding(dn, fo, normal). MUST(environment->initialize_binding(vm, name, function, Environment::InitializeBindingHint::Normal)); diff --git a/Libraries/LibWeb/WebDriver/ExecuteScript.cpp b/Libraries/LibWeb/WebDriver/ExecuteScript.cpp index ef202fef8d4..a7db8feccc4 100644 --- a/Libraries/LibWeb/WebDriver/ExecuteScript.cpp +++ b/Libraries/LibWeb/WebDriver/ExecuteScript.cpp @@ -67,7 +67,12 @@ static JS::ThrowCompletionOr execute_a_function_body(HTML::BrowsingCo // The result of parsing global scope above. // strict // The result of parsing strict above. - auto function = JS::ECMAScriptFunctionObject::create(realm, ""_fly_string, move(source_text), function_expression->body(), function_expression->parameters(), function_expression->function_length(), function_expression->local_variables_names(), &global_scope, nullptr, function_expression->kind(), function_expression->is_strict_mode(), function_expression->parsing_insights()); + auto function = JS::ECMAScriptFunctionObject::create_from_function_node( + function_expression, + ""_fly_string, + realm, + &global_scope, + nullptr); // 9. Let completion be Function.[[Call]](window, parameters) with function as the this value. // NOTE: This is not entirely clear, but I don't think they mean actually passing `function` as