mirror of
https://github.com/RGBCube/serenity
synced 2025-07-26 18:47:44 +00:00
LibJS: Follow the spec more closely when determining the this value
Co-authored-by: davidot <david.tuin@gmail.com>
This commit is contained in:
parent
a394aa5830
commit
c6e9c6d6ab
3 changed files with 36 additions and 11 deletions
|
@ -161,14 +161,10 @@ CallExpression::ThisAndCallee CallExpression::compute_this_and_callee(Interprete
|
||||||
return { this_value, callee };
|
return { this_value, callee };
|
||||||
}
|
}
|
||||||
|
|
||||||
if (interpreter.vm().in_strict_mode()) {
|
// [[Call]] will handle that in non-strict mode the this value becomes the global object
|
||||||
// If we are in strict mode, |this| should never be bound to global object by default.
|
|
||||||
return { js_undefined(), m_callee->execute(interpreter, global_object) };
|
return { js_undefined(), m_callee->execute(interpreter, global_object) };
|
||||||
}
|
}
|
||||||
|
|
||||||
return { &global_object, m_callee->execute(interpreter, global_object) };
|
|
||||||
}
|
|
||||||
|
|
||||||
// 13.3.8.1 Runtime Semantics: ArgumentListEvaluation, https://tc39.es/ecma262/#sec-runtime-semantics-argumentlistevaluation
|
// 13.3.8.1 Runtime Semantics: ArgumentListEvaluation, https://tc39.es/ecma262/#sec-runtime-semantics-argumentlistevaluation
|
||||||
static void argument_list_evaluation(Interpreter& interpreter, GlobalObject& global_object, Vector<CallExpression::Argument> const& arguments, MarkedValueList& list)
|
static void argument_list_evaluation(Interpreter& interpreter, GlobalObject& global_object, Vector<CallExpression::Argument> const& arguments, MarkedValueList& list)
|
||||||
{
|
{
|
||||||
|
|
|
@ -589,6 +589,36 @@ void VM::prepare_for_ordinary_call(FunctionObject& function, ExecutionContext& c
|
||||||
// 15. Return calleeContext. (See NOTE above about how contexts are allocated on the C++ stack.)
|
// 15. 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 VM::ordinary_call_bind_this(FunctionObject& function, ExecutionContext& callee_context, Value this_argument)
|
||||||
|
{
|
||||||
|
auto this_mode = function.this_mode();
|
||||||
|
auto* callee_realm = function.realm();
|
||||||
|
|
||||||
|
auto* local_environment = callee_context.lexical_environment;
|
||||||
|
auto& function_environment = verify_cast<FunctionEnvironment>(*local_environment);
|
||||||
|
|
||||||
|
// This is not completely as the spec describes it however without this stuff breaks
|
||||||
|
// (Could be related to the note at https://tc39.es/ecma262/#sec-runtime-semantics-instantiatearrowfunctionexpression )
|
||||||
|
if (!callee_realm || this_mode == FunctionObject::ThisMode::Lexical) {
|
||||||
|
function_environment.bind_this_value(function.global_object(), callee_context.this_value);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Value this_value;
|
||||||
|
if (function.is_strict_mode()) {
|
||||||
|
this_value = this_argument;
|
||||||
|
} else if (this_argument.is_nullish()) {
|
||||||
|
auto& global_environment = callee_realm->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;
|
||||||
|
}
|
||||||
|
|
||||||
Value VM::call_internal(FunctionObject& function, Value this_value, Optional<MarkedValueList> arguments)
|
Value VM::call_internal(FunctionObject& function, Value this_value, Optional<MarkedValueList> arguments)
|
||||||
{
|
{
|
||||||
VERIFY(!exception());
|
VERIFY(!exception());
|
||||||
|
@ -611,11 +641,8 @@ Value VM::call_internal(FunctionObject& function, Value this_value, Optional<Mar
|
||||||
if (arguments.has_value())
|
if (arguments.has_value())
|
||||||
callee_context.arguments.extend(arguments.value().values());
|
callee_context.arguments.extend(arguments.value().values());
|
||||||
|
|
||||||
if (auto* environment = callee_context.lexical_environment) {
|
if (callee_context.lexical_environment)
|
||||||
auto& function_environment = verify_cast<FunctionEnvironment>(*environment);
|
ordinary_call_bind_this(function, callee_context, this_value);
|
||||||
VERIFY(function_environment.this_binding_status() == FunctionEnvironment::ThisBindingStatus::Uninitialized);
|
|
||||||
function_environment.bind_this_value(function.global_object(), callee_context.this_value);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (exception())
|
if (exception())
|
||||||
return {};
|
return {};
|
||||||
|
|
|
@ -260,6 +260,8 @@ public:
|
||||||
private:
|
private:
|
||||||
VM();
|
VM();
|
||||||
|
|
||||||
|
void ordinary_call_bind_this(FunctionObject&, ExecutionContext&, Value this_argument);
|
||||||
|
|
||||||
[[nodiscard]] Value call_internal(FunctionObject&, Value this_value, Optional<MarkedValueList> arguments);
|
[[nodiscard]] Value call_internal(FunctionObject&, Value this_value, Optional<MarkedValueList> arguments);
|
||||||
void prepare_for_ordinary_call(FunctionObject&, ExecutionContext& callee_context, Value new_target);
|
void prepare_for_ordinary_call(FunctionObject&, ExecutionContext& callee_context, Value new_target);
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue