1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-07-26 07:37:35 +00:00

LibJS: Add a helper for calling JS::Function's with arguments

The fact that a `MarkedValueList` had to be created was just annoying,
so here's an alternative.
This patchset also removes some (now) unneeded MarkedValueList.h includes.
This commit is contained in:
AnotherTest 2020-08-25 22:18:32 +04:30 committed by Andreas Kling
parent 521e730df1
commit 394e4c04cd
15 changed files with 72 additions and 113 deletions

View file

@ -31,7 +31,6 @@
#include <LibJS/Heap/Heap.h>
#include <LibJS/Heap/HeapBlock.h>
#include <LibJS/Interpreter.h>
#include <LibJS/Runtime/MarkedValueList.h>
#include <LibJS/Runtime/Object.h>
#include <setjmp.h>
#include <stdio.h>

View file

@ -245,7 +245,7 @@ void Interpreter::gather_roots(Badge<Heap>, HashTable<Cell*>& roots)
roots.set(symbol.value);
}
Value Interpreter::call(Function& function, Value this_value, Optional<MarkedValueList> arguments)
Value Interpreter::call_internal(Function& function, Value this_value, Optional<MarkedValueList> arguments)
{
ASSERT(!exception());

View file

@ -83,6 +83,21 @@ public:
return interpreter;
}
template<typename... Args>
[[nodiscard]] ALWAYS_INLINE Value call(Function& function, Value this_value, Args... args)
{
// Are there any values in this argpack?
// args = [] -> if constexpr (false)
// args = [x, y, z] -> if constexpr ((void)x, true || ...)
if constexpr ((((void)args, true) || ...)) {
MarkedValueList arglist { heap() };
(..., arglist.append(move(args)));
return call(function, this_value, move(arglist));
}
return call(function, this_value);
}
~Interpreter();
Value run(GlobalObject&, const Statement&, ArgumentVector = {}, ScopeType = ScopeType::Block);
@ -118,7 +133,6 @@ public:
void enter_scope(const ScopeNode&, ArgumentVector, ScopeType, GlobalObject&);
void exit_scope(const ScopeNode&);
[[nodiscard]] Value call(Function&, Value this_value, Optional<MarkedValueList> arguments = {});
Value construct(Function&, Function& new_target, Optional<MarkedValueList> arguments, GlobalObject&);
CallFrame& push_call_frame()
@ -215,6 +229,8 @@ public:
private:
Interpreter();
[[nodiscard]] Value call_internal(Function&, Value this_value, Optional<MarkedValueList>);
Heap m_heap;
Value m_last_value;
@ -241,4 +257,13 @@ private:
#undef __JS_ENUMERATE
};
template<>
[[nodiscard]] ALWAYS_INLINE Value Interpreter::call(Function& function, Value this_value, MarkedValueList arguments) { return call_internal(function, this_value, move(arguments)); }
template<>
[[nodiscard]] ALWAYS_INLINE Value Interpreter::call(Function& function, Value this_value, Optional<MarkedValueList> arguments) { return call_internal(function, this_value, move(arguments)); }
template<>
[[nodiscard]] ALWAYS_INLINE Value Interpreter::call(Function& function, Value this_value) { return call(function, this_value, Optional<MarkedValueList> {}); }
}

View file

@ -29,7 +29,6 @@
#include <LibJS/Interpreter.h>
#include <LibJS/Runtime/Function.h>
#include <LibJS/Runtime/MarkedValueList.h>
namespace JS {
@ -63,10 +62,8 @@ public:
{
if (!m_setter)
return;
MarkedValueList arguments(interpreter().heap());
arguments.append(setter_value);
// FIXME: It might be nice if we had a way to communicate to our caller if an exception happened after this.
(void)interpreter().call(*m_setter, this_value, move(arguments));
(void)interpreter().call(*m_setter, this_value, setter_value);
}
void visit_children(Cell::Visitor& visitor) override

View file

@ -35,7 +35,6 @@
#include <LibJS/Runtime/Error.h>
#include <LibJS/Runtime/Function.h>
#include <LibJS/Runtime/GlobalObject.h>
#include <LibJS/Runtime/MarkedValueList.h>
#include <LibJS/Runtime/ObjectPrototype.h>
#include <LibJS/Runtime/Value.h>
@ -136,12 +135,7 @@ static void for_each_item(Interpreter& interpreter, GlobalObject& global_object,
value = js_undefined();
}
MarkedValueList arguments(interpreter.heap());
arguments.append(value);
arguments.append(Value((i32)i));
arguments.append(this_object);
auto callback_result = interpreter.call(*callback_function, this_value, move(arguments));
auto callback_result = interpreter.call(*callback_function, this_value, value, Value((i32)i), this_object);
if (interpreter.exception())
return;
@ -494,13 +488,7 @@ JS_DEFINE_NATIVE_FUNCTION(ArrayPrototype::reduce)
if (value.is_empty())
continue;
MarkedValueList arguments(interpreter.heap());
arguments.append(accumulator);
arguments.append(value);
arguments.append(Value((i32)i));
arguments.append(this_object);
accumulator = interpreter.call(*callback_function, this_value, move(arguments));
accumulator = interpreter.call(*callback_function, this_value, accumulator, value, Value((i32)i), this_object);
if (interpreter.exception())
return {};
}
@ -553,13 +541,7 @@ JS_DEFINE_NATIVE_FUNCTION(ArrayPrototype::reduce_right)
if (value.is_empty())
continue;
MarkedValueList arguments(interpreter.heap());
arguments.append(accumulator);
arguments.append(value);
arguments.append(Value(i));
arguments.append(this_object);
accumulator = interpreter.call(*callback_function, this_value, move(arguments));
accumulator = interpreter.call(*callback_function, this_value, accumulator, value, Value((i32)i), this_object);
if (interpreter.exception())
return {};
}

View file

@ -72,13 +72,10 @@ Object* iterator_next(Object& iterator, Value value)
}
Value result;
if (value.is_empty()) {
if (value.is_empty())
result = interpreter.call(next_method.as_function(), &iterator);
} else {
MarkedValueList arguments(iterator.heap());
arguments.append(value);
result = interpreter.call(next_method.as_function(), &iterator, move(arguments));
}
else
result = interpreter.call(next_method.as_function(), &iterator, value);
if (interpreter.exception())
return {};

View file

@ -56,7 +56,8 @@ JSONObject::~JSONObject()
{
}
String JSONObject::stringify_impl(Interpreter& interpreter, GlobalObject& global_object, Value value, Value replacer, Value space) {
String JSONObject::stringify_impl(Interpreter& interpreter, GlobalObject& global_object, Value value, Value replacer, Value space)
{
StringifyState state;
@ -154,19 +155,14 @@ String JSONObject::serialize_json_property(Interpreter& interpreter, StringifySt
if (interpreter.exception())
return {};
if (to_json.is_function()) {
MarkedValueList arguments(interpreter.heap());
arguments.append(js_string(interpreter, key.to_string()));
value = interpreter.call(to_json.as_function(), value, move(arguments));
value = interpreter.call(to_json.as_function(), value, js_string(interpreter, key.to_string()));
if (interpreter.exception())
return {};
}
}
if (state.replacer_function) {
MarkedValueList arguments(interpreter.heap());
arguments.append(js_string(interpreter, key.to_string()));
arguments.append(value);
value = interpreter.call(*state.replacer_function, holder, move(arguments));
value = interpreter.call(*state.replacer_function, holder, js_string(interpreter, key.to_string()), value);
if (interpreter.exception())
return {};
}
@ -494,10 +490,8 @@ Value JSONObject::internalize_json_property(Interpreter& interpreter, Object* ho
}
}
}
MarkedValueList arguments(interpreter.heap());
arguments.append(js_string(interpreter, name.to_string()));
arguments.append(value);
return interpreter.call(reviver, Value(holder), move(arguments));
return interpreter.call(reviver, Value(holder), js_string(interpreter, name.to_string()), value);
}
}

View file

@ -89,9 +89,8 @@ Object* ProxyObject::prototype()
interpreter().throw_exception<TypeError>(ErrorType::ProxyInvalidTrap, "getPrototypeOf");
return nullptr;
}
MarkedValueList arguments(interpreter().heap());
arguments.append(Value(&m_target));
auto trap_result = interpreter().call(trap.as_function(), Value(&m_handler), move(arguments));
auto trap_result = interpreter().call(trap.as_function(), Value(&m_handler), Value(&m_target));
if (interpreter().exception())
return nullptr;
if (!trap_result.is_object() && !trap_result.is_null()) {
@ -139,10 +138,8 @@ bool ProxyObject::set_prototype(Object* object)
interpreter().throw_exception<TypeError>(ErrorType::ProxyInvalidTrap, "setPrototypeOf");
return false;
}
MarkedValueList arguments(interpreter().heap());
arguments.append(Value(&m_target));
arguments.append(Value(object));
auto trap_result = interpreter().call(trap.as_function(), Value(&m_handler), move(arguments)).to_boolean();
auto trap_result = interpreter().call(trap.as_function(), Value(&m_handler), Value(&m_target), Value(object)).to_boolean();
if (interpreter().exception() || !trap_result)
return false;
if (m_target.is_extensible())
@ -172,9 +169,8 @@ bool ProxyObject::is_extensible() const
interpreter().throw_exception<TypeError>(ErrorType::ProxyInvalidTrap, "isExtensible");
return {};
}
MarkedValueList arguments(interpreter().heap());
arguments.append(Value(&m_target));
auto trap_result = interpreter().call(trap.as_function(), Value(&m_handler), move(arguments)).to_boolean();
auto trap_result = interpreter().call(trap.as_function(), Value(&m_handler), Value(&m_target)).to_boolean();
if (interpreter().exception())
return false;
if (trap_result != m_target.is_extensible()) {
@ -200,9 +196,8 @@ bool ProxyObject::prevent_extensions()
interpreter().throw_exception<TypeError>(ErrorType::ProxyInvalidTrap, "preventExtensions");
return {};
}
MarkedValueList arguments(interpreter().heap());
arguments.append(Value(&m_target));
auto trap_result = interpreter().call(trap.as_function(), Value(&m_handler), move(arguments)).to_boolean();
auto trap_result = interpreter().call(trap.as_function(), Value(&m_handler), Value(&m_target)).to_boolean();
if (interpreter().exception())
return false;
if (trap_result && m_target.is_extensible()) {
@ -228,10 +223,8 @@ Optional<PropertyDescriptor> ProxyObject::get_own_property_descriptor(const Prop
interpreter().throw_exception<TypeError>(ErrorType::ProxyInvalidTrap, "getOwnPropertyDescriptor");
return {};
}
MarkedValueList arguments(interpreter().heap());
arguments.append(Value(&m_target));
arguments.append(js_string(interpreter(), name.to_string()));
auto trap_result = interpreter().call(trap.as_function(), Value(&m_handler), move(arguments));
auto trap_result = interpreter().call(trap.as_function(), Value(&m_handler), Value(&m_target), js_string(interpreter(), name.to_string()));
if (interpreter().exception())
return {};
if (!trap_result.is_object() && !trap_result.is_undefined()) {
@ -285,11 +278,8 @@ bool ProxyObject::define_property(const StringOrSymbol& property_name, const Obj
interpreter().throw_exception<TypeError>(ErrorType::ProxyInvalidTrap, "defineProperty");
return false;
}
MarkedValueList arguments(interpreter().heap());
arguments.append(Value(&m_target));
arguments.append(property_name.to_value(interpreter()));
arguments.append(Value(const_cast<Object*>(&descriptor)));
auto trap_result = interpreter().call(trap.as_function(), Value(&m_handler), move(arguments)).to_boolean();
auto trap_result = interpreter().call(trap.as_function(), Value(&m_handler), Value(&m_target), property_name.to_value(interpreter()), Value(const_cast<Object*>(&descriptor))).to_boolean();
if (interpreter().exception() || !trap_result)
return false;
auto target_desc = m_target.get_own_property_descriptor(property_name);
@ -339,10 +329,8 @@ bool ProxyObject::has_property(const PropertyName& name) const
interpreter().throw_exception<TypeError>(ErrorType::ProxyInvalidTrap, "has");
return false;
}
MarkedValueList arguments(interpreter().heap());
arguments.append(Value(&m_target));
arguments.append(js_string(interpreter(), name.to_string()));
auto trap_result = interpreter().call(trap.as_function(), Value(&m_handler), move(arguments)).to_boolean();
auto trap_result = interpreter().call(trap.as_function(), Value(&m_handler), Value(&m_target), js_string(interpreter(), name.to_string())).to_boolean();
if (interpreter().exception())
return false;
if (!trap_result) {
@ -379,11 +367,8 @@ Value ProxyObject::get(const PropertyName& name, Value) const
interpreter().throw_exception<TypeError>(ErrorType::ProxyInvalidTrap, "get");
return {};
}
MarkedValueList arguments(interpreter().heap());
arguments.append(Value(&m_target));
arguments.append(js_string(interpreter(), name.to_string()));
arguments.append(Value(const_cast<ProxyObject*>(this)));
auto trap_result = interpreter().call(trap.as_function(), Value(&m_handler), move(arguments));
auto trap_result = interpreter().call(trap.as_function(), Value(&m_handler), Value(&m_target), js_string(interpreter(), name.to_string()), Value(const_cast<ProxyObject*>(this)));
if (interpreter().exception())
return {};
auto target_desc = m_target.get_own_property_descriptor(name);
@ -417,12 +402,7 @@ bool ProxyObject::put(const PropertyName& name, Value value, Value)
interpreter().throw_exception<TypeError>(ErrorType::ProxyInvalidTrap, "set");
return false;
}
MarkedValueList arguments(interpreter().heap());
arguments.append(Value(&m_target));
arguments.append(js_string(interpreter(), name.to_string()));
arguments.append(value);
arguments.append(Value(const_cast<ProxyObject*>(this)));
auto trap_result = interpreter().call(trap.as_function(), Value(&m_handler), move(arguments)).to_boolean();
auto trap_result = interpreter().call(trap.as_function(), Value(&m_handler), Value(&m_target), js_string(interpreter(), name.to_string()), value, Value(const_cast<ProxyObject*>(this))).to_boolean();
if (interpreter().exception() || !trap_result)
return false;
auto target_desc = m_target.get_own_property_descriptor(name);
@ -455,10 +435,8 @@ Value ProxyObject::delete_property(const PropertyName& name)
interpreter().throw_exception<TypeError>(ErrorType::ProxyInvalidTrap, "deleteProperty");
return {};
}
MarkedValueList arguments(interpreter().heap());
arguments.append(Value(&m_target));
arguments.append(js_string(interpreter(), name.to_string()));
auto trap_result = interpreter().call(trap.as_function(), Value(&m_handler), move(arguments)).to_boolean();
auto trap_result = interpreter().call(trap.as_function(), Value(&m_handler), Value(&m_target), js_string(interpreter(), name.to_string())).to_boolean();
if (interpreter().exception())
return {};
if (!trap_result)

View file

@ -708,9 +708,8 @@ Value instance_of(Interpreter& interpreter, Value lhs, Value rhs)
interpreter.throw_exception<TypeError>(ErrorType::NotAFunction, has_instance_method.to_string_without_side_effects().characters());
return {};
}
MarkedValueList arguments(interpreter.heap());
arguments.append(lhs);
return Value(interpreter.call(has_instance_method.as_function(), rhs, move(arguments)).to_boolean());
return Value(interpreter.call(has_instance_method.as_function(), rhs, lhs).to_boolean());
}
if (!rhs.is_function()) {