فهرست منبع

LibJS/Bytecode: Give TypeofBinding instructions a lookup cache

These can use an EnvironmentCoordinate for caching, just like normal
binding lookups. Saves a bunch of time for repeated typeof checks.
Andreas Kling 1 سال پیش
والد
کامیت
60a05ef414

+ 0 - 18
Userland/Libraries/LibJS/Bytecode/CommonImplementations.h

@@ -389,24 +389,6 @@ inline ThrowCompletionOr<void> throw_if_needed_for_call(Interpreter& interpreter
     return {};
 }
 
-inline ThrowCompletionOr<Value> typeof_binding(VM& vm, DeprecatedFlyString const& string)
-{
-    // 1. Let val be the result of evaluating UnaryExpression.
-    auto reference = TRY(vm.resolve_binding(string));
-
-    // 2. If val is a Reference Record, then
-    //    a. If IsUnresolvableReference(val) is true, return "undefined".
-    if (reference.is_unresolvable())
-        return PrimitiveString::create(vm, "undefined"_string);
-
-    // 3. Set val to ? GetValue(val).
-    auto value = TRY(reference.get_value(vm));
-
-    // 4. NOTE: This step is replaced in section B.3.6.3.
-    // 5. Return a String according to Table 41.
-    return PrimitiveString::create(vm, value.typeof());
-}
-
 inline Value new_function(VM& vm, FunctionNode const& function_node, Optional<IdentifierTableIndex> const& lhs_name, Optional<Operand> const& home_object)
 {
     Value value;

+ 32 - 1
Userland/Libraries/LibJS/Bytecode/Interpreter.cpp

@@ -1976,7 +1976,38 @@ ThrowCompletionOr<void> NewClass::execute_impl(Bytecode::Interpreter& interprete
 ThrowCompletionOr<void> TypeofBinding::execute_impl(Bytecode::Interpreter& interpreter) const
 {
     auto& vm = interpreter.vm();
-    interpreter.set(dst(), TRY(typeof_binding(vm, interpreter.current_executable().get_identifier(m_identifier))));
+
+    if (m_cache.is_valid()) {
+        auto const* environment = interpreter.running_execution_context().lexical_environment.ptr();
+        for (size_t i = 0; i < m_cache.hops; ++i)
+            environment = environment->outer_environment();
+        if (!environment->is_permanently_screwed_by_eval()) {
+            auto value = TRY(static_cast<DeclarativeEnvironment const&>(*environment).get_binding_value_direct(vm, m_cache.index));
+            interpreter.set(dst(), PrimitiveString::create(vm, value.typeof()));
+            return {};
+        }
+        m_cache = {};
+    }
+
+    // 1. Let val be the result of evaluating UnaryExpression.
+    auto reference = TRY(vm.resolve_binding(interpreter.current_executable().get_identifier(m_identifier)));
+
+    // 2. If val is a Reference Record, then
+    //    a. If IsUnresolvableReference(val) is true, return "undefined".
+    if (reference.is_unresolvable()) {
+        interpreter.set(dst(), PrimitiveString::create(vm, "undefined"_string));
+        return {};
+    }
+
+    // 3. Set val to ? GetValue(val).
+    auto value = TRY(reference.get_value(vm));
+
+    if (reference.environment_coordinate().has_value())
+        m_cache = reference.environment_coordinate().value();
+
+    // 4. NOTE: This step is replaced in section B.3.6.3.
+    // 5. Return a String according to Table 41.
+    interpreter.set(dst(), PrimitiveString::create(vm, value.typeof()));
     return {};
 }
 

+ 1 - 0
Userland/Libraries/LibJS/Bytecode/Op.h

@@ -2645,6 +2645,7 @@ public:
 private:
     Operand m_dst;
     IdentifierTableIndex m_identifier;
+    mutable EnvironmentCoordinate m_cache;
 };
 
 class End final : public Instruction {