Przeglądaj źródła

LibJS: Keep return value in a call frame register

Andreas Kling 1 rok temu
rodzic
commit
0c746366cc

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

@@ -31,8 +31,6 @@ Interpreter::~Interpreter()
 
 void Interpreter::visit_edges(Cell::Visitor& visitor)
 {
-    if (m_return_value.has_value())
-        visitor.visit(*m_return_value);
     for (auto& frame : m_call_frames) {
         frame.visit([&](auto& value) { value->visit_edges(visitor); });
     }
@@ -226,7 +224,7 @@ Interpreter::ValueAndFrame Interpreter::run_and_return_frame(Executable& executa
                 will_jump = true;
                 break;
             }
-            if (m_return_value.has_value()) {
+            if (!reg(Register::return_value()).is_empty()) {
                 will_return = true;
                 // Note: A `yield` statement will not go through a finally statement,
                 //       hence we need to set a flag to not do so,
@@ -245,7 +243,8 @@ Interpreter::ValueAndFrame Interpreter::run_and_return_frame(Executable& executa
         if (!unwind_contexts().is_empty() && !will_yield) {
             auto& unwind_context = unwind_contexts().last();
             if (unwind_context.executable == m_current_executable && unwind_context.finalizer) {
-                reg(Register::saved_return_value()) = m_return_value.release_value();
+                reg(Register::saved_return_value()) = reg(Register::return_value());
+                reg(Register::return_value()) = {};
                 m_current_block = unwind_context.finalizer;
                 // the unwind_context will be pop'ed when entering the finally block
                 continue;
@@ -275,18 +274,15 @@ Interpreter::ValueAndFrame Interpreter::run_and_return_frame(Executable& executa
         }
     }
 
-    auto saved_return_value = reg(Register::saved_return_value());
+    auto return_value = js_undefined();
+    if (!reg(Register::return_value()).is_empty())
+        return_value = reg(Register::return_value());
+    else if (!reg(Register::saved_return_value()).is_empty())
+        return_value = reg(Register::saved_return_value());
     auto exception = reg(Register::exception());
 
     auto frame = pop_call_frame();
 
-    Value return_value = js_undefined();
-    if (m_return_value.has_value()) {
-        return_value = m_return_value.release_value();
-    } else if (!saved_return_value.is_empty()) {
-        return_value = saved_return_value;
-    }
-
     // NOTE: The return value from a called function is put into $0 in the caller context.
     if (!m_call_frames.is_empty())
         call_frame().registers[0] = return_value;
@@ -374,6 +370,7 @@ void Interpreter::push_call_frame(Variant<NonnullOwnPtr<CallFrame>, CallFrame*>
     m_call_frames.append(move(frame));
     this->call_frame().registers.resize(register_count);
     m_current_call_frame = this->call_frame().registers;
+    reg(Register::return_value()) = {};
 }
 
 Variant<NonnullOwnPtr<CallFrame>, CallFrame*> Interpreter::pop_call_frame()

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

@@ -74,9 +74,9 @@ public:
         VERIFY(unwind_contexts().last().finalizer);
         jump(Label { *unwind_contexts().last().finalizer });
     }
-    void do_return(Value return_value)
+    void do_return(Value value)
     {
-        m_return_value = return_value;
+        reg(Register::return_value()) = value;
         reg(Register::exception()) = {};
     }
 
@@ -114,7 +114,6 @@ private:
     Span<Value> m_current_call_frame;
     Optional<BasicBlock const*> m_pending_jump;
     BasicBlock const* m_scheduled_jump { nullptr };
-    Optional<Value> m_return_value;
     Executable* m_current_executable { nullptr };
     BasicBlock const* m_current_block { nullptr };
     Optional<InstructionStreamIterator&> m_pc {};

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

@@ -39,7 +39,13 @@ public:
         return Register(this_value_index);
     }
 
-    static constexpr u32 reserved_register_count = 4;
+    static constexpr Register return_value()
+    {
+        constexpr u32 return_value_index = 4;
+        return Register(return_value_index);
+    }
+
+    static constexpr u32 reserved_register_count = 5;
 
     constexpr explicit Register(u32 index)
         : m_index(index)