LibJS: Cache dynamic environment coordinates

Dynamic environment binding opcodes lost the old coordinate warmup.
They were split away from the static coordinate opcodes. Hot closures
and eval-sensitive functions then resolved the same binding by name on
every execution, which regressed JS benchmark throughput badly.

Give each dynamic environment opcode a per-executable coordinate cache
slot. The cache keeps the bytecode stream immutable while letting both
interpreters take a direct declarative environment fast path after the
first lookup. Keep the existing eval invalidation behavior and only warm
caches for declarative-only chains so with environments continue to
observe object shadowing.

Reject cached bytecode that uses the no-cache sentinel for dynamic
environment coordinate cache operands, since execution indexes those
cache arrays unconditionally.

Rebaseline bytecode expectations for the instruction size changes. Add
coverage for with-object shadowing across repeated dynamic lookups and
for rejecting corrupt dynamic environment cache indices.
This commit is contained in:
Andreas Kling 2026-05-19 11:22:33 +02:00 committed by Andreas Kling
parent 73e7cacd78
commit 4ac744082b
Notes: github-actions[bot] 2026-05-19 13:56:48 +00:00
21 changed files with 379 additions and 35 deletions

View file

@ -262,6 +262,7 @@ Executable::Executable(
NonnullRefPtr<SourceCode const> source_code,
size_t number_of_property_lookup_caches,
size_t number_of_global_variable_caches,
size_t number_of_environment_coordinate_caches,
size_t number_of_template_object_caches,
size_t number_of_object_shape_caches,
size_t number_of_object_property_iterator_caches,
@ -280,6 +281,7 @@ Executable::Executable(
{
property_lookup_caches.resize(number_of_property_lookup_caches);
global_variable_caches.resize(number_of_global_variable_caches);
environment_coordinate_caches.resize(number_of_environment_coordinate_caches);
template_object_caches.resize(number_of_template_object_caches);
object_shape_caches.resize(number_of_object_shape_caches);
object_property_iterator_caches.resize(number_of_object_property_iterator_caches);
@ -563,6 +565,7 @@ size_t Executable::external_memory_size() const
for (auto const& cache : property_lookup_caches)
size = saturating_add_external_memory_size(size, cache.external_memory_size());
size = saturating_add_external_memory_size(size, vector_external_memory_size(global_variable_caches));
size = saturating_add_external_memory_size(size, vector_external_memory_size(environment_coordinate_caches));
size = saturating_add_external_memory_size(size, vector_external_memory_size(template_object_caches));
size = saturating_add_external_memory_size(size, vector_external_memory_size(object_shape_caches));
for (auto const& cache : object_shape_caches)