diff --git a/Libraries/LibJS/AST.cpp b/Libraries/LibJS/AST.cpp index 7046bbf7c62..9b3c3a7906f 100644 --- a/Libraries/LibJS/AST.cpp +++ b/Libraries/LibJS/AST.cpp @@ -1046,8 +1046,8 @@ Value ObjectExpression::execute(Interpreter& interpreter) const } else if (key_result.is_object()) { auto& obj_to_spread = key_result.as_object(); - for (auto& it : obj_to_spread.shape().property_table()) { - if (obj_to_spread.has_own_property(it.key) && it.value.attributes & Attribute::Enumerable) + for (auto& it : obj_to_spread.shape().property_table_ordered()) { + if (it.value.attributes & Attribute::Enumerable) object->put(it.key, obj_to_spread.get(it.key)); } } else if (key_result.is_string()) { diff --git a/Libraries/LibJS/Runtime/Cell.cpp b/Libraries/LibJS/Runtime/Cell.cpp index c80b59e824d..4c8cb695112 100644 --- a/Libraries/LibJS/Runtime/Cell.cpp +++ b/Libraries/LibJS/Runtime/Cell.cpp @@ -56,6 +56,11 @@ Interpreter& Cell::interpreter() return heap().interpreter(); } +Interpreter& Cell::interpreter() const +{ + return heap().interpreter(); +} + const LogStream& operator<<(const LogStream& stream, const Cell* cell) { if (!cell) diff --git a/Libraries/LibJS/Runtime/Cell.h b/Libraries/LibJS/Runtime/Cell.h index 9989618ed45..e08a31ac626 100644 --- a/Libraries/LibJS/Runtime/Cell.h +++ b/Libraries/LibJS/Runtime/Cell.h @@ -60,6 +60,7 @@ public: Heap& heap() const; Interpreter& interpreter(); + Interpreter& interpreter() const; protected: Cell() {} diff --git a/Libraries/LibJS/Runtime/Object.cpp b/Libraries/LibJS/Runtime/Object.cpp index 5144e754442..403c99f0666 100644 --- a/Libraries/LibJS/Runtime/Object.cpp +++ b/Libraries/LibJS/Runtime/Object.cpp @@ -34,6 +34,7 @@ #include #include #include +#include #include namespace JS { diff --git a/Libraries/LibJS/Runtime/ObjectConstructor.cpp b/Libraries/LibJS/Runtime/ObjectConstructor.cpp index e7738ecfeb4..475bbd56f40 100644 --- a/Libraries/LibJS/Runtime/ObjectConstructor.cpp +++ b/Libraries/LibJS/Runtime/ObjectConstructor.cpp @@ -76,7 +76,7 @@ Value ObjectConstructor::get_own_property_names(Interpreter& interpreter) result->elements().append(js_string(interpreter, String::number(i))); } - for (auto& it : object->shape().property_table()) { + for (auto& it : object->shape().property_table_ordered()) { result->elements().append(js_string(interpreter, it.key)); } return result; diff --git a/Libraries/LibJS/Runtime/Shape.cpp b/Libraries/LibJS/Runtime/Shape.cpp index d03ad74a360..ef10ea8c51b 100644 --- a/Libraries/LibJS/Runtime/Shape.cpp +++ b/Libraries/LibJS/Runtime/Shape.cpp @@ -117,6 +117,18 @@ size_t Shape::property_count() const return property_table().size(); } +Vector Shape::property_table_ordered() const +{ + auto vec = Vector(); + vec.resize(property_table().size()); + + for (auto& it : property_table()) { + vec[it.value.offset] = { it.key, it.value }; + } + + return vec; +} + void Shape::ensure_property_table() const { if (m_property_table) diff --git a/Libraries/LibJS/Runtime/Shape.h b/Libraries/LibJS/Runtime/Shape.h index 26c8eb574bb..44cf3bdb437 100644 --- a/Libraries/LibJS/Runtime/Shape.h +++ b/Libraries/LibJS/Runtime/Shape.h @@ -88,6 +88,13 @@ public: const HashMap& property_table() const; size_t property_count() const; + struct Property { + FlyString key; + PropertyMetadata value; + }; + + Vector property_table_ordered() const; + void set_prototype_without_transition(Object* new_prototype) { m_prototype = new_prototype; } void remove_property_from_unique_shape(const FlyString&, size_t offset); diff --git a/Libraries/LibJS/Tests/Object.getOwnPropertyNames.js b/Libraries/LibJS/Tests/Object.getOwnPropertyNames.js index cbb90108fc1..72f77d62766 100644 --- a/Libraries/LibJS/Tests/Object.getOwnPropertyNames.js +++ b/Libraries/LibJS/Tests/Object.getOwnPropertyNames.js @@ -1,13 +1,19 @@ load("test-common.js"); try { - var names = Object.getOwnPropertyNames([1, 2, 3]); + let names = Object.getOwnPropertyNames([1, 2, 3]); assert(names.length === 4); - assert(names[0] === '0'); - assert(names[1] === '1'); - assert(names[2] === '2'); - assert(names[3] === 'length'); + assert(names[0] === "0"); + assert(names[1] === "1"); + assert(names[2] === "2"); + assert(names[3] === "length"); + + names = Object.getOwnPropertyNames({ foo: 1, bar: 2, baz: 3 }); + assert(names.length === 3); + assert(names[0] === "foo"); + assert(names[1] === "bar"); + assert(names[2] === "baz"); console.log("PASS"); } catch (e) { diff --git a/Userland/js.cpp b/Userland/js.cpp index 93fa1fd18c2..4edcbba2f45 100644 --- a/Userland/js.cpp +++ b/Userland/js.cpp @@ -142,7 +142,7 @@ static void print_object(const JS::Object& object, HashTable& seen_ fputs(", ", stdout); size_t index = 0; - for (auto& it : object.shape().property_table()) { + for (auto& it : object.shape().property_table_ordered()) { printf("\"\033[33;1m%s\033[0m\": ", it.key.characters()); print_value(object.get_direct(it.value.offset), seen_objects); if (index != object.shape().property_count() - 1)