فهرست منبع

LibJS/Bytecode: Move environment coordinate caches to Executable

Moving them out of the respective instructions allows the bytecode
stream to be immutable.
Andreas Kling 1 سال پیش
والد
کامیت
2e23f00a2f

+ 3 - 3
Userland/Libraries/LibJS/Bytecode/ASTCodegen.cpp

@@ -314,7 +314,7 @@ Bytecode::CodeGenerationErrorOr<void> Identifier::generate_bytecode(Bytecode::Ge
     } else if (is_local()) {
     } else if (is_local()) {
         generator.emit<Bytecode::Op::GetLocal>(local_variable_index());
         generator.emit<Bytecode::Op::GetLocal>(local_variable_index());
     } else {
     } else {
-        generator.emit<Bytecode::Op::GetVariable>(generator.intern_identifier(m_string));
+        generator.emit<Bytecode::Op::GetVariable>(generator.intern_identifier(m_string), generator.next_environment_variable_cache());
     }
     }
     return {};
     return {};
 }
 }
@@ -1061,7 +1061,7 @@ Bytecode::CodeGenerationErrorOr<void> FunctionDeclaration::generate_bytecode(Byt
     if (m_is_hoisted) {
     if (m_is_hoisted) {
         Bytecode::Generator::SourceLocationScope scope(generator, *this);
         Bytecode::Generator::SourceLocationScope scope(generator, *this);
         auto index = generator.intern_identifier(name());
         auto index = generator.intern_identifier(name());
-        generator.emit<Bytecode::Op::GetVariable>(index);
+        generator.emit<Bytecode::Op::GetVariable>(index, generator.next_environment_variable_cache());
         generator.emit<Bytecode::Op::SetVariable>(index, Bytecode::Op::SetVariable::InitializationMode::Set, Bytecode::Op::EnvironmentMode::Var);
         generator.emit<Bytecode::Op::SetVariable>(index, Bytecode::Op::SetVariable::InitializationMode::Set, Bytecode::Op::EnvironmentMode::Var);
     }
     }
     return {};
     return {};
@@ -1534,7 +1534,7 @@ Bytecode::CodeGenerationErrorOr<void> CallExpression::generate_bytecode(Bytecode
         //       a `with` binding, so we can skip this.
         //       a `with` binding, so we can skip this.
         auto& identifier = static_cast<Identifier const&>(*m_callee);
         auto& identifier = static_cast<Identifier const&>(*m_callee);
         if (!identifier.is_local() && !identifier.is_global()) {
         if (!identifier.is_local() && !identifier.is_global()) {
-            generator.emit<Bytecode::Op::GetCalleeAndThisFromEnvironment>(generator.intern_identifier(identifier.string()), callee_reg, this_reg);
+            generator.emit<Bytecode::Op::GetCalleeAndThisFromEnvironment>(generator.intern_identifier(identifier.string()), callee_reg, this_reg, generator.next_environment_variable_cache());
         } else {
         } else {
             TRY(m_callee->generate_bytecode(generator));
             TRY(m_callee->generate_bytecode(generator));
             generator.emit<Bytecode::Op::Store>(callee_reg);
             generator.emit<Bytecode::Op::Store>(callee_reg);

+ 2 - 0
Userland/Libraries/LibJS/Bytecode/Executable.cpp

@@ -18,6 +18,7 @@ Executable::Executable(
     NonnullRefPtr<SourceCode const> source_code,
     NonnullRefPtr<SourceCode const> source_code,
     size_t number_of_property_lookup_caches,
     size_t number_of_property_lookup_caches,
     size_t number_of_global_variable_caches,
     size_t number_of_global_variable_caches,
+    size_t number_of_environment_variable_caches,
     size_t number_of_registers,
     size_t number_of_registers,
     Vector<NonnullOwnPtr<BasicBlock>> basic_blocks,
     Vector<NonnullOwnPtr<BasicBlock>> basic_blocks,
     bool is_strict_mode)
     bool is_strict_mode)
@@ -31,6 +32,7 @@ Executable::Executable(
 {
 {
     property_lookup_caches.resize(number_of_property_lookup_caches);
     property_lookup_caches.resize(number_of_property_lookup_caches);
     global_variable_caches.resize(number_of_global_variable_caches);
     global_variable_caches.resize(number_of_global_variable_caches);
+    environment_variable_caches.resize(number_of_environment_variable_caches);
 }
 }
 
 
 Executable::~Executable() = default;
 Executable::~Executable() = default;

+ 3 - 0
Userland/Libraries/LibJS/Bytecode/Executable.h

@@ -12,6 +12,7 @@
 #include <LibJS/Bytecode/IdentifierTable.h>
 #include <LibJS/Bytecode/IdentifierTable.h>
 #include <LibJS/Bytecode/StringTable.h>
 #include <LibJS/Bytecode/StringTable.h>
 #include <LibJS/Forward.h>
 #include <LibJS/Forward.h>
+#include <LibJS/Runtime/EnvironmentCoordinate.h>
 
 
 namespace JS::Bytecode {
 namespace JS::Bytecode {
 
 
@@ -39,6 +40,7 @@ public:
         NonnullRefPtr<SourceCode const>,
         NonnullRefPtr<SourceCode const>,
         size_t number_of_property_lookup_caches,
         size_t number_of_property_lookup_caches,
         size_t number_of_global_variable_caches,
         size_t number_of_global_variable_caches,
+        size_t number_of_environment_variable_caches,
         size_t number_of_registers,
         size_t number_of_registers,
         Vector<NonnullOwnPtr<BasicBlock>>,
         Vector<NonnullOwnPtr<BasicBlock>>,
         bool is_strict_mode);
         bool is_strict_mode);
@@ -48,6 +50,7 @@ public:
     DeprecatedFlyString name;
     DeprecatedFlyString name;
     Vector<PropertyLookupCache> property_lookup_caches;
     Vector<PropertyLookupCache> property_lookup_caches;
     Vector<GlobalVariableCache> global_variable_caches;
     Vector<GlobalVariableCache> global_variable_caches;
+    Vector<Optional<EnvironmentCoordinate>> environment_variable_caches;
     Vector<NonnullOwnPtr<BasicBlock>> basic_blocks;
     Vector<NonnullOwnPtr<BasicBlock>> basic_blocks;
     NonnullOwnPtr<StringTable> string_table;
     NonnullOwnPtr<StringTable> string_table;
     NonnullOwnPtr<IdentifierTable> identifier_table;
     NonnullOwnPtr<IdentifierTable> identifier_table;

+ 1 - 0
Userland/Libraries/LibJS/Bytecode/Generator.cpp

@@ -63,6 +63,7 @@ CodeGenerationErrorOr<NonnullRefPtr<Executable>> Generator::generate(ASTNode con
         node.source_code(),
         node.source_code(),
         generator.m_next_property_lookup_cache,
         generator.m_next_property_lookup_cache,
         generator.m_next_global_variable_cache,
         generator.m_next_global_variable_cache,
+        generator.m_next_environment_variable_cache,
         generator.m_next_register,
         generator.m_next_register,
         move(generator.m_root_basic_blocks),
         move(generator.m_root_basic_blocks),
         is_strict_mode));
         is_strict_mode));

+ 2 - 0
Userland/Libraries/LibJS/Bytecode/Generator.h

@@ -206,6 +206,7 @@ public:
     void emit_get_by_id_with_this(IdentifierTableIndex, Register);
     void emit_get_by_id_with_this(IdentifierTableIndex, Register);
 
 
     [[nodiscard]] size_t next_global_variable_cache() { return m_next_global_variable_cache++; }
     [[nodiscard]] size_t next_global_variable_cache() { return m_next_global_variable_cache++; }
+    [[nodiscard]] size_t next_environment_variable_cache() { return m_next_environment_variable_cache++; }
 
 
 private:
 private:
     enum class JumpType {
     enum class JumpType {
@@ -236,6 +237,7 @@ private:
     u32 m_next_block { 1 };
     u32 m_next_block { 1 };
     u32 m_next_property_lookup_cache { 0 };
     u32 m_next_property_lookup_cache { 0 };
     u32 m_next_global_variable_cache { 0 };
     u32 m_next_global_variable_cache { 0 };
+    u32 m_next_environment_variable_cache { 0 };
     FunctionKind m_enclosing_function_kind { FunctionKind::Normal };
     FunctionKind m_enclosing_function_kind { FunctionKind::Normal };
     Vector<LabelableScope> m_continuable_scopes;
     Vector<LabelableScope> m_continuable_scopes;
     Vector<LabelableScope> m_breakable_scopes;
     Vector<LabelableScope> m_breakable_scopes;

+ 12 - 10
Userland/Libraries/LibJS/Bytecode/Interpreter.cpp

@@ -812,23 +812,24 @@ ThrowCompletionOr<void> GetVariable::execute_impl(Bytecode::Interpreter& interpr
 {
 {
     auto& vm = interpreter.vm();
     auto& vm = interpreter.vm();
 
 
-    if (m_cached_environment_coordinate.has_value()) {
+    auto& cached_environment_coordinate = interpreter.current_executable().environment_variable_caches[m_cache_index];
+    if (cached_environment_coordinate.has_value()) {
         auto environment = vm.running_execution_context().lexical_environment;
         auto environment = vm.running_execution_context().lexical_environment;
-        for (size_t i = 0; i < m_cached_environment_coordinate->hops; ++i)
+        for (size_t i = 0; i < cached_environment_coordinate->hops; ++i)
             environment = environment->outer_environment();
             environment = environment->outer_environment();
         VERIFY(environment);
         VERIFY(environment);
         VERIFY(environment->is_declarative_environment());
         VERIFY(environment->is_declarative_environment());
         if (!environment->is_permanently_screwed_by_eval()) {
         if (!environment->is_permanently_screwed_by_eval()) {
-            interpreter.accumulator() = TRY(verify_cast<DeclarativeEnvironment>(*environment).get_binding_value_direct(vm, m_cached_environment_coordinate.value().index, vm.in_strict_mode()));
+            interpreter.accumulator() = TRY(verify_cast<DeclarativeEnvironment>(*environment).get_binding_value_direct(vm, cached_environment_coordinate.value().index, vm.in_strict_mode()));
             return {};
             return {};
         }
         }
-        m_cached_environment_coordinate = {};
+        cached_environment_coordinate = {};
     }
     }
 
 
     auto const& string = interpreter.current_executable().get_identifier(m_identifier);
     auto const& string = interpreter.current_executable().get_identifier(m_identifier);
     auto reference = TRY(vm.resolve_binding(string));
     auto reference = TRY(vm.resolve_binding(string));
     if (reference.environment_coordinate().has_value())
     if (reference.environment_coordinate().has_value())
-        m_cached_environment_coordinate = reference.environment_coordinate();
+        cached_environment_coordinate = reference.environment_coordinate();
     interpreter.accumulator() = TRY(reference.get_value(vm));
     interpreter.accumulator() = TRY(reference.get_value(vm));
     return {};
     return {};
 }
 }
@@ -837,27 +838,28 @@ ThrowCompletionOr<void> GetCalleeAndThisFromEnvironment::execute_impl(Bytecode::
 {
 {
     auto& vm = interpreter.vm();
     auto& vm = interpreter.vm();
 
 
-    if (m_cached_environment_coordinate.has_value()) {
+    auto& cached_environment_coordinate = interpreter.current_executable().environment_variable_caches[m_cache_index];
+    if (cached_environment_coordinate.has_value()) {
         auto environment = vm.running_execution_context().lexical_environment;
         auto environment = vm.running_execution_context().lexical_environment;
-        for (size_t i = 0; i < m_cached_environment_coordinate->hops; ++i)
+        for (size_t i = 0; i < cached_environment_coordinate->hops; ++i)
             environment = environment->outer_environment();
             environment = environment->outer_environment();
         VERIFY(environment);
         VERIFY(environment);
         VERIFY(environment->is_declarative_environment());
         VERIFY(environment->is_declarative_environment());
         if (!environment->is_permanently_screwed_by_eval()) {
         if (!environment->is_permanently_screwed_by_eval()) {
-            interpreter.reg(m_callee_reg) = TRY(verify_cast<DeclarativeEnvironment>(*environment).get_binding_value_direct(vm, m_cached_environment_coordinate.value().index, vm.in_strict_mode()));
+            interpreter.reg(m_callee_reg) = TRY(verify_cast<DeclarativeEnvironment>(*environment).get_binding_value_direct(vm, cached_environment_coordinate.value().index, vm.in_strict_mode()));
             Value this_value = js_undefined();
             Value this_value = js_undefined();
             if (auto base_object = environment->with_base_object())
             if (auto base_object = environment->with_base_object())
                 this_value = base_object;
                 this_value = base_object;
             interpreter.reg(m_this_reg) = this_value;
             interpreter.reg(m_this_reg) = this_value;
             return {};
             return {};
         }
         }
-        m_cached_environment_coordinate = {};
+        cached_environment_coordinate = {};
     }
     }
 
 
     auto const& string = interpreter.current_executable().get_identifier(m_identifier);
     auto const& string = interpreter.current_executable().get_identifier(m_identifier);
     auto reference = TRY(vm.resolve_binding(string));
     auto reference = TRY(vm.resolve_binding(string));
     if (reference.environment_coordinate().has_value())
     if (reference.environment_coordinate().has_value())
-        m_cached_environment_coordinate = reference.environment_coordinate();
+        cached_environment_coordinate = reference.environment_coordinate();
 
 
     interpreter.reg(m_callee_reg) = TRY(reference.get_value(vm));
     interpreter.reg(m_callee_reg) = TRY(reference.get_value(vm));
 
 

+ 8 - 7
Userland/Libraries/LibJS/Bytecode/Op.h

@@ -18,7 +18,6 @@
 #include <LibJS/Bytecode/StringTable.h>
 #include <LibJS/Bytecode/StringTable.h>
 #include <LibJS/Heap/Cell.h>
 #include <LibJS/Heap/Cell.h>
 #include <LibJS/Runtime/Environment.h>
 #include <LibJS/Runtime/Environment.h>
-#include <LibJS/Runtime/EnvironmentCoordinate.h>
 #include <LibJS/Runtime/Iterator.h>
 #include <LibJS/Runtime/Iterator.h>
 #include <LibJS/Runtime/Value.h>
 #include <LibJS/Runtime/Value.h>
 #include <LibJS/Runtime/ValueTraits.h>
 #include <LibJS/Runtime/ValueTraits.h>
@@ -451,11 +450,12 @@ private:
 
 
 class GetCalleeAndThisFromEnvironment final : public Instruction {
 class GetCalleeAndThisFromEnvironment final : public Instruction {
 public:
 public:
-    explicit GetCalleeAndThisFromEnvironment(IdentifierTableIndex identifier, Register callee_reg, Register this_reg)
+    explicit GetCalleeAndThisFromEnvironment(IdentifierTableIndex identifier, Register callee_reg, Register this_reg, u32 cache_index)
         : Instruction(Type::GetCalleeAndThisFromEnvironment, sizeof(*this))
         : Instruction(Type::GetCalleeAndThisFromEnvironment, sizeof(*this))
         , m_identifier(identifier)
         , m_identifier(identifier)
         , m_callee_reg(callee_reg)
         , m_callee_reg(callee_reg)
         , m_this_reg(this_reg)
         , m_this_reg(this_reg)
+        , m_cache_index(cache_index)
     {
     {
     }
     }
 
 
@@ -463,20 +463,21 @@ public:
     DeprecatedString to_deprecated_string_impl(Bytecode::Executable const&) const;
     DeprecatedString to_deprecated_string_impl(Bytecode::Executable const&) const;
 
 
     IdentifierTableIndex identifier() const { return m_identifier; }
     IdentifierTableIndex identifier() const { return m_identifier; }
+    u32 cache_index() const { return m_cache_index; }
 
 
 private:
 private:
     IdentifierTableIndex m_identifier;
     IdentifierTableIndex m_identifier;
     Register m_callee_reg;
     Register m_callee_reg;
     Register m_this_reg;
     Register m_this_reg;
-
-    Optional<EnvironmentCoordinate> mutable m_cached_environment_coordinate;
+    u32 m_cache_index { 0 };
 };
 };
 
 
 class GetVariable final : public Instruction {
 class GetVariable final : public Instruction {
 public:
 public:
-    explicit GetVariable(IdentifierTableIndex identifier)
+    explicit GetVariable(IdentifierTableIndex identifier, u32 cache_index)
         : Instruction(Type::GetVariable, sizeof(*this))
         : Instruction(Type::GetVariable, sizeof(*this))
         , m_identifier(identifier)
         , m_identifier(identifier)
+        , m_cache_index(cache_index)
     {
     {
     }
     }
 
 
@@ -484,11 +485,11 @@ public:
     DeprecatedString to_deprecated_string_impl(Bytecode::Executable const&) const;
     DeprecatedString to_deprecated_string_impl(Bytecode::Executable const&) const;
 
 
     IdentifierTableIndex identifier() const { return m_identifier; }
     IdentifierTableIndex identifier() const { return m_identifier; }
+    u32 cache_index() const { return m_cache_index; }
 
 
 private:
 private:
     IdentifierTableIndex m_identifier;
     IdentifierTableIndex m_identifier;
-
-    Optional<EnvironmentCoordinate> mutable m_cached_environment_coordinate;
+    u32 m_cache_index { 0 };
 };
 };
 
 
 class GetGlobal final : public Instruction {
 class GetGlobal final : public Instruction {