mirror of
https://github.com/RGBCube/serenity
synced 2025-05-31 14:28:12 +00:00
LibJS: Move [[BoundThis]] and [[BoundArguments]] to BoundFunction
This commit is contained in:
parent
4566472ed6
commit
9043041dd3
7 changed files with 31 additions and 39 deletions
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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();
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue