mirror of
https://github.com/zebrajr/ladybird.git
synced 2025-12-06 00:19:53 +01:00
LibJS: Invalidate PrototypeChainValidity when prototype shape is a dict
Adds missing PrototypeChainValidity invalidation for add/set/delete operations on dictionary-mode prototype shapes.
This commit is contained in:
parent
3272b8c0f3
commit
2a288f6d53
|
|
@ -1,5 +1,6 @@
|
|||
/*
|
||||
* Copyright (c) 2020-2024, Andreas Kling <andreas@ladybird.org>
|
||||
* Copyright (c) 2025, Aliaksandr Kalenik <kalenik.aliaksandr@gmail.com>
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*/
|
||||
|
|
@ -285,6 +286,7 @@ GC::Ref<Shape> Shape::create_delete_transition(PropertyKey const& property_key)
|
|||
|
||||
void Shape::add_property_without_transition(PropertyKey const& property_key, PropertyAttributes attributes)
|
||||
{
|
||||
invalidate_prototype_if_needed_for_change_without_transition();
|
||||
ensure_property_table();
|
||||
if (m_property_table->set(property_key, { m_property_count, attributes }) == AK::HashSetResult::InsertedNewEntry) {
|
||||
VERIFY(m_property_count < NumericLimits<u32>::max());
|
||||
|
|
@ -294,6 +296,7 @@ void Shape::add_property_without_transition(PropertyKey const& property_key, Pro
|
|||
|
||||
void Shape::set_property_attributes_without_transition(PropertyKey const& property_key, PropertyAttributes attributes)
|
||||
{
|
||||
invalidate_prototype_if_needed_for_change_without_transition();
|
||||
VERIFY(is_dictionary());
|
||||
VERIFY(m_property_table);
|
||||
auto it = m_property_table->find(property_key);
|
||||
|
|
@ -304,6 +307,7 @@ void Shape::set_property_attributes_without_transition(PropertyKey const& proper
|
|||
|
||||
void Shape::remove_property_without_transition(PropertyKey const& property_key, u32 offset)
|
||||
{
|
||||
invalidate_prototype_if_needed_for_change_without_transition();
|
||||
VERIFY(is_uncacheable_dictionary());
|
||||
VERIFY(m_property_table);
|
||||
if (m_property_table->remove(property_key))
|
||||
|
|
@ -356,6 +360,16 @@ void Shape::invalidate_prototype_if_needed_for_new_prototype(GC::Ref<Shape> new_
|
|||
invalidate_all_prototype_chains_leading_to_this();
|
||||
}
|
||||
|
||||
void Shape::invalidate_prototype_if_needed_for_change_without_transition()
|
||||
{
|
||||
if (!m_is_prototype_shape)
|
||||
return;
|
||||
m_prototype_chain_validity->set_valid(false);
|
||||
m_prototype_chain_validity = heap().allocate<PrototypeChainValidity>();
|
||||
|
||||
invalidate_all_prototype_chains_leading_to_this();
|
||||
}
|
||||
|
||||
void Shape::invalidate_all_prototype_chains_leading_to_this()
|
||||
{
|
||||
HashTable<Shape*> shapes_to_invalidate;
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
/*
|
||||
* Copyright (c) 2020-2024, Andreas Kling <andreas@ladybird.org>
|
||||
* Copyright (c) 2025, Aliaksandr Kalenik <kalenik.aliaksandr@gmail.com>
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*/
|
||||
|
|
@ -113,6 +114,7 @@ private:
|
|||
Shape(Shape& previous_shape, Object* new_prototype);
|
||||
|
||||
void invalidate_prototype_if_needed_for_new_prototype(GC::Ref<Shape> new_prototype_shape);
|
||||
void invalidate_prototype_if_needed_for_change_without_transition();
|
||||
void invalidate_all_prototype_chains_leading_to_this();
|
||||
|
||||
virtual void visit_edges(Visitor&) override;
|
||||
|
|
|
|||
|
|
@ -32,3 +32,62 @@ test("Overriding an inherited getter with a data property on an intermediate pro
|
|||
Object.defineProperty(proto, "hm", { value: 321 });
|
||||
f(obj, 321);
|
||||
});
|
||||
|
||||
test("Modifying prototype in dictionary mode should cause prototype-chain validity invalidation (dict-mode prototype is in the middle of prototype chain)", () => {
|
||||
function f(obj, expected) {
|
||||
expect(obj.hm).toBe(expected);
|
||||
}
|
||||
|
||||
const midProto = {};
|
||||
midProto.__proto__ = {
|
||||
get hm() {
|
||||
return 321;
|
||||
},
|
||||
};
|
||||
|
||||
const proto = {};
|
||||
proto.__proto__ = midProto;
|
||||
|
||||
const obj = Object.create(proto);
|
||||
// put midProto into dictionary mode
|
||||
for (let i = 0; i < 1000; i++) {
|
||||
midProto["i" + i] = i;
|
||||
}
|
||||
|
||||
f(obj, 321);
|
||||
Object.defineProperty(midProto, "hm", {
|
||||
get() {
|
||||
return 123;
|
||||
},
|
||||
configurable: true,
|
||||
});
|
||||
f(obj, 123);
|
||||
});
|
||||
|
||||
test("Modifying prototype in dictionary mode should cause prototype-chain validity invalidation (dict-mode prototype is direct prototype of target object)", () => {
|
||||
function f(obj, expected) {
|
||||
expect(obj.hm).toBe(expected);
|
||||
}
|
||||
|
||||
const proto = {};
|
||||
proto.__proto__ = {
|
||||
get hm() {
|
||||
return 321;
|
||||
},
|
||||
};
|
||||
|
||||
const obj = Object.create(proto);
|
||||
// put proto into dictionary mode
|
||||
for (let i = 0; i < 1000; i++) {
|
||||
proto["i" + i] = i;
|
||||
}
|
||||
|
||||
f(obj, 321);
|
||||
Object.defineProperty(proto, "hm", {
|
||||
get() {
|
||||
return 123;
|
||||
},
|
||||
configurable: true,
|
||||
});
|
||||
f(obj, 123);
|
||||
});
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user