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.
This commit is contained in:
Andreas Kling 2020-09-21 15:28:09 +02:00
parent 675b482fe7
commit 4a8bfcdd1c
Notes: sideshowbarker 2024-07-19 02:16:42 +09:00
12 changed files with 26 additions and 23 deletions

View file

@ -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;
}

View file

@ -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;
}

View file

@ -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

View file

@ -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);
}

View file

@ -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;

View file

@ -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);
}

View file

@ -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;
};

View file

@ -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;
}

View file

@ -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();
}
}

View file

@ -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);
});

View file

@ -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)

View file

@ -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()) {