1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-07-28 00:07:35 +00:00

LibJS: Move most of Interpreter into VM

This patch moves the exception state, call stack and scope stack from
Interpreter to VM. I'm doing this to help myself discover what the
split between Interpreter and VM should be, by shuffling things around
and seeing what falls where.

With these changes, we no longer have a persistent lexical environment
for the current global object on the Interpreter's call stack. Instead,
we push/pop that environment on Interpreter::run() enter/exit.
Since it should only be used to find the global "this", and not for
variable storage (that goes directly into the global object instead!),
I had to insert some short-circuiting when walking the environment
parent chain during variable lookup.

Note that this is a "stepping stone" commit, not a final design.
This commit is contained in:
Andreas Kling 2020-09-27 15:18:55 +02:00
parent 838d9fa251
commit 6861c619c6
48 changed files with 765 additions and 726 deletions

View file

@ -349,7 +349,7 @@ static bool parse_and_run(JS::Interpreter& interpreter, const StringView& source
auto hint = error.source_location_hint(source);
if (!hint.is_empty())
printf("%s\n", hint.characters());
interpreter.throw_exception<JS::SyntaxError>(error.to_string());
vm->throw_exception<JS::SyntaxError>(interpreter.global_object(), error.to_string());
} else {
interpreter.run(interpreter.global_object(), *program);
}
@ -362,11 +362,11 @@ static bool parse_and_run(JS::Interpreter& interpreter, const StringView& source
for (auto& function_name : trace)
printf(" -> %s\n", function_name.characters());
}
interpreter.vm().clear_exception();
vm->clear_exception();
return false;
}
if (s_print_last_result)
print(interpreter.last_value());
print(vm->last_value());
return true;
}
@ -470,32 +470,32 @@ public:
virtual JS::Value log() override
{
puts(interpreter().join_arguments().characters());
puts(interpreter().vm().join_arguments().characters());
return JS::js_undefined();
}
virtual JS::Value info() override
{
printf("(i) %s\n", interpreter().join_arguments().characters());
printf("(i) %s\n", interpreter().vm().join_arguments().characters());
return JS::js_undefined();
}
virtual JS::Value debug() override
{
printf("\033[36;1m");
puts(interpreter().join_arguments().characters());
puts(interpreter().vm().join_arguments().characters());
printf("\033[0m");
return JS::js_undefined();
}
virtual JS::Value warn() override
{
printf("\033[33;1m");
puts(interpreter().join_arguments().characters());
puts(interpreter().vm().join_arguments().characters());
printf("\033[0m");
return JS::js_undefined();
}
virtual JS::Value error() override
{
printf("\033[31;1m");
puts(interpreter().join_arguments().characters());
puts(interpreter().vm().join_arguments().characters());
printf("\033[0m");
return JS::js_undefined();
}
@ -507,7 +507,7 @@ public:
}
virtual JS::Value trace() override
{
puts(interpreter().join_arguments().characters());
puts(interpreter().vm().join_arguments().characters());
auto trace = get_trace();
for (auto& function_name : trace) {
if (function_name.is_empty())
@ -558,7 +558,7 @@ int main(int argc, char** argv)
interrupt_interpreter = [&] {
auto error = JS::Error::create(interpreter->global_object(), "Error", "Received SIGINT");
interpreter->throw_exception(error);
vm->throw_exception(interpreter->global_object(), error);
};
if (script_path == nullptr) {
@ -567,7 +567,7 @@ int main(int argc, char** argv)
ReplConsoleClient console_client(interpreter->console());
interpreter->console().set_client(console_client);
interpreter->heap().set_should_collect_on_every_allocation(gc_on_every_allocation);
interpreter->set_underscore_is_last_value(true);
interpreter->vm().set_underscore_is_last_value(true);
s_editor = Line::Editor::construct();
@ -811,7 +811,7 @@ int main(int argc, char** argv)
switch (mode) {
case CompleteProperty: {
auto maybe_variable = interpreter->get_variable(variable_name, interpreter->global_object());
auto maybe_variable = vm->get_variable(variable_name, interpreter->global_object());
if (maybe_variable.is_empty()) {
maybe_variable = interpreter->global_object().get(FlyString(variable_name));
if (maybe_variable.is_empty())

View file

@ -260,7 +260,7 @@ static Result<NonnullRefPtr<JS::Program>, ParserError> parse_file(const String&
static Optional<JsonValue> get_test_results(JS::Interpreter& interpreter)
{
auto result = interpreter.get_variable("__TestResults__", interpreter.global_object());
auto result = interpreter.vm().get_variable("__TestResults__", interpreter.global_object());
auto json_string = JS::JSONObject::stringify_impl(interpreter, interpreter.global_object(), result, JS::js_undefined(), JS::js_undefined());
auto json = JsonValue::from_string(json_string);
@ -310,7 +310,7 @@ JSFileResult TestRunner::run_file_test(const String& 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& arr = interpreter->get_variable("__UserOutput__", interpreter->global_object()).as_array();
auto& arr = interpreter->vm().get_variable("__UserOutput__", interpreter->global_object()).as_array();
for (auto& entry : arr.indexed_properties()) {
auto message = entry.value_and_attributes(&interpreter->global_object()).value;
file_result.logged_messages.append(message.to_string_without_side_effects());
@ -579,7 +579,6 @@ void TestRunner::print_test_results() const
int main(int argc, char** argv)
{
bool print_times = false;
struct sigaction act;
memset(&act, 0, sizeof(act));
act.sa_flags = SA_NOCLDWAIT;

View file

@ -174,11 +174,13 @@ static void cleanup_and_exit()
exit(1);
}
#if 0
static void handle_sigabrt(int)
{
dbg() << "test-web: SIGABRT received, cleaning up.";
cleanup_and_exit();
}
#endif
static double get_time_in_ms()
{
@ -288,7 +290,7 @@ static Result<NonnullRefPtr<JS::Program>, ParserError> parse_file(const String&
static Optional<JsonValue> get_test_results(JS::Interpreter& interpreter)
{
auto result = interpreter.get_variable("__TestResults__", interpreter.global_object());
auto result = interpreter.vm().get_variable("__TestResults__", interpreter.global_object());
auto json_string = JS::JSONObject::stringify_impl(interpreter, interpreter.global_object(), result, JS::js_undefined(), JS::js_undefined());
auto json = JsonValue::from_string(json_string);
@ -336,7 +338,7 @@ JSFileResult TestRunner::run_file_test(const String& test_path)
// Setup the test on the current page to get "__PageToLoad__".
old_interpreter.run(old_interpreter.global_object(), *m_web_test_common);
old_interpreter.run(old_interpreter.global_object(), *file_program.value());
auto page_to_load = URL(old_interpreter.get_variable("__PageToLoad__", old_interpreter.global_object()).as_string().string());
auto page_to_load = URL(old_interpreter.vm().get_variable("__PageToLoad__", old_interpreter.global_object()).as_string().string());
if (!page_to_load.is_valid()) {
printf("Invalid page URL for %s", test_path.characters());
cleanup_and_exit();
@ -360,7 +362,7 @@ JSFileResult TestRunner::run_file_test(const String& test_path)
new_interpreter.run(new_interpreter.global_object(), *m_web_test_common);
new_interpreter.run(new_interpreter.global_object(), *file_program.value());
auto& before_initial_page_load = new_interpreter.get_variable("__BeforeInitialPageLoad__", new_interpreter.global_object()).as_function();
auto& before_initial_page_load = new_interpreter.vm().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.vm().clear_exception();
@ -370,7 +372,7 @@ JSFileResult TestRunner::run_file_test(const String& test_path)
m_page_view->set_document(&parser.document());
// Finally run the test by calling "__AfterInitialPageLoad__"
auto& after_initial_page_load = new_interpreter.get_variable("__AfterInitialPageLoad__", new_interpreter.global_object()).as_function();
auto& after_initial_page_load = new_interpreter.vm().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.vm().clear_exception();
@ -384,7 +386,7 @@ JSFileResult TestRunner::run_file_test(const String& test_path)
file_result = { test_path.substring(m_web_test_root.length() + 1, test_path.length() - m_web_test_root.length() - 1) };
// Collect logged messages
auto& arr = new_interpreter.get_variable("__UserOutput__", new_interpreter.global_object()).as_array();
auto& arr = new_interpreter.vm().get_variable("__UserOutput__", new_interpreter.global_object()).as_array();
for (auto& entry : arr.indexed_properties()) {
auto message = entry.value_and_attributes(&new_interpreter.global_object()).value;
file_result.logged_messages.append(message.to_string_without_side_effects());
@ -660,6 +662,7 @@ int main(int argc, char** argv)
bool print_times = false;
bool show_window = false;
#if 0
struct sigaction act;
memset(&act, 0, sizeof(act));
act.sa_flags = SA_NOCLDWAIT;
@ -669,6 +672,7 @@ int main(int argc, char** argv)
perror("sigaction");
return 1;
}
#endif
Core::ArgsParser args_parser;
args_parser.add_option(print_times, "Show duration of each test", "show-time", 't');