mirror of
				https://github.com/RGBCube/serenity
				synced 2025-10-31 17:52:45 +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
	
	 Andreas Kling
						Andreas Kling