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:
parent
675b482fe7
commit
4a8bfcdd1c
Notes:
sideshowbarker
2024-07-19 02:16:42 +09:00
Author: https://github.com/awesomekling Commit: https://github.com/SerenityOS/serenity/commit/4a8bfcdd1cb
12 changed files with 26 additions and 23 deletions
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
});
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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()) {
|
||||
|
|
Loading…
Add table
Reference in a new issue