From fcc72a787bf45559df396baad0986df6e12c02d9 Mon Sep 17 00:00:00 2001 From: Andreas Kling Date: Tue, 8 Aug 2023 07:12:40 +0200 Subject: [PATCH] Spreadsheet: Use the LibJS bytecode VM --- Userland/Applications/Spreadsheet/Cell.cpp | 2 +- .../Spreadsheet/CellType/String.cpp | 2 +- .../Applications/Spreadsheet/Spreadsheet.cpp | 40 +++++++++---------- .../Applications/Spreadsheet/Spreadsheet.h | 7 +++- .../Applications/Spreadsheet/Workbook.cpp | 18 +++++---- Userland/Applications/Spreadsheet/Workbook.h | 4 +- 6 files changed, 38 insertions(+), 35 deletions(-) diff --git a/Userland/Applications/Spreadsheet/Cell.cpp b/Userland/Applications/Spreadsheet/Cell.cpp index 4b5864a12c..eb1c3b7823 100644 --- a/Userland/Applications/Spreadsheet/Cell.cpp +++ b/Userland/Applications/Spreadsheet/Cell.cpp @@ -158,7 +158,7 @@ JS::Value Cell::js_data() if (m_kind == Formula) return m_evaluated_data; - auto& vm = m_sheet->interpreter().vm(); + auto& vm = m_sheet->vm(); return JS::PrimitiveString::create(vm, m_data); } diff --git a/Userland/Applications/Spreadsheet/CellType/String.cpp b/Userland/Applications/Spreadsheet/CellType/String.cpp index 7379a19231..23520ecad6 100644 --- a/Userland/Applications/Spreadsheet/CellType/String.cpp +++ b/Userland/Applications/Spreadsheet/CellType/String.cpp @@ -27,7 +27,7 @@ JS::ThrowCompletionOr StringCell::display(Cell& cell, CellType JS::ThrowCompletionOr StringCell::js_value(Cell& cell, CellTypeMetadata const& metadata) const { - auto& vm = cell.sheet().interpreter().vm(); + auto& vm = cell.sheet().vm(); auto string = TRY(display(cell, metadata)); return JS::PrimitiveString::create(vm, string); } diff --git a/Userland/Applications/Spreadsheet/Spreadsheet.cpp b/Userland/Applications/Spreadsheet/Spreadsheet.cpp index b41408a191..f643c44a93 100644 --- a/Userland/Applications/Spreadsheet/Spreadsheet.cpp +++ b/Userland/Applications/Spreadsheet/Spreadsheet.cpp @@ -17,7 +17,8 @@ #include #include #include -#include +#include +#include #include #include #include @@ -40,10 +41,13 @@ Sheet::Sheet(StringView name, Workbook& workbook) Sheet::Sheet(Workbook& workbook) : m_workbook(workbook) - , m_interpreter(JS::Interpreter::create(m_workbook.vm(), *this)) + , m_vm(workbook.vm()) + , m_root_execution_context(JS::create_simple_execution_context(m_workbook.vm(), *this)) { - JS::DeferGC defer_gc(m_workbook.vm().heap()); - m_global_object = static_cast(&m_interpreter->realm().global_object()); + auto& vm = m_workbook.vm(); + JS::DeferGC defer_gc(vm.heap()); + auto& realm = *m_root_execution_context->realm; + m_global_object = static_cast(&realm.global_object()); global_object().define_direct_property("workbook", m_workbook.workbook_object(), JS::default_attributes); global_object().define_direct_property("thisSheet", &global_object(), JS::default_attributes); // Self-reference is unfortunate, but required. @@ -52,7 +56,7 @@ Sheet::Sheet(Workbook& workbook) auto file_or_error = Core::File::open(runtime_file_path, Core::File::OpenMode::Read); if (!file_or_error.is_error()) { auto buffer = file_or_error.value()->read_until_eof().release_value_but_fixme_should_propagate_errors(); - auto script_or_error = JS::Script::parse(buffer, interpreter().realm(), runtime_file_path); + auto script_or_error = JS::Script::parse(buffer, realm, runtime_file_path); if (script_or_error.is_error()) { warnln("Spreadsheet: Failed to parse runtime code"); for (auto& error : script_or_error.error()) { @@ -60,14 +64,14 @@ Sheet::Sheet(Workbook& workbook) warnln("SyntaxError: {}", error.to_deprecated_string()); } } else { - auto result = interpreter().run(script_or_error.value()); + auto result = vm.bytecode_interpreter().run(script_or_error.value()); if (result.is_error()) { warnln("Spreadsheet: Failed to run runtime code:"); auto thrown_value = *result.throw_completion().value(); warn("Threw: {}", MUST(thrown_value.to_string_without_side_effects())); if (thrown_value.is_object() && is(thrown_value.as_object())) { auto& error = static_cast(thrown_value.as_object()); - warnln(" with message '{}'", error.get_without_side_effects(interpreter().vm().names.message)); + warnln(" with message '{}'", error.get_without_side_effects(vm.names.message)); for (auto& traceback_frame : error.traceback()) { auto& function_name = traceback_frame.function_name; auto& source_range = traceback_frame.source_range(); @@ -81,11 +85,6 @@ Sheet::Sheet(Workbook& workbook) } } -JS::Interpreter& Sheet::interpreter() const -{ - return const_cast(*m_interpreter); -} - size_t Sheet::add_row() { return m_rows++; @@ -168,13 +167,13 @@ JS::ThrowCompletionOr Sheet::evaluate(StringView source, Cell* on_beh auto name = on_behalf_of ? on_behalf_of->name_for_javascript(*this) : "cell "sv; auto script_or_error = JS::Script::parse( source, - interpreter().realm(), + realm(), name); if (script_or_error.is_error()) - return interpreter().vm().throw_completion(TRY_OR_THROW_OOM(interpreter().vm(), script_or_error.error().first().to_string())); + return vm().throw_completion(TRY_OR_THROW_OOM(vm(), script_or_error.error().first().to_string())); - return interpreter().run(script_or_error.value()); + return vm().bytecode_interpreter().run(script_or_error.value()); } Cell* Sheet::at(StringView name) @@ -425,7 +424,7 @@ RefPtr Sheet::from_json(JsonObject const& object, Workbook& workbook) cell = make(obj.get_deprecated_string("value"sv).value_or({}), position, *sheet); break; case Cell::Formula: { - auto& vm = sheet->interpreter().vm(); + auto& vm = sheet->vm(); auto value_or_error = JS::call(vm, parse_function, json, JS::PrimitiveString::create(vm, obj.get_deprecated_string("value"sv).value_or({}))); if (value_or_error.is_error()) { warnln("Failed to load previous value for cell {}, leaving as undefined", position.to_cell_identifier(sheet)); @@ -557,10 +556,9 @@ JsonObject Sheet::to_json() const JsonObject data; data.set("kind", it.value->kind() == Cell::Kind::Formula ? "Formula" : "LiteralString"); if (it.value->kind() == Cell::Formula) { - auto& vm = interpreter().vm(); data.set("source", it.value->data()); - auto json = interpreter().realm().global_object().get_without_side_effects("JSON"); - auto stringified_or_error = JS::call(vm, json.as_object().get_without_side_effects("stringify").as_function(), json, it.value->evaluated_data()); + auto json = realm().global_object().get_without_side_effects("JSON"); + auto stringified_or_error = JS::call(vm(), json.as_object().get_without_side_effects("stringify").as_function(), json, it.value->evaluated_data()); VERIFY(!stringified_or_error.is_error()); data.set("value", stringified_or_error.release_value().to_string_without_side_effects().release_value_but_fixme_should_propagate_errors().to_deprecated_string()); } else { @@ -702,8 +700,8 @@ JsonObject Sheet::gather_documentation() const dbgln("Sheet::gather_documentation(): Failed to parse the documentation for '{}'!", it.key.to_display_string()); }; - for (auto& it : interpreter().realm().global_object().shape().property_table()) - add_docs_from(it, interpreter().realm().global_object()); + for (auto& it : realm().global_object().shape().property_table()) + add_docs_from(it, realm().global_object()); for (auto& it : global_object().shape().property_table()) add_docs_from(it, global_object()); diff --git a/Userland/Applications/Spreadsheet/Spreadsheet.h b/Userland/Applications/Spreadsheet/Spreadsheet.h index 4762f011a8..8e3ab61fd3 100644 --- a/Userland/Applications/Spreadsheet/Spreadsheet.h +++ b/Userland/Applications/Spreadsheet/Spreadsheet.h @@ -127,7 +127,6 @@ public: } JS::ThrowCompletionOr evaluate(StringView, Cell* = nullptr); - JS::Interpreter& interpreter() const; SheetGlobalObject& global_object() const { return *m_global_object; } Cell*& current_evaluated_cell() { return m_current_cell_being_evaluated; } @@ -149,6 +148,9 @@ public: DeprecatedString generate_inline_documentation_for(StringView function, size_t argument_index); + JS::Realm& realm() const { return *m_root_execution_context->realm; } + JS::VM& vm() const { return realm().vm(); } + private: explicit Sheet(Workbook&); explicit Sheet(StringView name, Workbook&); @@ -162,7 +164,8 @@ private: Workbook& m_workbook; mutable JS::GCPtr m_global_object; - NonnullOwnPtr m_interpreter; + NonnullRefPtr m_vm; + NonnullOwnPtr m_root_execution_context; Cell* m_current_cell_being_evaluated { nullptr }; diff --git a/Userland/Applications/Spreadsheet/Workbook.cpp b/Userland/Applications/Spreadsheet/Workbook.cpp index 2a61a1764f..4e62247de6 100644 --- a/Userland/Applications/Spreadsheet/Workbook.cpp +++ b/Userland/Applications/Spreadsheet/Workbook.cpp @@ -14,6 +14,7 @@ #include #include #include +#include #include namespace Spreadsheet { @@ -21,19 +22,20 @@ namespace Spreadsheet { Workbook::Workbook(Vector>&& sheets, GUI::Window& parent_window) : m_sheets(move(sheets)) , m_vm(JS::VM::create().release_value_but_fixme_should_propagate_errors()) - , m_interpreter(JS::Interpreter::create(m_vm)) - , m_interpreter_scope(*m_interpreter) + , m_root_execution_context(JS::create_simple_execution_context(m_vm)) , m_main_execution_context(m_vm->heap()) , m_parent_window(parent_window) { - m_workbook_object = m_vm->heap().allocate(m_interpreter->realm(), m_interpreter->realm(), *this).release_allocated_value_but_fixme_should_propagate_errors(); - m_interpreter->realm().global_object().define_direct_property("workbook", workbook_object(), JS::default_attributes); + auto& realm = *m_root_execution_context->realm; + auto& vm = realm.vm(); + m_workbook_object = vm.heap().allocate(realm, realm, *this).release_allocated_value_but_fixme_should_propagate_errors(); + realm.global_object().define_direct_property("workbook", workbook_object(), JS::default_attributes); - m_main_execution_context.this_value = &m_interpreter->realm().global_object(); + m_main_execution_context.this_value = &realm.global_object(); m_main_execution_context.function_name = "(global execution context)"sv; - m_main_execution_context.lexical_environment = &m_interpreter->realm().global_environment(); - m_main_execution_context.variable_environment = &m_interpreter->realm().global_environment(); - m_main_execution_context.realm = &m_interpreter->realm(); + m_main_execution_context.lexical_environment = &realm.global_environment(); + m_main_execution_context.variable_environment = &realm.global_environment(); + m_main_execution_context.realm = &realm; m_main_execution_context.is_strict_mode = true; m_vm->push_execution_context(m_main_execution_context); m_vm->enable_default_host_import_module_dynamically_hook(); diff --git a/Userland/Applications/Spreadsheet/Workbook.h b/Userland/Applications/Spreadsheet/Workbook.h index 3e87d8d164..b6bf8ac59e 100644 --- a/Userland/Applications/Spreadsheet/Workbook.h +++ b/Userland/Applications/Spreadsheet/Workbook.h @@ -44,8 +44,8 @@ public: private: Vector> m_sheets; NonnullRefPtr m_vm; - NonnullOwnPtr m_interpreter; - JS::VM::InterpreterExecutionScope m_interpreter_scope; + NonnullOwnPtr m_root_execution_context; + JS::GCPtr m_workbook_object; JS::ExecutionContext m_main_execution_context; GUI::Window& m_parent_window;