mirror of
https://github.com/RGBCube/serenity
synced 2025-05-31 15:38:10 +00:00
LibJS/Bytecode: Simplify Bytecode::Interpreter lifetime model
The JS::VM now owns the one Bytecode::Interpreter. We no longer have multiple bytecode interpreters, and there is no concept of a "current" bytecode interpreter. If you ask for VM::bytecode_interpreter_if_exists(), it will return null if we're not running the program in "bytecode enabled" mode. If you ask for VM::bytecode_interpreter(), it will return a bytecode interpreter in all modes. This is used for situations where even the AST interpreter switches to bytecode mode (generators, etc.)
This commit is contained in:
parent
6150960671
commit
6537ed8fff
15 changed files with 117 additions and 106 deletions
|
@ -32,26 +32,15 @@ void Interpreter::set_enabled(bool enabled)
|
|||
s_bytecode_interpreter_enabled = enabled;
|
||||
}
|
||||
|
||||
static Interpreter* s_current;
|
||||
bool g_dump_bytecode = false;
|
||||
|
||||
Interpreter* Interpreter::current()
|
||||
Interpreter::Interpreter(VM& vm)
|
||||
: m_vm(vm)
|
||||
{
|
||||
return s_current;
|
||||
}
|
||||
|
||||
Interpreter::Interpreter(Realm& realm)
|
||||
: m_vm(realm.vm())
|
||||
, m_realm(realm)
|
||||
{
|
||||
VERIFY(!s_current);
|
||||
s_current = this;
|
||||
}
|
||||
|
||||
Interpreter::~Interpreter()
|
||||
{
|
||||
VERIFY(s_current == this);
|
||||
s_current = nullptr;
|
||||
}
|
||||
|
||||
// 16.1.6 ScriptEvaluation ( scriptRecord ), https://tc39.es/ecma262/#sec-runtime-semantics-scriptevaluation
|
||||
|
@ -124,7 +113,7 @@ ThrowCompletionOr<Value> Interpreter::run(Script& script_record, JS::GCPtr<Envir
|
|||
executable->dump();
|
||||
|
||||
// a. Set result to the result of evaluating script.
|
||||
auto result_or_error = run_and_return_frame(*executable, nullptr);
|
||||
auto result_or_error = run_and_return_frame(script_record.realm(), *executable, nullptr);
|
||||
if (result_or_error.value.is_error())
|
||||
result = result_or_error.value.release_error();
|
||||
else
|
||||
|
@ -189,7 +178,7 @@ void Interpreter::set_optimizations_enabled(bool enabled)
|
|||
m_optimizations_enabled = enabled;
|
||||
}
|
||||
|
||||
Interpreter::ValueAndFrame Interpreter::run_and_return_frame(Executable const& executable, BasicBlock const* entry_point, RegisterWindow* in_frame)
|
||||
Interpreter::ValueAndFrame Interpreter::run_and_return_frame(Realm& realm, Executable const& executable, BasicBlock const* entry_point, RegisterWindow* in_frame)
|
||||
{
|
||||
dbgln_if(JS_BYTECODE_DEBUG, "Bytecode::Interpreter will run unit {:p}", &executable);
|
||||
|
||||
|
@ -201,12 +190,12 @@ Interpreter::ValueAndFrame Interpreter::run_and_return_frame(Executable const& e
|
|||
ExecutionContext execution_context(vm().heap());
|
||||
if (vm().execution_context_stack().is_empty() || !vm().running_execution_context().lexical_environment) {
|
||||
// The "normal" interpreter pushes an execution context without environment so in that case we also want to push one.
|
||||
execution_context.this_value = &m_realm->global_object();
|
||||
execution_context.this_value = &realm.global_object();
|
||||
static DeprecatedFlyString global_execution_context_name = "(*BC* global execution context)";
|
||||
execution_context.function_name = global_execution_context_name;
|
||||
execution_context.lexical_environment = &m_realm->global_environment();
|
||||
execution_context.variable_environment = &m_realm->global_environment();
|
||||
execution_context.realm = m_realm;
|
||||
execution_context.lexical_environment = &realm.global_environment();
|
||||
execution_context.variable_environment = &realm.global_environment();
|
||||
execution_context.realm = realm;
|
||||
execution_context.is_strict_mode = executable.is_strict_mode;
|
||||
vm().push_execution_context(execution_context);
|
||||
pushed_execution_context = true;
|
||||
|
@ -395,10 +384,10 @@ ThrowCompletionOr<void> Interpreter::continue_pending_unwind(Label const& resume
|
|||
return {};
|
||||
}
|
||||
|
||||
VM::InterpreterExecutionScope Interpreter::ast_interpreter_scope()
|
||||
VM::InterpreterExecutionScope Interpreter::ast_interpreter_scope(Realm& realm)
|
||||
{
|
||||
if (!m_ast_interpreter)
|
||||
m_ast_interpreter = JS::Interpreter::create_with_existing_realm(m_realm);
|
||||
m_ast_interpreter = JS::Interpreter::create_with_existing_realm(realm);
|
||||
|
||||
return { *m_ast_interpreter };
|
||||
}
|
||||
|
@ -449,4 +438,29 @@ DeprecatedString Interpreter::debug_position() const
|
|||
return DeprecatedString::formatted("{}:{:2}:{:4x}", m_current_executable->name, m_current_block->name(), pc());
|
||||
}
|
||||
|
||||
ThrowCompletionOr<NonnullOwnPtr<Bytecode::Executable>> compile(VM& vm, ASTNode const& node, FunctionKind kind, DeprecatedFlyString const& name)
|
||||
{
|
||||
auto executable_result = Bytecode::Generator::generate(node, kind);
|
||||
if (executable_result.is_error())
|
||||
return vm.throw_completion<InternalError>(ErrorType::NotImplemented, TRY_OR_THROW_OOM(vm, executable_result.error().to_string()));
|
||||
|
||||
auto bytecode_executable = executable_result.release_value();
|
||||
bytecode_executable->name = name;
|
||||
auto& passes = Bytecode::Interpreter::optimization_pipeline();
|
||||
passes.perform(*bytecode_executable);
|
||||
if constexpr (JS_BYTECODE_DEBUG) {
|
||||
dbgln("Optimisation passes took {}us", passes.elapsed());
|
||||
dbgln("Compiled Bytecode::Block for function '{}':", name);
|
||||
}
|
||||
if (Bytecode::g_dump_bytecode)
|
||||
bytecode_executable->dump();
|
||||
|
||||
return bytecode_executable;
|
||||
}
|
||||
|
||||
Realm& Interpreter::realm()
|
||||
{
|
||||
return *m_vm.current_realm();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -11,6 +11,7 @@
|
|||
#include <LibJS/Forward.h>
|
||||
#include <LibJS/Heap/Cell.h>
|
||||
#include <LibJS/Heap/Handle.h>
|
||||
#include <LibJS/Runtime/FunctionKind.h>
|
||||
#include <LibJS/Runtime/VM.h>
|
||||
#include <LibJS/Runtime/Value.h>
|
||||
|
||||
|
@ -31,13 +32,10 @@ public:
|
|||
[[nodiscard]] static bool enabled();
|
||||
static void set_enabled(bool);
|
||||
|
||||
explicit Interpreter(Realm&);
|
||||
explicit Interpreter(VM&);
|
||||
~Interpreter();
|
||||
|
||||
// FIXME: Remove this thing once we don't need it anymore!
|
||||
static Interpreter* current();
|
||||
|
||||
Realm& realm() { return m_realm; }
|
||||
Realm& realm();
|
||||
VM& vm() { return m_vm; }
|
||||
|
||||
void set_optimizations_enabled(bool);
|
||||
|
@ -45,9 +43,9 @@ public:
|
|||
ThrowCompletionOr<Value> run(Script&, JS::GCPtr<Environment> lexical_environment_override = nullptr);
|
||||
ThrowCompletionOr<Value> run(SourceTextModule&);
|
||||
|
||||
ThrowCompletionOr<Value> run(Bytecode::Executable const& executable, Bytecode::BasicBlock const* entry_point = nullptr)
|
||||
ThrowCompletionOr<Value> run(Realm& realm, Bytecode::Executable const& executable, Bytecode::BasicBlock const* entry_point = nullptr)
|
||||
{
|
||||
auto value_and_frame = run_and_return_frame(executable, entry_point);
|
||||
auto value_and_frame = run_and_return_frame(realm, executable, entry_point);
|
||||
return move(value_and_frame.value);
|
||||
}
|
||||
|
||||
|
@ -55,7 +53,7 @@ public:
|
|||
ThrowCompletionOr<Value> value;
|
||||
OwnPtr<RegisterWindow> frame;
|
||||
};
|
||||
ValueAndFrame run_and_return_frame(Bytecode::Executable const&, Bytecode::BasicBlock const* entry_point, RegisterWindow* = nullptr);
|
||||
ValueAndFrame run_and_return_frame(Realm&, Bytecode::Executable const&, Bytecode::BasicBlock const* entry_point, RegisterWindow* = nullptr);
|
||||
|
||||
ALWAYS_INLINE Value& accumulator() { return reg(Register::accumulator()); }
|
||||
Value& reg(Register const& r) { return registers()[r.index()]; }
|
||||
|
@ -97,7 +95,7 @@ public:
|
|||
};
|
||||
static Bytecode::PassManager& optimization_pipeline(OptimizationLevel = OptimizationLevel::Default);
|
||||
|
||||
VM::InterpreterExecutionScope ast_interpreter_scope();
|
||||
VM::InterpreterExecutionScope ast_interpreter_scope(Realm&);
|
||||
|
||||
private:
|
||||
RegisterWindow& window()
|
||||
|
@ -115,7 +113,6 @@ private:
|
|||
static AK::Array<OwnPtr<PassManager>, static_cast<UnderlyingType<Interpreter::OptimizationLevel>>(Interpreter::OptimizationLevel::__Count)> s_optimization_pipelines;
|
||||
|
||||
VM& m_vm;
|
||||
NonnullGCPtr<Realm> m_realm;
|
||||
Vector<Variant<NonnullOwnPtr<RegisterWindow>, RegisterWindow*>> m_register_windows;
|
||||
Optional<BasicBlock const*> m_pending_jump;
|
||||
BasicBlock const* m_scheduled_jump { nullptr };
|
||||
|
@ -131,4 +128,6 @@ private:
|
|||
|
||||
extern bool g_dump_bytecode;
|
||||
|
||||
ThrowCompletionOr<NonnullOwnPtr<Bytecode::Executable>> compile(VM&, ASTNode const& no, JS::FunctionKind kind, DeprecatedFlyString const& name);
|
||||
|
||||
}
|
||||
|
|
|
@ -1081,7 +1081,7 @@ ThrowCompletionOr<void> IteratorResultValue::execute_impl(Bytecode::Interpreter&
|
|||
ThrowCompletionOr<void> NewClass::execute_impl(Bytecode::Interpreter& interpreter) const
|
||||
{
|
||||
auto name = m_class_expression.name();
|
||||
auto scope = interpreter.ast_interpreter_scope();
|
||||
auto scope = interpreter.ast_interpreter_scope(interpreter.realm());
|
||||
auto& ast_interpreter = scope.interpreter();
|
||||
|
||||
auto* class_object = TRY(m_class_expression.class_definition_evaluation(ast_interpreter, name, name.is_null() ? ""sv : name));
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue