diff --git a/Userland/Libraries/LibJS/AST.cpp b/Userland/Libraries/LibJS/AST.cpp index c085f99cb7542e7..89b02ccfc41173a 100644 --- a/Userland/Libraries/LibJS/AST.cpp +++ b/Userland/Libraries/LibJS/AST.cpp @@ -242,6 +242,7 @@ ThrowCompletionOr ClassField::class_element_evaluation auto function_code = create_ast_node(m_initializer->source_range(), copy_initializer.release_nonnull(), name); FunctionParsingInsights parsing_insights; parsing_insights.uses_this_from_environment = true; + parsing_insights.uses_this = 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); } @@ -288,6 +289,7 @@ ThrowCompletionOr StaticInitializer::class_element_eva // Note: The function bodyFunction is never directly accessible to ECMAScript code. FunctionParsingInsights parsing_insights; parsing_insights.uses_this_from_environment = true; + parsing_insights.uses_this = 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). @@ -337,6 +339,7 @@ ThrowCompletionOr ClassExpression::create_class_const auto const& constructor = *m_constructor; auto parsing_insights = constructor.parsing_insights(); parsing_insights.uses_this_from_environment = true; + parsing_insights.uses_this = true; auto class_constructor = ECMAScriptFunctionObject::create( realm, constructor.name(), diff --git a/Userland/Libraries/LibJS/AST.h b/Userland/Libraries/LibJS/AST.h index afab6050e7a707b..e13f272782cc4c7 100644 --- a/Userland/Libraries/LibJS/AST.h +++ b/Userland/Libraries/LibJS/AST.h @@ -694,6 +694,7 @@ struct FunctionParameter { }; struct FunctionParsingInsights { + bool uses_this { false }; bool uses_this_from_environment { false }; bool contains_direct_call_to_eval { false }; bool might_need_arguments_object { false }; diff --git a/Userland/Libraries/LibJS/Parser.cpp b/Userland/Libraries/LibJS/Parser.cpp index 8d1a455e48dc1b6..4f2e761bab336f7 100644 --- a/Userland/Libraries/LibJS/Parser.cpp +++ b/Userland/Libraries/LibJS/Parser.cpp @@ -433,32 +433,29 @@ class ScopePusher { } } - bool uses_this_from_environment() const - { - return m_uses_this_from_environment; - } + bool uses_this() const { return m_uses_this; } + bool uses_this_from_environment() const { return m_uses_this_from_environment; } void set_uses_this() { auto const* closest_function_scope = last_function_scope(); - if (!closest_function_scope || !closest_function_scope->m_is_arrow_function) - return; - + auto uses_this_from_environment = closest_function_scope && closest_function_scope->m_is_arrow_function; for (auto* scope_ptr = this; scope_ptr; scope_ptr = scope_ptr->m_parent_scope) { - if (scope_ptr->m_uses_this_from_environment) - break; - if (scope_ptr->m_type == ScopeType::Function) - scope_ptr->m_uses_this_from_environment = true; + if (scope_ptr->m_type == ScopeType::Function) { + scope_ptr->m_uses_this = true; + if (uses_this_from_environment) + scope_ptr->m_uses_this_from_environment = true; + } } } void set_uses_new_target() { for (auto* scope_ptr = this; scope_ptr; scope_ptr = scope_ptr->m_parent_scope) { - if (scope_ptr->m_uses_this_from_environment) - break; - if (scope_ptr->m_type == ScopeType::Function) + if (scope_ptr->m_type == ScopeType::Function) { + scope_ptr->m_uses_this = true; scope_ptr->m_uses_this_from_environment = true; + } } } @@ -512,6 +509,7 @@ class ScopePusher { // 1. It's an arrow function or establish parent scope for an arrow function // 2. Uses new.target bool m_uses_this_from_environment { false }; + bool m_uses_this { false }; bool m_is_arrow_function { false }; }; @@ -2307,6 +2305,7 @@ NonnullRefPtr Parser::parse_expression(int min_precedence, Ass auto& callee = static_ptr_cast(expression)->callee(); if (is(callee) && static_cast(callee).string() == "eval"sv) { m_state.current_scope_pusher->set_contains_direct_call_to_eval(); + m_state.current_scope_pusher->set_uses_this(); } } @@ -2845,6 +2844,7 @@ NonnullRefPtr Parser::parse_function_body(Vectortype() == ScopePusher::ScopeType::Function); 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(); + parsing_insights.uses_this = m_state.current_scope_pusher->uses_this(); return function_body; } diff --git a/Userland/Libraries/LibJS/Runtime/ECMAScriptFunctionObject.cpp b/Userland/Libraries/LibJS/Runtime/ECMAScriptFunctionObject.cpp index 41d7eee3f46649b..cc7a4b085ae0fad 100644 --- a/Userland/Libraries/LibJS/Runtime/ECMAScriptFunctionObject.cpp +++ b/Userland/Libraries/LibJS/Runtime/ECMAScriptFunctionObject.cpp @@ -332,6 +332,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 || parsing_insights.uses_this_from_environment || m_contains_direct_call_to_eval; + m_uses_this = parsing_insights.uses_this; } void ECMAScriptFunctionObject::initialize(Realm& realm) @@ -414,7 +415,8 @@ ThrowCompletionOr ECMAScriptFunctionObject::internal_call(Value this_argu } // 5. Perform OrdinaryCallBindThis(F, calleeContext, thisArgument). - ordinary_call_bind_this(*callee_context, this_argument); + if (m_uses_this) + ordinary_call_bind_this(*callee_context, this_argument); // 6. Let result be Completion(OrdinaryCallEvaluateBody(F, argumentsList)). auto result = ordinary_call_evaluate_body(); @@ -477,7 +479,8 @@ ThrowCompletionOr> ECMAScriptFunctionObject::internal_const // 6. If kind is base, then if (kind == ConstructorKind::Base) { // a. Perform OrdinaryCallBindThis(F, calleeContext, thisArgument). - ordinary_call_bind_this(*callee_context, this_argument); + if (m_uses_this) + ordinary_call_bind_this(*callee_context, this_argument); // b. Let initializeResult be Completion(InitializeInstanceElements(thisArgument, F)). auto initialize_result = this_argument->initialize_instance_elements(*this); diff --git a/Userland/Libraries/LibJS/Runtime/ECMAScriptFunctionObject.h b/Userland/Libraries/LibJS/Runtime/ECMAScriptFunctionObject.h index 495c88450fffee1..8d2f2aded2559cb 100644 --- a/Userland/Libraries/LibJS/Runtime/ECMAScriptFunctionObject.h +++ b/Userland/Libraries/LibJS/Runtime/ECMAScriptFunctionObject.h @@ -164,6 +164,7 @@ class ECMAScriptFunctionObject final : public FunctionObject { bool m_arguments_object_needed { false }; bool m_is_module_wrapper { false }; bool m_function_environment_needed { false }; + bool m_uses_this { false }; Vector m_var_names_to_initialize_binding; Vector m_function_names_to_initialize_binding; diff --git a/Userland/Libraries/LibJS/SourceTextModule.cpp b/Userland/Libraries/LibJS/SourceTextModule.cpp index 3c8eca9c80d0889..63069144167de62 100644 --- a/Userland/Libraries/LibJS/SourceTextModule.cpp +++ b/Userland/Libraries/LibJS/SourceTextModule.cpp @@ -760,6 +760,7 @@ ThrowCompletionOr SourceTextModule::execute_module(VM& vm, GCPtrm_ecmascript_code, {}, 0, {}, environment(), nullptr, FunctionKind::Async, true, parsing_insights);