diff --git a/Tests/LibJS/test-js.cpp b/Tests/LibJS/test-js.cpp index bd642d6997e..39753f4946a 100644 --- a/Tests/LibJS/test-js.cpp +++ b/Tests/LibJS/test-js.cpp @@ -93,7 +93,7 @@ TESTJS_GLOBAL_FUNCTION(detach_array_buffer, detachArrayBuffer) return JS::js_null(); } -TESTJS_RUN_FILE_FUNCTION(DeprecatedString const& test_file, JS::Interpreter& interpreter, JS::ExecutionContext&) +TESTJS_RUN_FILE_FUNCTION(DeprecatedString const& test_file, JS::Realm& realm, JS::ExecutionContext&) { if (!test262_parser_tests) return Test::JS::RunFileHookResult::RunAsNormal; @@ -123,9 +123,9 @@ TESTJS_RUN_FILE_FUNCTION(DeprecatedString const& test_file, JS::Interpreter& int auto program_type = path.basename().ends_with(".module.js"sv) ? JS::Program::Type::Module : JS::Program::Type::Script; bool parse_succeeded = false; if (program_type == JS::Program::Type::Module) - parse_succeeded = !Test::JS::parse_module(test_file, interpreter.realm()).is_error(); + parse_succeeded = !Test::JS::parse_module(test_file, realm).is_error(); else - parse_succeeded = !Test::JS::parse_script(test_file, interpreter.realm()).is_error(); + parse_succeeded = !Test::JS::parse_script(test_file, realm).is_error(); bool test_passed = true; DeprecatedString message; diff --git a/Tests/Spreadsheet/test-spreadsheet.cpp b/Tests/Spreadsheet/test-spreadsheet.cpp index 88d3296a3bd..541728182a0 100644 --- a/Tests/Spreadsheet/test-spreadsheet.cpp +++ b/Tests/Spreadsheet/test-spreadsheet.cpp @@ -15,10 +15,10 @@ static constexpr auto s_spreadsheet_runtime_path = "/res/js/Spreadsheet/runtime. static constexpr auto s_spreadsheet_runtime_path = "../../../../Base/res/js/Spreadsheet/runtime.js"sv; #endif -TESTJS_RUN_FILE_FUNCTION(DeprecatedString const&, JS::Interpreter& interpreter, JS::ExecutionContext& global_execution_context) +TESTJS_RUN_FILE_FUNCTION(DeprecatedString const&, JS::Realm& realm, JS::ExecutionContext& global_execution_context) { auto run_file = [&](StringView name) { - auto result = Test::JS::parse_script(name, interpreter.realm()); + auto result = Test::JS::parse_script(name, realm); if (result.is_error()) { warnln("Unable to parse {}", name); warnln("{}", result.error().error.to_deprecated_string()); @@ -27,9 +27,9 @@ TESTJS_RUN_FILE_FUNCTION(DeprecatedString const&, JS::Interpreter& interpreter, } auto script = result.release_value(); - interpreter.vm().push_execution_context(global_execution_context); - MUST(interpreter.run(*script)); - interpreter.vm().pop_execution_context(); + realm.vm().push_execution_context(global_execution_context); + MUST(realm.vm().bytecode_interpreter().run(*script)); + realm.vm().pop_execution_context(); }; #ifdef AK_OS_SERENITY diff --git a/Userland/Libraries/LibTest/JavaScriptTestRunner.h b/Userland/Libraries/LibTest/JavaScriptTestRunner.h index 361d706e246..80a69d9a34e 100644 --- a/Userland/Libraries/LibTest/JavaScriptTestRunner.h +++ b/Userland/Libraries/LibTest/JavaScriptTestRunner.h @@ -90,26 +90,16 @@ #define TEST_ROOT(path) \ DeprecatedString Test::JS::g_test_root_fragment = path -#define TESTJS_RUN_FILE_FUNCTION(...) \ - struct __TestJS_run_file { \ - __TestJS_run_file() \ - { \ - ::Test::JS::g_run_file = hook; \ - } \ - static ::Test::JS::IntermediateRunFileResult hook(DeprecatedString const&, JS::Interpreter&, JS::ExecutionContext&); \ - } __testjs_common_run_file {}; \ +#define TESTJS_RUN_FILE_FUNCTION(...) \ + struct __TestJS_run_file { \ + __TestJS_run_file() \ + { \ + ::Test::JS::g_run_file = hook; \ + } \ + static ::Test::JS::IntermediateRunFileResult hook(DeprecatedString const&, JS::Realm&, JS::ExecutionContext&); \ + } __testjs_common_run_file {}; \ ::Test::JS::IntermediateRunFileResult __TestJS_run_file::hook(__VA_ARGS__) -#define TESTJS_CREATE_INTERPRETER_HOOK(...) \ - struct __TestJS_create_interpreter_hook { \ - __TestJS_create_interpreter_hook() \ - { \ - ::Test::JS::g_create_interpreter_hook = hook; \ - } \ - static NonnullOwnPtr hook(); \ - } __testjs_create_interpreter_hook {}; \ - NonnullOwnPtr __TestJS_create_interpreter_hook::hook(__VA_ARGS__) - namespace Test::JS { namespace JS = ::JS; @@ -138,7 +128,6 @@ extern DeprecatedString g_test_root; extern int g_test_argc; extern char** g_test_argv; extern Function g_main_hook; -extern Function()> g_create_interpreter_hook; extern HashMap> g_extra_args; struct ParserError { @@ -163,7 +152,7 @@ enum class RunFileHookResult { }; using IntermediateRunFileResult = AK::Result; -extern IntermediateRunFileResult (*g_run_file)(DeprecatedString const&, JS::Interpreter&, JS::ExecutionContext&); +extern IntermediateRunFileResult (*g_run_file)(DeprecatedString const&, JS::Realm&, JS::ExecutionContext&); class TestRunner : public ::Test::TestRunner { public: @@ -256,9 +245,9 @@ inline AK::Result, ParserError> parse_mod return script_or_errors.release_value(); } -inline ErrorOr get_test_results(JS::Interpreter& interpreter) +inline ErrorOr get_test_results(JS::Realm& realm) { - auto results = MUST(interpreter.realm().global_object().get("__TestResults__")); + auto results = MUST(realm.global_object().get("__TestResults__")); auto json_string = MUST(JS::JSONObject::stringify_impl(*g_vm, results, JS::js_undefined(), JS::js_undefined())); return JsonValue::from_string(json_string); @@ -297,23 +286,24 @@ inline JSFileResult TestRunner::run_file_test(DeprecatedString const& test_path) #endif double start_time = get_time_in_ms(); - auto interpreter = JS::Interpreter::create(*g_vm); - // Since g_vm is reused for each new interpreter, Interpreter::create will end up pushing multiple - // global execution contexts onto the VM's execution context stack. To prevent this, we immediately - // pop the global execution context off the execution context stack and manually handle pushing - // and popping it. Since the global execution context should be the only thing on the stack - // at interpreter creation, let's assert there is only one. - VERIFY(g_vm->execution_context_stack().size() == 1); - auto& global_execution_context = *g_vm->execution_context_stack().take_first(); + JS::GCPtr realm; + JS::GCPtr global_object; + auto root_execution_context = MUST(JS::Realm::initialize_host_defined_realm( + *g_vm, + [&](JS::Realm& realm_) -> JS::GlobalObject* { + realm = &realm_; + global_object = g_vm->heap().allocate(*realm, *realm).release_allocated_value_but_fixme_should_propagate_errors(); + return global_object; + }, + nullptr)); + auto& global_execution_context = *root_execution_context; + g_vm->pop_execution_context(); - // FIXME: This is a hack while we're refactoring Interpreter/VM stuff. - JS::VM::InterpreterExecutionScope scope(*interpreter); - - interpreter->heap().set_should_collect_on_every_allocation(g_collect_on_every_allocation); + g_vm->heap().set_should_collect_on_every_allocation(g_collect_on_every_allocation); if (g_run_file) { - auto result = g_run_file(test_path, *interpreter, global_execution_context); + auto result = g_run_file(test_path, *realm, global_execution_context); if (result.is_error() && result.error() == RunFileHookResult::SkipFile) { return { test_path, @@ -347,9 +337,9 @@ inline JSFileResult TestRunner::run_file_test(DeprecatedString const& test_path) } } - // FIXME: Since a new interpreter is created every time with a new realm, we no longer cache the test-common.js file as scripts are parsed for the current realm only. + // FIXME: Since a new realm is created every time, we no longer cache the test-common.js file as scripts are parsed for the current realm only. // Find a way to cache this. - auto result = parse_script(m_common_path, interpreter->realm()); + auto result = parse_script(m_common_path, *realm); if (result.is_error()) { warnln("Unable to parse test-common.js"); warnln("{}", result.error().error.to_deprecated_string()); @@ -358,30 +348,20 @@ inline JSFileResult TestRunner::run_file_test(DeprecatedString const& test_path) } auto test_script = result.release_value(); - if (auto* bytecode_interpreter = g_vm->bytecode_interpreter_if_exists()) { - g_vm->push_execution_context(global_execution_context); - MUST(bytecode_interpreter->run(*test_script)); - g_vm->pop_execution_context(); - } else { - g_vm->push_execution_context(global_execution_context); - MUST(interpreter->run(*test_script)); - g_vm->pop_execution_context(); - } + g_vm->push_execution_context(global_execution_context); + MUST(g_vm->bytecode_interpreter().run(*test_script)); + g_vm->pop_execution_context(); - auto file_script = parse_script(test_path, interpreter->realm()); + auto file_script = parse_script(test_path, *realm); JS::ThrowCompletionOr top_level_result { JS::js_undefined() }; if (file_script.is_error()) return { test_path, file_script.error() }; g_vm->push_execution_context(global_execution_context); - if (auto* bytecode_interpreter = g_vm->bytecode_interpreter_if_exists()) { - top_level_result = bytecode_interpreter->run(file_script.value()); - } else { - top_level_result = interpreter->run(file_script.value()); - } + top_level_result = g_vm->bytecode_interpreter().run(file_script.value()); g_vm->pop_execution_context(); g_vm->push_execution_context(global_execution_context); - auto test_json = get_test_results(*interpreter); + auto test_json = get_test_results(*realm); g_vm->pop_execution_context(); if (test_json.is_error()) { warnln("Received malformed JSON from test \"{}\"", test_path); @@ -391,7 +371,7 @@ inline JSFileResult TestRunner::run_file_test(DeprecatedString const& test_path) JSFileResult file_result { test_path.substring(m_test_root.length() + 1, test_path.length() - m_test_root.length() - 1) }; // Collect logged messages - auto user_output = MUST(interpreter->realm().global_object().get("__UserOutput__")); + auto user_output = MUST(realm->global_object().get("__UserOutput__")); auto& arr = user_output.as_array(); for (auto& entry : arr.indexed_properties()) { diff --git a/Userland/Libraries/LibTest/JavaScriptTestRunnerMain.cpp b/Userland/Libraries/LibTest/JavaScriptTestRunnerMain.cpp index fd49868546c..510e4d16730 100644 --- a/Userland/Libraries/LibTest/JavaScriptTestRunnerMain.cpp +++ b/Userland/Libraries/LibTest/JavaScriptTestRunnerMain.cpp @@ -23,9 +23,8 @@ bool g_collect_on_every_allocation = false; DeprecatedString g_currently_running_test; HashMap s_exposed_global_functions; Function g_main_hook; -Function()> g_create_interpreter_hook; HashMap> g_extra_args; -IntermediateRunFileResult (*g_run_file)(DeprecatedString const&, JS::Interpreter&, JS::ExecutionContext&) = nullptr; +IntermediateRunFileResult (*g_run_file)(DeprecatedString const&, JS::Realm&, JS::ExecutionContext&) = nullptr; DeprecatedString g_test_root; int g_test_argc; char** g_test_argv; @@ -93,7 +92,6 @@ int main(int argc, char** argv) #endif bool print_json = false; bool per_file = false; - bool use_ast_interpreter = false; StringView specified_test_root; DeprecatedString common_path; DeprecatedString test_glob; @@ -119,7 +117,6 @@ int main(int argc, char** argv) args_parser.add_option(print_json, "Show results as JSON", "json", 'j'); args_parser.add_option(per_file, "Show detailed per-file results as JSON (implies -j)", "per-file", 0); args_parser.add_option(g_collect_on_every_allocation, "Collect garbage after every allocation", "collect-often", 'g'); - args_parser.add_option(use_ast_interpreter, "Enable JavaScript AST interpreter (deprecated)", "ast", 0); args_parser.add_option(JS::Bytecode::g_dump_bytecode, "Dump the bytecode", "dump-bytecode", 'd'); args_parser.add_option(test_glob, "Only run tests matching the given glob", "filter", 'f', "glob"); for (auto& entry : g_extra_args) @@ -137,12 +134,7 @@ int main(int argc, char** argv) AK::set_debug_enabled(false); } - if (JS::Bytecode::g_dump_bytecode && use_ast_interpreter) { - warnln("--dump-bytecode can not be used when --ast is specified."); - return 1; - } - - JS::Bytecode::Interpreter::set_enabled(!use_ast_interpreter); + JS::Bytecode::Interpreter::set_enabled(true); DeprecatedString test_root;