Prechádzať zdrojové kódy

LibJS: Keep current exception in a call frame register

Instead of keeping it in a Bytecode::Interpreter member, move it into
a dedicated call frame register.
Andreas Kling 1 rok pred
rodič
commit
3887b840a3

+ 1 - 1
Userland/Libraries/LibJS/Bytecode/Generator.h

@@ -252,7 +252,7 @@ private:
     NonnullOwnPtr<IdentifierTable> m_identifier_table;
     NonnullOwnPtr<RegexTable> m_regex_table;
 
-    u32 m_next_register { 2 };
+    u32 m_next_register { 3 };
     u32 m_next_block { 1 };
     u32 m_next_property_lookup_cache { 0 };
     u32 m_next_global_variable_cache { 0 };

+ 11 - 17
Userland/Libraries/LibJS/Bytecode/Interpreter.cpp

@@ -33,8 +33,6 @@ void Interpreter::visit_edges(Cell::Visitor& visitor)
 {
     if (m_return_value.has_value())
         visitor.visit(*m_return_value);
-    if (m_saved_exception.has_value())
-        visitor.visit(*m_saved_exception);
     for (auto& frame : m_call_frames) {
         frame.visit([&](auto& value) { value->visit_edges(visitor); });
     }
@@ -171,7 +169,6 @@ Interpreter::ValueAndFrame Interpreter::run_and_return_frame(Executable& executa
 
     TemporaryChange restore_executable { m_current_executable, &executable };
     TemporaryChange restore_saved_jump { m_scheduled_jump, static_cast<BasicBlock const*>(nullptr) };
-    TemporaryChange restore_saved_exception { m_saved_exception, {} };
 
     VERIFY(!vm().execution_context_stack().is_empty());
 
@@ -196,8 +193,7 @@ Interpreter::ValueAndFrame Interpreter::run_and_return_frame(Executable& executa
             auto& instruction = *pc;
             auto ran_or_error = instruction.execute(*this);
             if (ran_or_error.is_error()) {
-                auto exception_value = *ran_or_error.throw_completion().value();
-                m_saved_exception = exception_value;
+                reg(Register::exception()) = *ran_or_error.throw_completion().value();
                 if (unwind_contexts().is_empty())
                     break;
                 auto& unwind_context = unwind_contexts().last();
@@ -208,8 +204,8 @@ Interpreter::ValueAndFrame Interpreter::run_and_return_frame(Executable& executa
                     m_current_block = unwind_context.handler;
                     unwind_context.handler_called = true;
 
-                    accumulator() = exception_value;
-                    m_saved_exception = {};
+                    accumulator() = reg(Register::exception());
+                    reg(Register::exception()) = {};
                     will_jump = true;
                     break;
                 }
@@ -219,7 +215,7 @@ Interpreter::ValueAndFrame Interpreter::run_and_return_frame(Executable& executa
                     // from the `finally` block. But if the exception is from the `try` block, and has already been
                     // handled by `catch`, we swallow it.
                     if (!unwind_context.handler_called)
-                        m_saved_exception = {};
+                        reg(Register::exception()) = {};
                     will_jump = true;
                     break;
                 }
@@ -261,7 +257,7 @@ Interpreter::ValueAndFrame Interpreter::run_and_return_frame(Executable& executa
         if (pc.at_end())
             break;
 
-        if (m_saved_exception.has_value())
+        if (!reg(Register::exception()).is_empty())
             break;
 
         if (will_return)
@@ -282,6 +278,7 @@ Interpreter::ValueAndFrame Interpreter::run_and_return_frame(Executable& executa
     }
 
     auto saved_return_value = reg(Register::saved_return_value());
+    auto exception = reg(Register::exception());
 
     auto frame = pop_call_frame();
 
@@ -302,12 +299,10 @@ Interpreter::ValueAndFrame Interpreter::run_and_return_frame(Executable& executa
 
     vm().finish_execution_generation();
 
-    if (m_saved_exception.has_value()) {
-        Value thrown_value = m_saved_exception.value();
-        m_saved_exception = {};
+    if (!exception.is_empty()) {
         if (auto* call_frame = frame.get_pointer<NonnullOwnPtr<CallFrame>>())
-            return { throw_completion(thrown_value), move(*call_frame) };
-        return { throw_completion(thrown_value), nullptr };
+            return { throw_completion(exception), move(*call_frame) };
+        return { throw_completion(exception), nullptr };
     }
 
     if (auto* call_frame = frame.get_pointer<NonnullOwnPtr<CallFrame>>())
@@ -331,9 +326,8 @@ void Interpreter::leave_unwind_context()
 
 ThrowCompletionOr<void> Interpreter::continue_pending_unwind(Label const& resume_label)
 {
-    if (m_saved_exception.has_value()) {
-        return throw_completion(m_saved_exception.release_value());
-    }
+    if (auto exception = reg(Register::exception()); !exception.is_empty())
+        return throw_completion(exception);
 
     if (!saved_return_value().is_empty()) {
         do_return(saved_return_value());

+ 1 - 2
Userland/Libraries/LibJS/Bytecode/Interpreter.h

@@ -77,7 +77,7 @@ public:
     void do_return(Value return_value)
     {
         m_return_value = return_value;
-        m_saved_exception = {};
+        reg(Register::exception()) = {};
     }
 
     void enter_unwind_context(Optional<Label> handler_target, Optional<Label> finalizer_target);
@@ -118,7 +118,6 @@ private:
     BasicBlock const* m_scheduled_jump { nullptr };
     Optional<Value> m_this_value;
     Optional<Value> m_return_value;
-    Optional<Value> m_saved_exception;
     Executable* m_current_executable { nullptr };
     BasicBlock const* m_current_block { nullptr };
     Optional<InstructionStreamIterator&> m_pc {};

+ 7 - 0
Userland/Libraries/LibJS/Bytecode/Register.h

@@ -26,6 +26,13 @@ public:
         return Register(saved_return_value_index);
     }
 
+    static constexpr u32 exception_index = 2;
+
+    static constexpr Register exception()
+    {
+        return Register(exception_index);
+    }
+
     constexpr explicit Register(u32 index)
         : m_index(index)
     {