This change implements a part responsible for this invariant in a more
efficient way:
"Enumerating the properties of the target object includes enumerating
properties of its prototype, and the prototype of the prototype, and so
on, recursively; but a property of a prototype is not processed if it
has the same name as a property that has already been processed by the
iterator's next method."
Previously we inserted `(key, enumerable)` pairs into an
`OrderedHashTable`. That always built and maintained a hash table, even
when no prototype-level filtering was needed.
Now we:
- Collect only enumerable keys into `Vector<PropertyKey>`.
- Track `seen_non_enumerable_properties` so a non-enumerable own
property still shadows prototype properties with the same name.
- Lazily materialize `HashTable<PropertyKey>` only if we encounter an
enumerable property on a prototype and must check for duplicates. In
the common case materialization is avoided, because default Object or
Array prototype properties are non-enumerable.