mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2024-11-22 15:40:19 +00:00
LibJS/Bytecode: Handle shadowed non-enumerable properties in for-in
Invariants 5 and 6 of the `EnumerateObjectProperties` AO mean that we must not include an enumerate property if there is a non-enumerable property higher up the prototype chain with the same name. The previous implementation did not adhere to this, as `EnumerableOwnPropertyNames` does not carry information about present but non-enumerable properties.
This commit is contained in:
parent
f21a30e45f
commit
d0dce5c60f
Notes:
sideshowbarker
2024-07-18 01:43:16 +09:00
Author: https://github.com/BertalanD Commit: https://github.com/SerenityOS/serenity/commit/d0dce5c60f Pull-request: https://github.com/SerenityOS/serenity/pull/19833
1 changed files with 18 additions and 3 deletions
|
@ -1156,18 +1156,33 @@ ThrowCompletionOr<void> GetObjectPropertyIterator::execute_impl(Bytecode::Interp
|
|||
// 9- Property attributes of the target object must be obtained by calling its [[GetOwnProperty]] internal method
|
||||
|
||||
// Invariant 3 effectively allows the implementation to ignore newly added keys, and we do so (similar to other implementations).
|
||||
// Invariants 1 and 6 through 9 are implemented in `enumerable_own_property_names`, which implements the EnumerableOwnPropertyNames AO.
|
||||
auto& vm = interpreter.vm();
|
||||
auto object = TRY(interpreter.accumulator().to_object(vm));
|
||||
// Note: While the spec doesn't explicitly require these to be ordered, it says that the values should be retrieved via OwnPropertyKeys,
|
||||
// so we just keep the order consistent anyway.
|
||||
OrderedHashTable<PropertyKey> properties;
|
||||
OrderedHashTable<PropertyKey> non_enumerable_properties;
|
||||
HashTable<NonnullGCPtr<Object>> seen_objects;
|
||||
// Collect all keys immediately (invariant no. 5)
|
||||
for (auto object_to_check = GCPtr { object.ptr() }; object_to_check && !seen_objects.contains(*object_to_check); object_to_check = TRY(object_to_check->internal_get_prototype_of())) {
|
||||
seen_objects.set(*object_to_check);
|
||||
for (auto& key : TRY(object_to_check->enumerable_own_property_names(Object::PropertyKind::Key))) {
|
||||
properties.set(TRY(PropertyKey::from_value(vm, key)));
|
||||
for (auto& key : TRY(object_to_check->internal_own_property_keys())) {
|
||||
if (key.is_symbol())
|
||||
continue;
|
||||
auto property_key = TRY(PropertyKey::from_value(vm, key));
|
||||
|
||||
// If there is a non-enumerable property higher up the prototype chain with the same key,
|
||||
// we mustn't include this property even if it's enumerable (invariant no. 5 and 6)
|
||||
if (non_enumerable_properties.contains(property_key))
|
||||
continue;
|
||||
if (properties.contains(property_key))
|
||||
continue;
|
||||
|
||||
auto descriptor = TRY(object_to_check->internal_get_own_property(property_key));
|
||||
if (!*descriptor->enumerable)
|
||||
non_enumerable_properties.set(move(property_key));
|
||||
else
|
||||
properties.set(move(property_key));
|
||||
}
|
||||
}
|
||||
IteratorRecord iterator {
|
||||
|
|
Loading…
Reference in a new issue