1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-07-25 03:57:43 +00:00

LibJS: Fast non-local variable access :^)

This patch introduces the "environment coordinate" concept, which
encodes the distance from a variable access to the binding it ends up
resolving to.

EnvironmentCoordinate has two fields:

    - hops:  The number of hops up the lexical environment chain we have
             to make before getting to the resolved binding.

    - index: The index of the resolved binding within its declarative
             environment record.

Whenever a variable lookup resolves somewhere inside a declarative
environment, we now cache the coordinates and reuse them in subsequent
lookups. This is achieved via a coordinate cache in JS::Identifier.

Note that non-strict direct eval() breaks this optimization and so it
will not be performed if the resolved environment has been permanently
screwed by eval().

This makes variable access *significantly* faster. :^)
This commit is contained in:
Andreas Kling 2021-10-07 01:06:21 +02:00
parent 421845b0cd
commit 41a072bded
8 changed files with 65 additions and 12 deletions

View file

@ -1005,7 +1005,20 @@ Reference Expression::to_reference(Interpreter&, GlobalObject&) const
Reference Identifier::to_reference(Interpreter& interpreter, GlobalObject&) const
{
return interpreter.vm().resolve_binding(string());
if (m_cached_environment_coordinate.has_value()) {
auto* environment = interpreter.vm().running_execution_context().lexical_environment;
for (size_t i = 0; i < m_cached_environment_coordinate->hops; ++i)
environment = environment->outer_environment();
VERIFY(environment);
VERIFY(environment->is_declarative_environment());
if (!environment->is_permanently_screwed_by_eval())
return Reference { *environment, string(), interpreter.vm().in_strict_mode(), m_cached_environment_coordinate };
m_cached_environment_coordinate = {};
}
auto reference = interpreter.vm().resolve_binding(string());
if (reference.environment_coordinate().has_value())
const_cast<Identifier&>(*this).m_cached_environment_coordinate = reference.environment_coordinate();
return reference;
}
Reference MemberExpression::to_reference(Interpreter& interpreter, GlobalObject& global_object) const