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 0c9d2ea12f8..65da8387c6e 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 f2089736212..b3ac9b79283 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 b1522a698cf..96a66a2f0ba 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 5bd458ae46c..19cfba74407 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 6ecc286cf67..4aa82f2c2b1 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 d2f09ff9f30..a9f573e6be7 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 899232ba78b..dc115c5a19b 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 480a069cfb8..8a5a3e9d442 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 22ea084ab6f..10246270f9c 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 4dbfcbaed45..0ed6fd11854 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 644bffa4815..b7d6b114b79 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 6e289b7f561..9ec245f4751 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 21287bd17db..b538591a444 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 fc24b858387..4996de3f725 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 e5a358eb3da..1be11f70f2f 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 5c945ea8885..fa812c102e6 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 1fcbe4e8e29..e7738ecfeb4 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 56f064be37a..53a3c4f5189 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 3086951a3a6..38a1096c17b 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 0858ceef2d3..0be1df0b245 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 a798cda9dc0..b62edcbe4a5 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 b04b236be25..57f4baa598e 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 411d0018ba3..0e66f897b11 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 66867d4ed91..0e00bb6861e 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 7fea4c1cc11..2a2acb829c4 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 d749663c206..a5d95c302e1 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()