LibJS: Move ordinary_call_bind_this() to ECMAScriptFunctionObject

Now that it only needs to deal with ECMAScriptFunctionObject via
internal_call() / internal_construct(), we can:

- Remove the generic FunctionObject parameter
- Move it from the VM to ECMAScriptFunctionObject
- Make it private
This commit is contained in:
Linus Groh 2021-10-08 21:15:53 +01:00
parent 25bcd36116
commit 53af66d57d
Notes: sideshowbarker 2024-07-18 02:53:11 +09:00
4 changed files with 52 additions and 33 deletions

View file

@ -136,7 +136,7 @@ ThrowCompletionOr<Value> 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<Object*> 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<FunctionEnvironment>(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()
{

View file

@ -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<void> function_declaration_instantiation(Interpreter*);

View file

@ -525,34 +525,6 @@ Value VM::get_new_target()
return verify_cast<FunctionEnvironment>(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<FunctionEnvironment>(*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<ECMAScriptFunctionObject>(function) && static_cast<ECMAScriptFunctionObject&>(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<Value> VM::call_internal(FunctionObject& function, Value this_value, Optional<MarkedValueList> arguments)

View file

@ -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<CustomData>);