1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-05-31 13:28:11 +00:00

LibJS: Move [[BoundThis]] and [[BoundArguments]] to BoundFunction

This commit is contained in:
Linus Groh 2021-09-25 00:38:23 +02:00
parent 4566472ed6
commit 9043041dd3
7 changed files with 31 additions and 39 deletions

View file

@ -9,9 +9,11 @@
namespace JS {
BoundFunction::BoundFunction(GlobalObject& global_object, FunctionObject& bound_target_function, Value bound_this, Vector<Value> arguments, i32 length, Object* constructor_prototype)
: FunctionObject(bound_this, move(arguments), *global_object.function_prototype())
BoundFunction::BoundFunction(GlobalObject& global_object, FunctionObject& bound_target_function, Value bound_this, Vector<Value> bound_arguments, i32 length, Object* constructor_prototype)
: FunctionObject(*global_object.function_prototype())
, m_bound_target_function(&bound_target_function)
, m_bound_this(bound_this)
, m_bound_arguments(move(bound_arguments))
, m_constructor_prototype(constructor_prototype)
, m_name(String::formatted("bound {}", bound_target_function.name()))
, m_length(length)
@ -52,7 +54,12 @@ FunctionEnvironment* BoundFunction::create_environment(FunctionObject& function_
void BoundFunction::visit_edges(Visitor& visitor)
{
Base::visit_edges(visitor);
visitor.visit(m_bound_target_function);
visitor.visit(m_bound_this);
for (auto argument : m_bound_arguments)
visitor.visit(argument);
visitor.visit(m_constructor_prototype);
}

View file

@ -14,7 +14,7 @@ class BoundFunction final : public FunctionObject {
JS_OBJECT(BoundFunction, FunctionObject);
public:
BoundFunction(GlobalObject&, FunctionObject& target_function, Value bound_this, Vector<Value> arguments, i32 length, Object* constructor_prototype);
BoundFunction(GlobalObject&, FunctionObject& target_function, Value bound_this, Vector<Value> bound_arguments, i32 length, Object* constructor_prototype);
virtual void initialize(GlobalObject&) override;
virtual ~BoundFunction();
@ -25,11 +25,15 @@ public:
virtual bool is_strict_mode() const override { return m_bound_target_function->is_strict_mode(); }
FunctionObject& bound_target_function() const { return *m_bound_target_function; }
Value bound_this() const { return m_bound_this; }
Vector<Value> const& bound_arguments() const { return m_bound_arguments; }
private:
virtual void visit_edges(Visitor&) override;
FunctionObject* m_bound_target_function { nullptr }; // [[BoundTargetFunction]]
Value m_bound_this; // [[BoundThis]]
Vector<Value> m_bound_arguments; // [[BoundArguments]]
Object* m_constructor_prototype { nullptr };
FlyString m_name;

View file

@ -34,11 +34,11 @@ ECMAScriptFunctionObject* ECMAScriptFunctionObject::create(GlobalObject& global_
prototype = global_object.generator_function_prototype();
break;
}
return global_object.heap().allocate<ECMAScriptFunctionObject>(global_object, global_object, move(name), ecmascript_code, move(parameters), m_function_length, parent_scope, *prototype, kind, is_strict, is_arrow_function);
return global_object.heap().allocate<ECMAScriptFunctionObject>(global_object, move(name), ecmascript_code, move(parameters), m_function_length, parent_scope, *prototype, kind, is_strict, is_arrow_function);
}
ECMAScriptFunctionObject::ECMAScriptFunctionObject(GlobalObject& global_object, FlyString name, Statement const& ecmascript_code, Vector<FunctionNode::Parameter> formal_parameters, i32 function_length, Environment* parent_scope, Object& prototype, FunctionKind kind, bool strict, bool is_arrow_function)
: FunctionObject(is_arrow_function ? vm().this_value(global_object) : Value(), {}, prototype)
ECMAScriptFunctionObject::ECMAScriptFunctionObject(FlyString name, Statement const& ecmascript_code, Vector<FunctionNode::Parameter> formal_parameters, i32 function_length, Environment* parent_scope, Object& prototype, FunctionKind kind, bool strict, bool is_arrow_function)
: FunctionObject(prototype)
, m_environment(parent_scope)
, m_formal_parameters(move(formal_parameters))
, m_ecmascript_code(ecmascript_code)

View file

@ -30,7 +30,7 @@ public:
static ECMAScriptFunctionObject* create(GlobalObject&, FlyString name, Statement const& ecmascript_code, Vector<FunctionNode::Parameter> parameters, i32 m_function_length, Environment* parent_scope, FunctionKind, bool is_strict, bool is_arrow_function = false);
ECMAScriptFunctionObject(GlobalObject&, FlyString name, Statement const& ecmascript_code, Vector<FunctionNode::Parameter> parameters, i32 m_function_length, Environment* parent_scope, Object& prototype, FunctionKind, bool is_strict, bool is_arrow_function = false);
ECMAScriptFunctionObject(FlyString name, Statement const& ecmascript_code, Vector<FunctionNode::Parameter> parameters, i32 m_function_length, Environment* parent_scope, Object& prototype, FunctionKind, bool is_strict, bool is_arrow_function = false);
virtual void initialize(GlobalObject&) override;
virtual ~ECMAScriptFunctionObject();

View file

@ -12,14 +12,7 @@
namespace JS {
FunctionObject::FunctionObject(Object& prototype)
: FunctionObject({}, {}, prototype)
{
}
FunctionObject::FunctionObject(Value bound_this, Vector<Value> bound_arguments, Object& prototype)
: Object(prototype)
, m_bound_this(bound_this)
, m_bound_arguments(move(bound_arguments))
{
}
@ -33,8 +26,8 @@ BoundFunction* FunctionObject::bind(Value bound_this_value, Vector<Value> argume
FunctionObject& target_function = is<BoundFunction>(*this) ? static_cast<BoundFunction&>(*this).bound_target_function() : *this;
auto bound_this_object = [&vm, bound_this_value, this]() -> Value {
if (!m_bound_this.is_empty())
return m_bound_this;
if (is<BoundFunction>(*this) && !static_cast<BoundFunction&>(*this).bound_this().is_empty())
return static_cast<BoundFunction&>(*this).bound_this();
switch (bound_this_value.type()) {
case Value::Type::Undefined:
case Value::Type::Null:
@ -60,20 +53,12 @@ BoundFunction* FunctionObject::bind(Value bound_this_value, Vector<Value> argume
if (prototype_property.is_object())
constructor_prototype = &prototype_property.as_object();
auto all_bound_arguments = bound_arguments();
Vector<Value> all_bound_arguments;
if (is<BoundFunction>(*this))
all_bound_arguments.extend(static_cast<BoundFunction&>(*this).bound_arguments());
all_bound_arguments.extend(move(arguments));
return heap().allocate<BoundFunction>(global_object(), global_object(), target_function, bound_this_object, move(all_bound_arguments), computed_length, constructor_prototype);
}
void FunctionObject::visit_edges(Visitor& visitor)
{
Base::visit_edges(visitor);
visitor.visit(m_bound_this);
for (auto argument : m_bound_arguments)
visitor.visit(argument);
}
}

View file

@ -25,10 +25,6 @@ public:
BoundFunction* bind(Value bound_this_value, Vector<Value> arguments);
Value bound_this() const { return m_bound_this; }
const Vector<Value>& bound_arguments() const { return m_bound_arguments; }
virtual bool is_strict_mode() const { return false; }
// [[Environment]]
@ -40,15 +36,10 @@ public:
virtual Realm* realm() const { return nullptr; }
protected:
virtual void visit_edges(Visitor&) override;
explicit FunctionObject(Object& prototype);
FunctionObject(Value bound_this, Vector<Value> bound_arguments, Object& prototype);
private:
virtual bool is_function() const override { return true; }
Value m_bound_this;
Vector<Value> m_bound_arguments;
};
}

View file

@ -494,7 +494,12 @@ Value VM::construct(FunctionObject& function, FunctionObject& new_target, Option
if (auto* interpreter = interpreter_if_exists())
callee_context.current_node = interpreter->current_node();
append_bound_and_passed_arguments(callee_context.arguments, function.bound_arguments(), move(arguments));
if (is<BoundFunction>(function)) {
auto& bound_function = static_cast<BoundFunction&>(function);
append_bound_and_passed_arguments(callee_context.arguments, bound_function.bound_arguments(), move(arguments));
} else {
append_bound_and_passed_arguments(callee_context.arguments, {}, move(arguments));
}
if (auto* environment = callee_context.lexical_environment) {
auto& function_environment = verify_cast<FunctionEnvironment>(*environment);
@ -694,8 +699,8 @@ ThrowCompletionOr<Value> VM::call_internal(FunctionObject& function, Value this_
if (auto* interpreter = interpreter_if_exists())
callee_context.current_node = interpreter->current_node();
callee_context.this_value = function.bound_this().value_or(this_value);
append_bound_and_passed_arguments(callee_context.arguments, function.bound_arguments(), move(arguments));
callee_context.this_value = this_value;
append_bound_and_passed_arguments(callee_context.arguments, {}, move(arguments));
if (callee_context.lexical_environment)
ordinary_call_bind_this(function, callee_context, this_value);