Browse Source

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.
Andreas Kling 4 năm trước cách đây
mục cha
commit
4a8bfcdd1c

+ 1 - 1
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;
         }
 

+ 2 - 2
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;
     }
 

+ 2 - 2
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

+ 1 - 3
Libraries/LibJS/Interpreter.cpp

@@ -225,8 +225,6 @@ Symbol* Interpreter::get_global_symbol(const String& description)
 
 void Interpreter::gather_roots(HashTable<Cell*>& 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);
 }
 

+ 1 - 8
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<typename T, typename... Args>
     void throw_exception(Args&&... args)
     {
@@ -252,8 +247,6 @@ private:
 
     Handle<Object> m_global_object;
 
-    Exception* m_exception { nullptr };
-
     ScopeType m_unwind_until { ScopeType::None };
     FlyString m_unwind_until_label;
 

+ 2 - 0
Libraries/LibJS/Runtime/VM.cpp

@@ -81,6 +81,8 @@ VM::InterpreterExecutionScope::~InterpreterExecutionScope()
 
 void VM::gather_roots(HashTable<Cell*>& roots)
 {
+    if (m_exception)
+        roots.set(m_exception);
     for (auto* interpreter : m_interpreters)
         interpreter->gather_roots(roots);
 }

+ 10 - 0
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<Interpreter>, 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<Interpreter*> m_interpreters;
 };

+ 1 - 1
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;
 }
 

+ 1 - 1
Libraries/LibWeb/DOM/EventDispatcher.cpp

@@ -48,7 +48,7 @@ void EventDispatcher::dispatch(EventTarget& target, NonnullRefPtr<Event> 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();
     }
 }
 

+ 2 - 2
Libraries/LibWeb/DOM/Window.cpp

@@ -97,7 +97,7 @@ void Window::timer_did_fire(Badge<Timer>, 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<Timer>)
@@ -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);
     });
 

+ 1 - 1
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)

+ 2 - 2
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()) {