diff --git a/Userland/Libraries/LibJS/Runtime/ECMAScriptFunctionObject.cpp b/Userland/Libraries/LibJS/Runtime/ECMAScriptFunctionObject.cpp index 4c4d885c67d..d3b8e2b3657 100644 --- a/Userland/Libraries/LibJS/Runtime/ECMAScriptFunctionObject.cpp +++ b/Userland/Libraries/LibJS/Runtime/ECMAScriptFunctionObject.cpp @@ -136,7 +136,7 @@ ThrowCompletionOr ECMAScriptFunctionObject::internal_call(Value this_argu } // 5. Perform OrdinaryCallBindThis(F, calleeContext, thisArgument). - vm.ordinary_call_bind_this(*this, callee_context, this_argument); + ordinary_call_bind_this(callee_context, this_argument); // 6. Let result be OrdinaryCallEvaluateBody(F, argumentsList). auto result = ordinary_call_evaluate_body(); @@ -200,7 +200,7 @@ ThrowCompletionOr ECMAScriptFunctionObject::internal_construct(MarkedVa // 6. If kind is base, then if (kind == ConstructorKind::Base) { // a. Perform OrdinaryCallBindThis(F, calleeContext, thisArgument). - vm.ordinary_call_bind_this(*this, callee_context, this_argument); + ordinary_call_bind_this(callee_context, this_argument); // b. Let initializeResult be InitializeInstanceElements(thisArgument, F). auto initialize_result = vm.initialize_instance_elements(*this_argument, *this); @@ -615,6 +615,55 @@ void ECMAScriptFunctionObject::prepare_for_ordinary_call(ExecutionContext& calle // 14. Return calleeContext. (See NOTE above about how contexts are allocated on the C++ stack.) } +// 10.2.1.2 OrdinaryCallBindThis ( F, calleeContext, thisArgument ), https://tc39.es/ecma262/#sec-ordinarycallbindthis +void ECMAScriptFunctionObject::ordinary_call_bind_this(ExecutionContext& callee_context, Value this_argument) +{ + // 1. Let thisMode be F.[[ThisMode]]. + auto this_mode = m_this_mode; + + // If thisMode is lexical, return NormalCompletion(undefined). + if (this_mode == ThisMode::Lexical) + return; + + // 3. Let calleeRealm be F.[[Realm]]. + auto* callee_realm = m_realm; + + // 4. Let localEnv be the LexicalEnvironment of calleeContext. + auto* local_env = callee_context.lexical_environment; + + Value this_value; + + // 5. If thisMode is strict, let thisValue be thisArgument. + if (this_mode == ThisMode::Strict) { + 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). + this_value = this_argument.to_object(global_object()); + + // ii. NOTE: ToObject produces wrapper objects using calleeRealm. + // FIXME: It currently doesn't, as we pass the function's global object. + } + } + + // 7. Assert: localEnv is a function Environment Record. + // 8. Assert: The next step never returns an abrupt completion because localEnv.[[ThisBindingStatus]] is not initialized. + // 9. Return localEnv.BindThisValue(thisValue). + verify_cast(local_env)->bind_this_value(global_object(), this_value); +} + // 10.2.1.4 OrdinaryCallEvaluateBody ( F, argumentsList ), https://tc39.es/ecma262/#sec-ordinarycallevaluatebody Completion ECMAScriptFunctionObject::ordinary_call_evaluate_body() { diff --git a/Userland/Libraries/LibJS/Runtime/ECMAScriptFunctionObject.h b/Userland/Libraries/LibJS/Runtime/ECMAScriptFunctionObject.h index d717328964a..5d4d35b1fce 100644 --- a/Userland/Libraries/LibJS/Runtime/ECMAScriptFunctionObject.h +++ b/Userland/Libraries/LibJS/Runtime/ECMAScriptFunctionObject.h @@ -83,6 +83,7 @@ private: virtual void visit_edges(Visitor&) override; void prepare_for_ordinary_call(ExecutionContext& callee_context, Object* new_target); + void ordinary_call_bind_this(ExecutionContext&, Value this_argument); Completion ordinary_call_evaluate_body(); ThrowCompletionOr function_declaration_instantiation(Interpreter*); diff --git a/Userland/Libraries/LibJS/Runtime/VM.cpp b/Userland/Libraries/LibJS/Runtime/VM.cpp index 91ffa62ab8b..6e6e59d54cf 100644 --- a/Userland/Libraries/LibJS/Runtime/VM.cpp +++ b/Userland/Libraries/LibJS/Runtime/VM.cpp @@ -525,34 +525,6 @@ Value VM::get_new_target() return verify_cast(env).new_target(); } -// 10.2.1.2 OrdinaryCallBindThis ( F, calleeContext, thisArgument ), https://tc39.es/ecma262/#sec-ordinarycallbindthis -void VM::ordinary_call_bind_this(FunctionObject& function, ExecutionContext& callee_context, Value this_argument) -{ - auto* callee_realm = function.realm(); - - auto* local_environment = callee_context.lexical_environment; - auto& function_environment = verify_cast(*local_environment); - - // This almost as the spec describes it however we sometimes don't have callee_realm when dealing - // with proxies and arrow functions however this does seemingly achieve spec like behavior. - if (!callee_realm || (is(function) && static_cast(function).this_mode() == ECMAScriptFunctionObject::ThisMode::Lexical)) { - return; - } - - Value this_value; - if (function.is_strict_mode()) { - this_value = this_argument; - } else if (this_argument.is_nullish()) { - auto& global_environment = callee_realm->global_environment(); - this_value = &global_environment.global_this_value(); - } else { - this_value = this_argument.to_object(function.global_object()); - } - - function_environment.bind_this_value(function.global_object(), this_value); - callee_context.this_value = this_value; -} - // NOTE: This is only here because there's a million invocations of vm.call() - it used to be tied to the VM in weird ways. // We should update all of those and then remove this, along with the call() template functions in VM.h, and use the standalone call() AO. ThrowCompletionOr VM::call_internal(FunctionObject& function, Value this_value, Optional arguments) diff --git a/Userland/Libraries/LibJS/Runtime/VM.h b/Userland/Libraries/LibJS/Runtime/VM.h index 8d75852b48b..d54f0ec15ce 100644 --- a/Userland/Libraries/LibJS/Runtime/VM.h +++ b/Userland/Libraries/LibJS/Runtime/VM.h @@ -274,9 +274,6 @@ public: void save_execution_context_stack(); void restore_execution_context_stack(); - // TODO: Move these elsewhere once only used for ECMAScriptFunctionObject. - void ordinary_call_bind_this(FunctionObject&, ExecutionContext&, Value this_argument); - private: explicit VM(OwnPtr);