LibJS: Capture PrototypeChainValidity before executing internal_get()

- Capture PrototypeChainValidity before invoking `internal_get()`. A
  getter may mutate the prototype chain (e.g., delete itself). Capturing
  earlier ensures such mutations invalidate the cached entry and prevent
  stale GetById hits.
- When caching, take PrototypeChainValidity from the base object
  (receiver), not from the prototype where the property was found.
  Otherwise, changes to an intermediate prototype between the base
  object and the cached prototype object go unnoticed, leading to
  incorrect cache hits.
This commit is contained in:
Aliaksandr Kalenik 2025-09-18 02:28:52 +02:00 committed by Alexander Kalenik
commit c3b0eabf18
Notes: github-actions[bot] 2025-09-18 13:57:32 +00:00
2 changed files with 39 additions and 1 deletions

View file

@ -996,6 +996,10 @@ inline ThrowCompletionOr<Value> get_by_id(VM& vm, Optional<IdentifierTableIndex>
auto& shape = base_obj->shape();
GC::Ptr<PrototypeChainValidity> prototype_chain_validity;
if (shape.prototype())
prototype_chain_validity = shape.prototype()->shape().prototype_chain_validity();
for (auto& cache_entry : cache.entries) {
if (cache_entry.prototype) {
// OPTIMIZATION: If the prototype chain hasn't been mutated in a way that would invalidate the cache, we can use it.
@ -1046,7 +1050,7 @@ inline ThrowCompletionOr<Value> get_by_id(VM& vm, Optional<IdentifierTableIndex>
entry.shape = &base_obj->shape();
entry.property_offset = cacheable_metadata.property_offset.value();
entry.prototype = *cacheable_metadata.prototype;
entry.prototype_chain_validity = *cacheable_metadata.prototype->shape().prototype_chain_validity();
entry.prototype_chain_validity = *prototype_chain_validity;
}
}