From 4a8bfcdd1cba2f79ec8bdcdc327ecfb4e497196f Mon Sep 17 00:00:00 2001 From: Andreas Kling Date: Mon, 21 Sep 2020 15:28:09 +0200 Subject: [PATCH] LibJS: Move the current exception from Interpreter to VM This will allow us to throw exceptions even when there is no active interpreter in the VM. --- Applications/Browser/ConsoleWidget.cpp | 2 +- Applications/Spreadsheet/Spreadsheet.cpp | 4 ++-- Libraries/LibJS/AST.cpp | 4 ++-- Libraries/LibJS/Interpreter.cpp | 4 +--- Libraries/LibJS/Interpreter.h | 9 +-------- Libraries/LibJS/Runtime/VM.cpp | 2 ++ Libraries/LibJS/Runtime/VM.h | 10 ++++++++++ Libraries/LibWeb/DOM/Document.cpp | 2 +- Libraries/LibWeb/DOM/EventDispatcher.cpp | 2 +- Libraries/LibWeb/DOM/Window.cpp | 4 ++-- Userland/js.cpp | 2 +- Userland/test-web.cpp | 4 ++-- 12 files changed, 26 insertions(+), 23 deletions(-) diff --git a/Applications/Browser/ConsoleWidget.cpp b/Applications/Browser/ConsoleWidget.cpp index 803efa6b546..fb1d37989d1 100644 --- a/Applications/Browser/ConsoleWidget.cpp +++ b/Applications/Browser/ConsoleWidget.cpp @@ -102,7 +102,7 @@ ConsoleWidget::ConsoleWidget() output_html.append(JS::MarkupGenerator::html_from_value(m_interpreter->exception()->value())); print_html(output_html.string_view()); - m_interpreter->clear_exception(); + m_interpreter->vm().clear_exception(); return; } diff --git a/Applications/Spreadsheet/Spreadsheet.cpp b/Applications/Spreadsheet/Spreadsheet.cpp index fb250d177ee..15d1a4499a8 100644 --- a/Applications/Spreadsheet/Spreadsheet.cpp +++ b/Applications/Spreadsheet/Spreadsheet.cpp @@ -73,7 +73,7 @@ Sheet::Sheet(Workbook& workbook) dbg() << "Spreadsheet: Failed to run runtime code: "; for (auto& t : exc->trace()) dbg() << t; - interpreter().clear_exception(); + interpreter().vm().clear_exception(); } } } @@ -160,7 +160,7 @@ JS::Value Sheet::evaluate(const StringView& source, Cell* on_behalf_of) interpreter().run(global_object(), program); if (interpreter().exception()) { auto exc = interpreter().exception()->value(); - interpreter().clear_exception(); + interpreter().vm().clear_exception(); return exc; } diff --git a/Libraries/LibJS/AST.cpp b/Libraries/LibJS/AST.cpp index 96a8d49d148..d2a8a85cacb 100644 --- a/Libraries/LibJS/AST.cpp +++ b/Libraries/LibJS/AST.cpp @@ -1796,7 +1796,7 @@ Value TryStatement::execute(Interpreter& interpreter, GlobalObject& global_objec interpreter.execute_statement(global_object, m_block, {}, ScopeType::Try); if (auto* exception = interpreter.exception()) { if (m_handler) { - interpreter.clear_exception(); + interpreter.vm().clear_exception(); ArgumentVector arguments { { m_handler->parameter(), exception->value() } }; interpreter.execute_statement(global_object, m_handler->body(), move(arguments)); } @@ -1806,7 +1806,7 @@ Value TryStatement::execute(Interpreter& interpreter, GlobalObject& global_objec // Keep, if any, and then clear the current exception so we can // execute() the finalizer without an exception in our way. auto* previous_exception = interpreter.exception(); - interpreter.clear_exception(); + interpreter.vm().clear_exception(); interpreter.stop_unwind(); m_finalizer->execute(interpreter, global_object); // If we previously had an exception and the finalizer didn't diff --git a/Libraries/LibJS/Interpreter.cpp b/Libraries/LibJS/Interpreter.cpp index 24927524f6c..e56fb20e116 100644 --- a/Libraries/LibJS/Interpreter.cpp +++ b/Libraries/LibJS/Interpreter.cpp @@ -225,8 +225,6 @@ Symbol* Interpreter::get_global_symbol(const String& description) void Interpreter::gather_roots(HashTable& roots) { - roots.set(m_exception); - if (m_last_value.is_cell()) roots.set(m_last_value.as_cell()); @@ -345,7 +343,7 @@ void Interpreter::throw_exception(Exception* exception) } } #endif - m_exception = exception; + vm().set_exception({}, exception); unwind(ScopeType::Try); } diff --git a/Libraries/LibJS/Interpreter.h b/Libraries/LibJS/Interpreter.h index 645520ed01b..a27abff4b52 100644 --- a/Libraries/LibJS/Interpreter.h +++ b/Libraries/LibJS/Interpreter.h @@ -113,6 +113,7 @@ public: VM& vm() { return *m_vm; } Heap& heap() { return vm().heap(); } + Exception* exception() { return vm().exception(); } void unwind(ScopeType type, FlyString label = {}) { @@ -195,12 +196,6 @@ public: return m_call_stack.last().this_value; } - Exception* exception() - { - return m_exception; - } - void clear_exception() { m_exception = nullptr; } - template void throw_exception(Args&&... args) { @@ -252,8 +247,6 @@ private: Handle m_global_object; - Exception* m_exception { nullptr }; - ScopeType m_unwind_until { ScopeType::None }; FlyString m_unwind_until_label; diff --git a/Libraries/LibJS/Runtime/VM.cpp b/Libraries/LibJS/Runtime/VM.cpp index 4517040ede8..a6c684b8013 100644 --- a/Libraries/LibJS/Runtime/VM.cpp +++ b/Libraries/LibJS/Runtime/VM.cpp @@ -81,6 +81,8 @@ VM::InterpreterExecutionScope::~InterpreterExecutionScope() void VM::gather_roots(HashTable& roots) { + if (m_exception) + roots.set(m_exception); for (auto* interpreter : m_interpreters) interpreter->gather_roots(roots); } diff --git a/Libraries/LibJS/Runtime/VM.h b/Libraries/LibJS/Runtime/VM.h index 38a1f59b090..0cef4ead9ad 100644 --- a/Libraries/LibJS/Runtime/VM.h +++ b/Libraries/LibJS/Runtime/VM.h @@ -45,10 +45,18 @@ public: void push_interpreter(Interpreter&); void pop_interpreter(Interpreter&); + Exception* exception() + { + return m_exception; + } + void set_exception(Badge, Exception* exception) { m_exception = exception; } + void clear_exception() { m_exception = nullptr; } + class InterpreterExecutionScope { public: InterpreterExecutionScope(Interpreter&); ~InterpreterExecutionScope(); + private: Interpreter& m_interpreter; }; @@ -58,6 +66,8 @@ public: private: VM(); + Exception* m_exception { nullptr }; + Heap m_heap; Vector m_interpreters; }; diff --git a/Libraries/LibWeb/DOM/Document.cpp b/Libraries/LibWeb/DOM/Document.cpp index d4814297b2e..d4ebfed6de8 100644 --- a/Libraries/LibWeb/DOM/Document.cpp +++ b/Libraries/LibWeb/DOM/Document.cpp @@ -434,7 +434,7 @@ JS::Value Document::run_javascript(const StringView& source) auto& interpreter = document().interpreter(); auto result = interpreter.run(interpreter.global_object(), *program); if (interpreter.exception()) - interpreter.clear_exception(); + interpreter.vm().clear_exception(); return result; } diff --git a/Libraries/LibWeb/DOM/EventDispatcher.cpp b/Libraries/LibWeb/DOM/EventDispatcher.cpp index bbdbbbc065d..682ce91a09d 100644 --- a/Libraries/LibWeb/DOM/EventDispatcher.cpp +++ b/Libraries/LibWeb/DOM/EventDispatcher.cpp @@ -48,7 +48,7 @@ void EventDispatcher::dispatch(EventTarget& target, NonnullRefPtr event) auto& interpreter = target.script_execution_context()->interpreter(); (void)interpreter.call(function, this_value, Bindings::wrap(global_object, target)); if (interpreter.exception()) - interpreter.clear_exception(); + interpreter.vm().clear_exception(); } } diff --git a/Libraries/LibWeb/DOM/Window.cpp b/Libraries/LibWeb/DOM/Window.cpp index 8b218a68ca0..6661639ce6f 100644 --- a/Libraries/LibWeb/DOM/Window.cpp +++ b/Libraries/LibWeb/DOM/Window.cpp @@ -97,7 +97,7 @@ void Window::timer_did_fire(Badge, Timer& timer) auto& interpreter = document().interpreter(); (void)interpreter.call(timer.callback(), wrapper()); if (interpreter.exception()) - interpreter.clear_exception(); + interpreter.vm().clear_exception(); } i32 Window::allocate_timer_id(Badge) @@ -126,7 +126,7 @@ i32 Window::request_animation_frame(JS::Function& callback) fake_timestamp += 10; (void)interpreter.call(function, {}, JS::Value(fake_timestamp)); if (interpreter.exception()) - interpreter.clear_exception(); + interpreter.vm().clear_exception(); GUI::DisplayLink::unregister_callback(link_id); }); diff --git a/Userland/js.cpp b/Userland/js.cpp index 08271c95d60..da6216fdcdb 100644 --- a/Userland/js.cpp +++ b/Userland/js.cpp @@ -361,7 +361,7 @@ static bool parse_and_run(JS::Interpreter& interpreter, const StringView& source for (auto& function_name : trace) printf(" -> %s\n", function_name.characters()); } - interpreter.clear_exception(); + interpreter.vm().clear_exception(); return false; } if (s_print_last_result) diff --git a/Userland/test-web.cpp b/Userland/test-web.cpp index c17a4aeadbd..7f493ac6ac2 100644 --- a/Userland/test-web.cpp +++ b/Userland/test-web.cpp @@ -363,7 +363,7 @@ JSFileResult TestRunner::run_file_test(const String& test_path) auto& before_initial_page_load = new_interpreter.get_variable("__BeforeInitialPageLoad__", new_interpreter.global_object()).as_function(); (void)new_interpreter.call(before_initial_page_load, JS::js_undefined()); if (new_interpreter.exception()) - new_interpreter.clear_exception(); + new_interpreter.vm().clear_exception(); // Now parse the HTML page. parser.run(page_to_load); @@ -373,7 +373,7 @@ JSFileResult TestRunner::run_file_test(const String& test_path) auto& after_initial_page_load = new_interpreter.get_variable("__AfterInitialPageLoad__", new_interpreter.global_object()).as_function(); (void)new_interpreter.call(after_initial_page_load, JS::js_undefined()); if (new_interpreter.exception()) - new_interpreter.clear_exception(); + new_interpreter.vm().clear_exception(); auto test_json = get_test_results(new_interpreter); if (!test_json.has_value()) {