1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-05-28 19:25:10 +00:00

LibJS: Make Function::call() not require an Interpreter&

This makes a difference inside ScriptFunction::call(), which will now
instantiate a temporary Interpreter if one is not attached to the VM.
This commit is contained in:
Andreas Kling 2020-09-27 17:24:14 +02:00
parent be31805e8b
commit 1ff9d33131
42 changed files with 167 additions and 142 deletions

View file

@ -44,6 +44,14 @@
namespace JS { namespace JS {
NonnullOwnPtr<Interpreter> Interpreter::create_with_existing_global_object(GlobalObject& global_object)
{
DeferGC defer_gc(global_object.heap());
auto interpreter = adopt_own(*new Interpreter(global_object.vm()));
interpreter->m_global_object = make_handle(static_cast<Object*>(&global_object));
return interpreter;
}
Interpreter::Interpreter(VM& vm) Interpreter::Interpreter(VM& vm)
: m_vm(vm) : m_vm(vm)
, m_console(*this) , m_console(*this)
@ -84,28 +92,6 @@ const GlobalObject& Interpreter::global_object() const
return static_cast<const GlobalObject&>(*m_global_object.cell()); return static_cast<const GlobalObject&>(*m_global_object.cell());
} }
Value Interpreter::call_internal(Function& function, Value this_value, Optional<MarkedValueList> arguments)
{
ASSERT(!exception());
VM::InterpreterExecutionScope scope(*this);
auto& call_frame = vm().push_call_frame();
call_frame.function_name = function.name();
call_frame.this_value = function.bound_this().value_or(this_value);
call_frame.arguments = function.bound_arguments();
if (arguments.has_value())
call_frame.arguments.append(arguments.value().values());
call_frame.environment = function.create_environment();
ASSERT(call_frame.environment->this_binding_status() == LexicalEnvironment::ThisBindingStatus::Uninitialized);
call_frame.environment->bind_this_value(call_frame.this_value);
auto result = function.call(*this);
vm().pop_call_frame();
return result;
}
void Interpreter::enter_scope(const ScopeNode& scope_node, ArgumentVector arguments, ScopeType scope_type, GlobalObject& global_object) void Interpreter::enter_scope(const ScopeNode& scope_node, ArgumentVector arguments, ScopeType scope_type, GlobalObject& global_object)
{ {
for (auto& declaration : scope_node.functions()) { for (auto& declaration : scope_node.functions()) {

View file

@ -58,6 +58,8 @@ public:
return interpreter; return interpreter;
} }
static NonnullOwnPtr<Interpreter> create_with_existing_global_object(GlobalObject&);
template<typename... Args> template<typename... Args>
[[nodiscard]] ALWAYS_INLINE Value call(Function& function, Value this_value, Args... args) [[nodiscard]] ALWAYS_INLINE Value call(Function& function, Value this_value, Args... args)
{ {
@ -110,7 +112,10 @@ public:
private: private:
explicit Interpreter(VM&); explicit Interpreter(VM&);
[[nodiscard]] Value call_internal(Function&, Value this_value, Optional<MarkedValueList>); [[nodiscard]] Value call_internal(Function& function, Value this_value, Optional<MarkedValueList> arguments)
{
return vm().call(function, this_value, move(arguments));
}
NonnullRefPtr<VM> m_vm; NonnullRefPtr<VM> m_vm;

View file

@ -59,15 +59,15 @@ void ArrayConstructor::initialize(GlobalObject& global_object)
define_native_function("of", of, 0, attr); define_native_function("of", of, 0, attr);
} }
Value ArrayConstructor::call(Interpreter& interpreter) Value ArrayConstructor::call()
{ {
if (interpreter.argument_count() <= 0) if (vm().argument_count() <= 0)
return Array::create(global_object()); return Array::create(global_object());
if (interpreter.argument_count() == 1 && interpreter.argument(0).is_number()) { if (vm().argument_count() == 1 && vm().argument(0).is_number()) {
auto array_length_value = interpreter.argument(0); auto array_length_value = vm().argument(0);
if (!array_length_value.is_integer() || array_length_value.as_i32() < 0) { if (!array_length_value.is_integer() || array_length_value.as_i32() < 0) {
interpreter.vm().throw_exception<TypeError>(global_object(), ErrorType::ArrayInvalidLength); vm().throw_exception<TypeError>(global_object(), ErrorType::ArrayInvalidLength);
return {}; return {};
} }
auto* array = Array::create(global_object()); auto* array = Array::create(global_object());
@ -76,14 +76,14 @@ Value ArrayConstructor::call(Interpreter& interpreter)
} }
auto* array = Array::create(global_object()); auto* array = Array::create(global_object());
for (size_t i = 0; i < interpreter.argument_count(); ++i) for (size_t i = 0; i < vm().argument_count(); ++i)
array->indexed_properties().append(interpreter.argument(i)); array->indexed_properties().append(vm().argument(i));
return array; return array;
} }
Value ArrayConstructor::construct(Interpreter& interpreter, Function&) Value ArrayConstructor::construct(Interpreter&, Function&)
{ {
return call(interpreter); return call();
} }
JS_DEFINE_NATIVE_FUNCTION(ArrayConstructor::from) JS_DEFINE_NATIVE_FUNCTION(ArrayConstructor::from)

View file

@ -38,7 +38,7 @@ public:
virtual void initialize(GlobalObject&) override; virtual void initialize(GlobalObject&) override;
virtual ~ArrayConstructor() override; virtual ~ArrayConstructor() override;
virtual Value call(Interpreter&) override; virtual Value call() override;
virtual Value construct(Interpreter&, Function& new_target) override; virtual Value construct(Interpreter&, Function& new_target) override;
private: private:

View file

@ -54,20 +54,20 @@ BigIntConstructor::~BigIntConstructor()
{ {
} }
Value BigIntConstructor::call(Interpreter& interpreter) Value BigIntConstructor::call()
{ {
auto primitive = interpreter.argument(0).to_primitive(interpreter, Value::PreferredType::Number); auto primitive = vm().argument(0).to_primitive(Value::PreferredType::Number);
if (interpreter.exception()) if (vm().exception())
return {}; return {};
if (primitive.is_number()) { if (primitive.is_number()) {
if (!primitive.is_integer()) { if (!primitive.is_integer()) {
interpreter.vm().throw_exception<RangeError>(global_object(), ErrorType::BigIntIntArgument); vm().throw_exception<RangeError>(global_object(), ErrorType::BigIntIntArgument);
return {}; return {};
} }
return js_bigint(interpreter, Crypto::SignedBigInteger { primitive.as_i32() }); return js_bigint(heap(), Crypto::SignedBigInteger { primitive.as_i32() });
} }
auto* bigint = interpreter.argument(0).to_bigint(interpreter); auto* bigint = vm().argument(0).to_bigint(global_object());
if (interpreter.exception()) if (vm().exception())
return {}; return {};
return bigint; return bigint;
} }

View file

@ -38,7 +38,7 @@ public:
virtual void initialize(GlobalObject&) override; virtual void initialize(GlobalObject&) override;
virtual ~BigIntConstructor() override; virtual ~BigIntConstructor() override;
virtual Value call(Interpreter&) override; virtual Value call() override;
virtual Value construct(Interpreter&, Function& new_target) override; virtual Value construct(Interpreter&, Function& new_target) override;
private: private:

View file

@ -49,9 +49,9 @@ BooleanConstructor::~BooleanConstructor()
{ {
} }
Value BooleanConstructor::call(Interpreter& interpreter) Value BooleanConstructor::call()
{ {
return Value(interpreter.argument(0).to_boolean()); return Value(vm().argument(0).to_boolean());
} }
Value BooleanConstructor::construct(Interpreter& interpreter, Function&) Value BooleanConstructor::construct(Interpreter& interpreter, Function&)

View file

@ -38,7 +38,7 @@ public:
virtual void initialize(GlobalObject&) override; virtual void initialize(GlobalObject&) override;
virtual ~BooleanConstructor() override; virtual ~BooleanConstructor() override;
virtual Value call(Interpreter&) override; virtual Value call() override;
virtual Value construct(Interpreter&, Function& new_target) override; virtual Value construct(Interpreter&, Function& new_target) override;
private: private:

View file

@ -49,9 +49,9 @@ BoundFunction::~BoundFunction()
{ {
} }
Value BoundFunction::call(Interpreter& interpreter) Value BoundFunction::call()
{ {
return m_target_function->call(interpreter); return m_target_function->call();
} }
Value BoundFunction::construct(Interpreter& interpreter, Function& new_target) Value BoundFunction::construct(Interpreter& interpreter, Function& new_target)

View file

@ -38,7 +38,7 @@ public:
virtual void initialize(GlobalObject&) override; virtual void initialize(GlobalObject&) override;
virtual ~BoundFunction(); virtual ~BoundFunction();
virtual Value call(Interpreter& interpreter) override; virtual Value call() override;
virtual Value construct(Interpreter&, Function& new_target) override; virtual Value construct(Interpreter&, Function& new_target) override;

View file

@ -157,12 +157,12 @@ DateConstructor::~DateConstructor()
{ {
} }
Value DateConstructor::call(Interpreter& interpreter) Value DateConstructor::call()
{ {
auto date = construct(interpreter, *this); auto date = construct(interpreter(), *this);
if (!date.is_object()) if (!date.is_object())
return {}; return {};
return js_string(interpreter, static_cast<Date&>(date.as_object()).string()); return js_string(heap(), static_cast<Date&>(date.as_object()).string());
} }
Value DateConstructor::construct(Interpreter& interpreter, Function&) Value DateConstructor::construct(Interpreter& interpreter, Function&)

View file

@ -38,7 +38,7 @@ public:
virtual void initialize(GlobalObject&) override; virtual void initialize(GlobalObject&) override;
virtual ~DateConstructor() override; virtual ~DateConstructor() override;
virtual Value call(Interpreter&) override; virtual Value call() override;
virtual Value construct(Interpreter&, Function& new_target) override; virtual Value construct(Interpreter&, Function& new_target) override;
private: private:

View file

@ -47,9 +47,9 @@ ErrorConstructor::~ErrorConstructor()
{ {
} }
Value ErrorConstructor::call(Interpreter& interpreter) Value ErrorConstructor::call()
{ {
return construct(interpreter, *this); return construct(interpreter(), *this);
} }
Value ErrorConstructor::construct(Interpreter& interpreter, Function&) Value ErrorConstructor::construct(Interpreter& interpreter, Function&)
@ -75,9 +75,9 @@ Value ErrorConstructor::construct(Interpreter& interpreter, Function&)
define_property("length", Value(1), Attribute::Configurable); \ define_property("length", Value(1), Attribute::Configurable); \
} \ } \
ConstructorName::~ConstructorName() { } \ ConstructorName::~ConstructorName() { } \
Value ConstructorName::call(Interpreter& interpreter) \ Value ConstructorName::call() \
{ \ { \
return construct(interpreter, *this); \ return construct(interpreter(), *this); \
} \ } \
Value ConstructorName::construct(Interpreter& interpreter, Function&) \ Value ConstructorName::construct(Interpreter& interpreter, Function&) \
{ \ { \

View file

@ -39,7 +39,7 @@ public:
virtual void initialize(GlobalObject&) override; virtual void initialize(GlobalObject&) override;
virtual ~ErrorConstructor() override; virtual ~ErrorConstructor() override;
virtual Value call(Interpreter&) override; virtual Value call() override;
virtual Value construct(Interpreter&, Function& new_target) override; virtual Value construct(Interpreter&, Function& new_target) override;
private: private:
@ -54,7 +54,7 @@ private:
explicit ConstructorName(GlobalObject&); \ explicit ConstructorName(GlobalObject&); \
virtual void initialize(GlobalObject&) override; \ virtual void initialize(GlobalObject&) override; \
virtual ~ConstructorName() override; \ virtual ~ConstructorName() override; \
virtual Value call(Interpreter&) override; \ virtual Value call() override; \
virtual Value construct(Interpreter&, Function& new_target) override; \ virtual Value construct(Interpreter&, Function& new_target) override; \
\ \
private: \ private: \

View file

@ -43,7 +43,7 @@ public:
virtual ~Function(); virtual ~Function();
virtual void initialize(GlobalObject&) override { } virtual void initialize(GlobalObject&) override { }
virtual Value call(Interpreter&) = 0; virtual Value call() = 0;
virtual Value construct(Interpreter&, Function& new_target) = 0; virtual Value construct(Interpreter&, Function& new_target) = 0;
virtual const FlyString& name() const = 0; virtual const FlyString& name() const = 0;
virtual LexicalEnvironment* create_environment() = 0; virtual LexicalEnvironment* create_environment() = 0;

View file

@ -51,9 +51,9 @@ FunctionConstructor::~FunctionConstructor()
{ {
} }
Value FunctionConstructor::call(Interpreter& interpreter) Value FunctionConstructor::call()
{ {
return construct(interpreter, *this); return construct(interpreter(), *this);
} }
Value FunctionConstructor::construct(Interpreter& interpreter, Function&) Value FunctionConstructor::construct(Interpreter& interpreter, Function&)

View file

@ -38,7 +38,7 @@ public:
virtual void initialize(GlobalObject&) override; virtual void initialize(GlobalObject&) override;
virtual ~FunctionConstructor() override; virtual ~FunctionConstructor() override;
virtual Value call(Interpreter&) override; virtual Value call() override;
virtual Value construct(Interpreter&, Function& new_target) override; virtual Value construct(Interpreter&, Function& new_target) override;
private: private:

View file

@ -58,9 +58,9 @@ NativeFunction::~NativeFunction()
{ {
} }
Value NativeFunction::call(Interpreter& interpreter) Value NativeFunction::call()
{ {
return m_native_function(interpreter, global_object()); return m_native_function(interpreter(), global_object());
} }
Value NativeFunction::construct(Interpreter&, Function&) Value NativeFunction::construct(Interpreter&, Function&)

View file

@ -41,7 +41,7 @@ public:
virtual void initialize(GlobalObject&) override { } virtual void initialize(GlobalObject&) override { }
virtual ~NativeFunction() override; virtual ~NativeFunction() override;
virtual Value call(Interpreter&) override; virtual Value call() override;
virtual Value construct(Interpreter&, Function& new_target) override; virtual Value construct(Interpreter&, Function& new_target) override;
virtual const FlyString& name() const override { return m_name; }; virtual const FlyString& name() const override { return m_name; };

View file

@ -65,11 +65,11 @@ NumberConstructor::~NumberConstructor()
{ {
} }
Value NumberConstructor::call(Interpreter& interpreter) Value NumberConstructor::call()
{ {
if (!interpreter.argument_count()) if (!vm().argument_count())
return Value(0); return Value(0);
return interpreter.argument(0).to_number(interpreter); return vm().argument(0).to_number(interpreter());
} }
Value NumberConstructor::construct(Interpreter& interpreter, Function&) Value NumberConstructor::construct(Interpreter& interpreter, Function&)

View file

@ -38,7 +38,7 @@ public:
virtual void initialize(GlobalObject&) override; virtual void initialize(GlobalObject&) override;
virtual ~NumberConstructor() override; virtual ~NumberConstructor() override;
virtual Value call(Interpreter&) override; virtual Value call() override;
virtual Value construct(Interpreter&, Function& new_target) override; virtual Value construct(Interpreter&, Function& new_target) override;
private: private:

View file

@ -870,20 +870,20 @@ Value Object::invoke(const StringOrSymbol& property_name, Optional<MarkedValueLi
Value Object::call_native_property_getter(Object* this_object, Value property) const Value Object::call_native_property_getter(Object* this_object, Value property) const
{ {
ASSERT(property.is_native_property()); ASSERT(property.is_native_property());
auto& call_frame = interpreter().vm().push_call_frame(); auto& call_frame = vm().push_call_frame();
call_frame.this_value = this_object; call_frame.this_value = this_object;
auto result = property.as_native_property().get(interpreter(), global_object()); auto result = property.as_native_property().get(interpreter(), global_object());
interpreter().vm().pop_call_frame(); vm().pop_call_frame();
return result; return result;
} }
void Object::call_native_property_setter(Object* this_object, Value property, Value value) const void Object::call_native_property_setter(Object* this_object, Value property, Value value) const
{ {
ASSERT(property.is_native_property()); ASSERT(property.is_native_property());
auto& call_frame = interpreter().vm().push_call_frame(); auto& call_frame = vm().push_call_frame();
call_frame.this_value = this_object; call_frame.this_value = this_object;
property.as_native_property().set(interpreter(), global_object(), value); property.as_native_property().set(interpreter(), global_object(), value);
interpreter().vm().pop_call_frame(); vm().pop_call_frame();
} }
} }

View file

@ -64,14 +64,14 @@ ObjectConstructor::~ObjectConstructor()
{ {
} }
Value ObjectConstructor::call(Interpreter&) Value ObjectConstructor::call()
{ {
return Object::create_empty(global_object()); return Object::create_empty(global_object());
} }
Value ObjectConstructor::construct(Interpreter& interpreter, Function&) Value ObjectConstructor::construct(Interpreter&, Function&)
{ {
return call(interpreter); return call();
} }
JS_DEFINE_NATIVE_FUNCTION(ObjectConstructor::get_own_property_names) JS_DEFINE_NATIVE_FUNCTION(ObjectConstructor::get_own_property_names)

View file

@ -38,7 +38,7 @@ public:
virtual void initialize(GlobalObject&) override; virtual void initialize(GlobalObject&) override;
virtual ~ObjectConstructor() override; virtual ~ObjectConstructor() override;
virtual Value call(Interpreter&) override; virtual Value call() override;
virtual Value construct(Interpreter&, Function& new_target) override; virtual Value construct(Interpreter&, Function& new_target) override;
private: private:

View file

@ -49,9 +49,9 @@ ProxyConstructor::~ProxyConstructor()
{ {
} }
Value ProxyConstructor::call(Interpreter& interpreter) Value ProxyConstructor::call()
{ {
interpreter.vm().throw_exception<TypeError>(global_object(), ErrorType::ProxyCallWithNew); vm().throw_exception<TypeError>(global_object(), ErrorType::ProxyCallWithNew);
return {}; return {};
} }

View file

@ -38,7 +38,7 @@ public:
virtual void initialize(GlobalObject&) override; virtual void initialize(GlobalObject&) override;
virtual ~ProxyConstructor() override; virtual ~ProxyConstructor() override;
virtual Value call(Interpreter&) override; virtual Value call() override;
virtual Value construct(Interpreter&, Function& new_target) override; virtual Value construct(Interpreter&, Function& new_target) override;
private: private:

View file

@ -460,36 +460,36 @@ void ProxyObject::visit_children(Cell::Visitor& visitor)
visitor.visit(&m_handler); visitor.visit(&m_handler);
} }
Value ProxyObject::call(Interpreter& interpreter) Value ProxyObject::call()
{ {
if (!is_function()) { if (!is_function()) {
interpreter.vm().throw_exception<TypeError>(global_object(), ErrorType::NotAFunction, Value(this).to_string_without_side_effects().characters()); vm().throw_exception<TypeError>(global_object(), ErrorType::NotAFunction, Value(this).to_string_without_side_effects().characters());
return {}; return {};
} }
if (m_is_revoked) { if (m_is_revoked) {
interpreter.vm().throw_exception<TypeError>(global_object(), ErrorType::ProxyRevoked); vm().throw_exception<TypeError>(global_object(), ErrorType::ProxyRevoked);
return {}; return {};
} }
auto trap = m_handler.get("apply"); auto trap = m_handler.get("apply");
if (interpreter.exception()) if (vm().exception())
return {}; return {};
if (trap.is_empty() || trap.is_undefined() || trap.is_null()) if (trap.is_empty() || trap.is_undefined() || trap.is_null())
return static_cast<Function&>(m_target).call(interpreter); return static_cast<Function&>(m_target).call();
if (!trap.is_function()) { if (!trap.is_function()) {
interpreter.vm().throw_exception<TypeError>(global_object(), ErrorType::ProxyInvalidTrap, "apply"); vm().throw_exception<TypeError>(global_object(), ErrorType::ProxyInvalidTrap, "apply");
return {}; return {};
} }
MarkedValueList arguments(interpreter.heap()); MarkedValueList arguments(heap());
arguments.append(Value(&m_target)); arguments.append(Value(&m_target));
arguments.append(Value(&m_handler)); arguments.append(Value(&m_handler));
// FIXME: Pass global object // FIXME: Pass global object
auto arguments_array = Array::create(interpreter.global_object()); auto arguments_array = Array::create(global_object());
interpreter.vm().for_each_argument([&](auto& argument) { vm().for_each_argument([&](auto& argument) {
arguments_array->indexed_properties().append(argument); arguments_array->indexed_properties().append(argument);
}); });
arguments.append(arguments_array); arguments.append(arguments_array);
return interpreter.call(trap.as_function(), Value(&m_handler), move(arguments)); return vm().call(trap.as_function(), Value(&m_handler), move(arguments));
} }
Value ProxyObject::construct(Interpreter& interpreter, Function& new_target) Value ProxyObject::construct(Interpreter& interpreter, Function& new_target)

View file

@ -39,7 +39,7 @@ public:
ProxyObject(Object& target, Object& handler, Object& prototype); ProxyObject(Object& target, Object& handler, Object& prototype);
virtual ~ProxyObject() override; virtual ~ProxyObject() override;
virtual Value call(Interpreter&) override; virtual Value call() override;
virtual Value construct(Interpreter&, Function& new_target) override; virtual Value construct(Interpreter&, Function& new_target) override;
virtual const FlyString& name() const override; virtual const FlyString& name() const override;
virtual LexicalEnvironment* create_environment() override; virtual LexicalEnvironment* create_environment() override;

View file

@ -48,9 +48,9 @@ RegExpConstructor::~RegExpConstructor()
{ {
} }
Value RegExpConstructor::call(Interpreter& interpreter) Value RegExpConstructor::call()
{ {
return construct(interpreter, *this); return construct(interpreter(), *this);
} }
Value RegExpConstructor::construct(Interpreter& interpreter, Function&) Value RegExpConstructor::construct(Interpreter& interpreter, Function&)

View file

@ -38,7 +38,7 @@ public:
virtual void initialize(GlobalObject&) override; virtual void initialize(GlobalObject&) override;
virtual ~RegExpConstructor() override; virtual ~RegExpConstructor() override;
virtual Value call(Interpreter&) override; virtual Value call() override;
virtual Value construct(Interpreter&, Function& new_target) override; virtual Value construct(Interpreter&, Function& new_target) override;
private: private:

View file

@ -106,9 +106,19 @@ LexicalEnvironment* ScriptFunction::create_environment()
return environment; return environment;
} }
Value ScriptFunction::call(Interpreter& interpreter) Value ScriptFunction::call()
{ {
auto& argument_values = interpreter.call_frame().arguments; OwnPtr<Interpreter> local_interpreter;
Interpreter* interpreter = vm().interpreter_if_exists();
if (!interpreter) {
local_interpreter = Interpreter::create_with_existing_global_object(global_object());
interpreter = local_interpreter.ptr();
}
VM::InterpreterExecutionScope scope(*interpreter);
auto& argument_values = vm().call_frame().arguments;
ArgumentVector arguments; ArgumentVector arguments;
for (size_t i = 0; i < m_parameters.size(); ++i) { for (size_t i = 0; i < m_parameters.size(); ++i) {
auto parameter = parameters()[i]; auto parameter = parameters()[i];
@ -122,24 +132,24 @@ Value ScriptFunction::call(Interpreter& interpreter)
if (i < argument_values.size() && !argument_values[i].is_undefined()) { if (i < argument_values.size() && !argument_values[i].is_undefined()) {
value = argument_values[i]; value = argument_values[i];
} else if (parameter.default_value) { } else if (parameter.default_value) {
value = parameter.default_value->execute(interpreter, global_object()); value = parameter.default_value->execute(*interpreter, global_object());
if (interpreter.exception()) if (vm().exception())
return {}; return {};
} }
} }
arguments.append({ parameter.name, value }); arguments.append({ parameter.name, value });
interpreter.current_environment()->set(parameter.name, { value, DeclarationKind::Var }); vm().current_environment()->set(parameter.name, { value, DeclarationKind::Var });
} }
return interpreter.execute_statement(global_object(), m_body, arguments, ScopeType::Function); return interpreter->execute_statement(global_object(), m_body, arguments, ScopeType::Function);
} }
Value ScriptFunction::construct(Interpreter& interpreter, Function&) Value ScriptFunction::construct(Interpreter&, Function&)
{ {
if (m_is_arrow_function) { if (m_is_arrow_function) {
interpreter.vm().throw_exception<TypeError>(global_object(), ErrorType::NotAConstructor, m_name.characters()); vm().throw_exception<TypeError>(global_object(), ErrorType::NotAConstructor, m_name.characters());
return {}; return {};
} }
return call(interpreter); return call();
} }
JS_DEFINE_NATIVE_GETTER(ScriptFunction::length_getter) JS_DEFINE_NATIVE_GETTER(ScriptFunction::length_getter)

View file

@ -44,7 +44,7 @@ public:
const Statement& body() const { return m_body; } const Statement& body() const { return m_body; }
const Vector<FunctionNode::Parameter>& parameters() const { return m_parameters; }; const Vector<FunctionNode::Parameter>& parameters() const { return m_parameters; };
virtual Value call(Interpreter&) override; virtual Value call() override;
virtual Value construct(Interpreter&, Function& new_target) override; virtual Value construct(Interpreter&, Function& new_target) override;
virtual const FlyString& name() const override { return m_name; }; virtual const FlyString& name() const override { return m_name; };

View file

@ -55,14 +55,14 @@ StringConstructor::~StringConstructor()
{ {
} }
Value StringConstructor::call(Interpreter& interpreter) Value StringConstructor::call()
{ {
if (!interpreter.argument_count()) if (!vm().argument_count())
return js_string(interpreter, ""); return js_string(heap(), "");
if (interpreter.argument(0).is_symbol()) if (vm().argument(0).is_symbol())
return js_string(interpreter, interpreter.argument(0).as_symbol().to_string()); return js_string(heap(), vm().argument(0).as_symbol().to_string());
auto* string = interpreter.argument(0).to_primitive_string(interpreter); auto* string = vm().argument(0).to_primitive_string(interpreter());
if (interpreter.exception()) if (vm().exception())
return {}; return {};
return string; return string;
} }

View file

@ -38,7 +38,7 @@ public:
virtual void initialize(GlobalObject&) override; virtual void initialize(GlobalObject&) override;
virtual ~StringConstructor() override; virtual ~StringConstructor() override;
virtual Value call(Interpreter&) override; virtual Value call() override;
virtual Value construct(Interpreter&, Function& new_target) override; virtual Value construct(Interpreter&, Function& new_target) override;
private: private:

View file

@ -56,11 +56,11 @@ SymbolConstructor::~SymbolConstructor()
{ {
} }
Value SymbolConstructor::call(Interpreter& interpreter) Value SymbolConstructor::call()
{ {
if (!interpreter.argument_count()) if (!vm().argument_count())
return js_symbol(interpreter, "", false); return js_symbol(heap(), "", false);
return js_symbol(interpreter, interpreter.argument(0).to_string(interpreter), false); return js_symbol(heap(), vm().argument(0).to_string(interpreter()), false);
} }
Value SymbolConstructor::construct(Interpreter& interpreter, Function&) Value SymbolConstructor::construct(Interpreter& interpreter, Function&)

View file

@ -38,7 +38,7 @@ public:
virtual void initialize(GlobalObject&) override; virtual void initialize(GlobalObject&) override;
virtual ~SymbolConstructor() override; virtual ~SymbolConstructor() override;
virtual Value call(Interpreter&) override; virtual Value call() override;
virtual Value construct(Interpreter&, Function& new_target) override; virtual Value construct(Interpreter&, Function& new_target) override;
private: private:

View file

@ -24,8 +24,8 @@
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/ */
#include <AK/StringBuilder.h>
#include <AK/ScopeGuard.h> #include <AK/ScopeGuard.h>
#include <AK/StringBuilder.h>
#include <LibJS/Interpreter.h> #include <LibJS/Interpreter.h>
#include <LibJS/Runtime/Error.h> #include <LibJS/Runtime/Error.h>
#include <LibJS/Runtime/GlobalObject.h> #include <LibJS/Runtime/GlobalObject.h>
@ -300,4 +300,24 @@ Value VM::get_new_target() const
return get_this_environment()->new_target(); return get_this_environment()->new_target();
} }
Value VM::call(Function& function, Value this_value, Optional<MarkedValueList> arguments)
{
ASSERT(!exception());
auto& call_frame = push_call_frame();
call_frame.function_name = function.name();
call_frame.this_value = function.bound_this().value_or(this_value);
call_frame.arguments = function.bound_arguments();
if (arguments.has_value())
call_frame.arguments.append(arguments.value().values());
call_frame.environment = function.create_environment();
ASSERT(call_frame.environment->this_binding_status() == LexicalEnvironment::ThisBindingStatus::Uninitialized);
call_frame.environment->bind_this_value(call_frame.this_value);
auto result = function.call();
pop_call_frame();
return result;
}
} }

View file

@ -206,6 +206,8 @@ public:
const LexicalEnvironment* get_this_environment() const; const LexicalEnvironment* get_this_environment() const;
Value get_new_target() const; Value get_new_target() const;
[[nodiscard]] Value call(Function&, Value this_value, Optional<MarkedValueList> arguments);
private: private:
VM(); VM();

View file

@ -41,6 +41,7 @@
#include <LibJS/Runtime/BoundFunction.h> #include <LibJS/Runtime/BoundFunction.h>
#include <LibJS/Runtime/Error.h> #include <LibJS/Runtime/Error.h>
#include <LibJS/Runtime/Function.h> #include <LibJS/Runtime/Function.h>
#include <LibJS/Runtime/GlobalObject.h>
#include <LibJS/Runtime/NumberObject.h> #include <LibJS/Runtime/NumberObject.h>
#include <LibJS/Runtime/Object.h> #include <LibJS/Runtime/Object.h>
#include <LibJS/Runtime/PrimitiveString.h> #include <LibJS/Runtime/PrimitiveString.h>
@ -203,7 +204,7 @@ bool Value::to_boolean() const
} }
} }
Value Value::to_primitive(Interpreter&, PreferredType preferred_type) const Value Value::to_primitive(PreferredType preferred_type) const
{ {
if (is_object()) if (is_object())
return as_object().to_primitive(preferred_type); return as_object().to_primitive(preferred_type);
@ -237,7 +238,7 @@ Object* Value::to_object(Interpreter& interpreter, GlobalObject& global_object)
Value Value::to_numeric(Interpreter& interpreter) const Value Value::to_numeric(Interpreter& interpreter) const
{ {
auto primitive = to_primitive(interpreter, Value::PreferredType::Number); auto primitive = to_primitive(Value::PreferredType::Number);
if (interpreter.exception()) if (interpreter.exception())
return {}; return {};
if (primitive.is_bigint()) if (primitive.is_bigint())
@ -287,37 +288,38 @@ Value Value::to_number(Interpreter& interpreter) const
} }
} }
BigInt* Value::to_bigint(Interpreter& interpreter) const BigInt* Value::to_bigint(GlobalObject& global_object) const
{ {
auto primitive = to_primitive(interpreter, PreferredType::Number); auto& vm = global_object.vm();
if (interpreter.exception()) auto primitive = to_primitive(PreferredType::Number);
if (vm.exception())
return nullptr; return nullptr;
switch (primitive.type()) { switch (primitive.type()) {
case Type::Undefined: case Type::Undefined:
interpreter.vm().throw_exception<TypeError>(interpreter.global_object(), ErrorType::Convert, "undefined", "BigInt"); vm.throw_exception<TypeError>(global_object, ErrorType::Convert, "undefined", "BigInt");
return nullptr; return nullptr;
case Type::Null: case Type::Null:
interpreter.vm().throw_exception<TypeError>(interpreter.global_object(), ErrorType::Convert, "null", "BigInt"); vm.throw_exception<TypeError>(global_object, ErrorType::Convert, "null", "BigInt");
return nullptr; return nullptr;
case Type::Boolean: { case Type::Boolean: {
auto value = primitive.as_bool() ? 1 : 0; auto value = primitive.as_bool() ? 1 : 0;
return js_bigint(interpreter, Crypto::SignedBigInteger { value }); return js_bigint(vm.heap(), Crypto::SignedBigInteger { value });
} }
case Type::BigInt: case Type::BigInt:
return &primitive.as_bigint(); return &primitive.as_bigint();
case Type::Number: case Type::Number:
interpreter.vm().throw_exception<TypeError>(interpreter.global_object(), ErrorType::Convert, "number", "BigInt"); vm.throw_exception<TypeError>(global_object, ErrorType::Convert, "number", "BigInt");
return {}; return {};
case Type::String: { case Type::String: {
auto& string = primitive.as_string().string(); auto& string = primitive.as_string().string();
if (!is_valid_bigint_value(string)) { if (!is_valid_bigint_value(string)) {
interpreter.vm().throw_exception<SyntaxError>(interpreter.global_object(), ErrorType::BigIntInvalidValue, string.characters()); vm.throw_exception<SyntaxError>(global_object, ErrorType::BigIntInvalidValue, string.characters());
return {}; return {};
} }
return js_bigint(interpreter, Crypto::SignedBigInteger::from_base10(string.trim_whitespace())); return js_bigint(vm.heap(), Crypto::SignedBigInteger::from_base10(string.trim_whitespace()));
} }
case Type::Symbol: case Type::Symbol:
interpreter.vm().throw_exception<TypeError>(interpreter.global_object(), ErrorType::Convert, "symbol", "BigInt"); vm.throw_exception<TypeError>(global_object, ErrorType::Convert, "symbol", "BigInt");
return {}; return {};
default: default:
ASSERT_NOT_REACHED(); ASSERT_NOT_REACHED();
@ -564,10 +566,10 @@ Value unsigned_right_shift(Interpreter& interpreter, Value lhs, Value rhs)
Value add(Interpreter& interpreter, Value lhs, Value rhs) Value add(Interpreter& interpreter, Value lhs, Value rhs)
{ {
auto lhs_primitive = lhs.to_primitive(interpreter); auto lhs_primitive = lhs.to_primitive();
if (interpreter.exception()) if (interpreter.exception())
return {}; return {};
auto rhs_primitive = rhs.to_primitive(interpreter); auto rhs_primitive = rhs.to_primitive();
if (interpreter.exception()) if (interpreter.exception())
return {}; return {};
@ -873,10 +875,10 @@ bool abstract_eq(Interpreter& interpreter, Value lhs, Value rhs)
return abstract_eq(interpreter, lhs, rhs.to_number(interpreter)); return abstract_eq(interpreter, lhs, rhs.to_number(interpreter));
if ((lhs.is_string() || lhs.is_number() || lhs.is_bigint() || lhs.is_symbol()) && rhs.is_object()) if ((lhs.is_string() || lhs.is_number() || lhs.is_bigint() || lhs.is_symbol()) && rhs.is_object())
return abstract_eq(interpreter, lhs, rhs.to_primitive(interpreter)); return abstract_eq(interpreter, lhs, rhs.to_primitive());
if (lhs.is_object() && (rhs.is_string() || rhs.is_number() || lhs.is_bigint() || rhs.is_symbol())) if (lhs.is_object() && (rhs.is_string() || rhs.is_number() || lhs.is_bigint() || rhs.is_symbol()))
return abstract_eq(interpreter, lhs.to_primitive(interpreter), rhs); return abstract_eq(interpreter, lhs.to_primitive(), rhs);
if ((lhs.is_bigint() && rhs.is_number()) || (lhs.is_number() && rhs.is_bigint())) { if ((lhs.is_bigint() && rhs.is_number()) || (lhs.is_number() && rhs.is_bigint())) {
if (lhs.is_nan() || lhs.is_infinity() || rhs.is_nan() || rhs.is_infinity()) if (lhs.is_nan() || lhs.is_infinity() || rhs.is_nan() || rhs.is_infinity())
@ -898,17 +900,17 @@ TriState abstract_relation(Interpreter& interpreter, bool left_first, Value lhs,
Value y_primitive; Value y_primitive;
if (left_first) { if (left_first) {
x_primitive = lhs.to_primitive(interpreter, Value::PreferredType::Number); x_primitive = lhs.to_primitive(Value::PreferredType::Number);
if (interpreter.exception()) if (interpreter.exception())
return {}; return {};
y_primitive = rhs.to_primitive(interpreter, Value::PreferredType::Number); y_primitive = rhs.to_primitive(Value::PreferredType::Number);
if (interpreter.exception()) if (interpreter.exception())
return {}; return {};
} else { } else {
y_primitive = lhs.to_primitive(interpreter, Value::PreferredType::Number); y_primitive = lhs.to_primitive(Value::PreferredType::Number);
if (interpreter.exception()) if (interpreter.exception())
return {}; return {};
x_primitive = rhs.to_primitive(interpreter, Value::PreferredType::Number); x_primitive = rhs.to_primitive(Value::PreferredType::Number);
if (interpreter.exception()) if (interpreter.exception())
return {}; return {};
} }

View file

@ -242,11 +242,11 @@ public:
String to_string(Interpreter&) const; String to_string(Interpreter&) const;
PrimitiveString* to_primitive_string(Interpreter&); PrimitiveString* to_primitive_string(Interpreter&);
Value to_primitive(Interpreter&, PreferredType preferred_type = PreferredType::Default) const; Value to_primitive(PreferredType preferred_type = PreferredType::Default) const;
Object* to_object(Interpreter&, GlobalObject&) const; Object* to_object(Interpreter&, GlobalObject&) const;
Value to_numeric(Interpreter&) const; Value to_numeric(Interpreter&) const;
Value to_number(Interpreter&) const; Value to_number(Interpreter&) const;
BigInt* to_bigint(Interpreter&) const; BigInt* to_bigint(GlobalObject&) const;
double to_double(Interpreter&) const; double to_double(Interpreter&) const;
i32 to_i32(Interpreter&) const; i32 to_i32(Interpreter&) const;
size_t to_size_t(Interpreter&) const; size_t to_size_t(Interpreter&) const;

View file

@ -56,9 +56,9 @@ XMLHttpRequestConstructor::~XMLHttpRequestConstructor()
{ {
} }
JS::Value XMLHttpRequestConstructor::call(JS::Interpreter& interpreter) JS::Value XMLHttpRequestConstructor::call()
{ {
return construct(interpreter, *this); return construct(interpreter(), *this);
} }
JS::Value XMLHttpRequestConstructor::construct(JS::Interpreter& interpreter, Function&) JS::Value XMLHttpRequestConstructor::construct(JS::Interpreter& interpreter, Function&)

View file

@ -36,7 +36,7 @@ public:
virtual void initialize(JS::GlobalObject&) override; virtual void initialize(JS::GlobalObject&) override;
virtual ~XMLHttpRequestConstructor() override; virtual ~XMLHttpRequestConstructor() override;
virtual JS::Value call(JS::Interpreter&) override; virtual JS::Value call() override;
virtual JS::Value construct(JS::Interpreter& interpreter, Function& new_target) override; virtual JS::Value construct(JS::Interpreter& interpreter, Function& new_target) override;
private: private: