summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Libraries/LibJS/AST.cpp28
-rw-r--r--Libraries/LibJS/Runtime/Accessor.h31
-rw-r--r--Libraries/LibJS/Runtime/Object.cpp29
3 files changed, 49 insertions, 39 deletions
diff --git a/Libraries/LibJS/AST.cpp b/Libraries/LibJS/AST.cpp
index 780af06b80..2053c9d314 100644
--- a/Libraries/LibJS/AST.cpp
+++ b/Libraries/LibJS/AST.cpp
@@ -1175,20 +1175,22 @@ Value ObjectExpression::execute(Interpreter& interpreter) const
update_function_name(value, name);
if (property.type() == ObjectProperty::Type::Getter || property.type() == ObjectProperty::Type::Setter) {
- Value getter;
- Value setter;
- auto existing_property_metadata = object->shape().lookup(key);
- Value existing_property;
- if (existing_property_metadata.has_value())
- existing_property = object->get_direct(existing_property_metadata.value().offset);
- if (property.type() == ObjectProperty::Type::Getter) {
- getter = value;
- setter = existing_property.is_accessor() ? existing_property.as_accessor().setter() : Value();
- } else {
- getter = existing_property.is_accessor() ? existing_property.as_accessor().getter() : Value();
- setter = value;
+ ASSERT(value.is_function());
+ Accessor* accessor { nullptr };
+ auto property_metadata = object->shape().lookup(key);
+ if (property_metadata.has_value()) {
+ auto existing_property = object->get_direct(property_metadata.value().offset);
+ if (existing_property.is_accessor())
+ accessor = &existing_property.as_accessor();
+ }
+ if (!accessor) {
+ accessor = Accessor::create(interpreter, nullptr, nullptr);
+ object->put_own_property(*object, key, Attribute::Configurable | Attribute::Enumerable, accessor, Object::PutOwnPropertyMode::DefineProperty);
}
- object->put_own_property(*object, key, Attribute::Configurable | Attribute::Enumerable, Accessor::create(interpreter, getter, setter), Object::PutOwnPropertyMode::DefineProperty);
+ if (property.type() == ObjectProperty::Type::Getter)
+ accessor->set_getter(&value.as_function());
+ else
+ accessor->set_setter(&value.as_function());
} else {
object->put(key, value);
}
diff --git a/Libraries/LibJS/Runtime/Accessor.h b/Libraries/LibJS/Runtime/Accessor.h
index ad00ad7155..9f7fd9451a 100644
--- a/Libraries/LibJS/Runtime/Accessor.h
+++ b/Libraries/LibJS/Runtime/Accessor.h
@@ -1,5 +1,6 @@
/*
* Copyright (c) 2020, Matthew Olsson <matthewcolsson@gmail.com>
+ * Copyright (c) 2020, Linus Groh <mail@linusgroh.de>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -26,41 +27,43 @@
#pragma once
-#include <LibJS/Runtime/Cell.h>
-#include <LibJS/Runtime/Value.h>
+#include <LibJS/Runtime/Function.h>
namespace JS {
class Accessor final : public Cell {
public:
- static Accessor* create(Interpreter& interpreter, Value getter, Value setter)
+ static Accessor* create(Interpreter& interpreter, Function* getter, Function* setter)
{
return interpreter.heap().allocate<Accessor>(getter, setter);
}
- Accessor(Value getter, Value setter)
+ Accessor(Function* getter, Function* setter)
: m_getter(getter)
, m_setter(setter)
{
}
- Value getter() { return m_getter; }
- Value setter() { return m_setter; }
+ Function* getter() const { return m_getter; }
+ void set_getter(Function* getter) { m_getter = getter; }
- Value call_getter(Value this_object)
+ Function* setter() const { return m_setter; }
+ void set_setter(Function* setter) { m_setter = setter; }
+
+ Value call_getter(Value this_value)
{
- if (!getter().is_function())
+ if (!m_getter)
return js_undefined();
- return interpreter().call(getter().as_function(), this_object);
+ return interpreter().call(*m_getter, this_value);
}
- void call_setter(Value this_object, Value setter_value)
+ void call_setter(Value this_value, Value setter_value)
{
- if (!setter().is_function())
+ if (!m_setter)
return;
MarkedValueList arguments(interpreter().heap());
arguments.values().append(setter_value);
- interpreter().call(setter().as_function(), this_object, move(arguments));
+ interpreter().call(*m_setter, this_value, move(arguments));
}
void visit_children(Cell::Visitor& visitor) override
@@ -72,8 +75,8 @@ public:
private:
const char* class_name() const override { return "Accessor"; };
- Value m_getter;
- Value m_setter;
+ Function* m_getter { nullptr };
+ Function* m_setter { nullptr };
};
}
diff --git a/Libraries/LibJS/Runtime/Object.cpp b/Libraries/LibJS/Runtime/Object.cpp
index b5e49ae7cb..daffc88a15 100644
--- a/Libraries/LibJS/Runtime/Object.cpp
+++ b/Libraries/LibJS/Runtime/Object.cpp
@@ -221,30 +221,35 @@ bool Object::define_property(const FlyString& property_name, const Object& descr
return false;
}
- auto getter = descriptor.get("get");
+ auto getter = descriptor.get("get").value_or(js_undefined());
if (interpreter().exception())
return {};
- auto setter = descriptor.get("set");
+ auto setter = descriptor.get("set").value_or(js_undefined());
if (interpreter().exception())
return {};
- if (!(getter.is_empty() || getter.is_undefined() || getter.is_function())) {
+ Function* getter_function { nullptr };
+ Function* setter_function { nullptr };
+
+ if (getter.is_function()) {
+ getter_function = &getter.as_function();
+ } else if (!getter.is_undefined()) {
interpreter().throw_exception<TypeError>("Accessor descriptor's 'get' field must be a function or undefined");
return false;
}
- if (!(setter.is_empty() || setter.is_undefined() || setter.is_function())) {
+ if (setter.is_function()) {
+ setter_function = &setter.as_function();
+ } else if (!setter.is_undefined()) {
interpreter().throw_exception<TypeError>("Accessor descriptor's 'set' field must be a function or undefined");
return false;
}
- // FIXME: Throw a TypeError if the setter does not take any arguments
-
- dbg() << "Defining new property " << property_name << " with accessor descriptor { attributes=" << attributes
- << " , getter=" << (getter.is_empty() ? "<empty>" : getter.to_string_without_side_effects())
- << ", setter=" << (setter.is_empty() ? "<empty>" : setter.to_string_without_side_effects()) << "}";
+ dbg() << "Defining new property " << property_name << " with accessor descriptor { attributes=" << attributes << ", "
+ << "getter=" << getter.to_string_without_side_effects() << ", "
+ << "setter=" << setter.to_string_without_side_effects() << "}";
- return put_own_property(*this, property_name, attributes, Accessor::create(interpreter(), getter, setter), PutOwnPropertyMode::DefineProperty, throw_exceptions);
+ return put_own_property(*this, property_name, attributes, Accessor::create(interpreter(), getter_function, setter_function), PutOwnPropertyMode::DefineProperty, throw_exceptions);
}
auto value = descriptor.get("value");
@@ -267,9 +272,9 @@ bool Object::put_own_property(Object& this_object, const FlyString& property_nam
if (value.is_accessor()) {
auto& accessor = value.as_accessor();
- if (accessor.getter().is_function())
+ if (accessor.getter())
attributes |= Attribute::HasGet;
- if (accessor.setter().is_function())
+ if (accessor.setter())
attributes |= Attribute::HasSet;
}