From 23ec578a016d5d8b4e55553924d3d37d899854c8 Mon Sep 17 00:00:00 2001 From: mattco98 Date: Mon, 27 Apr 2020 23:05:02 -0700 Subject: [PATCH] LibJS: Implement correct attributes for (almost) all properties Added the ability to include a u8 attributes parameter with all of the various put methods in the Object class. They can be omitted, in which case it defaults to "Writable | Enumerable | Configurable", just like before this commit. All of the attribute values for each property were gathered from SpiderMonkey in the Firefox console. Some properties (e.g. all of the canvas element properties) have undefined property descriptors... not quite sure what that means. Those were left as the default specified above. --- Libraries/LibJS/Runtime/ArrayConstructor.cpp | 4 +- Libraries/LibJS/Runtime/ArrayPrototype.cpp | 38 ++++++++-------- .../LibJS/Runtime/BooleanConstructor.cpp | 4 +- Libraries/LibJS/Runtime/BooleanPrototype.cpp | 4 +- Libraries/LibJS/Runtime/BoundFunction.cpp | 2 +- Libraries/LibJS/Runtime/DateConstructor.cpp | 6 +-- Libraries/LibJS/Runtime/DatePrototype.cpp | 25 +++++------ Libraries/LibJS/Runtime/ErrorConstructor.cpp | 8 ++-- Libraries/LibJS/Runtime/ErrorPrototype.cpp | 7 +-- .../LibJS/Runtime/FunctionConstructor.cpp | 4 +- Libraries/LibJS/Runtime/FunctionPrototype.cpp | 11 ++--- Libraries/LibJS/Runtime/GlobalObject.cpp | 22 +++++----- Libraries/LibJS/Runtime/MathObject.cpp | 43 ++++++++++--------- Libraries/LibJS/Runtime/NumberConstructor.cpp | 25 +++++------ Libraries/LibJS/Runtime/Object.cpp | 35 ++++++++------- Libraries/LibJS/Runtime/Object.h | 13 +++--- Libraries/LibJS/Runtime/ObjectConstructor.cpp | 15 ++++--- Libraries/LibJS/Runtime/ObjectPrototype.cpp | 7 +-- Libraries/LibJS/Runtime/ScriptFunction.cpp | 4 +- Libraries/LibJS/Runtime/StringConstructor.cpp | 4 +- Libraries/LibJS/Runtime/StringPrototype.cpp | 34 ++++++++------- Libraries/LibJS/Runtime/Uint8ClampedArray.cpp | 3 +- Libraries/LibJS/Runtime/Uint8ClampedArray.h | 2 +- Libraries/LibWeb/Bindings/WindowObject.cpp | 11 ++--- .../Bindings/XMLHttpRequestConstructor.cpp | 13 +++--- .../Bindings/XMLHttpRequestPrototype.cpp | 14 +++--- 26 files changed, 189 insertions(+), 169 deletions(-) diff --git a/Libraries/LibJS/Runtime/ArrayConstructor.cpp b/Libraries/LibJS/Runtime/ArrayConstructor.cpp index 0c9d2ea12f..65da8387c6 100644 --- a/Libraries/LibJS/Runtime/ArrayConstructor.cpp +++ b/Libraries/LibJS/Runtime/ArrayConstructor.cpp @@ -37,8 +37,8 @@ namespace JS { ArrayConstructor::ArrayConstructor() : NativeFunction("Array", *interpreter().global_object().function_prototype()) { - put("prototype", interpreter().global_object().array_prototype()); - put("length", Value(1)); + put("prototype", interpreter().global_object().array_prototype(), 0); + put("length", Value(1), Attribute::Configurable); } ArrayConstructor::~ArrayConstructor() diff --git a/Libraries/LibJS/Runtime/ArrayPrototype.cpp b/Libraries/LibJS/Runtime/ArrayPrototype.cpp index f208973621..b3ac9b7928 100644 --- a/Libraries/LibJS/Runtime/ArrayPrototype.cpp +++ b/Libraries/LibJS/Runtime/ArrayPrototype.cpp @@ -42,24 +42,26 @@ namespace JS { ArrayPrototype::ArrayPrototype() : Object(interpreter().global_object().object_prototype()) { - put_native_function("filter", filter, 1); - put_native_function("forEach", for_each, 1); - put_native_function("map", map, 1); - put_native_function("pop", pop, 0); - put_native_function("push", push, 1); - put_native_function("shift", shift, 0); - put_native_function("toString", to_string, 0); - put_native_function("unshift", unshift, 1); - put_native_function("join", join, 1); - put_native_function("concat", concat, 1); - put_native_function("slice", slice, 2); - put_native_function("indexOf", index_of, 1); - put_native_function("reverse", reverse, 0); - put_native_function("lastIndexOf", last_index_of, 1); - put_native_function("includes", includes, 1); - put_native_function("find", find, 1); - put_native_function("findIndex", find_index, 1); - put("length", Value(0)); + u8 attr = Attribute::Writable | Attribute::Configurable; + + put_native_function("filter", filter, 1, attr); + put_native_function("forEach", for_each, 1, attr); + put_native_function("map", map, 1, attr); + put_native_function("pop", pop, 0, attr); + put_native_function("push", push, 1, attr); + put_native_function("shift", shift, 0, attr); + put_native_function("toString", to_string, 0, attr); + put_native_function("unshift", unshift, 1, attr); + put_native_function("join", join, 1, attr); + put_native_function("concat", concat, 1, attr); + put_native_function("slice", slice, 2, attr); + put_native_function("indexOf", index_of, 1, attr); + put_native_function("reverse", reverse, 0, attr); + put_native_function("lastIndexOf", last_index_of, 1, attr); + put_native_function("includes", includes, 1, attr); + put_native_function("find", find, 1, attr); + put_native_function("findIndex", find_index, 1, attr); + put("length", Value(0), Attribute::Configurable); } ArrayPrototype::~ArrayPrototype() diff --git a/Libraries/LibJS/Runtime/BooleanConstructor.cpp b/Libraries/LibJS/Runtime/BooleanConstructor.cpp index b1522a698c..96a66a2f0b 100644 --- a/Libraries/LibJS/Runtime/BooleanConstructor.cpp +++ b/Libraries/LibJS/Runtime/BooleanConstructor.cpp @@ -36,8 +36,8 @@ namespace JS { BooleanConstructor::BooleanConstructor() : NativeFunction("Boolean", *interpreter().global_object().function_prototype()) { - put("prototype", Value(interpreter().global_object().boolean_prototype())); - put("length", Value(1)); + put("prototype", Value(interpreter().global_object().boolean_prototype()), 0); + put("length", Value(1), Attribute::Configurable); } BooleanConstructor::~BooleanConstructor() diff --git a/Libraries/LibJS/Runtime/BooleanPrototype.cpp b/Libraries/LibJS/Runtime/BooleanPrototype.cpp index 5bd458ae46..19cfba7440 100644 --- a/Libraries/LibJS/Runtime/BooleanPrototype.cpp +++ b/Libraries/LibJS/Runtime/BooleanPrototype.cpp @@ -35,8 +35,8 @@ namespace JS { BooleanPrototype::BooleanPrototype() : BooleanObject(false, *interpreter().global_object().object_prototype()) { - put_native_function("toString", to_string); - put_native_function("valueOf", value_of); + put_native_function("toString", to_string, 0, Attribute::Writable | Attribute::Configurable); + put_native_function("valueOf", value_of, 0, Attribute::Writable | Attribute::Configurable); } BooleanPrototype::~BooleanPrototype() {} diff --git a/Libraries/LibJS/Runtime/BoundFunction.cpp b/Libraries/LibJS/Runtime/BoundFunction.cpp index 6ecc286cf6..4aa82f2c2b 100644 --- a/Libraries/LibJS/Runtime/BoundFunction.cpp +++ b/Libraries/LibJS/Runtime/BoundFunction.cpp @@ -36,7 +36,7 @@ BoundFunction::BoundFunction(Function& target_function, Value bound_this, Vector , m_constructor_prototype(constructor_prototype) , m_name(String::format("bound %s", target_function.name().characters())) { - put("length", Value(length)); + put("length", Value(length), Attribute::Configurable); } BoundFunction::~BoundFunction() diff --git a/Libraries/LibJS/Runtime/DateConstructor.cpp b/Libraries/LibJS/Runtime/DateConstructor.cpp index d2f09ff9f3..a9f573e6be 100644 --- a/Libraries/LibJS/Runtime/DateConstructor.cpp +++ b/Libraries/LibJS/Runtime/DateConstructor.cpp @@ -37,10 +37,10 @@ namespace JS { DateConstructor::DateConstructor() : NativeFunction("Date", *interpreter().global_object().function_prototype()) { - put("prototype", interpreter().global_object().date_prototype()); - put("length", Value(7)); + put("prototype", interpreter().global_object().date_prototype(), 0); + put("length", Value(7), Attribute::Configurable); - put_native_function("now", now); + put_native_function("now", now, 0, Attribute::Writable | Attribute::Configurable); } DateConstructor::~DateConstructor() diff --git a/Libraries/LibJS/Runtime/DatePrototype.cpp b/Libraries/LibJS/Runtime/DatePrototype.cpp index 899232ba78..dc115c5a19 100644 --- a/Libraries/LibJS/Runtime/DatePrototype.cpp +++ b/Libraries/LibJS/Runtime/DatePrototype.cpp @@ -51,18 +51,19 @@ static Date* this_date_from_interpreter(Interpreter& interpreter) DatePrototype::DatePrototype() : Object(interpreter().global_object().object_prototype()) { - put_native_function("getDate", get_date); - put_native_function("getDay", get_day); - put_native_function("getFullYear", get_full_year); - put_native_function("getHours", get_hours); - put_native_function("getMilliseconds", get_milliseconds); - put_native_function("getMinutes", get_minutes); - put_native_function("getMonth", get_month); - put_native_function("getSeconds", get_seconds); - put_native_function("getTime", get_time); - put_native_function("toDateString", to_date_string); - put_native_function("toTimeString", to_time_string); - put_native_function("toString", to_string); + u8 attr = Attribute::Writable | Attribute::Configurable; + put_native_function("getDate", get_date, 0, attr); + put_native_function("getDay", get_day, 0, attr); + put_native_function("getFullYear", get_full_year, 0, attr); + put_native_function("getHours", get_hours, 0, attr); + put_native_function("getMilliseconds", get_milliseconds, 0, attr); + put_native_function("getMinutes", get_minutes, 0, attr); + put_native_function("getMonth", get_month, 0, attr); + put_native_function("getSeconds", get_seconds, 0, attr); + put_native_function("getTime", get_time, 0, attr); + put_native_function("toDateString", to_date_string, 0, attr); + put_native_function("toTimeString", to_time_string, 0, attr); + put_native_function("toString", to_string, 0, attr); } DatePrototype::~DatePrototype() diff --git a/Libraries/LibJS/Runtime/ErrorConstructor.cpp b/Libraries/LibJS/Runtime/ErrorConstructor.cpp index 480a069cfb..8a5a3e9d44 100644 --- a/Libraries/LibJS/Runtime/ErrorConstructor.cpp +++ b/Libraries/LibJS/Runtime/ErrorConstructor.cpp @@ -34,8 +34,8 @@ namespace JS { ErrorConstructor::ErrorConstructor() : NativeFunction("Error", *interpreter().global_object().function_prototype()) { - put("prototype", interpreter().global_object().error_prototype()); - put("length", Value(1)); + put("prototype", interpreter().global_object().error_prototype(), 0); + put("length", Value(1), Attribute::Configurable); } ErrorConstructor::~ErrorConstructor() @@ -59,8 +59,8 @@ Value ErrorConstructor::construct(Interpreter& interpreter) ConstructorName::ConstructorName() \ : NativeFunction(*interpreter().global_object().function_prototype()) \ { \ - put("prototype", interpreter().global_object().snake_name##_prototype()); \ - put("length", Value(1)); \ + put("prototype", interpreter().global_object().snake_name##_prototype(), 0); \ + put("length", Value(1), Attribute::Configurable); \ } \ ConstructorName::~ConstructorName() {} \ Value ConstructorName::call(Interpreter& interpreter) \ diff --git a/Libraries/LibJS/Runtime/ErrorPrototype.cpp b/Libraries/LibJS/Runtime/ErrorPrototype.cpp index 22ea084ab6..10246270f9 100644 --- a/Libraries/LibJS/Runtime/ErrorPrototype.cpp +++ b/Libraries/LibJS/Runtime/ErrorPrototype.cpp @@ -38,9 +38,10 @@ namespace JS { ErrorPrototype::ErrorPrototype() : Object(interpreter().global_object().object_prototype()) { - put_native_property("name", name_getter, name_setter); - put_native_property("message", message_getter, nullptr); - put_native_function("toString", to_string); + u8 attr = Attribute::Writable | Attribute::Configurable; + put_native_property("name", name_getter, name_setter, attr); + put_native_property("message", message_getter, nullptr, attr); + put_native_function("toString", to_string, 0, attr); } ErrorPrototype::~ErrorPrototype() diff --git a/Libraries/LibJS/Runtime/FunctionConstructor.cpp b/Libraries/LibJS/Runtime/FunctionConstructor.cpp index 4dbfcbaed4..0ed6fd1185 100644 --- a/Libraries/LibJS/Runtime/FunctionConstructor.cpp +++ b/Libraries/LibJS/Runtime/FunctionConstructor.cpp @@ -38,8 +38,8 @@ namespace JS { FunctionConstructor::FunctionConstructor() : NativeFunction("Function", *interpreter().global_object().function_prototype()) { - put("prototype", interpreter().global_object().function_prototype()); - put("length", Value(1)); + put("prototype", interpreter().global_object().function_prototype(), 0); + put("length", Value(1), Attribute::Configurable); } FunctionConstructor::~FunctionConstructor() diff --git a/Libraries/LibJS/Runtime/FunctionPrototype.cpp b/Libraries/LibJS/Runtime/FunctionPrototype.cpp index 644bffa481..b7d6b114b7 100644 --- a/Libraries/LibJS/Runtime/FunctionPrototype.cpp +++ b/Libraries/LibJS/Runtime/FunctionPrototype.cpp @@ -45,11 +45,12 @@ FunctionPrototype::FunctionPrototype() void FunctionPrototype::initialize() { - put_native_function("apply", apply, 2); - put_native_function("bind", bind, 1); - put_native_function("call", call, 1); - put_native_function("toString", to_string); - put("length", Value(0)); + u8 attr = Attribute::Writable | Attribute::Configurable; + put_native_function("apply", apply, 2, attr); + put_native_function("bind", bind, 1, attr); + put_native_function("call", call, 1, attr); + put_native_function("toString", to_string, 0, attr); + put("length", Value(0), Attribute::Configurable); } FunctionPrototype::~FunctionPrototype() diff --git a/Libraries/LibJS/Runtime/GlobalObject.cpp b/Libraries/LibJS/Runtime/GlobalObject.cpp index 6e289b7f56..9ec245f475 100644 --- a/Libraries/LibJS/Runtime/GlobalObject.cpp +++ b/Libraries/LibJS/Runtime/GlobalObject.cpp @@ -61,7 +61,7 @@ void GlobalObject::add_constructor(const FlyString& property_name, ConstructorTy { constructor = heap().allocate(); prototype.put("constructor", constructor); - put(property_name, constructor); + put(property_name, constructor, Attribute::Writable | Attribute::Configurable); } GlobalObject::GlobalObject() @@ -85,18 +85,18 @@ void GlobalObject::initialize() JS_ENUMERATE_BUILTIN_TYPES #undef __JS_ENUMERATE - put_native_function("gc", gc); - put_native_function("isNaN", is_nan, 1); - put_native_function("isFinite", is_finite, 1); + u8 attr = Attribute::Writable | Attribute::Configurable; + put_native_function("gc", gc, 0, attr); + put_native_function("isNaN", is_nan, 1, attr); + put_native_function("isFinite", is_finite, 1, attr); - // FIXME: These are read-only in ES5 - put("NaN", js_nan()); - put("Infinity", js_infinity()); - put("undefined", js_undefined()); + put("NaN", js_nan(), 0); + put("Infinity", js_infinity(), 0); + put("undefined", js_undefined(), 0); - put("globalThis", this); - put("console", heap().allocate()); - put("Math", heap().allocate()); + put("globalThis", this, attr); + put("console", heap().allocate(), attr); + put("Math", heap().allocate(), attr); add_constructor("Array", m_array_constructor, *m_array_prototype); add_constructor("Boolean", m_boolean_constructor, *m_boolean_prototype); diff --git a/Libraries/LibJS/Runtime/MathObject.cpp b/Libraries/LibJS/Runtime/MathObject.cpp index 21287bd17d..b538591a44 100644 --- a/Libraries/LibJS/Runtime/MathObject.cpp +++ b/Libraries/LibJS/Runtime/MathObject.cpp @@ -36,28 +36,29 @@ namespace JS { MathObject::MathObject() : Object(interpreter().global_object().object_prototype()) { - put_native_function("abs", abs, 1); - put_native_function("random", random); - put_native_function("sqrt", sqrt, 1); - put_native_function("floor", floor, 1); - put_native_function("ceil", ceil, 1); - put_native_function("round", round, 1); - put_native_function("max", max, 2); - put_native_function("min", min, 2); - put_native_function("trunc", trunc, 1); - put_native_function("sin", sin, 1); - put_native_function("cos", cos, 1); - put_native_function("tan", tan, 1); - put_native_function("pow", pow, 2); + u8 attr = Attribute::Writable | Attribute::Configurable; + put_native_function("abs", abs, 1, attr); + put_native_function("random", random, 0, attr); + put_native_function("sqrt", sqrt, 1, attr); + put_native_function("floor", floor, 1, attr); + put_native_function("ceil", ceil, 1, attr); + put_native_function("round", round, 1, attr); + put_native_function("max", max, 2, attr); + put_native_function("min", min, 2, attr); + put_native_function("trunc", trunc, 1, attr); + put_native_function("sin", sin, 1, attr); + put_native_function("cos", cos, 1, attr); + put_native_function("tan", tan, 1, attr); + put_native_function("pow", pow, 2, attr); - put("E", Value(M_E)); - put("LN2", Value(M_LN2)); - put("LN10", Value(M_LN10)); - put("LOG2E", Value(log2(M_E))); - put("LOG10E", Value(log10(M_E))); - put("PI", Value(M_PI)); - put("SQRT1_2", Value(::sqrt(1.0 / 2.0))); - put("SQRT2", Value(::sqrt(2))); + put("E", Value(M_E), 0); + put("LN2", Value(M_LN2), 0); + put("LN10", Value(M_LN10), 0); + put("LOG2E", Value(log2(M_E)), 0); + put("LOG10E", Value(log10(M_E)), 0); + put("PI", Value(M_PI), 0); + put("SQRT1_2", Value(::sqrt(1.0 / 2.0)), 0); + put("SQRT2", Value(::sqrt(2)), 0); } MathObject::~MathObject() diff --git a/Libraries/LibJS/Runtime/NumberConstructor.cpp b/Libraries/LibJS/Runtime/NumberConstructor.cpp index fc24b85838..4996de3f72 100644 --- a/Libraries/LibJS/Runtime/NumberConstructor.cpp +++ b/Libraries/LibJS/Runtime/NumberConstructor.cpp @@ -40,19 +40,20 @@ namespace JS { NumberConstructor::NumberConstructor() : NativeFunction("Number", *interpreter().global_object().function_prototype()) { - put_native_function("isFinite", is_finite, 1); - put_native_function("isInteger", is_integer, 1); - put_native_function("isNaN", is_nan, 1); - put_native_function("isSafeInteger", is_safe_integer, 1); + u8 attr = Attribute::Writable | Attribute::Configurable; + put_native_function("isFinite", is_finite, 1, attr); + put_native_function("isInteger", is_integer, 1, attr); + put_native_function("isNaN", is_nan, 1, attr); + put_native_function("isSafeInteger", is_safe_integer, 1, attr); - put("prototype", interpreter().global_object().number_prototype()); - put("length", Value(1)); - put("EPSILON", Value(EPSILON)); - put("MAX_SAFE_INTEGER", Value(MAX_SAFE_INTEGER)); - put("MIN_SAFE_INTEGER", Value(MIN_SAFE_INTEGER)); - put("NEGATIVE_INFINITY", js_negative_infinity()); - put("POSITIVE_INFINITY", js_infinity()); - put("NaN", js_nan()); + put("prototype", interpreter().global_object().number_prototype(), 0); + put("length", Value(1), Attribute::Configurable); + put("EPSILON", Value(EPSILON), 0); + put("MAX_SAFE_INTEGER", Value(MAX_SAFE_INTEGER), 0); + put("MIN_SAFE_INTEGER", Value(MIN_SAFE_INTEGER), 0); + put("NEGATIVE_INFINITY", js_negative_infinity(), 0); + put("POSITIVE_INFINITY", js_infinity(), 0); + put("NaN", js_nan(), 0); } NumberConstructor::~NumberConstructor() diff --git a/Libraries/LibJS/Runtime/Object.cpp b/Libraries/LibJS/Runtime/Object.cpp index e5a358eb3d..1be11f70f2 100644 --- a/Libraries/LibJS/Runtime/Object.cpp +++ b/Libraries/LibJS/Runtime/Object.cpp @@ -116,7 +116,9 @@ void Object::set_shape(Shape& new_shape) void Object::put_own_property(Object& this_object, const FlyString& property_name, u8 attributes, Value value, PutOwnPropertyMode mode) { auto metadata = shape().lookup(property_name); - if (!metadata.has_value()) { + bool new_property = !metadata.has_value(); + + if (new_property) { if (m_shape->is_unique()) { m_shape->add_property_to_unique_shape(property_name, attributes); m_storage.resize(m_shape->property_count()); @@ -127,7 +129,7 @@ void Object::put_own_property(Object& this_object, const FlyString& property_nam ASSERT(metadata.has_value()); } - if (mode == PutOwnPropertyMode::DefineProperty && !(metadata.value().attributes & Attribute::Configurable) && attributes != metadata.value().attributes) { + if (!new_property && mode == PutOwnPropertyMode::DefineProperty && !(metadata.value().attributes & Attribute::Configurable) && attributes != metadata.value().attributes) { dbg() << "Disallow reconfig of non-configurable property"; interpreter().throw_exception(String::format("Cannot redefine property '%s'", property_name.characters())); return; @@ -144,7 +146,7 @@ void Object::put_own_property(Object& this_object, const FlyString& property_nam dbg() << "Reconfigured property " << property_name << ", new shape says offset is " << metadata.value().offset << " and my storage capacity is " << m_storage.size(); } - if (mode == PutOwnPropertyMode::Put && !(metadata.value().attributes & Attribute::Writable)) { + if (!new_property && mode == PutOwnPropertyMode::Put && !(metadata.value().attributes & Attribute::Writable)) { dbg() << "Disallow write to non-writable property"; return; } @@ -240,24 +242,25 @@ Value Object::get(PropertyName property_name) const return get(property_name.as_string()); } -void Object::put_by_index(i32 property_index, Value value) +void Object::put_by_index(i32 property_index, Value value, u8 attributes) { ASSERT(!value.is_empty()); if (property_index < 0) - return put(String::number(property_index), value); + return put(String::number(property_index), value, attributes); // FIXME: Implement some kind of sparse storage for arrays with huge indices. + // Also: Take attributes into account here if (static_cast(property_index) >= m_elements.size()) m_elements.resize(property_index + 1); m_elements[property_index] = value; } -void Object::put(const FlyString& property_name, Value value) +void Object::put(const FlyString& property_name, Value value, u8 attributes) { ASSERT(!value.is_empty()); bool ok; i32 property_index = property_name.to_int(ok); if (ok && property_index >= 0) - return put_by_index(property_index, value); + return put_by_index(property_index, value, attributes); // If there's a setter in the prototype chain, we go to the setter. // Otherwise, it goes in the own property storage. @@ -278,26 +281,26 @@ void Object::put(const FlyString& property_name, Value value) } object = object->prototype(); } - put_own_property(*this, property_name, Attribute::Configurable | Attribute::Enumerable | Attribute::Writable, value, PutOwnPropertyMode::Put); + put_own_property(*this, property_name, attributes, value, PutOwnPropertyMode::Put); } -void Object::put(PropertyName property_name, Value value) +void Object::put(PropertyName property_name, Value value, u8 attributes) { if (property_name.is_number()) - return put_by_index(property_name.as_number(), value); - return put(property_name.as_string(), value); + return put_by_index(property_name.as_number(), value, attributes); + return put(property_name.as_string(), value, attributes); } -void Object::put_native_function(const FlyString& property_name, AK::Function native_function, i32 length) +void Object::put_native_function(const FlyString& property_name, AK::Function native_function, i32 length, u8 attributes) { auto* function = NativeFunction::create(interpreter(), interpreter().global_object(), property_name, move(native_function)); - function->put("length", Value(length)); - put(property_name, function); + function->put("length", Value(length), Attribute::Configurable); + put(property_name, function, attributes); } -void Object::put_native_property(const FlyString& property_name, AK::Function getter, AK::Function setter) +void Object::put_native_property(const FlyString& property_name, AK::Function getter, AK::Function setter, u8 attributes) { - put(property_name, heap().allocate(move(getter), move(setter))); + put(property_name, heap().allocate(move(getter), move(setter)), attributes); } void Object::visit_children(Cell::Visitor& visitor) diff --git a/Libraries/LibJS/Runtime/Object.h b/Libraries/LibJS/Runtime/Object.h index 5c945ea888..fa812c102e 100644 --- a/Libraries/LibJS/Runtime/Object.h +++ b/Libraries/LibJS/Runtime/Object.h @@ -32,10 +32,13 @@ #include #include #include +#include #include namespace JS { +const u8 default_attributes = Attribute::Configurable | Attribute::Writable | Attribute::Enumerable; + class Object : public Cell { public: static Object* create_empty(Interpreter&, GlobalObject&); @@ -52,9 +55,9 @@ public: Value get(const FlyString& property_name) const; Value get(PropertyName) const; - virtual void put_by_index(i32 property_index, Value); - void put(const FlyString& property_name, Value); - void put(PropertyName, Value); + virtual void put_by_index(i32 property_index, Value, u8 attributes = default_attributes); + void put(const FlyString& property_name, Value, u8 attributes = default_attributes); + void put(PropertyName, Value, u8 attributes = default_attributes); Value get_own_property(const Object& this_object, const FlyString& property_name) const; @@ -65,8 +68,8 @@ public: void put_own_property(Object& this_object, const FlyString& property_name, u8 attributes, Value, PutOwnPropertyMode); - void put_native_function(const FlyString& property_name, AK::Function, i32 length = 0); - void put_native_property(const FlyString& property_name, AK::Function getter, AK::Function setter); + void put_native_function(const FlyString& property_name, AK::Function, i32 length = 0, u8 attribute = default_attributes); + void put_native_property(const FlyString& property_name, AK::Function getter, AK::Function setter, u8 attribute = default_attributes); virtual bool is_array() const { return false; } virtual bool is_boolean() const { return false; } diff --git a/Libraries/LibJS/Runtime/ObjectConstructor.cpp b/Libraries/LibJS/Runtime/ObjectConstructor.cpp index 1fcbe4e8e2..e7738ecfeb 100644 --- a/Libraries/LibJS/Runtime/ObjectConstructor.cpp +++ b/Libraries/LibJS/Runtime/ObjectConstructor.cpp @@ -38,14 +38,15 @@ namespace JS { ObjectConstructor::ObjectConstructor() : NativeFunction("Object", *interpreter().global_object().function_prototype()) { - put("prototype", interpreter().global_object().object_prototype()); + put("prototype", interpreter().global_object().object_prototype(), 0); - put_native_function("defineProperty", define_property, 3); - put_native_function("is", is, 2); - put_native_function("getOwnPropertyDescriptor", get_own_property_descriptor, 2); - put_native_function("getOwnPropertyNames", get_own_property_names, 1); - put_native_function("getPrototypeOf", get_prototype_of, 1); - put_native_function("setPrototypeOf", set_prototype_of, 2); + u8 attr = Attribute::Writable | Attribute::Configurable; + put_native_function("defineProperty", define_property, 3, attr); + put_native_function("is", is, 2, attr); + put_native_function("getOwnPropertyDescriptor", get_own_property_descriptor, 2, attr); + put_native_function("getOwnPropertyNames", get_own_property_names, 1, attr); + put_native_function("getPrototypeOf", get_prototype_of, 1, attr); + put_native_function("setPrototypeOf", set_prototype_of, 2, attr); } ObjectConstructor::~ObjectConstructor() diff --git a/Libraries/LibJS/Runtime/ObjectPrototype.cpp b/Libraries/LibJS/Runtime/ObjectPrototype.cpp index 56f064be37..53a3c4f518 100644 --- a/Libraries/LibJS/Runtime/ObjectPrototype.cpp +++ b/Libraries/LibJS/Runtime/ObjectPrototype.cpp @@ -42,9 +42,10 @@ void ObjectPrototype::initialize() { // This must be called after the constructor has returned, so that the below code // can find the ObjectPrototype through normal paths. - put_native_function("hasOwnProperty", has_own_property, 1); - put_native_function("toString", to_string); - put_native_function("valueOf", value_of); + u8 attr = Attribute::Writable | Attribute::Configurable; + put_native_function("hasOwnProperty", has_own_property, 1, attr); + put_native_function("toString", to_string, 0, attr); + put_native_function("valueOf", value_of, 0, attr); } ObjectPrototype::~ObjectPrototype() diff --git a/Libraries/LibJS/Runtime/ScriptFunction.cpp b/Libraries/LibJS/Runtime/ScriptFunction.cpp index 3086951a3a..38a1096c17 100644 --- a/Libraries/LibJS/Runtime/ScriptFunction.cpp +++ b/Libraries/LibJS/Runtime/ScriptFunction.cpp @@ -46,8 +46,8 @@ ScriptFunction::ScriptFunction(const FlyString& name, const Statement& body, Vec , m_parameters(move(parameters)) , m_parent_environment(parent_environment) { - put("prototype", Object::create_empty(interpreter(), interpreter().global_object())); - put_native_property("length", length_getter, length_setter); + put("prototype", Object::create_empty(interpreter(), interpreter().global_object()), 0); + put_native_property("length", length_getter, length_setter, Attribute::Configurable); } ScriptFunction::~ScriptFunction() diff --git a/Libraries/LibJS/Runtime/StringConstructor.cpp b/Libraries/LibJS/Runtime/StringConstructor.cpp index 0858ceef2d..0be1df0b24 100644 --- a/Libraries/LibJS/Runtime/StringConstructor.cpp +++ b/Libraries/LibJS/Runtime/StringConstructor.cpp @@ -36,8 +36,8 @@ namespace JS { StringConstructor::StringConstructor() : NativeFunction("String", *interpreter().global_object().function_prototype()) { - put("prototype", interpreter().global_object().string_prototype()); - put("length", Value(1)); + put("prototype", interpreter().global_object().string_prototype(), 0); + put("length", Value(1), Attribute::Configurable); } StringConstructor::~StringConstructor() diff --git a/Libraries/LibJS/Runtime/StringPrototype.cpp b/Libraries/LibJS/Runtime/StringPrototype.cpp index a798cda9dc..b62edcbe4a 100644 --- a/Libraries/LibJS/Runtime/StringPrototype.cpp +++ b/Libraries/LibJS/Runtime/StringPrototype.cpp @@ -41,23 +41,25 @@ namespace JS { StringPrototype::StringPrototype() : StringObject(*js_string(interpreter(), String::empty()), *interpreter().global_object().object_prototype()) { - put_native_property("length", length_getter, nullptr); - put_native_function("charAt", char_at, 1); - put_native_function("repeat", repeat, 1); - put_native_function("startsWith", starts_with, 1); - put_native_function("indexOf", index_of, 1); - put_native_function("toLowerCase", to_lowercase, 0); - put_native_function("toUpperCase", to_uppercase, 0); - put_native_function("toString", to_string, 0); - put_native_function("padStart", pad_start, 1); - put_native_function("padEnd", pad_end, 1); + u8 attr = Attribute::Writable | Attribute::Configurable; - put_native_function("trim", trim, 0); - put_native_function("trimStart", trim_start, 0); - put_native_function("trimEnd", trim_end, 0); - put_native_function("concat", concat, 1); - put_native_function("substring", substring, 2); - put_native_function("includes", includes, 1); + put_native_property("length", length_getter, nullptr, 0); + put_native_function("charAt", char_at, 1, attr); + put_native_function("repeat", repeat, 1, attr); + put_native_function("startsWith", starts_with, 1, attr); + put_native_function("indexOf", index_of, 1, attr); + put_native_function("toLowerCase", to_lowercase, 0, attr); + put_native_function("toUpperCase", to_uppercase, 0, attr); + put_native_function("toString", to_string, 0, attr); + put_native_function("padStart", pad_start, 1, attr); + put_native_function("padEnd", pad_end, 1, attr); + + put_native_function("trim", trim, 0, attr); + put_native_function("trimStart", trim_start, 0, attr); + put_native_function("trimEnd", trim_end, 0, attr); + put_native_function("concat", concat, 1, attr); + put_native_function("substring", substring, 2, attr); + put_native_function("includes", includes, 1, attr); } StringPrototype::~StringPrototype() diff --git a/Libraries/LibJS/Runtime/Uint8ClampedArray.cpp b/Libraries/LibJS/Runtime/Uint8ClampedArray.cpp index b04b236be2..57f4baa598 100644 --- a/Libraries/LibJS/Runtime/Uint8ClampedArray.cpp +++ b/Libraries/LibJS/Runtime/Uint8ClampedArray.cpp @@ -65,8 +65,9 @@ Value Uint8ClampedArray::length_getter(Interpreter& interpreter) return Value(static_cast(this_object)->length()); } -void Uint8ClampedArray::put_by_index(i32 property_index, Value value) +void Uint8ClampedArray::put_by_index(i32 property_index, Value value, u8) { + // FIXME: Use attributes ASSERT(property_index >= 0); ASSERT(property_index < m_length); m_data[property_index] = clamp(value.to_i32(), 0, 255); diff --git a/Libraries/LibJS/Runtime/Uint8ClampedArray.h b/Libraries/LibJS/Runtime/Uint8ClampedArray.h index 411d0018ba..0e66f897b1 100644 --- a/Libraries/LibJS/Runtime/Uint8ClampedArray.h +++ b/Libraries/LibJS/Runtime/Uint8ClampedArray.h @@ -39,7 +39,7 @@ public: i32 length() const { return m_length; } - virtual void put_by_index(i32 property_index, Value value) override; + virtual void put_by_index(i32 property_index, Value value, u8 attribute = default_attributes) override; virtual Value get_by_index(i32 property_index) const override; u8* data() { return m_data; } diff --git a/Libraries/LibWeb/Bindings/WindowObject.cpp b/Libraries/LibWeb/Bindings/WindowObject.cpp index 66867d4ed9..0e00bb6861 100644 --- a/Libraries/LibWeb/Bindings/WindowObject.cpp +++ b/Libraries/LibWeb/Bindings/WindowObject.cpp @@ -29,6 +29,7 @@ #include #include #include +#include #include #include #include @@ -49,8 +50,8 @@ void WindowObject::initialize() { GlobalObject::initialize(); - put("window", this); - put_native_property("document", document_getter, document_setter); + put("window", this, JS::Attribute::Enumerable); + put_native_property("document", document_getter, document_setter, JS::Attribute::Enumerable); put_native_function("alert", alert); put_native_function("confirm", confirm); put_native_function("setInterval", set_interval, 1); @@ -58,12 +59,12 @@ void WindowObject::initialize() put_native_function("requestAnimationFrame", request_animation_frame, 1); put_native_function("cancelAnimationFrame", cancel_animation_frame, 1); - put("navigator", heap().allocate()); + put("navigator", heap().allocate(), JS::Attribute::Enumerable | JS::Attribute::Configurable); m_xhr_prototype = heap().allocate(); m_xhr_constructor = heap().allocate(); - m_xhr_constructor->put("prototype", m_xhr_prototype); - put("XMLHttpRequest", m_xhr_constructor); + m_xhr_constructor->put("prototype", m_xhr_prototype, 0); + put("XMLHttpRequest", m_xhr_constructor, JS::Attribute::Writable | JS::Attribute::Configurable); } WindowObject::~WindowObject() diff --git a/Libraries/LibWeb/Bindings/XMLHttpRequestConstructor.cpp b/Libraries/LibWeb/Bindings/XMLHttpRequestConstructor.cpp index 7fea4c1cc1..2a2acb829c 100644 --- a/Libraries/LibWeb/Bindings/XMLHttpRequestConstructor.cpp +++ b/Libraries/LibWeb/Bindings/XMLHttpRequestConstructor.cpp @@ -27,6 +27,7 @@ #include #include #include +#include #include #include #include @@ -38,13 +39,13 @@ namespace Bindings { XMLHttpRequestConstructor::XMLHttpRequestConstructor() : NativeFunction(*interpreter().global_object().function_prototype()) { - put("length", JS::Value(1)); + put("length", JS::Value(1), JS::Attribute::Configurable); - put("UNSENT", JS::Value((i32)XMLHttpRequest::ReadyState::Unsent)); - put("OPENED", JS::Value((i32)XMLHttpRequest::ReadyState::Opened)); - put("HEADERS_RECEIVED", JS::Value((i32)XMLHttpRequest::ReadyState::HeadersReceived)); - put("LOADING", JS::Value((i32)XMLHttpRequest::ReadyState::Loading)); - put("DONE", JS::Value((i32)XMLHttpRequest::ReadyState::Done)); + put("UNSENT", JS::Value((i32)XMLHttpRequest::ReadyState::Unsent), JS::Attribute::Enumerable); + put("OPENED", JS::Value((i32)XMLHttpRequest::ReadyState::Opened), JS::Attribute::Enumerable); + put("HEADERS_RECEIVED", JS::Value((i32)XMLHttpRequest::ReadyState::HeadersReceived), JS::Attribute::Enumerable); + put("LOADING", JS::Value((i32)XMLHttpRequest::ReadyState::Loading), JS::Attribute::Enumerable); + put("DONE", JS::Value((i32)XMLHttpRequest::ReadyState::Done), JS::Attribute::Enumerable); } XMLHttpRequestConstructor::~XMLHttpRequestConstructor() diff --git a/Libraries/LibWeb/Bindings/XMLHttpRequestPrototype.cpp b/Libraries/LibWeb/Bindings/XMLHttpRequestPrototype.cpp index d749663c20..a5d95c302e 100644 --- a/Libraries/LibWeb/Bindings/XMLHttpRequestPrototype.cpp +++ b/Libraries/LibWeb/Bindings/XMLHttpRequestPrototype.cpp @@ -40,14 +40,14 @@ XMLHttpRequestPrototype::XMLHttpRequestPrototype() { put_native_function("open", open, 2); put_native_function("send", send, 0); - put_native_property("readyState", ready_state_getter, nullptr); - put_native_property("responseText", response_text_getter, nullptr); + put_native_property("readyState", ready_state_getter, nullptr, JS::Attribute::Enumerable | JS::Attribute::Configurable); + put_native_property("responseText", response_text_getter, nullptr, JS::Attribute::Enumerable | JS::Attribute::Configurable); - put("UNSENT", JS::Value((i32)XMLHttpRequest::ReadyState::Unsent)); - put("OPENED", JS::Value((i32)XMLHttpRequest::ReadyState::Opened)); - put("HEADERS_RECEIVED", JS::Value((i32)XMLHttpRequest::ReadyState::HeadersReceived)); - put("LOADING", JS::Value((i32)XMLHttpRequest::ReadyState::Loading)); - put("DONE", JS::Value((i32)XMLHttpRequest::ReadyState::Done)); + put("UNSENT", JS::Value((i32)XMLHttpRequest::ReadyState::Unsent), JS::Attribute::Enumerable); + put("OPENED", JS::Value((i32)XMLHttpRequest::ReadyState::Opened), JS::Attribute::Enumerable); + put("HEADERS_RECEIVED", JS::Value((i32)XMLHttpRequest::ReadyState::HeadersReceived), JS::Attribute::Enumerable); + put("LOADING", JS::Value((i32)XMLHttpRequest::ReadyState::Loading), JS::Attribute::Enumerable); + put("DONE", JS::Value((i32)XMLHttpRequest::ReadyState::Done), JS::Attribute::Enumerable); } XMLHttpRequestPrototype::~XMLHttpRequestPrototype()