summaryrefslogtreecommitdiff
path: root/Userland/Libraries/LibJS/Runtime
diff options
context:
space:
mode:
authordavidot <david.tuin@gmail.com>2021-08-09 15:21:15 +0200
committerLinus Groh <mail@linusgroh.de>2021-08-09 17:33:14 +0100
commite1573991a3aff3d2c32f29aaa15793b78b9fb474 (patch)
treefb367e9e32beef5014d280240b69698ebd024617 /Userland/Libraries/LibJS/Runtime
parent151447bdf7207b4b5cd85708f579e5c3808fe0d8 (diff)
downloadserenity-e1573991a3aff3d2c32f29aaa15793b78b9fb474.zip
LibJS: Fix this values in arrow functions
Also added a large this value test (and strict variant) to ensure this values have no regressions.
Diffstat (limited to 'Userland/Libraries/LibJS/Runtime')
-rw-r--r--Userland/Libraries/LibJS/Runtime/OrdinaryFunctionObject.cpp1
-rw-r--r--Userland/Libraries/LibJS/Runtime/VM.cpp22
2 files changed, 19 insertions, 4 deletions
diff --git a/Userland/Libraries/LibJS/Runtime/OrdinaryFunctionObject.cpp b/Userland/Libraries/LibJS/Runtime/OrdinaryFunctionObject.cpp
index 9fbff65da7..0f1ffc0b72 100644
--- a/Userland/Libraries/LibJS/Runtime/OrdinaryFunctionObject.cpp
+++ b/Userland/Libraries/LibJS/Runtime/OrdinaryFunctionObject.cpp
@@ -132,6 +132,7 @@ FunctionEnvironment* OrdinaryFunctionObject::create_environment(FunctionObject&
auto* environment = heap().allocate<FunctionEnvironment>(global_object(), m_environment, variables);
environment->set_function_object(function_being_invoked);
if (m_is_arrow_function) {
+ environment->set_this_binding_status(FunctionEnvironment::ThisBindingStatus::Lexical);
if (is<FunctionEnvironment>(m_environment))
environment->set_new_target(static_cast<FunctionEnvironment*>(m_environment)->new_target());
}
diff --git a/Userland/Libraries/LibJS/Runtime/VM.cpp b/Userland/Libraries/LibJS/Runtime/VM.cpp
index bcc012411f..8e993bcd7f 100644
--- a/Userland/Libraries/LibJS/Runtime/VM.cpp
+++ b/Userland/Libraries/LibJS/Runtime/VM.cpp
@@ -11,6 +11,7 @@
#include <LibJS/Interpreter.h>
#include <LibJS/Runtime/AbstractOperations.h>
#include <LibJS/Runtime/Array.h>
+#include <LibJS/Runtime/BoundFunction.h>
#include <LibJS/Runtime/Error.h>
#include <LibJS/Runtime/FinalizationRegistry.h>
#include <LibJS/Runtime/FunctionEnvironment.h>
@@ -471,7 +472,7 @@ Value VM::construct(FunctionObject& function, FunctionObject& new_target, Option
if (auto* environment = callee_context.lexical_environment) {
auto& function_environment = verify_cast<FunctionEnvironment>(*environment);
function_environment.set_new_target(&new_target);
- if (!this_argument.is_empty()) {
+ if (!this_argument.is_empty() && function_environment.this_binding_status() != FunctionEnvironment::ThisBindingStatus::Lexical) {
function_environment.bind_this_value(global_object, this_argument);
if (exception())
return {};
@@ -603,10 +604,9 @@ void VM::ordinary_call_bind_this(FunctionObject& function, ExecutionContext& cal
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 )
+ // 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 || this_mode == FunctionObject::ThisMode::Lexical) {
- function_environment.bind_this_value(function.global_object(), callee_context.this_value);
return;
}
@@ -629,6 +629,20 @@ Value VM::call_internal(FunctionObject& function, Value this_value, Optional<Mar
VERIFY(!exception());
VERIFY(!this_value.is_empty());
+ if (is<BoundFunction>(function)) {
+ auto& bound_function = static_cast<BoundFunction&>(function);
+ auto bound_arguments = bound_function.bound_arguments();
+ if (arguments.has_value())
+ bound_arguments.extend(*arguments);
+
+ MarkedValueList with_bound_arguments { heap() };
+ with_bound_arguments.extend(bound_function.bound_arguments());
+ if (arguments.has_value())
+ with_bound_arguments.extend(*arguments);
+
+ return call_internal(bound_function.target_function(), bound_function.bound_this(), move(with_bound_arguments));
+ }
+
ExecutionContext callee_context;
prepare_for_ordinary_call(function, callee_context, js_undefined());
if (exception())