mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2025-04-22 04:25:13 +00:00
LibJS: Explicitly pass a "Function& new_target" to Function::construct
This allows the proxy handler to pass the proper new.target to construct handlers.
This commit is contained in:
parent
19411e22d0
commit
bda39ef7ab
Notes:
sideshowbarker
2024-07-19 05:18:39 +09:00
Author: https://github.com/mattco98 Commit: https://github.com/SerenityOS/serenity/commit/bda39ef7ab3 Pull-request: https://github.com/SerenityOS/serenity/pull/2630 Issue: https://github.com/SerenityOS/serenity/issues/2624 Reviewed-by: https://github.com/awesomekling
38 changed files with 63 additions and 50 deletions
|
@ -268,7 +268,7 @@ Value Interpreter::construct(Function& function, Function& new_target, Optional<
|
|||
// If we are a Derived constructor, |this| has not been constructed before super is called.
|
||||
Value this_value = function.constructor_kind() == Function::ConstructorKind::Base ? new_object : Value {};
|
||||
call_frame.this_value = this_value;
|
||||
auto result = function.construct(*this);
|
||||
auto result = function.construct(*this, new_target);
|
||||
|
||||
this_value = current_environment()->get_this_binding();
|
||||
pop_call_frame();
|
||||
|
|
|
@ -79,7 +79,7 @@ Value ArrayConstructor::call(Interpreter& interpreter)
|
|||
return array;
|
||||
}
|
||||
|
||||
Value ArrayConstructor::construct(Interpreter& interpreter)
|
||||
Value ArrayConstructor::construct(Interpreter& interpreter, Function&)
|
||||
{
|
||||
return call(interpreter);
|
||||
}
|
||||
|
|
|
@ -39,7 +39,7 @@ public:
|
|||
virtual ~ArrayConstructor() override;
|
||||
|
||||
virtual Value call(Interpreter&) override;
|
||||
virtual Value construct(Interpreter&) override;
|
||||
virtual Value construct(Interpreter&, Function& new_target) override;
|
||||
|
||||
private:
|
||||
virtual bool has_constructor() const override { return true; }
|
||||
|
|
|
@ -72,7 +72,7 @@ Value BigIntConstructor::call(Interpreter& interpreter)
|
|||
return bigint;
|
||||
}
|
||||
|
||||
Value BigIntConstructor::construct(Interpreter& interpreter)
|
||||
Value BigIntConstructor::construct(Interpreter& interpreter, Function&)
|
||||
{
|
||||
interpreter.throw_exception<TypeError>(ErrorType::NotAConstructor, "BigInt");
|
||||
return {};
|
||||
|
|
|
@ -39,7 +39,7 @@ public:
|
|||
virtual ~BigIntConstructor() override;
|
||||
|
||||
virtual Value call(Interpreter&) override;
|
||||
virtual Value construct(Interpreter&) override;
|
||||
virtual Value construct(Interpreter&, Function& new_target) override;
|
||||
|
||||
private:
|
||||
virtual bool has_constructor() const override { return true; }
|
||||
|
|
|
@ -54,7 +54,7 @@ Value BooleanConstructor::call(Interpreter& interpreter)
|
|||
return Value(interpreter.argument(0).to_boolean());
|
||||
}
|
||||
|
||||
Value BooleanConstructor::construct(Interpreter& interpreter)
|
||||
Value BooleanConstructor::construct(Interpreter& interpreter, Function&)
|
||||
{
|
||||
return BooleanObject::create(global_object(), interpreter.argument(0).to_boolean());
|
||||
}
|
||||
|
|
|
@ -39,7 +39,7 @@ public:
|
|||
virtual ~BooleanConstructor() override;
|
||||
|
||||
virtual Value call(Interpreter&) override;
|
||||
virtual Value construct(Interpreter&) override;
|
||||
virtual Value construct(Interpreter&, Function& new_target) override;
|
||||
|
||||
private:
|
||||
virtual bool has_constructor() const override { return true; }
|
||||
|
|
|
@ -54,14 +54,14 @@ Value BoundFunction::call(Interpreter& interpreter)
|
|||
return m_target_function->call(interpreter);
|
||||
}
|
||||
|
||||
Value BoundFunction::construct(Interpreter& interpreter)
|
||||
Value BoundFunction::construct(Interpreter& interpreter, Function& new_target)
|
||||
{
|
||||
if (auto this_value = interpreter.this_value(global_object()); m_constructor_prototype && this_value.is_object()) {
|
||||
this_value.as_object().set_prototype(m_constructor_prototype);
|
||||
if (interpreter.exception())
|
||||
return {};
|
||||
}
|
||||
return m_target_function->construct(interpreter);
|
||||
return m_target_function->construct(interpreter, new_target);
|
||||
}
|
||||
|
||||
LexicalEnvironment* BoundFunction::create_environment()
|
||||
|
|
|
@ -40,7 +40,7 @@ public:
|
|||
|
||||
virtual Value call(Interpreter& interpreter) override;
|
||||
|
||||
virtual Value construct(Interpreter& interpreter) override;
|
||||
virtual Value construct(Interpreter&, Function& new_target) override;
|
||||
|
||||
virtual LexicalEnvironment* create_environment() override;
|
||||
|
||||
|
|
|
@ -54,13 +54,13 @@ DateConstructor::~DateConstructor()
|
|||
|
||||
Value DateConstructor::call(Interpreter& interpreter)
|
||||
{
|
||||
auto date = construct(interpreter);
|
||||
auto date = construct(interpreter, *this);
|
||||
if (!date.is_object())
|
||||
return {};
|
||||
return js_string(interpreter, static_cast<Date&>(date.as_object()).string());
|
||||
}
|
||||
|
||||
Value DateConstructor::construct(Interpreter&)
|
||||
Value DateConstructor::construct(Interpreter&, Function&)
|
||||
{
|
||||
// TODO: Support args
|
||||
struct timeval tv;
|
||||
|
|
|
@ -39,7 +39,7 @@ public:
|
|||
virtual ~DateConstructor() override;
|
||||
|
||||
virtual Value call(Interpreter&) override;
|
||||
virtual Value construct(Interpreter&) override;
|
||||
virtual Value construct(Interpreter&, Function& new_target) override;
|
||||
|
||||
private:
|
||||
virtual bool has_constructor() const override { return true; }
|
||||
|
|
|
@ -49,10 +49,10 @@ ErrorConstructor::~ErrorConstructor()
|
|||
|
||||
Value ErrorConstructor::call(Interpreter& interpreter)
|
||||
{
|
||||
return construct(interpreter);
|
||||
return construct(interpreter, *this);
|
||||
}
|
||||
|
||||
Value ErrorConstructor::construct(Interpreter& interpreter)
|
||||
Value ErrorConstructor::construct(Interpreter& interpreter, Function&)
|
||||
{
|
||||
String message = "";
|
||||
if (!interpreter.call_frame().arguments.is_empty() && !interpreter.call_frame().arguments[0].is_undefined()) {
|
||||
|
@ -77,9 +77,9 @@ Value ErrorConstructor::construct(Interpreter& interpreter)
|
|||
ConstructorName::~ConstructorName() { } \
|
||||
Value ConstructorName::call(Interpreter& interpreter) \
|
||||
{ \
|
||||
return construct(interpreter); \
|
||||
return construct(interpreter, *this); \
|
||||
} \
|
||||
Value ConstructorName::construct(Interpreter& interpreter) \
|
||||
Value ConstructorName::construct(Interpreter& interpreter, Function&) \
|
||||
{ \
|
||||
String message = ""; \
|
||||
if (!interpreter.call_frame().arguments.is_empty() && !interpreter.call_frame().arguments[0].is_undefined()) { \
|
||||
|
|
|
@ -40,7 +40,7 @@ public:
|
|||
virtual ~ErrorConstructor() override;
|
||||
|
||||
virtual Value call(Interpreter&) override;
|
||||
virtual Value construct(Interpreter&) override;
|
||||
virtual Value construct(Interpreter&, Function& new_target) override;
|
||||
|
||||
private:
|
||||
virtual bool has_constructor() const override { return true; }
|
||||
|
@ -55,7 +55,7 @@ private:
|
|||
virtual void initialize(Interpreter&, GlobalObject&) override; \
|
||||
virtual ~ConstructorName() override; \
|
||||
virtual Value call(Interpreter&) override; \
|
||||
virtual Value construct(Interpreter&) override; \
|
||||
virtual Value construct(Interpreter&, Function& new_target) override; \
|
||||
\
|
||||
private: \
|
||||
virtual bool has_constructor() const override { return true; } \
|
||||
|
|
|
@ -68,7 +68,7 @@
|
|||
"Object prototype must not be %s on a super property access") \
|
||||
M(ObjectPrototypeWrongType, "Prototype must be an object or null") \
|
||||
M(ProxyCallWithNew, "Proxy must be called with the 'new' operator") \
|
||||
M(ProxyConstructBadReturnType, "Proxy handler's construct trap violates invariant: must return" \
|
||||
M(ProxyConstructBadReturnType, "Proxy handler's construct trap violates invariant: must return " \
|
||||
"an object") \
|
||||
M(ProxyConstructorBadType, "Expected %s argument of Proxy constructor to be object, got %s") \
|
||||
M(ProxyDefinePropExistingConfigurable, "Proxy handler's defineProperty trap violates " \
|
||||
|
|
|
@ -44,7 +44,7 @@ public:
|
|||
virtual void initialize(Interpreter&, GlobalObject&) override { }
|
||||
|
||||
virtual Value call(Interpreter&) = 0;
|
||||
virtual Value construct(Interpreter&) = 0;
|
||||
virtual Value construct(Interpreter&, Function& new_target) = 0;
|
||||
virtual const FlyString& name() const = 0;
|
||||
virtual LexicalEnvironment* create_environment() = 0;
|
||||
|
||||
|
|
|
@ -53,10 +53,10 @@ FunctionConstructor::~FunctionConstructor()
|
|||
|
||||
Value FunctionConstructor::call(Interpreter& interpreter)
|
||||
{
|
||||
return construct(interpreter);
|
||||
return construct(interpreter, *this);
|
||||
}
|
||||
|
||||
Value FunctionConstructor::construct(Interpreter& interpreter)
|
||||
Value FunctionConstructor::construct(Interpreter& interpreter, Function&)
|
||||
{
|
||||
String parameters_source = "";
|
||||
String body_source = "";
|
||||
|
|
|
@ -39,7 +39,7 @@ public:
|
|||
virtual ~FunctionConstructor() override;
|
||||
|
||||
virtual Value call(Interpreter&) override;
|
||||
virtual Value construct(Interpreter&) override;
|
||||
virtual Value construct(Interpreter&, Function& new_target) override;
|
||||
|
||||
private:
|
||||
virtual bool has_constructor() const override { return true; }
|
||||
|
|
|
@ -63,7 +63,7 @@ Value NativeFunction::call(Interpreter& interpreter)
|
|||
return m_native_function(interpreter, global_object());
|
||||
}
|
||||
|
||||
Value NativeFunction::construct(Interpreter&)
|
||||
Value NativeFunction::construct(Interpreter&, Function&)
|
||||
{
|
||||
return {};
|
||||
}
|
||||
|
|
|
@ -42,7 +42,7 @@ public:
|
|||
virtual ~NativeFunction() override;
|
||||
|
||||
virtual Value call(Interpreter&) override;
|
||||
virtual Value construct(Interpreter&) override;
|
||||
virtual Value construct(Interpreter&, Function& new_target) override;
|
||||
|
||||
virtual const FlyString& name() const override { return m_name; };
|
||||
virtual bool has_constructor() const { return false; }
|
||||
|
|
|
@ -72,7 +72,7 @@ Value NumberConstructor::call(Interpreter& interpreter)
|
|||
return interpreter.argument(0).to_number(interpreter);
|
||||
}
|
||||
|
||||
Value NumberConstructor::construct(Interpreter& interpreter)
|
||||
Value NumberConstructor::construct(Interpreter& interpreter, Function&)
|
||||
{
|
||||
double number = 0;
|
||||
if (interpreter.argument_count()) {
|
||||
|
|
|
@ -39,7 +39,7 @@ public:
|
|||
virtual ~NumberConstructor() override;
|
||||
|
||||
virtual Value call(Interpreter&) override;
|
||||
virtual Value construct(Interpreter&) override;
|
||||
virtual Value construct(Interpreter&, Function& new_target) override;
|
||||
|
||||
private:
|
||||
virtual bool has_constructor() const override { return true; }
|
||||
|
|
|
@ -69,7 +69,7 @@ Value ObjectConstructor::call(Interpreter& interpreter)
|
|||
return Object::create_empty(interpreter, global_object());
|
||||
}
|
||||
|
||||
Value ObjectConstructor::construct(Interpreter& interpreter)
|
||||
Value ObjectConstructor::construct(Interpreter& interpreter, Function&)
|
||||
{
|
||||
return call(interpreter);
|
||||
}
|
||||
|
|
|
@ -39,7 +39,7 @@ public:
|
|||
virtual ~ObjectConstructor() override;
|
||||
|
||||
virtual Value call(Interpreter&) override;
|
||||
virtual Value construct(Interpreter&) override;
|
||||
virtual Value construct(Interpreter&, Function& new_target) override;
|
||||
|
||||
private:
|
||||
virtual bool has_constructor() const override { return true; }
|
||||
|
|
|
@ -54,7 +54,7 @@ Value ProxyConstructor::call(Interpreter& interpreter)
|
|||
return interpreter.throw_exception<TypeError>(ErrorType::ProxyCallWithNew);
|
||||
}
|
||||
|
||||
Value ProxyConstructor::construct(Interpreter& interpreter)
|
||||
Value ProxyConstructor::construct(Interpreter& interpreter, Function&)
|
||||
{
|
||||
if (interpreter.argument_count() < 2)
|
||||
return interpreter.throw_exception<TypeError>(ErrorType::ProxyTwoArguments);
|
||||
|
|
|
@ -39,7 +39,7 @@ public:
|
|||
virtual ~ProxyConstructor() override;
|
||||
|
||||
virtual Value call(Interpreter&) override;
|
||||
virtual Value construct(Interpreter&) override;
|
||||
virtual Value construct(Interpreter&, Function& new_target) override;
|
||||
|
||||
private:
|
||||
virtual bool has_constructor() const override { return true; }
|
||||
|
|
|
@ -501,7 +501,7 @@ Value ProxyObject::call(Interpreter& interpreter) {
|
|||
return interpreter.call(trap.as_function(), Value(&m_handler), move(arguments));
|
||||
}
|
||||
|
||||
Value ProxyObject::construct(Interpreter& interpreter) {
|
||||
Value ProxyObject::construct(Interpreter& interpreter, Function& new_target) {
|
||||
if (!is_function())
|
||||
return interpreter.throw_exception<TypeError>(ErrorType::NotAConstructor, Value(this).to_string_without_side_effects().characters());
|
||||
|
||||
|
@ -513,7 +513,7 @@ Value ProxyObject::construct(Interpreter& interpreter) {
|
|||
if (interpreter.exception())
|
||||
return {};
|
||||
if (trap.is_empty() || trap.is_undefined() || trap.is_null())
|
||||
return static_cast<Function&>(m_target).construct(interpreter);
|
||||
return static_cast<Function&>(m_target).construct(interpreter, new_target);
|
||||
if (!trap.is_function())
|
||||
return interpreter.throw_exception<TypeError>(ErrorType::ProxyInvalidTrap, "construct");
|
||||
|
||||
|
@ -524,9 +524,7 @@ Value ProxyObject::construct(Interpreter& interpreter) {
|
|||
arguments_array->indexed_properties().append(argument);
|
||||
});
|
||||
arguments.values().append(arguments_array);
|
||||
// FIXME: We need access to the actual newTarget property here. This is just
|
||||
// a quick fix
|
||||
arguments.values().append(Value(this));
|
||||
arguments.values().append(Value(&new_target));
|
||||
auto result = interpreter.call(trap.as_function(), Value(&m_handler), move(arguments));
|
||||
if (!result.is_object())
|
||||
return interpreter.throw_exception<TypeError>(ErrorType::ProxyConstructBadReturnType);
|
||||
|
|
|
@ -40,7 +40,7 @@ public:
|
|||
virtual ~ProxyObject() override;
|
||||
|
||||
virtual Value call(Interpreter&) override;
|
||||
virtual Value construct(Interpreter&) override;
|
||||
virtual Value construct(Interpreter&, Function& new_target) override;
|
||||
virtual const FlyString& name() const override;
|
||||
virtual LexicalEnvironment* create_environment() override;
|
||||
|
||||
|
|
|
@ -50,10 +50,10 @@ RegExpConstructor::~RegExpConstructor()
|
|||
|
||||
Value RegExpConstructor::call(Interpreter& interpreter)
|
||||
{
|
||||
return construct(interpreter);
|
||||
return construct(interpreter, *this);
|
||||
}
|
||||
|
||||
Value RegExpConstructor::construct(Interpreter& interpreter)
|
||||
Value RegExpConstructor::construct(Interpreter& interpreter, Function&)
|
||||
{
|
||||
if (!interpreter.argument_count())
|
||||
return RegExpObject::create(global_object(), "(?:)", "");
|
||||
|
|
|
@ -39,7 +39,7 @@ public:
|
|||
virtual ~RegExpConstructor() override;
|
||||
|
||||
virtual Value call(Interpreter&) override;
|
||||
virtual Value construct(Interpreter&) override;
|
||||
virtual Value construct(Interpreter&, Function& new_target) override;
|
||||
|
||||
private:
|
||||
virtual bool has_constructor() const override { return true; }
|
||||
|
|
|
@ -133,7 +133,7 @@ Value ScriptFunction::call(Interpreter& interpreter)
|
|||
return interpreter.run(global_object(), m_body, arguments, ScopeType::Function);
|
||||
}
|
||||
|
||||
Value ScriptFunction::construct(Interpreter& interpreter)
|
||||
Value ScriptFunction::construct(Interpreter& interpreter, Function&)
|
||||
{
|
||||
if (m_is_arrow_function)
|
||||
return interpreter.throw_exception<TypeError>(ErrorType::NotAConstructor, m_name.characters());
|
||||
|
|
|
@ -45,7 +45,7 @@ public:
|
|||
const Vector<FunctionNode::Parameter>& parameters() const { return m_parameters; };
|
||||
|
||||
virtual Value call(Interpreter&) override;
|
||||
virtual Value construct(Interpreter&) override;
|
||||
virtual Value construct(Interpreter&, Function& new_target) override;
|
||||
|
||||
virtual const FlyString& name() const override { return m_name; };
|
||||
void set_name(const FlyString& name) { m_name = name; };
|
||||
|
|
|
@ -65,7 +65,7 @@ Value StringConstructor::call(Interpreter& interpreter)
|
|||
return string;
|
||||
}
|
||||
|
||||
Value StringConstructor::construct(Interpreter& interpreter)
|
||||
Value StringConstructor::construct(Interpreter& interpreter, Function&)
|
||||
{
|
||||
PrimitiveString* primitive_string = nullptr;
|
||||
if (!interpreter.argument_count())
|
||||
|
|
|
@ -39,7 +39,7 @@ public:
|
|||
virtual ~StringConstructor() override;
|
||||
|
||||
virtual Value call(Interpreter&) override;
|
||||
virtual Value construct(Interpreter&) override;
|
||||
virtual Value construct(Interpreter&, Function& new_target) override;
|
||||
|
||||
private:
|
||||
virtual bool has_constructor() const override { return true; }
|
||||
|
|
|
@ -74,7 +74,7 @@ Value SymbolConstructor::call(Interpreter& interpreter)
|
|||
return js_symbol(interpreter, interpreter.argument(0).to_string(interpreter), false);
|
||||
}
|
||||
|
||||
Value SymbolConstructor::construct(Interpreter& interpreter)
|
||||
Value SymbolConstructor::construct(Interpreter& interpreter, Function&)
|
||||
{
|
||||
interpreter.throw_exception<TypeError>(ErrorType::NotAConstructor, "Symbol");
|
||||
return {};
|
||||
|
|
|
@ -39,7 +39,7 @@ public:
|
|||
virtual ~SymbolConstructor() override;
|
||||
|
||||
virtual Value call(Interpreter&) override;
|
||||
virtual Value construct(Interpreter&) override;
|
||||
virtual Value construct(Interpreter&, Function& new_target) override;
|
||||
|
||||
private:
|
||||
virtual bool has_constructor() const override { return true; }
|
||||
|
|
|
@ -27,6 +27,21 @@ try {
|
|||
assert(new p(15).x === 15);
|
||||
assert(new p(15, true).x === 30);
|
||||
|
||||
let p;
|
||||
function theNewTarget() {};
|
||||
const handler = {
|
||||
construct(target, arguments, newTarget) {
|
||||
assert(target === f);
|
||||
assert(newTarget === theNewTarget);
|
||||
if (arguments[1])
|
||||
return Reflect.construct(target, [arguments[0] * 2], newTarget);
|
||||
return Reflect.construct(target, arguments, newTarget);
|
||||
},
|
||||
};
|
||||
p = new Proxy(f, handler);
|
||||
|
||||
Reflect.construct(p, [15], theNewTarget);
|
||||
|
||||
// Invariants
|
||||
[{}, [], new Proxy({}, {})].forEach(item => {
|
||||
assertThrowsError(() => {
|
||||
|
|
|
@ -59,10 +59,10 @@ XMLHttpRequestConstructor::~XMLHttpRequestConstructor()
|
|||
|
||||
JS::Value XMLHttpRequestConstructor::call(JS::Interpreter& interpreter)
|
||||
{
|
||||
return construct(interpreter);
|
||||
return construct(interpreter, *this);
|
||||
}
|
||||
|
||||
JS::Value XMLHttpRequestConstructor::construct(JS::Interpreter& interpreter)
|
||||
JS::Value XMLHttpRequestConstructor::construct(JS::Interpreter& interpreter, Function&)
|
||||
{
|
||||
auto& window = static_cast<WindowObject&>(global_object());
|
||||
return interpreter.heap().allocate<XMLHttpRequestWrapper>(window, window, XMLHttpRequest::create(window.impl()));
|
||||
|
|
|
@ -38,7 +38,7 @@ public:
|
|||
virtual ~XMLHttpRequestConstructor() override;
|
||||
|
||||
virtual JS::Value call(JS::Interpreter&) override;
|
||||
virtual JS::Value construct(JS::Interpreter&) override;
|
||||
virtual JS::Value construct(JS::Interpreter& interpreter, Function& new_target) override;
|
||||
|
||||
private:
|
||||
virtual bool has_constructor() const override { return true; }
|
||||
|
|
Loading…
Add table
Reference in a new issue