/* * Copyright (c) 2020, Andreas Kling * Copyright (c) 2020-2021, Linus Groh * * SPDX-License-Identifier: BSD-2-Clause */ #include #include #include #include #include #include #include #include #include #include #include namespace JS { NonnullOwnPtr Interpreter::create_with_existing_realm(Realm& realm) { auto& global_object = realm.global_object(); DeferGC defer_gc(global_object.heap()); auto interpreter = adopt_own(*new Interpreter(global_object.vm())); interpreter->m_global_object = make_handle(&global_object); interpreter->m_realm = make_handle(&realm); return interpreter; } Interpreter::Interpreter(VM& vm) : m_vm(vm) { } Interpreter::~Interpreter() { } void Interpreter::run(GlobalObject& global_object, const Program& program) { // FIXME: Why does this receive a GlobalObject? Interpreter has one already, and this might not be in sync with the Realm's GlobalObject. auto& vm = this->vm(); VERIFY(!vm.exception()); VM::InterpreterExecutionScope scope(*this); vm.set_last_value(Badge {}, {}); ExecutionContext execution_context(heap()); execution_context.current_node = &program; execution_context.this_value = &global_object; static FlyString global_execution_context_name = "(global execution context)"; execution_context.function_name = global_execution_context_name; execution_context.lexical_environment = &realm().global_environment(); execution_context.variable_environment = &realm().global_environment(); execution_context.realm = &realm(); execution_context.is_strict_mode = program.is_strict_mode(); vm.push_execution_context(execution_context, global_object); VERIFY(!vm.exception()); auto value = program.execute(*this, global_object); vm.set_last_value(Badge {}, value.value_or(js_undefined())); // FIXME: We unconditionally stop the unwind here this should be done using completions leaving // the VM in a cleaner state after executing. For example it does still store the exception. vm.stop_unwind(); vm.pop_execution_context(); // At this point we may have already run any queued promise jobs via on_call_stack_emptied, // in which case this is a no-op. vm.run_queued_promise_jobs(); vm.run_queued_finalization_registry_cleanup_jobs(); vm.finish_execution_generation(); } GlobalObject& Interpreter::global_object() { return static_cast(*m_global_object.cell()); } const GlobalObject& Interpreter::global_object() const { return static_cast(*m_global_object.cell()); } Realm& Interpreter::realm() { return static_cast(*m_realm.cell()); } const Realm& Interpreter::realm() const { return static_cast(*m_realm.cell()); } }