LibJS: Make PutById inline cache polymorphic (4 shapes)

2.44x speedup on MicroBench/pic-put-own.js
1.48x speedup on MicroBench/pic-put-pchain.js
This commit is contained in:
Andreas Kling 2025-05-06 13:58:27 +02:00 committed by Andreas Kling
commit d462731a4d
Notes: github-actions[bot] 2025-05-06 22:28:06 +00:00

View file

@ -1234,51 +1234,57 @@ inline ThrowCompletionOr<void> put_by_property_key(VM& vm, Value base, Value thi
} }
case Op::PropertyKind::KeyValue: { case Op::PropertyKind::KeyValue: {
if (caches) { if (caches) {
auto* cache = &caches->entries[0]; for (auto& cache : caches->entries) {
if (cache->prototype) { if (cache.prototype) {
// OPTIMIZATION: If the prototype chain hasn't been mutated in a way that would invalidate the cache, we can use it. // OPTIMIZATION: If the prototype chain hasn't been mutated in a way that would invalidate the cache, we can use it.
bool can_use_cache = [&]() -> bool { bool can_use_cache = [&]() -> bool {
if (&object->shape() != cache->shape) if (&object->shape() != cache.shape)
return false; return false;
if (!cache->prototype_chain_validity) if (!cache.prototype_chain_validity)
return false; return false;
if (!cache->prototype_chain_validity->is_valid()) if (!cache.prototype_chain_validity->is_valid())
return false; return false;
return true; return true;
}(); }();
if (can_use_cache) { if (can_use_cache) {
auto value_in_prototype = cache->prototype->get_direct(cache->property_offset.value()); auto value_in_prototype = cache.prototype->get_direct(cache.property_offset.value());
if (value_in_prototype.is_accessor()) { if (value_in_prototype.is_accessor()) {
TRY(call(vm, value_in_prototype.as_accessor().setter(), this_value, value)); TRY(call(vm, value_in_prototype.as_accessor().setter(), this_value, value));
return {}; return {};
} }
} }
} else if (cache->shape == &object->shape()) { } else if (cache.shape == &object->shape()) {
auto value_in_object = object->get_direct(cache->property_offset.value()); auto value_in_object = object->get_direct(cache.property_offset.value());
if (value_in_object.is_accessor()) { if (value_in_object.is_accessor()) {
TRY(call(vm, value_in_object.as_accessor().setter(), this_value, value)); TRY(call(vm, value_in_object.as_accessor().setter(), this_value, value));
} else { } else {
object->put_direct(*cache->property_offset, value); object->put_direct(*cache.property_offset, value);
} }
return {}; return {};
} }
} }
}
CacheablePropertyMetadata cacheable_metadata; CacheablePropertyMetadata cacheable_metadata;
bool succeeded = TRY(object->internal_set(name, value, this_value, &cacheable_metadata)); bool succeeded = TRY(object->internal_set(name, value, this_value, &cacheable_metadata));
if (succeeded && caches) { if (succeeded && caches) {
auto* cache = &caches->entries[0]; auto get_cache_slot = [&] -> PropertyLookupCache::Entry& {
for (size_t i = caches->entries.size() - 1; i >= 1; --i) {
caches->entries[i] = caches->entries[i - 1];
}
caches->entries[0] = {};
return caches->entries[0];
};
auto& cache = get_cache_slot();
if (cacheable_metadata.type == CacheablePropertyMetadata::Type::OwnProperty) { if (cacheable_metadata.type == CacheablePropertyMetadata::Type::OwnProperty) {
*cache = {}; cache.shape = object->shape();
cache->shape = object->shape(); cache.property_offset = cacheable_metadata.property_offset.value();
cache->property_offset = cacheable_metadata.property_offset.value();
} else if (cacheable_metadata.type == CacheablePropertyMetadata::Type::InPrototypeChain) { } else if (cacheable_metadata.type == CacheablePropertyMetadata::Type::InPrototypeChain) {
*cache = {}; cache.shape = object->shape();
cache->shape = object->shape(); cache.property_offset = cacheable_metadata.property_offset.value();
cache->property_offset = cacheable_metadata.property_offset.value(); cache.prototype = *cacheable_metadata.prototype;
cache->prototype = *cacheable_metadata.prototype; cache.prototype_chain_validity = *cacheable_metadata.prototype->shape().prototype_chain_validity();
cache->prototype_chain_validity = *cacheable_metadata.prototype->shape().prototype_chain_validity();
} }
} }