mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2025-04-22 04:25:13 +00:00
LibJS: Rework how native functions are called to improve |this| value
Native functions now only get the Interpreter& as an argument. They can then extract |this| along with any indexed arguments it wants from it. This forces functions that want |this| to actually deal with calling interpreter.this_value().to_object(), and dealing with the possibility of a non-object |this|. This is still not great but let's keep massaging it forward.
This commit is contained in:
parent
c209ea1985
commit
7c4e53f31e
Notes:
sideshowbarker
2024-07-19 08:05:16 +09:00
Author: https://github.com/awesomekling Commit: https://github.com/SerenityOS/serenity/commit/7c4e53f31e2
25 changed files with 145 additions and 102 deletions
|
@ -99,7 +99,7 @@ Value CallExpression::execute(Interpreter& interpreter) const
|
|||
}
|
||||
}
|
||||
|
||||
auto result = function->call(interpreter, call_frame.arguments);
|
||||
auto result = function->call(interpreter);
|
||||
interpreter.pop_call_frame();
|
||||
|
||||
if (is_new_expression()) {
|
||||
|
@ -554,10 +554,10 @@ Value AssignmentExpression::execute(Interpreter& interpreter) const
|
|||
};
|
||||
} else if (m_lhs->is_member_expression()) {
|
||||
commit = [&](Value value) {
|
||||
auto object = static_cast<const MemberExpression&>(*m_lhs).object().execute(interpreter).to_object(interpreter.heap());
|
||||
ASSERT(object.is_object());
|
||||
auto property_name = static_cast<const MemberExpression&>(*m_lhs).computed_property_name(interpreter);
|
||||
object.as_object()->put(property_name, value);
|
||||
if (auto* object = static_cast<const MemberExpression&>(*m_lhs).object().execute(interpreter).to_object(interpreter.heap())) {
|
||||
auto property_name = static_cast<const MemberExpression&>(*m_lhs).computed_property_name(interpreter);
|
||||
object->put(property_name, value);
|
||||
}
|
||||
};
|
||||
} else {
|
||||
ASSERT_NOT_REACHED();
|
||||
|
@ -751,11 +751,10 @@ FlyString MemberExpression::computed_property_name(Interpreter& interpreter) con
|
|||
|
||||
Value MemberExpression::execute(Interpreter& interpreter) const
|
||||
{
|
||||
auto object_result = m_object->execute(interpreter).to_object(interpreter.heap());
|
||||
auto* object_result = m_object->execute(interpreter).to_object(interpreter.heap());
|
||||
if (interpreter.exception())
|
||||
return {};
|
||||
ASSERT(object_result.is_object());
|
||||
auto result = object_result.as_object()->get(computed_property_name(interpreter));
|
||||
auto result = object_result->get(computed_property_name(interpreter));
|
||||
return result.value_or({});
|
||||
}
|
||||
|
||||
|
|
|
@ -190,7 +190,7 @@ Value Interpreter::call(Function* function, Value this_value, const Vector<Value
|
|||
auto& call_frame = push_call_frame();
|
||||
call_frame.this_value = this_value;
|
||||
call_frame.arguments = arguments;
|
||||
auto result = function->call(*this, call_frame.arguments);
|
||||
auto result = function->call(*this);
|
||||
pop_call_frame();
|
||||
return result;
|
||||
}
|
||||
|
|
|
@ -96,6 +96,8 @@ public:
|
|||
return m_call_stack.last();
|
||||
}
|
||||
void pop_call_frame() { m_call_stack.take_last(); }
|
||||
const CallFrame& call_frame() { return m_call_stack.last(); }
|
||||
|
||||
Value this_value() const
|
||||
{
|
||||
if (m_call_stack.is_empty())
|
||||
|
|
|
@ -35,24 +35,30 @@ namespace JS {
|
|||
|
||||
ArrayPrototype::ArrayPrototype()
|
||||
{
|
||||
put_native_function("shift", [](Object* this_object, const Vector<Value>&) -> Value {
|
||||
ASSERT(this_object);
|
||||
put_native_function("shift", [](Interpreter& interpreter) -> Value {
|
||||
auto* this_object = interpreter.this_value().to_object(interpreter.heap());
|
||||
if (!this_object)
|
||||
return {};
|
||||
ASSERT(this_object->is_array());
|
||||
return static_cast<Array*>(this_object)->shift();
|
||||
});
|
||||
|
||||
put_native_function("pop", [](Object* this_object, const Vector<Value>&) -> Value {
|
||||
ASSERT(this_object);
|
||||
put_native_function("pop", [](Interpreter& interpreter) -> Value {
|
||||
auto* this_object = interpreter.this_value().to_object(interpreter.heap());
|
||||
if (!this_object)
|
||||
return {};
|
||||
ASSERT(this_object->is_array());
|
||||
return static_cast<Array*>(this_object)->pop();
|
||||
});
|
||||
|
||||
put_native_function("push", [](Object* this_object, const Vector<Value>& arguments) -> Value {
|
||||
if (arguments.is_empty())
|
||||
return js_undefined();
|
||||
ASSERT(this_object);
|
||||
put_native_function("push", [](Interpreter& interpreter) -> Value {
|
||||
auto* this_object = interpreter.this_value().to_object(interpreter.heap());
|
||||
if (!this_object)
|
||||
return {};
|
||||
ASSERT(this_object->is_array());
|
||||
static_cast<Array*>(this_object)->push(arguments[0]);
|
||||
if (interpreter.call_frame().arguments.is_empty())
|
||||
return js_undefined();
|
||||
static_cast<Array*>(this_object)->push(interpreter.call_frame().arguments[0]);
|
||||
return Value(static_cast<const Array*>(this_object)->length());
|
||||
});
|
||||
}
|
||||
|
|
|
@ -24,8 +24,9 @@
|
|||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <AK/Function.h>
|
||||
#include <AK/FlyString.h>
|
||||
#include <AK/Function.h>
|
||||
#include <LibJS/Interpreter.h>
|
||||
#include <LibJS/Runtime/ConsoleObject.h>
|
||||
#include <stdio.h>
|
||||
|
||||
|
@ -33,10 +34,10 @@ namespace JS {
|
|||
|
||||
ConsoleObject::ConsoleObject()
|
||||
{
|
||||
put_native_function("log", [](Object*, const Vector<Value>& arguments) -> Value {
|
||||
for (size_t i = 0; i < arguments.size(); ++i) {
|
||||
printf("%s", arguments[i].to_string().characters());
|
||||
if (i != arguments.size() - 1)
|
||||
put_native_function("log", [](Interpreter& interpreter) -> Value {
|
||||
for (size_t i = 0; i < interpreter.call_frame().arguments.size(); ++i) {
|
||||
printf("%s", interpreter.call_frame().arguments[i].to_string().characters());
|
||||
if (i != interpreter.call_frame().arguments.size() - 1)
|
||||
putchar(' ');
|
||||
}
|
||||
putchar('\n');
|
||||
|
|
|
@ -35,7 +35,7 @@ class Function : public Object {
|
|||
public:
|
||||
virtual ~Function();
|
||||
|
||||
virtual Value call(Interpreter&, const Vector<Value>&) = 0;
|
||||
virtual Value call(Interpreter&) = 0;
|
||||
|
||||
protected:
|
||||
Function();
|
||||
|
|
|
@ -14,15 +14,15 @@ namespace JS {
|
|||
GlobalObject::GlobalObject()
|
||||
{
|
||||
put("console", heap().allocate<ConsoleObject>());
|
||||
put_native_function("gc", [](Object* this_object, Vector<Value>) -> Value {
|
||||
put_native_function("gc", [](Interpreter& interpreter) -> Value {
|
||||
dbg() << "Forced garbage collection requested!";
|
||||
this_object->heap().collect_garbage();
|
||||
interpreter.heap().collect_garbage();
|
||||
return js_undefined();
|
||||
});
|
||||
put_native_function("isNaN", [](Object*, Vector<Value> arguments) -> Value {
|
||||
if (arguments.size() < 1)
|
||||
put_native_function("isNaN", [](Interpreter& interpreter) -> Value {
|
||||
if (interpreter.call_frame().arguments.size() < 1)
|
||||
return js_undefined();
|
||||
return Value(arguments[0].to_number().is_nan());
|
||||
return Value(interpreter.call_frame().arguments[0].to_number().is_nan());
|
||||
});
|
||||
put("Math", heap().allocate<MathObject>());
|
||||
put("Object", heap().allocate<ObjectConstructor>());
|
||||
|
|
|
@ -32,7 +32,7 @@ namespace JS {
|
|||
|
||||
MathObject::MathObject()
|
||||
{
|
||||
put_native_function("random", [](Object*, const Vector<Value>&) {
|
||||
put_native_function("random", [](Interpreter&) {
|
||||
#ifdef __serenity__
|
||||
double r = (double)arc4random() / (double)UINT32_MAX;
|
||||
#else
|
||||
|
|
|
@ -30,7 +30,7 @@
|
|||
|
||||
namespace JS {
|
||||
|
||||
NativeFunction::NativeFunction(AK::Function<Value(Object*, const Vector<Value>&)> native_function)
|
||||
NativeFunction::NativeFunction(AK::Function<Value(Interpreter&)> native_function)
|
||||
: m_native_function(move(native_function))
|
||||
{
|
||||
}
|
||||
|
@ -39,14 +39,9 @@ NativeFunction::~NativeFunction()
|
|||
{
|
||||
}
|
||||
|
||||
Value NativeFunction::call(Interpreter& interpreter, const Vector<Value>& arguments)
|
||||
Value NativeFunction::call(Interpreter& interpreter)
|
||||
{
|
||||
auto this_value = interpreter.this_value();
|
||||
// FIXME: Why are we here with a non-object 'this'?
|
||||
Object* this_object = nullptr;
|
||||
if (this_value.is_object())
|
||||
this_object = this_value.as_object();
|
||||
return m_native_function(this_object, arguments);
|
||||
return m_native_function(interpreter);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -33,10 +33,10 @@ namespace JS {
|
|||
|
||||
class NativeFunction : public Function {
|
||||
public:
|
||||
explicit NativeFunction(AK::Function<Value(Object*, const Vector<Value>&)>);
|
||||
explicit NativeFunction(AK::Function<Value(Interpreter&)>);
|
||||
virtual ~NativeFunction() override;
|
||||
|
||||
virtual Value call(Interpreter&, const Vector<Value>&) override;
|
||||
virtual Value call(Interpreter&) override;
|
||||
|
||||
protected:
|
||||
NativeFunction() {}
|
||||
|
@ -45,7 +45,7 @@ private:
|
|||
virtual bool is_native_function() const override { return true; }
|
||||
virtual const char* class_name() const override { return "NativeFunction"; }
|
||||
|
||||
AK::Function<Value(Object*, const Vector<Value>&)> m_native_function;
|
||||
AK::Function<Value(Interpreter&)> m_native_function;
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -102,7 +102,7 @@ void Object::put(const FlyString& property_name, Value value)
|
|||
put_own_property(*this, property_name, value);
|
||||
}
|
||||
|
||||
void Object::put_native_function(const FlyString& property_name, AK::Function<Value(Object*, Vector<Value>)> native_function)
|
||||
void Object::put_native_function(const FlyString& property_name, AK::Function<Value(Interpreter&)> native_function)
|
||||
{
|
||||
put(property_name, heap().allocate<NativeFunction>(move(native_function)));
|
||||
}
|
||||
|
|
|
@ -46,7 +46,7 @@ public:
|
|||
virtual Optional<Value> get_own_property(const Object& this_object, const FlyString& property_name) const;
|
||||
virtual bool put_own_property(Object& this_object, const FlyString& property_name, Value);
|
||||
|
||||
void put_native_function(const FlyString& property_name, AK::Function<Value(Object*, Vector<Value>)>);
|
||||
void put_native_function(const FlyString& property_name, AK::Function<Value(Interpreter&)>);
|
||||
void put_native_property(const FlyString& property_name, AK::Function<Value(Object*)> getter, AK::Function<void(Object*, Value)> setter);
|
||||
|
||||
virtual bool is_error() const { return false; }
|
||||
|
|
|
@ -35,39 +35,40 @@ ObjectConstructor::ObjectConstructor()
|
|||
{
|
||||
put("prototype", interpreter().object_prototype());
|
||||
|
||||
put_native_function("getPrototypeOf", [this](Object*, const Vector<Value>& arguments) -> Value {
|
||||
if (arguments.size() < 1)
|
||||
return {};
|
||||
auto object = arguments[0].to_object(heap());
|
||||
if (interpreter().exception())
|
||||
return {};
|
||||
if (!object.is_object())
|
||||
return {};
|
||||
return object.as_object()->prototype();
|
||||
});
|
||||
|
||||
put_native_function("setPrototypeOf", [this](Object*, const Vector<Value>& arguments) -> Value {
|
||||
if (arguments.size() < 2)
|
||||
return {};
|
||||
auto object = arguments[0].to_object(heap());
|
||||
if (interpreter().exception())
|
||||
return {};
|
||||
if (!object.is_object())
|
||||
return {};
|
||||
if (!arguments[1].is_object())
|
||||
return {};
|
||||
const_cast<Object*>(object.as_object())->set_prototype(const_cast<Object*>(arguments[1].as_object()));
|
||||
return {};
|
||||
});
|
||||
put_native_function("getPrototypeOf", get_prototype_of);
|
||||
put_native_function("setPrototypeOf", set_prototype_of);
|
||||
}
|
||||
|
||||
ObjectConstructor::~ObjectConstructor()
|
||||
{
|
||||
}
|
||||
|
||||
Value ObjectConstructor::call(Interpreter& interpreter, const Vector<Value>&)
|
||||
Value ObjectConstructor::call(Interpreter& interpreter)
|
||||
{
|
||||
return interpreter.heap().allocate<Object>();
|
||||
}
|
||||
|
||||
Value ObjectConstructor::get_prototype_of(Interpreter& interpreter)
|
||||
{
|
||||
if (interpreter.call_frame().arguments.size() < 1)
|
||||
return {};
|
||||
auto* object = interpreter.call_frame().arguments[0].to_object(interpreter.heap());
|
||||
if (interpreter.exception())
|
||||
return {};
|
||||
return object->prototype();
|
||||
}
|
||||
|
||||
Value ObjectConstructor::set_prototype_of(Interpreter& interpreter)
|
||||
{
|
||||
if (interpreter.call_frame().arguments.size() < 2)
|
||||
return {};
|
||||
if (!interpreter.call_frame().arguments[1].is_object())
|
||||
return {};
|
||||
auto* object = interpreter.call_frame().arguments[0].to_object(interpreter.heap());
|
||||
if (interpreter.exception())
|
||||
return {};
|
||||
object->set_prototype(const_cast<Object*>(interpreter.call_frame().arguments[1].as_object()));
|
||||
return {};
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -35,10 +35,13 @@ public:
|
|||
ObjectConstructor();
|
||||
virtual ~ObjectConstructor() override;
|
||||
|
||||
virtual Value call(Interpreter&, const Vector<Value>&) override;
|
||||
virtual Value call(Interpreter&) override;
|
||||
|
||||
private:
|
||||
virtual const char* class_name() const override { return "ObjectConstructor"; }
|
||||
|
||||
static Value get_prototype_of(Interpreter&);
|
||||
static Value set_prototype_of(Interpreter&);
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -37,21 +37,26 @@ ObjectPrototype::ObjectPrototype()
|
|||
{
|
||||
set_prototype(nullptr);
|
||||
|
||||
put_native_function("hasOwnProperty", [](Object* this_object, const Vector<Value>& arguments) -> Value {
|
||||
ASSERT(this_object);
|
||||
if (arguments.is_empty())
|
||||
put_native_function("hasOwnProperty", [](Interpreter& interpreter) -> Value {
|
||||
auto* this_object = interpreter.this_value().to_object(interpreter.heap());
|
||||
if (!this_object)
|
||||
return {};
|
||||
if (interpreter.call_frame().arguments.is_empty())
|
||||
return js_undefined();
|
||||
return Value(this_object->has_own_property(arguments[0].to_string()));
|
||||
return Value(this_object->has_own_property(interpreter.call_frame().arguments[0].to_string()));
|
||||
});
|
||||
|
||||
put_native_function("toString", [](Object* this_object, Vector<Value>) -> Value {
|
||||
ASSERT(this_object);
|
||||
|
||||
put_native_function("toString", [](Interpreter& interpreter) -> Value {
|
||||
auto* this_object = interpreter.this_value().to_object(interpreter.heap());
|
||||
if (!this_object)
|
||||
return {};
|
||||
return Value(this_object->to_string());
|
||||
});
|
||||
|
||||
put_native_function("valueOf", [](Object* this_object, Vector<Value>) -> Value {
|
||||
ASSERT(this_object);
|
||||
put_native_function("valueOf", [](Interpreter& interpreter) -> Value {
|
||||
auto* this_object = interpreter.this_value().to_object(interpreter.heap());
|
||||
if (!this_object)
|
||||
return {};
|
||||
return this_object->value_of();
|
||||
});
|
||||
}
|
||||
|
|
|
@ -41,8 +41,9 @@ ScriptFunction::~ScriptFunction()
|
|||
{
|
||||
}
|
||||
|
||||
Value ScriptFunction::call(Interpreter& interpreter, const Vector<Value>& argument_values)
|
||||
Value ScriptFunction::call(Interpreter& interpreter)
|
||||
{
|
||||
auto& argument_values = interpreter.call_frame().arguments;
|
||||
Vector<Argument> arguments;
|
||||
for (size_t i = 0; i < m_parameters.size(); ++i) {
|
||||
auto name = parameters()[i];
|
||||
|
|
|
@ -38,7 +38,7 @@ public:
|
|||
const ScopeNode& body() const { return m_body; }
|
||||
const Vector<FlyString>& parameters() const { return m_parameters; };
|
||||
|
||||
virtual Value call(Interpreter&, const Vector<Value>&) override;
|
||||
virtual Value call(Interpreter&) override;
|
||||
|
||||
private:
|
||||
virtual bool is_script_function() const final { return true; }
|
||||
|
|
|
@ -44,23 +44,28 @@ StringPrototype::StringPrototype()
|
|||
return Value((i32) static_cast<const StringObject*>(this_object)->primitive_string()->string().length());
|
||||
},
|
||||
nullptr);
|
||||
put_native_function("charAt", [](Object* this_object, const Vector<Value>& arguments) -> Value {
|
||||
ASSERT(this_object);
|
||||
put_native_function("charAt", [](Interpreter& interpreter) -> Value {
|
||||
auto* this_object = interpreter.this_value().to_object(interpreter.heap());
|
||||
if (!this_object)
|
||||
return {};
|
||||
i32 index = 0;
|
||||
if (!arguments.is_empty())
|
||||
index = arguments[0].to_i32();
|
||||
if (!interpreter.call_frame().arguments.is_empty())
|
||||
index = interpreter.call_frame().arguments[0].to_i32();
|
||||
ASSERT(this_object->is_string_object());
|
||||
auto underlying_string = static_cast<const StringObject*>(this_object)->primitive_string()->string();
|
||||
if (index < 0 || index >= static_cast<i32>(underlying_string.length()))
|
||||
return js_string(this_object->heap(), String::empty());
|
||||
return js_string(this_object->heap(), underlying_string.substring(index, 1));
|
||||
});
|
||||
put_native_function("repeat", [](Object* this_object, const Vector<Value>& arguments) -> Value {
|
||||
put_native_function("repeat", [](Interpreter& interpreter) -> Value {
|
||||
auto* this_object = interpreter.this_value().to_object(interpreter.heap());
|
||||
if (!this_object)
|
||||
return {};
|
||||
ASSERT(this_object->is_string_object());
|
||||
if (arguments.is_empty())
|
||||
if (interpreter.call_frame().arguments.is_empty())
|
||||
return js_string(this_object->heap(), String::empty());
|
||||
i32 count = 0;
|
||||
count = arguments[0].to_i32();
|
||||
count = interpreter.call_frame().arguments[0].to_i32();
|
||||
if (count < 0) {
|
||||
// FIXME: throw RangeError
|
||||
return js_undefined();
|
||||
|
|
|
@ -27,6 +27,8 @@
|
|||
#include <AK/FlyString.h>
|
||||
#include <AK/String.h>
|
||||
#include <LibJS/Heap/Heap.h>
|
||||
#include <LibJS/Interpreter.h>
|
||||
#include <LibJS/Runtime/Error.h>
|
||||
#include <LibJS/Runtime/Object.h>
|
||||
#include <LibJS/Runtime/PrimitiveString.h>
|
||||
#include <LibJS/Runtime/StringObject.h>
|
||||
|
@ -86,7 +88,7 @@ bool Value::to_boolean() const
|
|||
}
|
||||
}
|
||||
|
||||
Value Value::to_object(Heap& heap) const
|
||||
Object* Value::to_object(Heap& heap) const
|
||||
{
|
||||
if (is_object())
|
||||
return const_cast<Object*>(as_object());
|
||||
|
@ -94,6 +96,11 @@ Value Value::to_object(Heap& heap) const
|
|||
if (is_string())
|
||||
return heap.allocate<StringObject>(m_value.as_string);
|
||||
|
||||
if (is_null() || is_undefined()) {
|
||||
heap.interpreter().throw_exception<Error>("TypeError", "ToObject on null or undefined.");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
ASSERT_NOT_REACHED();
|
||||
}
|
||||
|
||||
|
|
|
@ -144,7 +144,7 @@ public:
|
|||
Value to_number() const;
|
||||
i32 to_i32() const;
|
||||
|
||||
Value to_object(Heap&) const;
|
||||
Object* to_object(Heap&) const;
|
||||
|
||||
private:
|
||||
Type m_type { Type::Undefined };
|
||||
|
|
|
@ -24,8 +24,9 @@
|
|||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <AK/Function.h>
|
||||
#include <AK/FlyString.h>
|
||||
#include <AK/Function.h>
|
||||
#include <LibJS/Interpreter.h>
|
||||
#include <LibJS/Runtime/PrimitiveString.h>
|
||||
#include <LibJS/Runtime/Value.h>
|
||||
#include <LibWeb/Bindings/CanvasRenderingContext2DWrapper.h>
|
||||
|
@ -50,7 +51,8 @@ CanvasRenderingContext2DWrapper::CanvasRenderingContext2DWrapper(CanvasRendering
|
|||
[this](JS::Object*, JS::Value value) {
|
||||
m_impl->set_fill_style(value.to_string());
|
||||
});
|
||||
put_native_function("fillRect", [this](JS::Object*, const Vector<JS::Value>& arguments) {
|
||||
put_native_function("fillRect", [this](JS::Interpreter& interpreter) {
|
||||
auto& arguments = interpreter.call_frame().arguments;
|
||||
if (arguments.size() >= 4) {
|
||||
m_impl->fill_rect(arguments[0].to_i32(), arguments[1].to_i32(), arguments[2].to_i32(), arguments[3].to_i32());
|
||||
}
|
||||
|
|
|
@ -25,6 +25,7 @@
|
|||
*/
|
||||
|
||||
#include <AK/FlyString.h>
|
||||
#include <LibJS/Interpreter.h>
|
||||
#include <LibJS/Runtime/PrimitiveString.h>
|
||||
#include <LibJS/Runtime/Value.h>
|
||||
#include <LibWeb/Bindings/DocumentWrapper.h>
|
||||
|
@ -37,7 +38,8 @@ namespace Bindings {
|
|||
DocumentWrapper::DocumentWrapper(Document& document)
|
||||
: NodeWrapper(document)
|
||||
{
|
||||
put_native_function("getElementById", [this](JS::Object*, const Vector<JS::Value>& arguments) -> JS::Value {
|
||||
put_native_function("getElementById", [this](JS::Interpreter& interpreter) -> JS::Value {
|
||||
auto& arguments = interpreter.call_frame().arguments;
|
||||
if (arguments.is_empty())
|
||||
return JS::js_null();
|
||||
auto id = arguments[0].to_string();
|
||||
|
|
|
@ -24,8 +24,9 @@
|
|||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <AK/Function.h>
|
||||
#include <AK/FlyString.h>
|
||||
#include <AK/Function.h>
|
||||
#include <LibJS/Interpreter.h>
|
||||
#include <LibJS/Runtime/Function.h>
|
||||
#include <LibWeb/Bindings/EventListenerWrapper.h>
|
||||
#include <LibWeb/Bindings/EventTargetWrapper.h>
|
||||
|
@ -38,7 +39,12 @@ namespace Bindings {
|
|||
EventTargetWrapper::EventTargetWrapper(EventTarget& impl)
|
||||
: m_impl(impl)
|
||||
{
|
||||
put_native_function("addEventListener", [](Object* this_object, const Vector<JS::Value>& arguments) {
|
||||
put_native_function("addEventListener", [](JS::Interpreter& interpreter) -> JS::Value {
|
||||
auto* this_object = interpreter.this_value().to_object(interpreter.heap());
|
||||
if (!this_object)
|
||||
return {};
|
||||
|
||||
auto& arguments = interpreter.call_frame().arguments;
|
||||
if (arguments.size() < 2)
|
||||
return JS::js_undefined();
|
||||
|
||||
|
|
|
@ -24,8 +24,9 @@
|
|||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <AK/Function.h>
|
||||
#include <AK/FlyString.h>
|
||||
#include <AK/Function.h>
|
||||
#include <LibJS/Interpreter.h>
|
||||
#include <LibJS/Runtime/PrimitiveString.h>
|
||||
#include <LibJS/Runtime/Value.h>
|
||||
#include <LibWeb/Bindings/CanvasRenderingContext2DWrapper.h>
|
||||
|
@ -39,7 +40,8 @@ namespace Bindings {
|
|||
HTMLCanvasElementWrapper::HTMLCanvasElementWrapper(HTMLCanvasElement& element)
|
||||
: ElementWrapper(element)
|
||||
{
|
||||
put_native_function("getContext", [this](JS::Object*, const Vector<JS::Value>& arguments) -> JS::Value {
|
||||
put_native_function("getContext", [this](JS::Interpreter& interpreter) -> JS::Value {
|
||||
auto& arguments = interpreter.call_frame().arguments;
|
||||
if (arguments.size() >= 1) {
|
||||
auto* context = node().get_context(arguments[0].to_string());
|
||||
return wrap(heap(), *context);
|
||||
|
|
|
@ -338,14 +338,16 @@ JS::Interpreter& Document::interpreter()
|
|||
if (!m_interpreter) {
|
||||
m_interpreter = make<JS::Interpreter>();
|
||||
|
||||
m_interpreter->global_object().put_native_function("alert", [](JS::Object*, const Vector<JS::Value>& arguments) -> JS::Value {
|
||||
m_interpreter->global_object().put_native_function("alert", [](JS::Interpreter& interpreter) -> JS::Value {
|
||||
auto& arguments = interpreter.call_frame().arguments;
|
||||
if (arguments.size() < 1)
|
||||
return JS::js_undefined();
|
||||
GUI::MessageBox::show(arguments[0].to_string(), "Alert", GUI::MessageBox::Type::Information);
|
||||
return JS::js_undefined();
|
||||
});
|
||||
|
||||
m_interpreter->global_object().put_native_function("setInterval", [this](JS::Object*, const Vector<JS::Value>& arguments) -> JS::Value {
|
||||
m_interpreter->global_object().put_native_function("setInterval", [this](JS::Interpreter& interpreter) -> JS::Value {
|
||||
auto& arguments = interpreter.call_frame().arguments;
|
||||
if (arguments.size() < 2)
|
||||
return JS::js_undefined();
|
||||
ASSERT(arguments[0].is_object());
|
||||
|
@ -355,14 +357,16 @@ JS::Interpreter& Document::interpreter()
|
|||
// FIXME: This timer should not be leaked! It should also be removable with clearInterval()!
|
||||
(void)Core::Timer::construct(
|
||||
arguments[1].to_i32(), [this, callback] {
|
||||
const_cast<JS::Function*>(static_cast<const JS::Function*>(callback.cell()))->call(*m_interpreter, {});
|
||||
// FIXME: Perform the call through Interpreter so it can set up a call frame!
|
||||
const_cast<JS::Function*>(static_cast<const JS::Function*>(callback.cell()))->call(*m_interpreter);
|
||||
})
|
||||
.leak_ref();
|
||||
|
||||
return JS::js_undefined();
|
||||
});
|
||||
|
||||
m_interpreter->global_object().put_native_function("requestAnimationFrame", [this](JS::Object*, const Vector<JS::Value>& arguments) -> JS::Value {
|
||||
m_interpreter->global_object().put_native_function("requestAnimationFrame", [this](JS::Interpreter& interpreter) -> JS::Value {
|
||||
auto& arguments = interpreter.call_frame().arguments;
|
||||
if (arguments.size() < 1)
|
||||
return JS::js_undefined();
|
||||
ASSERT(arguments[0].is_object());
|
||||
|
@ -370,13 +374,15 @@ JS::Interpreter& Document::interpreter()
|
|||
auto callback = make_handle(const_cast<JS::Object*>(arguments[0].as_object()));
|
||||
// FIXME: Don't hand out raw DisplayLink ID's to JavaScript!
|
||||
i32 link_id = GUI::DisplayLink::register_callback([this, callback](i32 link_id) {
|
||||
const_cast<JS::Function*>(static_cast<const JS::Function*>(callback.cell()))->call(*m_interpreter, {});
|
||||
// FIXME: Perform the call through Interpreter so it can set up a call frame!
|
||||
const_cast<JS::Function*>(static_cast<const JS::Function*>(callback.cell()))->call(*m_interpreter);
|
||||
GUI::DisplayLink::unregister_callback(link_id);
|
||||
});
|
||||
return JS::Value(link_id);
|
||||
});
|
||||
|
||||
m_interpreter->global_object().put_native_function("cancelAnimationFrame", [](JS::Object*, const Vector<JS::Value>& arguments) -> JS::Value {
|
||||
m_interpreter->global_object().put_native_function("cancelAnimationFrame", [](JS::Interpreter& interpreter) -> JS::Value {
|
||||
auto& arguments = interpreter.call_frame().arguments;
|
||||
if (arguments.size() < 1)
|
||||
return JS::js_undefined();
|
||||
// FIXME: We should not be passing untrusted numbers to DisplayLink::unregistered_callback()!
|
||||
|
|
Loading…
Add table
Reference in a new issue