diff --git a/Userland/Libraries/LibJS/Bytecode/BasicBlock.h b/Userland/Libraries/LibJS/Bytecode/BasicBlock.h index fe046434a51..653989de31f 100644 --- a/Userland/Libraries/LibJS/Bytecode/BasicBlock.h +++ b/Userland/Libraries/LibJS/Bytecode/BasicBlock.h @@ -18,8 +18,8 @@ struct UnwindInfo { BasicBlock const* handler; BasicBlock const* finalizer; - Handle lexical_environment; - Handle variable_environment; + JS::GCPtr lexical_environment; + JS::GCPtr variable_environment; }; class BasicBlock { diff --git a/Userland/Libraries/LibJS/Bytecode/Interpreter.cpp b/Userland/Libraries/LibJS/Bytecode/Interpreter.cpp index d0ec45c665b..317ebe5bd14 100644 --- a/Userland/Libraries/LibJS/Bytecode/Interpreter.cpp +++ b/Userland/Libraries/LibJS/Bytecode/Interpreter.cpp @@ -50,6 +50,19 @@ Interpreter::~Interpreter() { } +void Interpreter::visit_edges(Cell::Visitor& visitor) +{ + if (m_return_value.has_value()) + visitor.visit(*m_return_value); + if (m_saved_return_value.has_value()) + visitor.visit(*m_saved_return_value); + if (m_saved_exception.has_value()) + visitor.visit(*m_saved_exception); + for (auto& window : m_register_windows) { + window.visit([&](auto& value) { value->visit_edges(visitor); }); + } +} + // 16.1.6 ScriptEvaluation ( scriptRecord ), https://tc39.es/ecma262/#sec-runtime-semantics-scriptevaluation ThrowCompletionOr Interpreter::run(Script& script_record, JS::GCPtr lexical_environment_override) { @@ -223,7 +236,7 @@ Interpreter::ValueAndFrame Interpreter::run_and_return_frame(Realm& realm, Execu 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 = make_handle(exception_value); + m_saved_exception = exception_value; if (unwind_contexts().is_empty()) break; auto& unwind_context = unwind_contexts().last(); @@ -254,7 +267,7 @@ Interpreter::ValueAndFrame Interpreter::run_and_return_frame(Realm& realm, Execu will_jump = true; break; } - if (!m_return_value.is_empty()) { + if (m_return_value.has_value()) { 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, @@ -273,7 +286,7 @@ Interpreter::ValueAndFrame Interpreter::run_and_return_frame(Realm& realm, Execu if (!unwind_contexts().is_empty() && !will_yield) { auto& unwind_context = unwind_contexts().last(); if (unwind_context.executable == m_current_executable && unwind_context.finalizer) { - m_saved_return_value = make_handle(m_return_value); + m_saved_return_value = m_return_value; m_return_value = {}; m_current_block = unwind_context.finalizer; // the unwind_context will be pop'ed when entering the finally block @@ -284,7 +297,7 @@ Interpreter::ValueAndFrame Interpreter::run_and_return_frame(Realm& realm, Execu if (pc.at_end()) break; - if (!m_saved_exception.is_null()) + if (m_saved_exception.has_value()) break; if (will_return) @@ -307,12 +320,10 @@ Interpreter::ValueAndFrame Interpreter::run_and_return_frame(Realm& realm, Execu auto frame = pop_register_window(); Value return_value = js_undefined(); - if (!m_return_value.is_empty()) { - return_value = m_return_value; - m_return_value = {}; - } else if (!m_saved_return_value.is_null() && m_saved_exception.is_null()) { - return_value = m_saved_return_value.value(); - m_saved_return_value = {}; + if (m_return_value.has_value()) { + return_value = m_return_value.release_value(); + } else if (m_saved_return_value.has_value() && !m_saved_exception.has_value()) { + return_value = m_saved_return_value.release_value(); } // NOTE: The return value from a called function is put into $0 in the caller context. @@ -330,7 +341,7 @@ Interpreter::ValueAndFrame Interpreter::run_and_return_frame(Realm& realm, Execu vm().finish_execution_generation(); - if (!m_saved_exception.is_null()) { + if (m_saved_exception.has_value()) { Value thrown_value = m_saved_exception.value(); m_saved_exception = {}; m_saved_return_value = {}; @@ -361,15 +372,12 @@ void Interpreter::leave_unwind_context() ThrowCompletionOr Interpreter::continue_pending_unwind(Label const& resume_label) { - if (!m_saved_exception.is_null()) { - auto result = throw_completion(m_saved_exception.value()); - m_saved_exception = {}; - return result; + if (m_saved_exception.has_value()) { + return throw_completion(m_saved_exception.release_value()); } - if (!m_saved_return_value.is_null()) { - do_return(m_saved_return_value.value()); - m_saved_return_value = {}; + if (m_saved_return_value.has_value()) { + do_return(m_saved_return_value.release_value()); return {}; } diff --git a/Userland/Libraries/LibJS/Bytecode/Interpreter.h b/Userland/Libraries/LibJS/Bytecode/Interpreter.h index ba146917237..515c50089e0 100644 --- a/Userland/Libraries/LibJS/Bytecode/Interpreter.h +++ b/Userland/Libraries/LibJS/Bytecode/Interpreter.h @@ -10,7 +10,6 @@ #include #include #include -#include #include #include #include @@ -21,9 +20,22 @@ class InstructionStreamIterator; class PassManager; struct RegisterWindow { - MarkedVector registers; - MarkedVector> saved_lexical_environments; - MarkedVector> saved_variable_environments; + void visit_edges(Cell::Visitor& visitor) + { + for (auto const& value : registers) + visitor.visit(value); + for (auto const& environment : saved_lexical_environments) + visitor.visit(environment); + for (auto const& environment : saved_variable_environments) + visitor.visit(environment); + for (auto& context : unwind_contexts) { + visitor.visit(context.lexical_environment); + visitor.visit(context.variable_environment); + } + } + Vector registers; + Vector> saved_lexical_environments; + Vector> saved_variable_environments; Vector unwind_contexts; }; @@ -90,6 +102,8 @@ public: VM::InterpreterExecutionScope ast_interpreter_scope(Realm&); + void visit_edges(Cell::Visitor&); + private: RegisterWindow& window() { @@ -112,10 +126,10 @@ private: Span m_current_register_window; Optional m_pending_jump; BasicBlock const* m_scheduled_jump { nullptr }; - Value m_return_value; - Handle m_saved_return_value; + Optional m_return_value; + Optional m_saved_return_value; + Optional m_saved_exception; Executable const* m_current_executable { nullptr }; - Handle m_saved_exception; OwnPtr m_ast_interpreter; BasicBlock const* m_current_block { nullptr }; InstructionStreamIterator* m_pc { nullptr }; diff --git a/Userland/Libraries/LibJS/Heap/Heap.cpp b/Userland/Libraries/LibJS/Heap/Heap.cpp index eceee1264c8..659582f7666 100644 --- a/Userland/Libraries/LibJS/Heap/Heap.cpp +++ b/Userland/Libraries/LibJS/Heap/Heap.cpp @@ -10,6 +10,7 @@ #include #include #include +#include #include #include #include @@ -270,6 +271,10 @@ void Heap::mark_live_cells(HashTable const& roots) dbgln_if(HEAP_DEBUG, "mark_live_cells:"); MarkingVisitor visitor(roots); + + if (auto* bytecode_interpreter = vm().bytecode_interpreter_if_exists()) + bytecode_interpreter->visit_edges(visitor); + visitor.mark_all_live_cells(); for (auto& inverse_root : m_uprooted_cells) diff --git a/Userland/Libraries/LibJS/Runtime/GeneratorObject.cpp b/Userland/Libraries/LibJS/Runtime/GeneratorObject.cpp index 4ec105b18d0..192034e3ef9 100644 --- a/Userland/Libraries/LibJS/Runtime/GeneratorObject.cpp +++ b/Userland/Libraries/LibJS/Runtime/GeneratorObject.cpp @@ -52,6 +52,8 @@ void GeneratorObject::visit_edges(Cell::Visitor& visitor) visitor.visit(m_generating_function); visitor.visit(m_previous_value); m_execution_context.visit_edges(visitor); + if (m_frame.has_value()) + m_frame->visit_edges(visitor); } // 27.5.3.2 GeneratorValidate ( generator, generatorBrand ), https://tc39.es/ecma262/#sec-generatorvalidate