diff --git a/Userland/Libraries/LibJS/AST.cpp b/Userland/Libraries/LibJS/AST.cpp index 9430bbc0bf7..c085f99cb75 100644 --- a/Userland/Libraries/LibJS/AST.cpp +++ b/Userland/Libraries/LibJS/AST.cpp @@ -107,7 +107,7 @@ Value FunctionExpression::instantiate_ordinary_function_expression(VM& vm, Depre 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(), - uses_this_from_environment(), might_need_arguments_object(), contains_direct_call_to_eval(), is_arrow_function()); + parsing_insights(), is_arrow_function()); // FIXME: 6. Perform SetFunctionName(closure, name). // FIXME: 7. Perform MakeConstructor(closure). @@ -153,7 +153,7 @@ 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->uses_this_from_environment(), m_function->might_need_arguments_object(), m_function->contains_direct_call_to_eval(), m_function->is_arrow_function()); + m_function->parsing_insights(), m_function->is_arrow_function()); auto method_value = Value(&method_function); method_function.make_method(target); @@ -240,7 +240,9 @@ ThrowCompletionOr ClassField::class_element_evaluation // FIXME: A potential optimization is not creating the functions here since these are never directly accessible. auto function_code = create_ast_node(m_initializer->source_range(), copy_initializer.release_nonnull(), name); - initializer = make_handle(*ECMAScriptFunctionObject::create(realm, "field", ByteString::empty(), *function_code, {}, 0, {}, vm.lexical_environment(), vm.running_execution_context().private_environment, FunctionKind::Normal, true, UsesThisFromEnvironment::Yes, false, m_contains_direct_call_to_eval, false, property_key_or_private_name)); + FunctionParsingInsights parsing_insights; + parsing_insights.uses_this_from_environment = true; + initializer = make_handle(*ECMAScriptFunctionObject::create(realm, "field", ByteString::empty(), *function_code, {}, 0, {}, vm.lexical_environment(), vm.running_execution_context().private_environment, FunctionKind::Normal, true, parsing_insights, false, property_key_or_private_name)); initializer->make_method(target); } @@ -284,7 +286,9 @@ ThrowCompletionOr StaticInitializer::class_element_eva // 4. Let formalParameters be an instance of the production FormalParameters : [empty] . // 5. Let bodyFunction be OrdinaryFunctionCreate(%Function.prototype%, sourceText, formalParameters, ClassStaticBlockBody, non-lexical-this, lex, privateEnv). // Note: The function bodyFunction is never directly accessible to ECMAScript code. - auto body_function = ECMAScriptFunctionObject::create(realm, ByteString::empty(), ByteString::empty(), *m_function_body, {}, 0, m_function_body->local_variables_names(), lexical_environment, private_environment, FunctionKind::Normal, true, UsesThisFromEnvironment::Yes, false, m_contains_direct_call_to_eval, false); + FunctionParsingInsights parsing_insights; + parsing_insights.uses_this_from_environment = true; + auto body_function = ECMAScriptFunctionObject::create(realm, ByteString::empty(), ByteString::empty(), *m_function_body, {}, 0, m_function_body->local_variables_names(), lexical_environment, private_environment, FunctionKind::Normal, true, parsing_insights, false); // 6. Perform MakeMethod(bodyFunction, homeObject). body_function->make_method(home_object); @@ -331,6 +335,8 @@ 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 parsing_insights = constructor.parsing_insights(); + parsing_insights.uses_this_from_environment = true; auto class_constructor = ECMAScriptFunctionObject::create( realm, constructor.name(), @@ -343,9 +349,7 @@ ThrowCompletionOr ClassExpression::create_class_const vm.running_execution_context().private_environment, constructor.kind(), constructor.is_strict_mode(), - UsesThisFromEnvironment::Yes, - constructor.might_need_arguments_object(), - constructor.contains_direct_call_to_eval(), + parsing_insights, constructor.is_arrow_function()); class_constructor->set_name(class_name); @@ -824,7 +828,7 @@ void FunctionNode::dump(int indent, ByteString const& class_name) const auto is_async = m_kind == FunctionKind::Async || m_kind == FunctionKind::AsyncGenerator; auto is_generator = m_kind == FunctionKind::Generator || m_kind == FunctionKind::AsyncGenerator; outln("{}{}{} '{}'", class_name, is_async ? " async" : "", is_generator ? "*" : "", name()); - if (m_contains_direct_call_to_eval) { + if (m_parsing_insights.contains_direct_call_to_eval) { print_indent(indent + 1); outln("\033[31;1m(direct eval)\033[0m"); } @@ -1623,7 +1627,7 @@ void ScopeNode::block_declaration_instantiation(VM& vm, Environment* environment // 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.uses_this_from_environment(), function_declaration.might_need_arguments_object(), function_declaration.contains_direct_call_to_eval()); + function_declaration.parsing_insights()); // iii. Perform ! env.InitializeBinding(fn, fo). NOTE: This step is replaced in section B.3.2.6. if (function_declaration.name_identifier()->is_local()) { @@ -1831,7 +1835,7 @@ ThrowCompletionOr Program::global_declaration_instantiation(VM& vm, Global // 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.uses_this_from_environment(), declaration.might_need_arguments_object(), declaration.contains_direct_call_to_eval()); + declaration.parsing_insights()); // c. Perform ? env.CreateGlobalFunctionBinding(fn, fo, false). TRY(global_environment.create_global_function_binding(declaration.name(), function, false)); diff --git a/Userland/Libraries/LibJS/AST.h b/Userland/Libraries/LibJS/AST.h index aba0d82d4b8..afab6050e7a 100644 --- a/Userland/Libraries/LibJS/AST.h +++ b/Userland/Libraries/LibJS/AST.h @@ -693,9 +693,10 @@ struct FunctionParameter { Handle bytecode_executable {}; }; -enum class UsesThisFromEnvironment { - Yes, - No +struct FunctionParsingInsights { + bool uses_this_from_environment { false }; + bool contains_direct_call_to_eval { false }; + bool might_need_arguments_object { false }; }; class FunctionNode { @@ -708,11 +709,12 @@ public: i32 function_length() const { return m_function_length; } Vector const& local_variables_names() const { return m_local_variables_names; } bool is_strict_mode() const { return m_is_strict_mode; } - bool might_need_arguments_object() const { return m_might_need_arguments_object; } - bool contains_direct_call_to_eval() const { return m_contains_direct_call_to_eval; } + bool might_need_arguments_object() const { return m_parsing_insights.might_need_arguments_object; } + bool contains_direct_call_to_eval() const { return m_parsing_insights.contains_direct_call_to_eval; } bool is_arrow_function() const { return m_is_arrow_function; } + FunctionParsingInsights const& parsing_insights() const { return m_parsing_insights; } FunctionKind kind() const { return m_kind; } - UsesThisFromEnvironment uses_this_from_environment() const { return m_uses_this_from_environment; } + bool uses_this_from_environment() const { return m_parsing_insights.uses_this_from_environment; } virtual bool has_name() const = 0; virtual Value instantiate_ordinary_function_expression(VM&, DeprecatedFlyString given_name) const = 0; @@ -720,7 +722,7 @@ public: virtual ~FunctionNode() {}; protected: - FunctionNode(RefPtr name, ByteString source_text, NonnullRefPtr body, Vector parameters, i32 function_length, FunctionKind kind, bool is_strict_mode, bool might_need_arguments_object, bool contains_direct_call_to_eval, bool is_arrow_function, Vector local_variables_names, UsesThisFromEnvironment uses_this_from_environment) + FunctionNode(RefPtr name, ByteString source_text, NonnullRefPtr body, Vector parameters, i32 function_length, FunctionKind kind, bool is_strict_mode, FunctionParsingInsights parsing_insights, bool is_arrow_function, Vector local_variables_names) : m_name(move(name)) , m_source_text(move(source_text)) , m_body(move(body)) @@ -728,14 +730,12 @@ protected: , m_function_length(function_length) , m_kind(kind) , m_is_strict_mode(is_strict_mode) - , m_might_need_arguments_object(might_need_arguments_object) - , m_contains_direct_call_to_eval(contains_direct_call_to_eval) , m_is_arrow_function(is_arrow_function) - , m_uses_this_from_environment(uses_this_from_environment) + , m_parsing_insights(parsing_insights) , m_local_variables_names(move(local_variables_names)) { if (m_is_arrow_function) - VERIFY(!m_might_need_arguments_object); + VERIFY(!parsing_insights.might_need_arguments_object); } void dump(int indent, ByteString const& class_name) const; @@ -749,10 +749,8 @@ private: i32 const m_function_length; FunctionKind m_kind; bool m_is_strict_mode : 1 { false }; - bool m_might_need_arguments_object : 1 { false }; - bool m_contains_direct_call_to_eval : 1 { false }; bool m_is_arrow_function : 1 { false }; - UsesThisFromEnvironment m_uses_this_from_environment : 1 { UsesThisFromEnvironment::No }; + FunctionParsingInsights m_parsing_insights; Vector m_local_variables_names; }; @@ -763,9 +761,9 @@ class FunctionDeclaration final public: static bool must_have_name() { return true; } - FunctionDeclaration(SourceRange source_range, RefPtr name, ByteString source_text, NonnullRefPtr body, Vector parameters, i32 function_length, FunctionKind kind, bool is_strict_mode, bool might_need_arguments_object, bool contains_direct_call_to_eval, Vector local_variables_names, UsesThisFromEnvironment uses_this_from_environment) + FunctionDeclaration(SourceRange source_range, RefPtr name, ByteString source_text, NonnullRefPtr body, Vector parameters, i32 function_length, FunctionKind kind, bool is_strict_mode, FunctionParsingInsights insights, Vector local_variables_names) : Declaration(move(source_range)) - , FunctionNode(move(name), move(source_text), move(body), move(parameters), function_length, kind, is_strict_mode, might_need_arguments_object, contains_direct_call_to_eval, false, move(local_variables_names), uses_this_from_environment) + , FunctionNode(move(name), move(source_text), move(body), move(parameters), function_length, kind, is_strict_mode, insights, false, move(local_variables_names)) { } @@ -793,9 +791,9 @@ class FunctionExpression final public: static bool must_have_name() { return false; } - FunctionExpression(SourceRange source_range, RefPtr name, ByteString source_text, NonnullRefPtr body, Vector parameters, i32 function_length, FunctionKind kind, bool is_strict_mode, bool might_need_arguments_object, bool contains_direct_call_to_eval, Vector local_variables_names, UsesThisFromEnvironment uses_this_from_environment = UsesThisFromEnvironment::No, bool is_arrow_function = false) + FunctionExpression(SourceRange source_range, RefPtr name, ByteString source_text, NonnullRefPtr body, Vector parameters, i32 function_length, FunctionKind kind, bool is_strict_mode, FunctionParsingInsights insights, Vector local_variables_names, bool is_arrow_function = false) : Expression(move(source_range)) - , FunctionNode(move(name), move(source_text), move(body), move(parameters), function_length, kind, is_strict_mode, might_need_arguments_object, contains_direct_call_to_eval, is_arrow_function, move(local_variables_names), uses_this_from_environment) + , FunctionNode(move(name), move(source_text), move(body), move(parameters), function_length, kind, is_strict_mode, insights, is_arrow_function, move(local_variables_names)) { } diff --git a/Userland/Libraries/LibJS/Bytecode/CommonImplementations.h b/Userland/Libraries/LibJS/Bytecode/CommonImplementations.h index 1f20d60f77f..2a76efa7a0a 100644 --- a/Userland/Libraries/LibJS/Bytecode/CommonImplementations.h +++ b/Userland/Libraries/LibJS/Bytecode/CommonImplementations.h @@ -418,7 +418,7 @@ inline Value new_function(VM& vm, FunctionNode const& function_node, Optional Parser::try_parse_arrow_function_expression(boo Vector parameters; i32 function_length = -1; - bool contains_direct_call_to_eval = false; - bool uses_this_from_environment = false; + FunctionParsingInsights parsing_insights; + parsing_insights.might_need_arguments_object = false; auto function_body_result = [&]() -> RefPtr { ScopePusher function_scope = ScopePusher::function_scope(*this); function_scope.set_is_arrow_function(); @@ -1071,7 +1071,7 @@ RefPtr Parser::try_parse_arrow_function_expression(boo if (match(TokenType::CurlyOpen)) { // Parse a function body with statements consume(TokenType::CurlyOpen); - auto body = parse_function_body(parameters, function_kind, contains_direct_call_to_eval, uses_this_from_environment); + auto body = parse_function_body(parameters, function_kind, parsing_insights); consume(TokenType::CurlyClose); return body; } @@ -1090,8 +1090,8 @@ RefPtr Parser::try_parse_arrow_function_expression(boo return_block->append({ m_source_code, rule_start.position(), position() }, move(return_expression)); if (m_state.strict_mode) const_cast(*return_block).set_strict_mode(); - contains_direct_call_to_eval = m_state.current_scope_pusher->contains_direct_call_to_eval(); - uses_this_from_environment = m_state.current_scope_pusher->uses_this_from_environment(); + parsing_insights.contains_direct_call_to_eval = m_state.current_scope_pusher->contains_direct_call_to_eval(); + parsing_insights.uses_this_from_environment = m_state.current_scope_pusher->uses_this_from_environment(); return return_block; } // Invalid arrow function body @@ -1123,7 +1123,7 @@ RefPtr Parser::try_parse_arrow_function_expression(boo return create_ast_node( { m_source_code, rule_start.position(), position() }, nullptr, move(source_text), move(body), move(parameters), function_length, function_kind, body->in_strict_mode(), - /* might_need_arguments_object */ false, contains_direct_call_to_eval, move(local_variables_names), uses_this_from_environment ? UsesThisFromEnvironment::Yes : UsesThisFromEnvironment::No, /* is_arrow_function */ true); + parsing_insights, move(local_variables_names), /* is_arrow_function */ true); } RefPtr Parser::try_parse_labelled_statement(AllowLabelledFunction allow_function) @@ -1616,15 +1616,17 @@ NonnullRefPtr Parser::parse_class_expression(bool expect_ // return statement here to create the correct completion. constructor_body->append(create_ast_node({ m_source_code, rule_start.position(), position() }, move(super_call))); + FunctionParsingInsights parsing_insights; constructor = create_ast_node( { m_source_code, rule_start.position(), position() }, class_name, "", move(constructor_body), Vector { FunctionParameter { move(argument_name), nullptr, true } }, 0, FunctionKind::Normal, - /* is_strict_mode */ true, /* might_need_arguments_object */ false, /* contains_direct_call_to_eval */ false, /* local_variables_names */ Vector {}); + /* is_strict_mode */ true, parsing_insights, /* local_variables_names */ Vector {}); } else { + FunctionParsingInsights parsing_insights; constructor = create_ast_node( { m_source_code, rule_start.position(), position() }, class_name, "", move(constructor_body), Vector {}, 0, FunctionKind::Normal, - /* is_strict_mode */ true, /* might_need_arguments_object */ false, /* contains_direct_call_to_eval */ false, /* local_variables_names */ Vector {}); + /* is_strict_mode */ true, parsing_insights, /* local_variables_names */ Vector {}); } } @@ -2766,7 +2768,7 @@ void Parser::parse_statement_list(ScopeNode& output_node, AllowLabelledFunction } // FunctionBody, https://tc39.es/ecma262/#prod-FunctionBody -NonnullRefPtr Parser::parse_function_body(Vector const& parameters, FunctionKind function_kind, bool& contains_direct_call_to_eval, bool& uses_this) +NonnullRefPtr Parser::parse_function_body(Vector const& parameters, FunctionKind function_kind, FunctionParsingInsights& parsing_insights) { auto rule_start = push_start(); auto function_body = create_ast_node({ m_source_code, rule_start.position(), position() }); @@ -2841,8 +2843,8 @@ NonnullRefPtr Parser::parse_function_body(Vectortype() == ScopePusher::ScopeType::Function); - contains_direct_call_to_eval = m_state.current_scope_pusher->contains_direct_call_to_eval(); - uses_this = m_state.current_scope_pusher->uses_this_from_environment(); + parsing_insights.contains_direct_call_to_eval = m_state.current_scope_pusher->contains_direct_call_to_eval(); + parsing_insights.uses_this_from_environment = m_state.current_scope_pusher->uses_this_from_environment(); return function_body; } @@ -2927,8 +2929,7 @@ NonnullRefPtr Parser::parse_function_node(u16 parse_options, O i32 function_length = -1; Vector parameters; - bool contains_direct_call_to_eval = false; - bool uses_this_from_environment = false; + FunctionParsingInsights parsing_insights; auto body = [&] { ScopePusher function_scope = ScopePusher::function_scope(*this, name); @@ -2948,7 +2949,7 @@ NonnullRefPtr Parser::parse_function_node(u16 parse_options, O consume(TokenType::CurlyOpen); - auto body = parse_function_body(parameters, function_kind, contains_direct_call_to_eval, uses_this_from_environment); + auto body = parse_function_body(parameters, function_kind, parsing_insights); return body; }(); @@ -2963,13 +2964,12 @@ NonnullRefPtr Parser::parse_function_node(u16 parse_options, O auto function_start_offset = rule_start.position().offset; auto function_end_offset = position().offset - m_state.current_token.trivia().length(); auto source_text = ByteString { m_state.lexer.source().substring_view(function_start_offset, function_end_offset - function_start_offset) }; + parsing_insights.might_need_arguments_object = m_state.function_might_need_arguments_object; return create_ast_node( { m_source_code, rule_start.position(), position() }, name, move(source_text), move(body), move(parameters), function_length, - function_kind, has_strict_directive, m_state.function_might_need_arguments_object, - contains_direct_call_to_eval, - move(local_variables_names), - uses_this_from_environment ? UsesThisFromEnvironment::Yes : UsesThisFromEnvironment::No); + function_kind, has_strict_directive, parsing_insights, + move(local_variables_names)); } Vector Parser::parse_formal_parameters(int& function_length, u16 parse_options) @@ -5153,7 +5153,7 @@ NonnullRefPtr Parser::create_identifier_and_register_in_curren return id; } -Parser Parser::parse_function_body_from_string(ByteString const& body_string, u16 parse_options, Vector const& parameters, FunctionKind kind, bool& contains_direct_call_to_eval, bool& uses_this_from_environment) +Parser Parser::parse_function_body_from_string(ByteString const& body_string, u16 parse_options, Vector const& parameters, FunctionKind kind, FunctionParsingInsights& parsing_insights) { RefPtr function_body; @@ -5166,7 +5166,7 @@ Parser Parser::parse_function_body_from_string(ByteString const& body_string, u1 body_parser.m_state.await_expression_is_valid = true; if ((parse_options & FunctionNodeParseOptions::IsGeneratorFunction) != 0) body_parser.m_state.in_generator_function_context = true; - function_body = body_parser.parse_function_body(parameters, kind, contains_direct_call_to_eval, uses_this_from_environment); + function_body = body_parser.parse_function_body(parameters, kind, parsing_insights); } return body_parser; diff --git a/Userland/Libraries/LibJS/Parser.h b/Userland/Libraries/LibJS/Parser.h index fafd3b92e7d..a53a0b9e15c 100644 --- a/Userland/Libraries/LibJS/Parser.h +++ b/Userland/Libraries/LibJS/Parser.h @@ -87,7 +87,7 @@ public: NonnullRefPtr parse_statement(AllowLabelledFunction allow_labelled_function = AllowLabelledFunction::No); NonnullRefPtr parse_block_statement(); - NonnullRefPtr parse_function_body(Vector const& parameters, FunctionKind function_kind, bool& contains_direct_call_to_eval, bool& uses_this); + NonnullRefPtr parse_function_body(Vector const& parameters, FunctionKind function_kind, FunctionParsingInsights&); NonnullRefPtr parse_return_statement(); enum class IsForLoopVariableDeclaration { @@ -211,7 +211,7 @@ public: // Needs to mess with m_state, and we're not going to expose a non-const getter for that :^) friend ThrowCompletionOr FunctionConstructor::create_dynamic_function(VM&, FunctionObject&, FunctionObject*, FunctionKind, MarkedVector const&); - static Parser parse_function_body_from_string(ByteString const& body_string, u16 parse_options, Vector const& parameters, FunctionKind kind, bool& contains_direct_call_to_eval, bool& uses_this_from_environment); + static Parser parse_function_body_from_string(ByteString const& body_string, u16 parse_options, Vector const& parameters, FunctionKind kind, FunctionParsingInsights&); private: friend class ScopePusher; diff --git a/Userland/Libraries/LibJS/Runtime/AbstractOperations.cpp b/Userland/Libraries/LibJS/Runtime/AbstractOperations.cpp index 1135393dc04..58a31b65ec5 100644 --- a/Userland/Libraries/LibJS/Runtime/AbstractOperations.cpp +++ b/Userland/Libraries/LibJS/Runtime/AbstractOperations.cpp @@ -973,7 +973,7 @@ ThrowCompletionOr eval_declaration_instantiation(VM& vm, Program const& pr // 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.uses_this_from_environment(), declaration.might_need_arguments_object()); + declaration.parsing_insights()); // c. If varEnv is a global Environment Record, then if (global_var_environment) { diff --git a/Userland/Libraries/LibJS/Runtime/ECMAScriptFunctionObject.cpp b/Userland/Libraries/LibJS/Runtime/ECMAScriptFunctionObject.cpp index eeef533ba8a..41d7eee3f46 100644 --- a/Userland/Libraries/LibJS/Runtime/ECMAScriptFunctionObject.cpp +++ b/Userland/Libraries/LibJS/Runtime/ECMAScriptFunctionObject.cpp @@ -33,7 +33,7 @@ namespace JS { JS_DEFINE_ALLOCATOR(ECMAScriptFunctionObject); -NonnullGCPtr ECMAScriptFunctionObject::create(Realm& realm, DeprecatedFlyString name, ByteString source_text, Statement const& ecmascript_code, Vector parameters, i32 m_function_length, Vector local_variables_names, Environment* parent_environment, PrivateEnvironment* private_environment, FunctionKind kind, bool is_strict, UsesThisFromEnvironment uses_this_from_environment, bool might_need_arguments_object, bool contains_direct_call_to_eval, bool is_arrow_function, Variant class_field_initializer_name) +NonnullGCPtr ECMAScriptFunctionObject::create(Realm& realm, DeprecatedFlyString name, ByteString source_text, Statement const& ecmascript_code, Vector parameters, i32 m_function_length, Vector local_variables_names, Environment* parent_environment, PrivateEnvironment* private_environment, FunctionKind kind, bool is_strict, FunctionParsingInsights parsing_insights, bool is_arrow_function, Variant class_field_initializer_name) { Object* prototype = nullptr; switch (kind) { @@ -50,15 +50,15 @@ NonnullGCPtr ECMAScriptFunctionObject::create(Realm& r prototype = realm.intrinsics().async_generator_function_prototype(); break; } - return realm.heap().allocate(realm, move(name), move(source_text), ecmascript_code, move(parameters), m_function_length, move(local_variables_names), parent_environment, private_environment, *prototype, kind, is_strict, uses_this_from_environment, might_need_arguments_object, contains_direct_call_to_eval, is_arrow_function, move(class_field_initializer_name)); + return realm.heap().allocate(realm, 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)); } -NonnullGCPtr ECMAScriptFunctionObject::create(Realm& realm, DeprecatedFlyString name, Object& prototype, ByteString source_text, Statement const& ecmascript_code, Vector parameters, i32 m_function_length, Vector local_variables_names, Environment* parent_environment, PrivateEnvironment* private_environment, FunctionKind kind, bool is_strict, UsesThisFromEnvironment uses_this_from_environment, bool might_need_arguments_object, bool contains_direct_call_to_eval, bool is_arrow_function, Variant class_field_initializer_name) +NonnullGCPtr ECMAScriptFunctionObject::create(Realm& realm, DeprecatedFlyString name, Object& prototype, ByteString source_text, Statement const& ecmascript_code, Vector parameters, i32 m_function_length, Vector local_variables_names, Environment* parent_environment, PrivateEnvironment* private_environment, FunctionKind kind, bool is_strict, FunctionParsingInsights parsing_insights, bool is_arrow_function, Variant class_field_initializer_name) { - return realm.heap().allocate(realm, move(name), move(source_text), ecmascript_code, move(parameters), m_function_length, move(local_variables_names), parent_environment, private_environment, prototype, kind, is_strict, uses_this_from_environment, might_need_arguments_object, contains_direct_call_to_eval, is_arrow_function, move(class_field_initializer_name)); + return realm.heap().allocate(realm, 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)); } -ECMAScriptFunctionObject::ECMAScriptFunctionObject(DeprecatedFlyString name, ByteString source_text, Statement const& ecmascript_code, Vector formal_parameters, i32 function_length, Vector local_variables_names, Environment* parent_environment, PrivateEnvironment* private_environment, Object& prototype, FunctionKind kind, bool strict, UsesThisFromEnvironment uses_this_from_environment, bool might_need_arguments_object, bool contains_direct_call_to_eval, bool is_arrow_function, Variant class_field_initializer_name) +ECMAScriptFunctionObject::ECMAScriptFunctionObject(DeprecatedFlyString name, ByteString source_text, Statement const& ecmascript_code, Vector 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)) , m_function_length(function_length) @@ -71,8 +71,8 @@ ECMAScriptFunctionObject::ECMAScriptFunctionObject(DeprecatedFlyString name, Byt , m_source_text(move(source_text)) , m_class_field_initializer_name(move(class_field_initializer_name)) , m_strict(strict) - , m_might_need_arguments_object(might_need_arguments_object) - , m_contains_direct_call_to_eval(contains_direct_call_to_eval) + , m_might_need_arguments_object(parsing_insights.might_need_arguments_object) + , m_contains_direct_call_to_eval(parsing_insights.contains_direct_call_to_eval) , m_is_arrow_function(is_arrow_function) , m_kind(kind) { @@ -331,7 +331,7 @@ ECMAScriptFunctionObject::ECMAScriptFunctionObject(DeprecatedFlyString name, Byt })); } - 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 || uses_this_from_environment == UsesThisFromEnvironment::Yes || m_contains_direct_call_to_eval; + 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; } void ECMAScriptFunctionObject::initialize(Realm& realm) diff --git a/Userland/Libraries/LibJS/Runtime/ECMAScriptFunctionObject.h b/Userland/Libraries/LibJS/Runtime/ECMAScriptFunctionObject.h index 9dbfef6eec2..495c88450ff 100644 --- a/Userland/Libraries/LibJS/Runtime/ECMAScriptFunctionObject.h +++ b/Userland/Libraries/LibJS/Runtime/ECMAScriptFunctionObject.h @@ -39,8 +39,8 @@ public: Global, }; - static NonnullGCPtr create(Realm&, DeprecatedFlyString name, ByteString source_text, Statement const& ecmascript_code, Vector parameters, i32 m_function_length, Vector local_variables_names, Environment* parent_environment, PrivateEnvironment* private_environment, FunctionKind, bool is_strict, UsesThisFromEnvironment, bool might_need_arguments_object = true, bool contains_direct_call_to_eval = true, bool is_arrow_function = false, Variant class_field_initializer_name = {}); - static NonnullGCPtr create(Realm&, DeprecatedFlyString name, Object& prototype, ByteString source_text, Statement const& ecmascript_code, Vector parameters, i32 m_function_length, Vector local_variables_names, Environment* parent_environment, PrivateEnvironment* private_environment, FunctionKind, bool is_strict, UsesThisFromEnvironment, bool might_need_arguments_object = true, bool contains_direct_call_to_eval = true, bool is_arrow_function = false, Variant class_field_initializer_name = {}); + static NonnullGCPtr create(Realm&, DeprecatedFlyString name, ByteString source_text, Statement const& ecmascript_code, Vector 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 NonnullGCPtr create(Realm&, DeprecatedFlyString name, Object& prototype, ByteString source_text, Statement const& ecmascript_code, Vector 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 = {}); virtual void initialize(Realm&) override; virtual ~ECMAScriptFunctionObject() override = default; @@ -109,7 +109,7 @@ protected: virtual Completion ordinary_call_evaluate_body(); private: - ECMAScriptFunctionObject(DeprecatedFlyString name, ByteString source_text, Statement const& ecmascript_code, Vector parameters, i32 m_function_length, Vector local_variables_names, Environment* parent_environment, PrivateEnvironment* private_environment, Object& prototype, FunctionKind, bool is_strict, UsesThisFromEnvironment, bool might_need_arguments_object, bool contains_direct_call_to_eval, bool is_arrow_function, Variant class_field_initializer_name); + ECMAScriptFunctionObject(DeprecatedFlyString name, ByteString source_text, Statement const& ecmascript_code, Vector parameters, i32 m_function_length, Vector local_variables_names, Environment* parent_environment, PrivateEnvironment* private_environment, Object& prototype, FunctionKind, bool is_strict, FunctionParsingInsights, bool is_arrow_function, Variant class_field_initializer_name); virtual bool is_ecmascript_function_object() const override { return true; } virtual void visit_edges(Visitor&) override; diff --git a/Userland/Libraries/LibJS/Runtime/FunctionConstructor.cpp b/Userland/Libraries/LibJS/Runtime/FunctionConstructor.cpp index f7033162992..dc3e680be80 100644 --- a/Userland/Libraries/LibJS/Runtime/FunctionConstructor.cpp +++ b/Userland/Libraries/LibJS/Runtime/FunctionConstructor.cpp @@ -182,9 +182,8 @@ ThrowCompletionOr FunctionConstructor::create_dynamic } // 18. Let body be ParseText(StringToCodePoints(bodyString), bodySym). - bool contains_direct_call_to_eval = false; - bool uses_this_from_environment = false; - auto body_parser = Parser::parse_function_body_from_string(body_string, parse_options, parameters, kind, contains_direct_call_to_eval, uses_this_from_environment); + FunctionParsingInsights parsing_insights; + auto body_parser = Parser::parse_function_body_from_string(body_string, parse_options, parameters, kind, parsing_insights); // 19. If body is a List of errors, throw a SyntaxError exception. if (body_parser.has_errors()) { @@ -219,7 +218,8 @@ ThrowCompletionOr FunctionConstructor::create_dynamic PrivateEnvironment* private_environment = nullptr; // 28. Let F be OrdinaryFunctionCreate(proto, sourceText, parameters, body, non-lexical-this, env, privateEnv). - auto function = ECMAScriptFunctionObject::create(realm, "anonymous", *prototype, move(source_text), expr->body(), expr->parameters(), expr->function_length(), expr->local_variables_names(), &environment, private_environment, expr->kind(), expr->is_strict_mode(), uses_this_from_environment ? UsesThisFromEnvironment::Yes : UsesThisFromEnvironment::No, expr->might_need_arguments_object(), contains_direct_call_to_eval); + parsing_insights.might_need_arguments_object = true; + auto function = ECMAScriptFunctionObject::create(realm, "anonymous", *prototype, move(source_text), expr->body(), expr->parameters(), expr->function_length(), expr->local_variables_names(), &environment, private_environment, expr->kind(), expr->is_strict_mode(), parsing_insights); // FIXME: Remove the name argument from create() and do this instead. // 29. Perform SetFunctionName(F, "anonymous"). diff --git a/Userland/Libraries/LibJS/SourceTextModule.cpp b/Userland/Libraries/LibJS/SourceTextModule.cpp index b917d613b00..3c8eca9c80d 100644 --- a/Userland/Libraries/LibJS/SourceTextModule.cpp +++ b/Userland/Libraries/LibJS/SourceTextModule.cpp @@ -499,7 +499,7 @@ ThrowCompletionOr SourceTextModule::initialize_environment(VM& vm) if (function_name == ExportStatement::local_name_for_default) function_name = "default"sv; 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.uses_this_from_environment(), function_declaration.might_need_arguments_object(), function_declaration.contains_direct_call_to_eval()); + function_declaration.parsing_insights()); // 2. Perform ! env.InitializeBinding(dn, fo, normal). MUST(environment->initialize_binding(vm, name, function, Environment::InitializeBindingHint::Normal)); @@ -758,9 +758,11 @@ ThrowCompletionOr SourceTextModule::execute_module(VM& vm, GCPtrm_ecmascript_code, - {}, 0, {}, environment(), nullptr, FunctionKind::Async, true, UsesThisFromEnvironment::Yes, false, false); + {}, 0, {}, environment(), nullptr, FunctionKind::Async, true, parsing_insights); module_wrapper_function->set_is_module_wrapper(true); // AD-HOC: We push/pop the moduleContext around the call to ensure that the async execution context diff --git a/Userland/Libraries/LibWeb/DOM/EventTarget.cpp b/Userland/Libraries/LibWeb/DOM/EventTarget.cpp index 7961a12c0d3..e3789bff83f 100644 --- a/Userland/Libraries/LibWeb/DOM/EventTarget.cpp +++ b/Userland/Libraries/LibWeb/DOM/EventTarget.cpp @@ -486,7 +486,7 @@ WebIDL::CallbackType* EventTarget::get_current_value_of_event_handler(FlyString // 6. Return scope. (NOTE: Not necessary) auto function = JS::ECMAScriptFunctionObject::create(realm, name.to_deprecated_fly_string(), builder.to_byte_string(), program->body(), program->parameters(), program->function_length(), program->local_variables_names(), scope, nullptr, JS::FunctionKind::Normal, program->is_strict_mode(), - program->uses_this_from_environment(), program->might_need_arguments_object(), is_arrow_function); + program->parsing_insights(), is_arrow_function); // 10. Remove settings object's realm execution context from the JavaScript execution context stack. VERIFY(vm.execution_context_stack().last() == &settings_object.realm_execution_context()); diff --git a/Userland/Libraries/LibWeb/WebDriver/ExecuteScript.cpp b/Userland/Libraries/LibWeb/WebDriver/ExecuteScript.cpp index 8b7f867656c..0821d169f72 100644 --- a/Userland/Libraries/LibWeb/WebDriver/ExecuteScript.cpp +++ b/Userland/Libraries/LibWeb/WebDriver/ExecuteScript.cpp @@ -237,7 +237,6 @@ static JS::ThrowCompletionOr execute_a_function_body(Web::Page& page, auto& realm = window->realm(); - bool contains_direct_call_to_eval = false; auto source_text = ByteString::formatted("function() {{ {} }}", body); auto parser = JS::Parser { JS::Lexer { source_text } }; auto function_expression = parser.parse_function_node(); @@ -266,8 +265,7 @@ static JS::ThrowCompletionOr execute_a_function_body(Web::Page& page, // The result of parsing global scope above. // strict // The result of parsing strict above. - auto function = JS::ECMAScriptFunctionObject::create(realm, "", 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->uses_this_from_environment(), function_expression->might_need_arguments_object(), contains_direct_call_to_eval); + auto function = JS::ECMAScriptFunctionObject::create(realm, "", 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()); // 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