diff --git a/Libraries/LibJS/AsmIntGen/src/codegen_aarch64.rs b/Libraries/LibJS/AsmIntGen/src/codegen_aarch64.rs index 0c24573d7c..cc362606b9 100644 --- a/Libraries/LibJS/AsmIntGen/src/codegen_aarch64.rs +++ b/Libraries/LibJS/AsmIntGen/src/codegen_aarch64.rs @@ -197,11 +197,11 @@ fn generate_exit_point(out: &mut String, fmt: ObjectFormat) { } fn generate_entry_point(out: &mut String, program: &Program) { - // void asm_interpreter_entry(u8 const* bytecode, u32 entry_point, Value* values, Interpreter* interp) - // AAPCS64: x0=bytecode, w1=entry_point, x2=values, x3=interp + // void asm_interpreter_entry(u8 const* bytecode, u32 entry_point, Value* values, VM* vm) + // AAPCS64: x0=bytecode, w1=entry_point, x2=values, x3=vm // Save callee-saved registers and link register. - // Pinned: x19(dispatch), x20(interp), x21(ip), x26(pb), x27(values), x28(exec_ctx) + // Pinned: x19(dispatch), x20(vm), x21(ip), x26(pb), x27(values), x28(exec_ctx) // x21 = ip (instruction pointer = pb + pc), the primary dispatch register. // x25 is only used when DSL code writes to pc directly (rare). // x22 = INT32_TAG, x23 = BOOLEAN_TAG, x24 = NAN_BASE_TAG (pinned constants). @@ -231,12 +231,12 @@ fn generate_entry_point(out: &mut String, program: &Program) { w!(out, " .cfi_offset d8, -16"); // Set up pinned registers - // x0=bytecode (pb), w1=entry_point (pc), x2=values, x3=interp + // x0=bytecode (pb), w1=entry_point (pc), x2=values, x3=vm let interp_ctx = program .constants - .get("INTERPRETER_RUNNING_EXECUTION_CONTEXT") + .get("VM_RUNNING_EXECUTION_CONTEXT") .copied() - .expect("INTERPRETER_RUNNING_EXECUTION_CONTEXT constant required"); + .expect("VM_RUNNING_EXECUTION_CONTEXT constant required"); let canon_nan = program .constants .get("CANON_NAN_BITS") @@ -244,8 +244,8 @@ fn generate_entry_point(out: &mut String, program: &Program) { .expect("CANON_NAN_BITS constant required"); w!(out, " mov x26, x0 // pb = bytecode base"); w!(out, " mov x27, x2 // values = values array"); - // Store Interpreter* in x20 (callee-saved) for C++ calls, pin exec_ctx in x28 - w!(out, " mov x20, x3 // interp = Interpreter*"); + // Store VM* in x20 (callee-saved) for C++ calls, pin exec_ctx in x28 + w!(out, " mov x20, x3 // vm = VM*"); emit_ldr64(out, "x28", "x3", interp_ctx); w!(out, " // x28 = exec_ctx"); emit_symbol_addr(out, "x19", "asm_dispatch_table", program.object_format); @@ -276,7 +276,7 @@ fn generate_entry_point(out: &mut String, program: &Program) { fn generate_fallback_handler(out: &mut String, program: &Program, _pinned: &PinnedConstants) { w!(out, ".p2align 4"); w!(out, "asm_handler_fallback:"); - // Set up args: x0=interp (x20), w1=pc (ip - pb) + // Set up args: x0=vm (x20), w1=pc (ip - pb) w!(out, " mov x0, x20"); w!(out, " sub w1, w21, w26"); w!(out, " bl CSYM(asm_fallback_handler)"); @@ -294,13 +294,13 @@ fn generate_fallback_handler(out: &mut String, program: &Program, _pinned: &Pinn } /// Emit instructions to reload exec_ctx (x28), pb (x26), and values (x27) -/// from the Interpreter* in x20. Uses x9 as scratch. +/// from the VM* in x20. Uses x9 as scratch. fn emit_state_reload(out: &mut String, program: &Program) { let interp_ctx = program .constants - .get("INTERPRETER_RUNNING_EXECUTION_CONTEXT") + .get("VM_RUNNING_EXECUTION_CONTEXT") .copied() - .expect("INTERPRETER_RUNNING_EXECUTION_CONTEXT constant required"); + .expect("VM_RUNNING_EXECUTION_CONTEXT constant required"); let exec_executable = program .constants .get("EXECUTION_CONTEXT_EXECUTABLE") @@ -921,13 +921,13 @@ fn emit_instruction( } } - // reload_exec_ctx: reload the pinned exec_ctx register from Interpreter* (x20) + // reload_exec_ctx: reload the pinned exec_ctx register from VM* (x20) "reload_exec_ctx" => { let interp_ctx = program .constants - .get("INTERPRETER_RUNNING_EXECUTION_CONTEXT") + .get("VM_RUNNING_EXECUTION_CONTEXT") .copied() - .expect("INTERPRETER_RUNNING_EXECUTION_CONTEXT constant required"); + .expect("VM_RUNNING_EXECUTION_CONTEXT constant required"); emit_ldr64(out, "x28", "x20", interp_ctx); } @@ -951,7 +951,7 @@ fn emit_instruction( // call_slow_path: TERMINAL call to C++ slow path "call_slow_path" => { if let Some(Operand::Register(func_name)) = insn.operands.first() { - w!(out, " mov x0, x20"); // interp + w!(out, " mov x0, x20"); // vm w!(out, " sub w1, w21, w26"); // pc = ip - pb w!(out, " bl CSYM({func_name})"); w!(out, " tbnz x0, #63, .Lexit"); @@ -973,7 +973,7 @@ fn emit_instruction( } } - // call_interp: NON-TERMINAL call with (Interpreter*, u32 pc) + // call_interp: NON-TERMINAL call with (VM*, u32 pc) "call_interp" => { if let Some(Operand::Register(func_name)) = insn.operands.first() { w!(out, " mov x0, x20"); diff --git a/Libraries/LibJS/AsmIntGen/src/codegen_x86_64.rs b/Libraries/LibJS/AsmIntGen/src/codegen_x86_64.rs index 1cfb0f3bce..1a581a9005 100644 --- a/Libraries/LibJS/AsmIntGen/src/codegen_x86_64.rs +++ b/Libraries/LibJS/AsmIntGen/src/codegen_x86_64.rs @@ -145,8 +145,8 @@ fn generate_exit_point(out: &mut String, fmt: ObjectFormat) { } fn generate_entry_point(out: &mut String, program: &Program) { - // void asm_interpreter_entry(u8 const* bytecode, u32 entry_point, Value* values, Interpreter* interp) - // System V AMD64: rdi=bytecode, esi=entry_point, rdx=values, rcx=interp + // void asm_interpreter_entry(u8 const* bytecode, u32 entry_point, Value* values, VM* vm) + // System V AMD64: rdi=bytecode, esi=entry_point, rdx=values, rcx=vm // Save callee-saved registers w!(out, " push rbp"); @@ -168,19 +168,19 @@ fn generate_entry_point(out: &mut String, program: &Program) { w!(out, " sub rsp, 8"); // Set up pinned registers - // rdi=bytecode (pb), esi=entry_point (pc), rdx=values, rcx=interp + // rdi=bytecode (pb), esi=entry_point (pc), rdx=values, rcx=vm w!(out, " mov r14, rdi # pb = bytecode base"); w!(out, " mov r13d, esi # pc = entry_point"); w!(out, " mov r15, rdx # values = values array"); - // Store Interpreter* on the stack for C++ calls, pin exec_ctx instead + // Store VM* on the stack for C++ calls, pin exec_ctx instead let interp_ctx = program .constants - .get("INTERPRETER_RUNNING_EXECUTION_CONTEXT") + .get("VM_RUNNING_EXECUTION_CONTEXT") .copied() - .expect("INTERPRETER_RUNNING_EXECUTION_CONTEXT constant required"); + .expect("VM_RUNNING_EXECUTION_CONTEXT constant required"); w!( out, - " mov QWORD PTR [rbp - 48], rcx # save Interpreter*" + " mov QWORD PTR [rbp - 48], rcx # save VM*" ); w!( out, @@ -199,11 +199,11 @@ fn generate_entry_point(out: &mut String, program: &Program) { fn generate_fallback_handler(out: &mut String, program: &Program) { // The fallback handler calls into C++ for any unhandled instruction. - // extern "C" i64 asm_fallback_handler(Interpreter* interp, u32 pc); + // extern "C" i64 asm_fallback_handler(VM* vm, u32 pc); // Returns >= 0: new pc to dispatch to. Returns < 0: exit. w!(out, ".p2align 4"); w!(out, "asm_handler_fallback:"); - // Set up args: rdi=interp (from stack), esi=pc (r13d) + // Set up args: rdi=vm (from stack), esi=pc (r13d) w!(out, " mov rdi, QWORD PTR [rbp - 48]"); w!(out, " mov esi, r13d"); w!(out, " call CSYM(asm_fallback_handler)"); @@ -223,13 +223,13 @@ fn generate_fallback_handler(out: &mut String, program: &Program) { } /// Emit instructions to reload exec_ctx (rbx), pb (r14) and values (r15) -/// from the Interpreter* saved on the stack. Uses rcx as scratch. +/// from the VM* saved on the stack. Uses rcx as scratch. fn emit_state_reload(out: &mut String, program: &Program) { let interp_ctx = program .constants - .get("INTERPRETER_RUNNING_EXECUTION_CONTEXT") + .get("VM_RUNNING_EXECUTION_CONTEXT") .copied() - .expect("INTERPRETER_RUNNING_EXECUTION_CONTEXT constant required"); + .expect("VM_RUNNING_EXECUTION_CONTEXT constant required"); let exec_executable = program .constants .get("EXECUTION_CONTEXT_EXECUTABLE") @@ -401,13 +401,13 @@ fn emit_instruction(out: &mut String, insn: &AsmInstruction, handler: &Handler, } } - // reload_exec_ctx: reload the pinned exec_ctx register from Interpreter* + // reload_exec_ctx: reload the pinned exec_ctx register from VM* "reload_exec_ctx" => { let interp_ctx = program .constants - .get("INTERPRETER_RUNNING_EXECUTION_CONTEXT") + .get("VM_RUNNING_EXECUTION_CONTEXT") .copied() - .expect("INTERPRETER_RUNNING_EXECUTION_CONTEXT constant required"); + .expect("VM_RUNNING_EXECUTION_CONTEXT constant required"); w!(out, " mov rcx, QWORD PTR [rbp - 48]"); w!(out, " mov rbx, QWORD PTR [rcx + {interp_ctx}]"); } @@ -429,14 +429,14 @@ fn emit_instruction(out: &mut String, insn: &AsmInstruction, handler: &Handler, } // call_slow_path pseudo-instruction - // Calls a slow path C function: i64 func(Interpreter*, u32 pc) + // Calls a slow path C function: i64 func(VM*, u32 pc) // Returns >= 0: new pc to dispatch to. Returns < 0: exit. // This is TERMINAL: it dispatches after return, control doesn't come back. // After the call, pb and values are reloaded from the running execution // context, since exception handling may have unwound inline frames. "call_slow_path" => { if let Some(Operand::Register(func_name)) = insn.operands.first() { - // Set up args: rdi=interp (from stack), esi=pc + // Set up args: rdi=vm (from stack), esi=pc w!(out, " mov rdi, QWORD PTR [rbp - 48]"); w!(out, " mov esi, r13d"); w!(out, " call CSYM({func_name})"); @@ -465,7 +465,7 @@ fn emit_instruction(out: &mut String, insn: &AsmInstruction, handler: &Handler, } // call_interp pseudo-instruction - // Calls a C++ helper: i64 func(Interpreter*, u32 pc) + // Calls a C++ helper: i64 func(VM*, u32 pc) // Same args as call_slow_path, but NON-TERMINAL: result in rax (t0), // handler continues after. "call_interp" => { diff --git a/Libraries/LibJS/AsmIntGen/src/main.rs b/Libraries/LibJS/AsmIntGen/src/main.rs index d5fba8a80f..5ee3e471d3 100644 --- a/Libraries/LibJS/AsmIntGen/src/main.rs +++ b/Libraries/LibJS/AsmIntGen/src/main.rs @@ -19,7 +19,7 @@ //! 3. Opcodes without an assembly handler are caught by a **fallback handler** //! that calls into C++ (`asm_fallback_handler`). //! -//! The entry point is `asm_interpreter_entry(bytecode, entry_point, values, interp)`. +//! The entry point is `asm_interpreter_entry(bytecode, entry_point, values, vm)`. //! It saves callee-saved registers, sets up pinned registers, and dispatches. //! //! ## Pinned registers @@ -61,7 +61,7 @@ //! //! ### C++ interop //! -//! - `call_slow_path func` -- **TERMINAL.** Calls `i64 func(Interpreter*, u32 pc)`. +//! - `call_slow_path func` -- **TERMINAL.** Calls `i64 func(VM*, u32 pc)`. //! If return >= 0, reloads pinned state (exec_ctx, pb, values -- they may //! have changed due to exception unwinding), sets pc to the return value, //! and dispatches. If return < 0, exits. Control does NOT return to the @@ -69,9 +69,9 @@ //! - `call_helper func` -- **Non-terminal.** Calls `u64 func(u64 value)`. //! Passes `t1` as the argument. Result lands in `t0`. The handler continues //! after the call. Does NOT reload pinned state. -//! - `call_interp func` -- **Non-terminal.** Calls `i64 func(Interpreter*, u32 pc)`. +//! - `call_interp func` -- **Non-terminal.** Calls `i64 func(VM*, u32 pc)`. //! Result lands in `t0`. The handler continues. Does NOT reload pinned state. -//! - `reload_exec_ctx` -- Reload the exec_ctx register from the Interpreter*. +//! - `reload_exec_ctx` -- Reload the exec_ctx register from the VM*. //! Used after non-terminal calls that may modify the running execution context. //! //! ### Bytecode operand access diff --git a/Libraries/LibJS/Bytecode/AsmInterpreter/AsmInterpreter.cpp b/Libraries/LibJS/Bytecode/AsmInterpreter/AsmInterpreter.cpp index f054634fca..7e97cbf293 100644 --- a/Libraries/LibJS/Bytecode/AsmInterpreter/AsmInterpreter.cpp +++ b/Libraries/LibJS/Bytecode/AsmInterpreter/AsmInterpreter.cpp @@ -7,7 +7,6 @@ #include #include #include -#include #include #include #include @@ -17,6 +16,7 @@ #include #include #include +#include #include #include #include @@ -92,7 +92,7 @@ namespace JS::Bytecode { #if HAS_ASM_INTERPRETER // Defined in generated assembly (asmint_x86_64.S or asmint_aarch64.S) -extern "C" void asm_interpreter_entry(u8 const* bytecode, u32 entry_point, Value* values, Interpreter* interp); +extern "C" void asm_interpreter_entry(u8 const* bytecode, u32 entry_point, Value* values, VM* vm); #endif bool AsmInterpreter::is_available() @@ -100,10 +100,10 @@ bool AsmInterpreter::is_available() return HAS_ASM_INTERPRETER; } -void AsmInterpreter::run(Interpreter& interp, [[maybe_unused]] size_t entry_point) +void AsmInterpreter::run(VM& vm, [[maybe_unused]] size_t entry_point) { #if !HAS_ASM_INTERPRETER - (void)interp; + (void)vm; VERIFY_NOT_REACHED(); #else # ifdef JS_ASMINT_SLOW_PATH_COUNTERS @@ -113,11 +113,11 @@ void AsmInterpreter::run(Interpreter& interp, [[maybe_unused]] size_t entry_poin } # endif - auto& context = interp.running_execution_context(); + auto& context = vm.running_execution_context(); auto* bytecode = context.executable->bytecode.data(); auto* values = context.registers_and_constants_and_locals_and_arguments_span().data(); - asm_interpreter_entry(bytecode, static_cast(entry_point), values, &interp); + asm_interpreter_entry(bytecode, static_cast(entry_point), values, &vm); #endif } @@ -125,32 +125,32 @@ void AsmInterpreter::run(Interpreter& interp, [[maybe_unused]] size_t entry_poin // ===== Slow path functions callable from assembly ===== // All slow path functions follow the same convention: -// i64 func(Interpreter* interp, u32 pc) +// i64 func(VM* vm, u32 pc) // Returns >= 0: new program counter to dispatch to // Returns < 0: should exit the asm interpreter using namespace JS; using namespace JS::Bytecode; -static i64 handle_asm_exception(Interpreter& interp, u32 pc, Value exception) +static i64 handle_asm_exception(VM& vm, u32 pc, Value exception) { - auto response = interp.handle_exception(pc, exception); - if (response == Interpreter::HandleExceptionResponse::ExitFromExecutable) + auto response = vm.handle_exception(pc, exception); + if (response == VM::HandleExceptionResponse::ExitFromExecutable) return -1; // ContinueInThisExecutable: new pc is in the execution context - return static_cast(interp.running_execution_context().program_counter); + return static_cast(vm.running_execution_context().program_counter); } // Helper: execute a throwing instruction and handle errors template -static i64 execute_throwing(Interpreter& interp, u32 pc) +static i64 execute_throwing(VM& vm, u32 pc) { - interp.running_execution_context().program_counter = pc; - auto* bytecode = interp.current_executable().bytecode.data(); + vm.running_execution_context().program_counter = pc; + auto* bytecode = vm.current_executable().bytecode.data(); auto& insn = *reinterpret_cast(&bytecode[pc]); - auto result = insn.execute_impl(interp); + auto result = insn.execute_impl(vm); if (result.is_error()) [[unlikely]] - return handle_asm_exception(interp, pc, result.error_value()); + return handle_asm_exception(vm, pc, result.error_value()); if constexpr (InsnType::IsVariableLength) return static_cast(pc + insn.length()); else @@ -159,12 +159,12 @@ static i64 execute_throwing(Interpreter& interp, u32 pc) // Helper: execute a non-throwing instruction template -static i64 execute_nonthrowing(Interpreter& interp, u32 pc) +static i64 execute_nonthrowing(VM& vm, u32 pc) { - interp.running_execution_context().program_counter = pc; - auto* bytecode = interp.current_executable().bytecode.data(); + vm.running_execution_context().program_counter = pc; + auto* bytecode = vm.current_executable().bytecode.data(); auto& insn = *reinterpret_cast(&bytecode[pc]); - insn.execute_impl(interp); + insn.execute_impl(vm); if constexpr (InsnType::IsVariableLength) return static_cast(pc + insn.length()); else @@ -174,132 +174,132 @@ static i64 execute_nonthrowing(Interpreter& interp, u32 pc) // Slow path wrappers: optionally bump per-opcode counter, then delegate. #ifdef JS_ASMINT_SLOW_PATH_COUNTERS template -ALWAYS_INLINE static i64 slow_path_throwing(Interpreter& interp, u32 pc) +ALWAYS_INLINE static i64 slow_path_throwing(VM& vm, u32 pc) { - ++s_stats.slow_path_by_type[static_cast(Instruction::Type { interp.current_executable().bytecode[pc] })]; - return execute_throwing(interp, pc); + ++s_stats.slow_path_by_type[static_cast(Instruction::Type { vm.current_executable().bytecode[pc] })]; + return execute_throwing(vm, pc); } template -ALWAYS_INLINE static i64 slow_path_nonthrowing(Interpreter& interp, u32 pc) +ALWAYS_INLINE static i64 slow_path_nonthrowing(VM& vm, u32 pc) { - ++s_stats.slow_path_by_type[static_cast(Instruction::Type { interp.current_executable().bytecode[pc] })]; - return execute_nonthrowing(interp, pc); + ++s_stats.slow_path_by_type[static_cast(Instruction::Type { vm.current_executable().bytecode[pc] })]; + return execute_nonthrowing(vm, pc); } -ALWAYS_INLINE static void bump_slow_path(Interpreter& interp, u32 pc) +ALWAYS_INLINE static void bump_slow_path(VM& vm, u32 pc) { - ++s_stats.slow_path_by_type[static_cast(Instruction::Type { interp.current_executable().bytecode[pc] })]; + ++s_stats.slow_path_by_type[static_cast(Instruction::Type { vm.current_executable().bytecode[pc] })]; } #else template -ALWAYS_INLINE static i64 slow_path_throwing(Interpreter& interp, u32 pc) +ALWAYS_INLINE static i64 slow_path_throwing(VM& vm, u32 pc) { - return execute_throwing(interp, pc); + return execute_throwing(vm, pc); } template -ALWAYS_INLINE static i64 slow_path_nonthrowing(Interpreter& interp, u32 pc) +ALWAYS_INLINE static i64 slow_path_nonthrowing(VM& vm, u32 pc) { - return execute_nonthrowing(interp, pc); + return execute_nonthrowing(vm, pc); } -ALWAYS_INLINE static void bump_slow_path(Interpreter&, u32) { } +ALWAYS_INLINE static void bump_slow_path(VM&, u32) { } #endif extern "C" { // Forward declarations for all functions called from assembly. -i64 asm_fallback_handler(Interpreter*, u32 pc); -i64 asm_slow_path_add(Interpreter*, u32 pc); -i64 asm_slow_path_sub(Interpreter*, u32 pc); -i64 asm_slow_path_mul(Interpreter*, u32 pc); -i64 asm_slow_path_div(Interpreter*, u32 pc); -i64 asm_slow_path_increment(Interpreter*, u32 pc); -i64 asm_slow_path_decrement(Interpreter*, u32 pc); -i64 asm_slow_path_less_than(Interpreter*, u32 pc); -i64 asm_slow_path_less_than_equals(Interpreter*, u32 pc); -i64 asm_slow_path_greater_than(Interpreter*, u32 pc); -i64 asm_slow_path_greater_than_equals(Interpreter*, u32 pc); -i64 asm_slow_path_jump_less_than(Interpreter*, u32 pc); -i64 asm_slow_path_jump_greater_than(Interpreter*, u32 pc); -i64 asm_slow_path_jump_less_than_equals(Interpreter*, u32 pc); -i64 asm_slow_path_jump_greater_than_equals(Interpreter*, u32 pc); -i64 asm_slow_path_jump_loosely_equals(Interpreter*, u32 pc); -i64 asm_slow_path_jump_loosely_inequals(Interpreter*, u32 pc); -i64 asm_slow_path_jump_strictly_equals(Interpreter*, u32 pc); -i64 asm_slow_path_jump_strictly_inequals(Interpreter*, u32 pc); -i64 asm_slow_path_set_lexical_environment(Interpreter*, u32 pc); -i64 asm_slow_path_postfix_increment(Interpreter*, u32 pc); -i64 asm_slow_path_get_by_id(Interpreter*, u32 pc); -i64 asm_slow_path_put_by_id(Interpreter*, u32 pc); -i64 asm_slow_path_get_by_value(Interpreter*, u32 pc); -i64 asm_slow_path_get_length(Interpreter*, u32 pc); -i64 asm_try_get_global_env_binding(Interpreter*, u32 pc); -i64 asm_try_set_global_env_binding(Interpreter*, u32 pc); -i64 asm_slow_path_get_global(Interpreter*, u32 pc); -i64 asm_slow_path_set_global(Interpreter*, u32 pc); -i64 asm_slow_path_call(Interpreter*, u32 pc); +i64 asm_fallback_handler(VM*, u32 pc); +i64 asm_slow_path_add(VM*, u32 pc); +i64 asm_slow_path_sub(VM*, u32 pc); +i64 asm_slow_path_mul(VM*, u32 pc); +i64 asm_slow_path_div(VM*, u32 pc); +i64 asm_slow_path_increment(VM*, u32 pc); +i64 asm_slow_path_decrement(VM*, u32 pc); +i64 asm_slow_path_less_than(VM*, u32 pc); +i64 asm_slow_path_less_than_equals(VM*, u32 pc); +i64 asm_slow_path_greater_than(VM*, u32 pc); +i64 asm_slow_path_greater_than_equals(VM*, u32 pc); +i64 asm_slow_path_jump_less_than(VM*, u32 pc); +i64 asm_slow_path_jump_greater_than(VM*, u32 pc); +i64 asm_slow_path_jump_less_than_equals(VM*, u32 pc); +i64 asm_slow_path_jump_greater_than_equals(VM*, u32 pc); +i64 asm_slow_path_jump_loosely_equals(VM*, u32 pc); +i64 asm_slow_path_jump_loosely_inequals(VM*, u32 pc); +i64 asm_slow_path_jump_strictly_equals(VM*, u32 pc); +i64 asm_slow_path_jump_strictly_inequals(VM*, u32 pc); +i64 asm_slow_path_set_lexical_environment(VM*, u32 pc); +i64 asm_slow_path_postfix_increment(VM*, u32 pc); +i64 asm_slow_path_get_by_id(VM*, u32 pc); +i64 asm_slow_path_put_by_id(VM*, u32 pc); +i64 asm_slow_path_get_by_value(VM*, u32 pc); +i64 asm_slow_path_get_length(VM*, u32 pc); +i64 asm_try_get_global_env_binding(VM*, u32 pc); +i64 asm_try_set_global_env_binding(VM*, u32 pc); +i64 asm_slow_path_get_global(VM*, u32 pc); +i64 asm_slow_path_set_global(VM*, u32 pc); +i64 asm_slow_path_call(VM*, u32 pc); #define DECLARE_CALL_BUILTIN_SLOW_PATH(name, snake_case_name, ...) \ - i64 asm_slow_path_call_builtin_##snake_case_name(Interpreter*, u32 pc); + i64 asm_slow_path_call_builtin_##snake_case_name(VM*, u32 pc); JS_ENUMERATE_BUILTINS(DECLARE_CALL_BUILTIN_SLOW_PATH) #undef DECLARE_CALL_BUILTIN_SLOW_PATH -i64 asm_slow_path_get_object_property_iterator(Interpreter*, u32 pc); -i64 asm_slow_path_object_property_iterator_next(Interpreter*, u32 pc); -i64 asm_slow_path_call_construct(Interpreter*, u32 pc); -i64 asm_slow_path_new_object(Interpreter*, u32 pc); -i64 asm_slow_path_cache_object_shape(Interpreter*, u32 pc); -i64 asm_slow_path_init_object_literal_property(Interpreter*, u32 pc); -i64 asm_slow_path_new_array(Interpreter*, u32 pc); -i64 asm_slow_path_bitwise_xor(Interpreter*, u32 pc); -i64 asm_slow_path_bitwise_and(Interpreter*, u32 pc); -i64 asm_slow_path_bitwise_or(Interpreter*, u32 pc); -i64 asm_slow_path_left_shift(Interpreter*, u32 pc); -i64 asm_slow_path_right_shift(Interpreter*, u32 pc); -i64 asm_slow_path_unsigned_right_shift(Interpreter*, u32 pc); -i64 asm_slow_path_mod(Interpreter*, u32 pc); -i64 asm_slow_path_strictly_equals(Interpreter*, u32 pc); -i64 asm_slow_path_strictly_inequals(Interpreter*, u32 pc); -i64 asm_slow_path_unary_minus(Interpreter*, u32 pc); -i64 asm_slow_path_postfix_decrement(Interpreter*, u32 pc); -i64 asm_slow_path_to_int32(Interpreter*, u32 pc); -i64 asm_slow_path_put_by_value(Interpreter*, u32 pc); -i64 asm_try_put_by_value_holey_array(Interpreter*, u32 pc); +i64 asm_slow_path_get_object_property_iterator(VM*, u32 pc); +i64 asm_slow_path_object_property_iterator_next(VM*, u32 pc); +i64 asm_slow_path_call_construct(VM*, u32 pc); +i64 asm_slow_path_new_object(VM*, u32 pc); +i64 asm_slow_path_cache_object_shape(VM*, u32 pc); +i64 asm_slow_path_init_object_literal_property(VM*, u32 pc); +i64 asm_slow_path_new_array(VM*, u32 pc); +i64 asm_slow_path_bitwise_xor(VM*, u32 pc); +i64 asm_slow_path_bitwise_and(VM*, u32 pc); +i64 asm_slow_path_bitwise_or(VM*, u32 pc); +i64 asm_slow_path_left_shift(VM*, u32 pc); +i64 asm_slow_path_right_shift(VM*, u32 pc); +i64 asm_slow_path_unsigned_right_shift(VM*, u32 pc); +i64 asm_slow_path_mod(VM*, u32 pc); +i64 asm_slow_path_strictly_equals(VM*, u32 pc); +i64 asm_slow_path_strictly_inequals(VM*, u32 pc); +i64 asm_slow_path_unary_minus(VM*, u32 pc); +i64 asm_slow_path_postfix_decrement(VM*, u32 pc); +i64 asm_slow_path_to_int32(VM*, u32 pc); +i64 asm_slow_path_put_by_value(VM*, u32 pc); +i64 asm_try_put_by_value_holey_array(VM*, u32 pc); u64 asm_helper_to_boolean(u64 encoded_value); u64 asm_helper_math_exp(u64 encoded_value); u64 asm_helper_empty_string(u64); u64 asm_helper_single_ascii_character_string(u64 encoded_value); u64 asm_helper_single_utf16_code_unit_string(u64 encoded_value); -i64 asm_try_inline_call(Interpreter*, u32 pc); -i64 asm_pop_inline_frame(Interpreter*, u32 pc); -i64 asm_pop_inline_frame_end(Interpreter*, u32 pc); -i64 asm_try_put_by_id_cache(Interpreter*, u32 pc); -i64 asm_try_get_by_id_cache(Interpreter*, u32 pc); -i64 asm_slow_path_initialize_lexical_binding(Interpreter*, u32 pc); +i64 asm_try_inline_call(VM*, u32 pc); +i64 asm_pop_inline_frame(VM*, u32 pc); +i64 asm_pop_inline_frame_end(VM*, u32 pc); +i64 asm_try_put_by_id_cache(VM*, u32 pc); +i64 asm_try_get_by_id_cache(VM*, u32 pc); +i64 asm_slow_path_initialize_lexical_binding(VM*, u32 pc); -i64 asm_try_get_by_value_typed_array(Interpreter*, u32 pc); -i64 asm_slow_path_get_initialized_binding(Interpreter*, u32 pc); -i64 asm_slow_path_get_binding(Interpreter*, u32 pc); -i64 asm_slow_path_set_lexical_binding(Interpreter*, u32 pc); -i64 asm_slow_path_bitwise_not(Interpreter*, u32 pc); -i64 asm_slow_path_unary_plus(Interpreter*, u32 pc); -i64 asm_slow_path_throw_if_tdz(Interpreter*, u32 pc); -i64 asm_slow_path_throw_if_not_object(Interpreter*, u32 pc); -i64 asm_slow_path_throw_if_nullish(Interpreter*, u32 pc); -i64 asm_slow_path_loosely_equals(Interpreter*, u32 pc); -i64 asm_slow_path_loosely_inequals(Interpreter*, u32 pc); -i64 asm_slow_path_get_callee_and_this(Interpreter*, u32 pc); -i64 asm_try_put_by_value_typed_array(Interpreter*, u32 pc); -i64 asm_slow_path_get_private_by_id(Interpreter*, u32 pc); -i64 asm_slow_path_put_private_by_id(Interpreter*, u32 pc); -i64 asm_slow_path_instance_of(Interpreter*, u32 pc); -i64 asm_slow_path_resolve_this_binding(Interpreter*, u32 pc); +i64 asm_try_get_by_value_typed_array(VM*, u32 pc); +i64 asm_slow_path_get_initialized_binding(VM*, u32 pc); +i64 asm_slow_path_get_binding(VM*, u32 pc); +i64 asm_slow_path_set_lexical_binding(VM*, u32 pc); +i64 asm_slow_path_bitwise_not(VM*, u32 pc); +i64 asm_slow_path_unary_plus(VM*, u32 pc); +i64 asm_slow_path_throw_if_tdz(VM*, u32 pc); +i64 asm_slow_path_throw_if_not_object(VM*, u32 pc); +i64 asm_slow_path_throw_if_nullish(VM*, u32 pc); +i64 asm_slow_path_loosely_equals(VM*, u32 pc); +i64 asm_slow_path_loosely_inequals(VM*, u32 pc); +i64 asm_slow_path_get_callee_and_this(VM*, u32 pc); +i64 asm_try_put_by_value_typed_array(VM*, u32 pc); +i64 asm_slow_path_get_private_by_id(VM*, u32 pc); +i64 asm_slow_path_put_private_by_id(VM*, u32 pc); +i64 asm_slow_path_instance_of(VM*, u32 pc); +i64 asm_slow_path_resolve_this_binding(VM*, u32 pc); // ===== Fallback handler for opcodes without DSL handlers ===== // NB: Opcodes with DSL handlers are dispatched directly and never reach here. -i64 asm_fallback_handler(Interpreter* interp, u32 pc) +i64 asm_fallback_handler(VM* vm, u32 pc) { - auto& ctx = interp->running_execution_context(); + auto& ctx = vm->running_execution_context(); ctx.program_counter = pc; auto* bytecode = ctx.executable->bytecode.data(); auto& insn = *reinterpret_cast(&bytecode[pc]); @@ -311,161 +311,161 @@ i64 asm_fallback_handler(Interpreter* interp, u32 pc) // Terminators case Instruction::Type::Throw: { auto& typed = *reinterpret_cast(&bytecode[pc]); - auto result = typed.execute_impl(*interp); - return handle_asm_exception(*interp, pc, result.error_value()); + auto result = typed.execute_impl(*vm); + return handle_asm_exception(*vm, pc, result.error_value()); } case Instruction::Type::Await: { auto& typed = *reinterpret_cast(&bytecode[pc]); - typed.execute_impl(*interp); + typed.execute_impl(*vm); return -1; } case Instruction::Type::Yield: { auto& typed = *reinterpret_cast(&bytecode[pc]); - typed.execute_impl(*interp); + typed.execute_impl(*vm); return -1; } // Non-throwing instructions case Instruction::Type::AddPrivateName: - return execute_nonthrowing(*interp, pc); + return execute_nonthrowing(*vm, pc); case Instruction::Type::Catch: - return execute_nonthrowing(*interp, pc); + return execute_nonthrowing(*vm, pc); case Instruction::Type::CreateAsyncFromSyncIterator: - return execute_nonthrowing(*interp, pc); + return execute_nonthrowing(*vm, pc); case Instruction::Type::CreateLexicalEnvironment: - return execute_nonthrowing(*interp, pc); + return execute_nonthrowing(*vm, pc); case Instruction::Type::CreateVariableEnvironment: - return execute_nonthrowing(*interp, pc); + return execute_nonthrowing(*vm, pc); case Instruction::Type::CreatePrivateEnvironment: - return execute_nonthrowing(*interp, pc); + return execute_nonthrowing(*vm, pc); case Instruction::Type::CreateRestParams: - return execute_nonthrowing(*interp, pc); + return execute_nonthrowing(*vm, pc); case Instruction::Type::CreateArguments: - return execute_nonthrowing(*interp, pc); + return execute_nonthrowing(*vm, pc); case Instruction::Type::GetCompletionFields: - return execute_nonthrowing(*interp, pc); + return execute_nonthrowing(*vm, pc); case Instruction::Type::GetImportMeta: - return execute_nonthrowing(*interp, pc); + return execute_nonthrowing(*vm, pc); case Instruction::Type::GetNewTarget: - return execute_nonthrowing(*interp, pc); + return execute_nonthrowing(*vm, pc); case Instruction::Type::GetTemplateObject: - return execute_nonthrowing(*interp, pc); + return execute_nonthrowing(*vm, pc); case Instruction::Type::IsCallable: - return execute_nonthrowing(*interp, pc); + return execute_nonthrowing(*vm, pc); case Instruction::Type::IsConstructor: - return execute_nonthrowing(*interp, pc); + return execute_nonthrowing(*vm, pc); case Instruction::Type::LeavePrivateEnvironment: - return execute_nonthrowing(*interp, pc); + return execute_nonthrowing(*vm, pc); case Instruction::Type::NewFunction: - return execute_nonthrowing(*interp, pc); + return execute_nonthrowing(*vm, pc); case Instruction::Type::NewObjectWithNoPrototype: - return execute_nonthrowing(*interp, pc); + return execute_nonthrowing(*vm, pc); case Instruction::Type::NewPrimitiveArray: - return execute_nonthrowing(*interp, pc); + return execute_nonthrowing(*vm, pc); case Instruction::Type::NewRegExp: - return execute_nonthrowing(*interp, pc); + return execute_nonthrowing(*vm, pc); case Instruction::Type::NewReferenceError: - return execute_nonthrowing(*interp, pc); + return execute_nonthrowing(*vm, pc); case Instruction::Type::NewTypeError: - return execute_nonthrowing(*interp, pc); + return execute_nonthrowing(*vm, pc); case Instruction::Type::SetCompletionType: - return execute_nonthrowing(*interp, pc); + return execute_nonthrowing(*vm, pc); case Instruction::Type::ToBoolean: - return execute_nonthrowing(*interp, pc); + return execute_nonthrowing(*vm, pc); case Instruction::Type::Typeof: - return execute_nonthrowing(*interp, pc); + return execute_nonthrowing(*vm, pc); // Throwing instructions case Instruction::Type::ArrayAppend: - return execute_throwing(*interp, pc); + return execute_throwing(*vm, pc); case Instruction::Type::ToString: - return execute_throwing(*interp, pc); + return execute_throwing(*vm, pc); case Instruction::Type::ToPrimitiveWithStringHint: - return execute_throwing(*interp, pc); + return execute_throwing(*vm, pc); case Instruction::Type::CallConstructWithArgumentArray: - return execute_throwing(*interp, pc); + return execute_throwing(*vm, pc); case Instruction::Type::CallDirectEval: - return execute_throwing(*interp, pc); + return execute_throwing(*vm, pc); case Instruction::Type::CallDirectEvalWithArgumentArray: - return execute_throwing(*interp, pc); + return execute_throwing(*vm, pc); case Instruction::Type::CallWithArgumentArray: - return execute_throwing(*interp, pc); + return execute_throwing(*vm, pc); case Instruction::Type::ConcatString: - return execute_throwing(*interp, pc); + return execute_throwing(*vm, pc); case Instruction::Type::CopyObjectExcludingProperties: - return execute_throwing(*interp, pc); + return execute_throwing(*vm, pc); case Instruction::Type::CreateDataPropertyOrThrow: - return execute_throwing(*interp, pc); + return execute_throwing(*vm, pc); case Instruction::Type::CreateImmutableBinding: - return execute_throwing(*interp, pc); + return execute_throwing(*vm, pc); case Instruction::Type::CreateMutableBinding: - return execute_throwing(*interp, pc); + return execute_throwing(*vm, pc); case Instruction::Type::CreateVariable: - return execute_throwing(*interp, pc); + return execute_throwing(*vm, pc); case Instruction::Type::DeleteById: - return execute_throwing(*interp, pc); + return execute_throwing(*vm, pc); case Instruction::Type::DeleteByValue: - return execute_throwing(*interp, pc); + return execute_throwing(*vm, pc); case Instruction::Type::DeleteVariable: - return execute_throwing(*interp, pc); + return execute_throwing(*vm, pc); case Instruction::Type::EnterObjectEnvironment: - return execute_throwing(*interp, pc); + return execute_throwing(*vm, pc); case Instruction::Type::Exp: - return execute_throwing(*interp, pc); + return execute_throwing(*vm, pc); case Instruction::Type::GetByIdWithThis: - return execute_throwing(*interp, pc); + return execute_throwing(*vm, pc); case Instruction::Type::GetByValueWithThis: - return execute_throwing(*interp, pc); + return execute_throwing(*vm, pc); case Instruction::Type::GetIterator: - return execute_throwing(*interp, pc); + return execute_throwing(*vm, pc); case Instruction::Type::GetLengthWithThis: - return execute_throwing(*interp, pc); + return execute_throwing(*vm, pc); case Instruction::Type::GetMethod: - return execute_throwing(*interp, pc); + return execute_throwing(*vm, pc); case Instruction::Type::GetObjectPropertyIterator: - return execute_throwing(*interp, pc); + return execute_throwing(*vm, pc); case Instruction::Type::ObjectPropertyIteratorNext: - return execute_throwing(*interp, pc); + return execute_throwing(*vm, pc); case Instruction::Type::HasPrivateId: - return execute_throwing(*interp, pc); + return execute_throwing(*vm, pc); case Instruction::Type::ImportCall: - return execute_throwing(*interp, pc); + return execute_throwing(*vm, pc); case Instruction::Type::In: - return execute_throwing(*interp, pc); + return execute_throwing(*vm, pc); case Instruction::Type::InitializeVariableBinding: - return execute_throwing(*interp, pc); + return execute_throwing(*vm, pc); case Instruction::Type::IteratorClose: - return execute_throwing(*interp, pc); + return execute_throwing(*vm, pc); case Instruction::Type::IteratorNext: - return execute_throwing(*interp, pc); + return execute_throwing(*vm, pc); case Instruction::Type::IteratorNextUnpack: - return execute_throwing(*interp, pc); + return execute_throwing(*vm, pc); case Instruction::Type::IteratorToArray: - return execute_throwing(*interp, pc); + return execute_throwing(*vm, pc); case Instruction::Type::NewArrayWithLength: - return execute_throwing(*interp, pc); + return execute_throwing(*vm, pc); case Instruction::Type::NewClass: - return execute_throwing(*interp, pc); + return execute_throwing(*vm, pc); case Instruction::Type::PutByIdWithThis: - return execute_throwing(*interp, pc); + return execute_throwing(*vm, pc); case Instruction::Type::PutBySpread: - return execute_throwing(*interp, pc); + return execute_throwing(*vm, pc); case Instruction::Type::PutByValueWithThis: - return execute_throwing(*interp, pc); + return execute_throwing(*vm, pc); case Instruction::Type::ResolveSuperBase: - return execute_throwing(*interp, pc); + return execute_throwing(*vm, pc); case Instruction::Type::SetVariableBinding: - return execute_throwing(*interp, pc); + return execute_throwing(*vm, pc); case Instruction::Type::SuperCallWithArgumentArray: - return execute_throwing(*interp, pc); + return execute_throwing(*vm, pc); case Instruction::Type::ThrowConstAssignment: - return execute_throwing(*interp, pc); + return execute_throwing(*vm, pc); case Instruction::Type::ToLength: - return execute_throwing(*interp, pc); + return execute_throwing(*vm, pc); case Instruction::Type::ToObject: - return execute_throwing(*interp, pc); + return execute_throwing(*vm, pc); case Instruction::Type::TypeofBinding: - return execute_throwing(*interp, pc); + return execute_throwing(*vm, pc); default: VERIFY_NOT_REACHED(); @@ -474,119 +474,119 @@ i64 asm_fallback_handler(Interpreter* interp, u32 pc) // ===== Specific slow paths for asm-optimized instructions ===== // These are called from asm handlers when the fast path fails. -// Convention: i64 func(Interpreter*, u32 pc) +// Convention: i64 func(VM*, u32 pc) // Returns >= 0: new pc // Returns < 0: exit -i64 asm_slow_path_add(Interpreter* interp, u32 pc) +i64 asm_slow_path_add(VM* vm, u32 pc) { - return slow_path_throwing(*interp, pc); + return slow_path_throwing(*vm, pc); } -i64 asm_slow_path_sub(Interpreter* interp, u32 pc) +i64 asm_slow_path_sub(VM* vm, u32 pc) { - return slow_path_throwing(*interp, pc); + return slow_path_throwing(*vm, pc); } -i64 asm_slow_path_mul(Interpreter* interp, u32 pc) +i64 asm_slow_path_mul(VM* vm, u32 pc) { - return slow_path_throwing(*interp, pc); + return slow_path_throwing(*vm, pc); } -i64 asm_slow_path_div(Interpreter* interp, u32 pc) +i64 asm_slow_path_div(VM* vm, u32 pc) { - return slow_path_throwing(*interp, pc); + return slow_path_throwing(*vm, pc); } -i64 asm_slow_path_less_than(Interpreter* interp, u32 pc) +i64 asm_slow_path_less_than(VM* vm, u32 pc) { - return slow_path_throwing(*interp, pc); + return slow_path_throwing(*vm, pc); } -i64 asm_slow_path_less_than_equals(Interpreter* interp, u32 pc) +i64 asm_slow_path_less_than_equals(VM* vm, u32 pc) { - return slow_path_throwing(*interp, pc); + return slow_path_throwing(*vm, pc); } -i64 asm_slow_path_greater_than(Interpreter* interp, u32 pc) +i64 asm_slow_path_greater_than(VM* vm, u32 pc) { - return slow_path_throwing(*interp, pc); + return slow_path_throwing(*vm, pc); } -i64 asm_slow_path_greater_than_equals(Interpreter* interp, u32 pc) +i64 asm_slow_path_greater_than_equals(VM* vm, u32 pc) { - return slow_path_throwing(*interp, pc); + return slow_path_throwing(*vm, pc); } -i64 asm_slow_path_increment(Interpreter* interp, u32 pc) +i64 asm_slow_path_increment(VM* vm, u32 pc) { - return slow_path_throwing(*interp, pc); + return slow_path_throwing(*vm, pc); } -i64 asm_slow_path_decrement(Interpreter* interp, u32 pc) +i64 asm_slow_path_decrement(VM* vm, u32 pc) { - return slow_path_throwing(*interp, pc); + return slow_path_throwing(*vm, pc); } // Comparison jump slow paths - these are terminators (execute_impl returns void), // so they need custom handling instead of the generic slow_path_throwing template. #define DEFINE_JUMP_COMPARISON_SLOW_PATH(snake_name, op_name, compare_call) \ - i64 asm_slow_path_jump_##snake_name(Interpreter* interp, u32 pc) \ + i64 asm_slow_path_jump_##snake_name(VM* vm, u32 pc) \ { \ - bump_slow_path(*interp, pc); \ - auto* bytecode = interp->current_executable().bytecode.data(); \ + bump_slow_path(*vm, pc); \ + auto* bytecode = vm->current_executable().bytecode.data(); \ auto& insn = *reinterpret_cast(&bytecode[pc]); \ - auto lhs = interp->get(insn.lhs()); \ - auto rhs = interp->get(insn.rhs()); \ + auto lhs = vm->get(insn.lhs()); \ + auto rhs = vm->get(insn.rhs()); \ auto result = compare_call; \ if (result.is_error()) [[unlikely]] \ - return handle_asm_exception(*interp, pc, result.error_value()); \ + return handle_asm_exception(*vm, pc, result.error_value()); \ if (result.value()) \ return static_cast(insn.true_target().address()); \ return static_cast(insn.false_target().address()); \ } -DEFINE_JUMP_COMPARISON_SLOW_PATH(less_than, LessThan, less_than(Interpreter::vm(), lhs, rhs)) -DEFINE_JUMP_COMPARISON_SLOW_PATH(greater_than, GreaterThan, greater_than(Interpreter::vm(), lhs, rhs)) -DEFINE_JUMP_COMPARISON_SLOW_PATH(less_than_equals, LessThanEquals, less_than_equals(Interpreter::vm(), lhs, rhs)) -DEFINE_JUMP_COMPARISON_SLOW_PATH(greater_than_equals, GreaterThanEquals, greater_than_equals(Interpreter::vm(), lhs, rhs)) -DEFINE_JUMP_COMPARISON_SLOW_PATH(loosely_equals, LooselyEquals, is_loosely_equal(Interpreter::vm(), lhs, rhs)) +DEFINE_JUMP_COMPARISON_SLOW_PATH(less_than, LessThan, less_than(VM::the(), lhs, rhs)) +DEFINE_JUMP_COMPARISON_SLOW_PATH(greater_than, GreaterThan, greater_than(VM::the(), lhs, rhs)) +DEFINE_JUMP_COMPARISON_SLOW_PATH(less_than_equals, LessThanEquals, less_than_equals(VM::the(), lhs, rhs)) +DEFINE_JUMP_COMPARISON_SLOW_PATH(greater_than_equals, GreaterThanEquals, greater_than_equals(VM::the(), lhs, rhs)) +DEFINE_JUMP_COMPARISON_SLOW_PATH(loosely_equals, LooselyEquals, is_loosely_equal(VM::the(), lhs, rhs)) #undef DEFINE_JUMP_COMPARISON_SLOW_PATH -i64 asm_slow_path_jump_loosely_inequals(Interpreter* interp, u32 pc) +i64 asm_slow_path_jump_loosely_inequals(VM* vm, u32 pc) { - bump_slow_path(*interp, pc); - auto* bytecode = interp->current_executable().bytecode.data(); + bump_slow_path(*vm, pc); + auto* bytecode = vm->current_executable().bytecode.data(); auto& insn = *reinterpret_cast(&bytecode[pc]); - auto lhs = interp->get(insn.lhs()); - auto rhs = interp->get(insn.rhs()); - auto result = is_loosely_equal(Interpreter::vm(), lhs, rhs); + auto lhs = vm->get(insn.lhs()); + auto rhs = vm->get(insn.rhs()); + auto result = is_loosely_equal(VM::the(), lhs, rhs); if (result.is_error()) [[unlikely]] - return handle_asm_exception(*interp, pc, result.error_value()); + return handle_asm_exception(*vm, pc, result.error_value()); if (!result.value()) return static_cast(insn.true_target().address()); return static_cast(insn.false_target().address()); } -i64 asm_slow_path_jump_strictly_equals(Interpreter* interp, u32 pc) +i64 asm_slow_path_jump_strictly_equals(VM* vm, u32 pc) { - bump_slow_path(*interp, pc); - auto* bytecode = interp->current_executable().bytecode.data(); + bump_slow_path(*vm, pc); + auto* bytecode = vm->current_executable().bytecode.data(); auto& insn = *reinterpret_cast(&bytecode[pc]); - auto lhs = interp->get(insn.lhs()); - auto rhs = interp->get(insn.rhs()); + auto lhs = vm->get(insn.lhs()); + auto rhs = vm->get(insn.rhs()); if (is_strictly_equal(lhs, rhs)) return static_cast(insn.true_target().address()); return static_cast(insn.false_target().address()); } -i64 asm_slow_path_jump_strictly_inequals(Interpreter* interp, u32 pc) +i64 asm_slow_path_jump_strictly_inequals(VM* vm, u32 pc) { - bump_slow_path(*interp, pc); - auto* bytecode = interp->current_executable().bytecode.data(); + bump_slow_path(*vm, pc); + auto* bytecode = vm->current_executable().bytecode.data(); auto& insn = *reinterpret_cast(&bytecode[pc]); - auto lhs = interp->get(insn.lhs()); - auto rhs = interp->get(insn.rhs()); + auto lhs = vm->get(insn.lhs()); + auto rhs = vm->get(insn.rhs()); if (!is_strictly_equal(lhs, rhs)) return static_cast(insn.true_target().address()); return static_cast(insn.false_target().address()); @@ -594,243 +594,243 @@ i64 asm_slow_path_jump_strictly_inequals(Interpreter* interp, u32 pc) // ===== Dedicated slow paths for hot instructions ===== -i64 asm_slow_path_set_lexical_environment(Interpreter* interp, u32 pc) +i64 asm_slow_path_set_lexical_environment(VM* vm, u32 pc) { - return slow_path_nonthrowing(*interp, pc); + return slow_path_nonthrowing(*vm, pc); } -i64 asm_slow_path_get_initialized_binding(Interpreter* interp, u32 pc) +i64 asm_slow_path_get_initialized_binding(VM* vm, u32 pc) { - return slow_path_throwing(*interp, pc); + return slow_path_throwing(*vm, pc); } -i64 asm_slow_path_loosely_equals(Interpreter* interp, u32 pc) +i64 asm_slow_path_loosely_equals(VM* vm, u32 pc) { - return slow_path_throwing(*interp, pc); + return slow_path_throwing(*vm, pc); } -i64 asm_slow_path_loosely_inequals(Interpreter* interp, u32 pc) +i64 asm_slow_path_loosely_inequals(VM* vm, u32 pc) { - return slow_path_throwing(*interp, pc); + return slow_path_throwing(*vm, pc); } -i64 asm_slow_path_get_callee_and_this(Interpreter* interp, u32 pc) +i64 asm_slow_path_get_callee_and_this(VM* vm, u32 pc) { - return slow_path_throwing(*interp, pc); + return slow_path_throwing(*vm, pc); } -i64 asm_slow_path_postfix_increment(Interpreter* interp, u32 pc) +i64 asm_slow_path_postfix_increment(VM* vm, u32 pc) { - return slow_path_throwing(*interp, pc); + return slow_path_throwing(*vm, pc); } -i64 asm_slow_path_get_by_id(Interpreter* interp, u32 pc) +i64 asm_slow_path_get_by_id(VM* vm, u32 pc) { - return slow_path_throwing(*interp, pc); + return slow_path_throwing(*vm, pc); } -i64 asm_slow_path_put_by_id(Interpreter* interp, u32 pc) +i64 asm_slow_path_put_by_id(VM* vm, u32 pc) { - return slow_path_throwing(*interp, pc); + return slow_path_throwing(*vm, pc); } -i64 asm_slow_path_get_by_value(Interpreter* interp, u32 pc) +i64 asm_slow_path_get_by_value(VM* vm, u32 pc) { - return slow_path_throwing(*interp, pc); + return slow_path_throwing(*vm, pc); } -i64 asm_slow_path_get_length(Interpreter* interp, u32 pc) +i64 asm_slow_path_get_length(VM* vm, u32 pc) { - return slow_path_throwing(*interp, pc); + return slow_path_throwing(*vm, pc); } -i64 asm_try_get_global_env_binding(Interpreter* interp, u32 pc) +i64 asm_try_get_global_env_binding(VM* vm, u32 pc) { - auto* bytecode = interp->current_executable().bytecode.data(); + auto* bytecode = vm->current_executable().bytecode.data(); auto& insn = *reinterpret_cast(&bytecode[pc]); auto& cache = *bit_cast(insn.cache()); if (!cache.has_environment_binding_index) [[unlikely]] return 1; - auto& vm = Interpreter::vm(); + auto& current_vm = *vm; ThrowCompletionOr result = js_undefined(); if (cache.in_module_environment) { - auto module = vm.running_execution_context().script_or_module.get_pointer>(); + auto module = current_vm.running_execution_context().script_or_module.get_pointer>(); if (!module) [[unlikely]] return 1; - result = (*module)->environment()->get_binding_value_direct(vm, cache.environment_binding_index); + result = (*module)->environment()->get_binding_value_direct(current_vm, cache.environment_binding_index); } else { - result = interp->global_declarative_environment().get_binding_value_direct(vm, cache.environment_binding_index); + result = vm->global_declarative_environment().get_binding_value_direct(current_vm, cache.environment_binding_index); } if (result.is_error()) [[unlikely]] return 1; - interp->set(insn.dst(), result.value()); + vm->set(insn.dst(), result.value()); return 0; } -i64 asm_slow_path_get_global(Interpreter* interp, u32 pc) +i64 asm_slow_path_get_global(VM* vm, u32 pc) { - return slow_path_throwing(*interp, pc); + return slow_path_throwing(*vm, pc); } -i64 asm_try_set_global_env_binding(Interpreter* interp, u32 pc) +i64 asm_try_set_global_env_binding(VM* vm, u32 pc) { - auto* bytecode = interp->current_executable().bytecode.data(); + auto* bytecode = vm->current_executable().bytecode.data(); auto& insn = *reinterpret_cast(&bytecode[pc]); auto& cache = *bit_cast(insn.cache()); if (!cache.has_environment_binding_index) [[unlikely]] return 1; - auto& vm = Interpreter::vm(); - auto src = interp->get(insn.src()); + auto& current_vm = *vm; + auto src = vm->get(insn.src()); ThrowCompletionOr result; if (cache.in_module_environment) { - auto module = vm.running_execution_context().script_or_module.get_pointer>(); + auto module = current_vm.running_execution_context().script_or_module.get_pointer>(); if (!module) [[unlikely]] return 1; - result = (*module)->environment()->set_mutable_binding_direct(vm, cache.environment_binding_index, src, insn.strict() == Strict::Yes); + result = (*module)->environment()->set_mutable_binding_direct(current_vm, cache.environment_binding_index, src, insn.strict() == Strict::Yes); } else { - result = interp->global_declarative_environment().set_mutable_binding_direct(vm, cache.environment_binding_index, src, insn.strict() == Strict::Yes); + result = vm->global_declarative_environment().set_mutable_binding_direct(current_vm, cache.environment_binding_index, src, insn.strict() == Strict::Yes); } if (result.is_error()) [[unlikely]] return 1; return 0; } -i64 asm_slow_path_set_global(Interpreter* interp, u32 pc) +i64 asm_slow_path_set_global(VM* vm, u32 pc) { - return slow_path_throwing(*interp, pc); + return slow_path_throwing(*vm, pc); } -i64 asm_slow_path_call(Interpreter* interp, u32 pc) +i64 asm_slow_path_call(VM* vm, u32 pc) { - return slow_path_throwing(*interp, pc); + return slow_path_throwing(*vm, pc); } -i64 asm_slow_path_get_object_property_iterator(Interpreter* interp, u32 pc) +i64 asm_slow_path_get_object_property_iterator(VM* vm, u32 pc) { - return slow_path_throwing(*interp, pc); + return slow_path_throwing(*vm, pc); } -i64 asm_slow_path_object_property_iterator_next(Interpreter* interp, u32 pc) +i64 asm_slow_path_object_property_iterator_next(VM* vm, u32 pc) { - return slow_path_throwing(*interp, pc); + return slow_path_throwing(*vm, pc); } -#define DEFINE_CALL_BUILTIN_SLOW_PATH(name, snake_case_name, ...) \ - i64 asm_slow_path_call_builtin_##snake_case_name(Interpreter* interp, u32 pc) \ - { \ - return slow_path_throwing(*interp, pc); \ +#define DEFINE_CALL_BUILTIN_SLOW_PATH(name, snake_case_name, ...) \ + i64 asm_slow_path_call_builtin_##snake_case_name(VM* vm, u32 pc) \ + { \ + return slow_path_throwing(*vm, pc); \ } JS_ENUMERATE_BUILTINS(DEFINE_CALL_BUILTIN_SLOW_PATH) #undef DEFINE_CALL_BUILTIN_SLOW_PATH -i64 asm_slow_path_call_construct(Interpreter* interp, u32 pc) +i64 asm_slow_path_call_construct(VM* vm, u32 pc) { - return slow_path_throwing(*interp, pc); + return slow_path_throwing(*vm, pc); } -i64 asm_slow_path_new_object(Interpreter* interp, u32 pc) +i64 asm_slow_path_new_object(VM* vm, u32 pc) { - return slow_path_nonthrowing(*interp, pc); + return slow_path_nonthrowing(*vm, pc); } -i64 asm_slow_path_cache_object_shape(Interpreter* interp, u32 pc) +i64 asm_slow_path_cache_object_shape(VM* vm, u32 pc) { - return slow_path_nonthrowing(*interp, pc); + return slow_path_nonthrowing(*vm, pc); } -i64 asm_slow_path_init_object_literal_property(Interpreter* interp, u32 pc) +i64 asm_slow_path_init_object_literal_property(VM* vm, u32 pc) { - return slow_path_nonthrowing(*interp, pc); + return slow_path_nonthrowing(*vm, pc); } -i64 asm_slow_path_new_array(Interpreter* interp, u32 pc) +i64 asm_slow_path_new_array(VM* vm, u32 pc) { - bump_slow_path(*interp, pc); - auto* bytecode = interp->current_executable().bytecode.data(); + bump_slow_path(*vm, pc); + auto* bytecode = vm->current_executable().bytecode.data(); auto& typed = *reinterpret_cast(&bytecode[pc]); - typed.execute_impl(*interp); + typed.execute_impl(*vm); return static_cast(pc + typed.length()); } -i64 asm_slow_path_bitwise_xor(Interpreter* interp, u32 pc) +i64 asm_slow_path_bitwise_xor(VM* vm, u32 pc) { - return slow_path_throwing(*interp, pc); + return slow_path_throwing(*vm, pc); } -i64 asm_slow_path_bitwise_and(Interpreter* interp, u32 pc) +i64 asm_slow_path_bitwise_and(VM* vm, u32 pc) { - return slow_path_throwing(*interp, pc); + return slow_path_throwing(*vm, pc); } -i64 asm_slow_path_bitwise_or(Interpreter* interp, u32 pc) +i64 asm_slow_path_bitwise_or(VM* vm, u32 pc) { - return slow_path_throwing(*interp, pc); + return slow_path_throwing(*vm, pc); } -i64 asm_slow_path_left_shift(Interpreter* interp, u32 pc) +i64 asm_slow_path_left_shift(VM* vm, u32 pc) { - return slow_path_throwing(*interp, pc); + return slow_path_throwing(*vm, pc); } -i64 asm_slow_path_right_shift(Interpreter* interp, u32 pc) +i64 asm_slow_path_right_shift(VM* vm, u32 pc) { - return slow_path_throwing(*interp, pc); + return slow_path_throwing(*vm, pc); } -i64 asm_slow_path_unsigned_right_shift(Interpreter* interp, u32 pc) +i64 asm_slow_path_unsigned_right_shift(VM* vm, u32 pc) { - return slow_path_throwing(*interp, pc); + return slow_path_throwing(*vm, pc); } -i64 asm_slow_path_mod(Interpreter* interp, u32 pc) +i64 asm_slow_path_mod(VM* vm, u32 pc) { - return slow_path_throwing(*interp, pc); + return slow_path_throwing(*vm, pc); } -i64 asm_slow_path_strictly_equals(Interpreter* interp, u32 pc) +i64 asm_slow_path_strictly_equals(VM* vm, u32 pc) { - return slow_path_throwing(*interp, pc); + return slow_path_throwing(*vm, pc); } -i64 asm_slow_path_strictly_inequals(Interpreter* interp, u32 pc) +i64 asm_slow_path_strictly_inequals(VM* vm, u32 pc) { - return slow_path_throwing(*interp, pc); + return slow_path_throwing(*vm, pc); } -i64 asm_slow_path_unary_minus(Interpreter* interp, u32 pc) +i64 asm_slow_path_unary_minus(VM* vm, u32 pc) { - return slow_path_throwing(*interp, pc); + return slow_path_throwing(*vm, pc); } -i64 asm_slow_path_postfix_decrement(Interpreter* interp, u32 pc) +i64 asm_slow_path_postfix_decrement(VM* vm, u32 pc) { - return slow_path_throwing(*interp, pc); + return slow_path_throwing(*vm, pc); } -i64 asm_slow_path_to_int32(Interpreter* interp, u32 pc) +i64 asm_slow_path_to_int32(VM* vm, u32 pc) { - return slow_path_throwing(*interp, pc); + return slow_path_throwing(*vm, pc); } -i64 asm_slow_path_put_by_value(Interpreter* interp, u32 pc) +i64 asm_slow_path_put_by_value(VM* vm, u32 pc) { - return slow_path_throwing(*interp, pc); + return slow_path_throwing(*vm, pc); } -i64 asm_try_put_by_value_holey_array(Interpreter* interp, u32 pc) +i64 asm_try_put_by_value_holey_array(VM* vm, u32 pc) { - auto* bytecode = interp->current_executable().bytecode.data(); + auto* bytecode = vm->current_executable().bytecode.data(); auto& insn = *reinterpret_cast(&bytecode[pc]); - auto base = interp->get(insn.base()); + auto base = vm->get(insn.base()); if (!base.is_object()) [[unlikely]] return 1; - auto property = interp->get(insn.property()); + auto property = vm->get(insn.property()); if (!property.is_non_negative_int32()) [[unlikely]] return 1; @@ -850,17 +850,17 @@ i64 asm_try_put_by_value_holey_array(Interpreter* interp, u32 pc) if (index >= array.indexed_array_like_size()) [[unlikely]] return 1; - array.indexed_put(index, interp->get(insn.src())); + array.indexed_put(index, vm->get(insn.src())); return 0; } // Try to inline a JS-to-JS call. Returns 0 on success (callee frame pushed), // 1 on failure (caller should fall through to slow path). -i64 asm_try_inline_call(Interpreter* interp, u32 pc) +i64 asm_try_inline_call(VM* vm, u32 pc) { - auto* bytecode = interp->current_executable().bytecode.data(); + auto* bytecode = vm->current_executable().bytecode.data(); auto& insn = *reinterpret_cast(&bytecode[pc]); - auto callee = interp->get(insn.callee()); + auto callee = vm->get(insn.callee()); if (!callee.is_object()) return 1; auto& callee_object = callee.as_object(); @@ -874,55 +874,52 @@ i64 asm_try_inline_call(Interpreter* interp, u32 pc) u32 return_pc = pc + insn.length(); - auto* callee_context = interp->push_inline_frame( + auto* callee_context = vm->push_inline_frame( callee_function, *callee_function.bytecode_executable(), insn.arguments(), return_pc, insn.dst().raw(), - interp->get(insn.this_value()), nullptr, false); + vm->get(insn.this_value()), nullptr, false); if (!callee_context) [[unlikely]] return 1; - // NB: push_inline_frame does NOT update m_running_execution_context. - // The C++ interpreter's try_inline_call does it, so we do too. - interp->set_running_execution_context(callee_context); return 0; } // Pop an inline frame after Return. Returns 0 on success. -i64 asm_pop_inline_frame(Interpreter* interp, u32 pc) +i64 asm_pop_inline_frame(VM* vm, u32 pc) { - auto* bytecode = interp->current_executable().bytecode.data(); + auto* bytecode = vm->current_executable().bytecode.data(); auto& insn = *reinterpret_cast(&bytecode[pc]); - auto value = interp->get(insn.value()); + auto value = vm->get(insn.value()); if (value.is_special_empty_value()) value = js_undefined(); - interp->pop_inline_frame(value); + vm->pop_inline_frame(value); return 0; } // Pop an inline frame after End. Returns 0 on success. -i64 asm_pop_inline_frame_end(Interpreter* interp, u32 pc) +i64 asm_pop_inline_frame_end(VM* vm, u32 pc) { - auto* bytecode = interp->current_executable().bytecode.data(); + auto* bytecode = vm->current_executable().bytecode.data(); auto& insn = *reinterpret_cast(&bytecode[pc]); - auto value = interp->get(insn.value()); + auto value = vm->get(insn.value()); if (value.is_special_empty_value()) value = js_undefined(); - interp->pop_inline_frame(value); + vm->pop_inline_frame(value); return 0; } // Fast cache-only PutById. Tries all cache entries for ChangeOwnProperty and // AddOwnProperty. Returns 0 on cache hit, 1 on miss (caller should use full slow path). -i64 asm_try_put_by_id_cache(Interpreter* interp, u32 pc) +i64 asm_try_put_by_id_cache(VM* vm, u32 pc) { - auto* bytecode = interp->current_executable().bytecode.data(); + auto* bytecode = vm->current_executable().bytecode.data(); auto& insn = *reinterpret_cast(&bytecode[pc]); - auto base = interp->get(insn.base()); + auto base = vm->get(insn.base()); if (!base.is_object()) [[unlikely]] return 1; auto& object = base.as_object(); - auto value = interp->get(insn.src()); + auto value = vm->get(insn.src()); auto& cache = *bit_cast(insn.cache()); for (size_t i = 0; i < cache.entries.size(); ++i) { @@ -969,11 +966,11 @@ i64 asm_try_put_by_id_cache(Interpreter* interp, u32 pc) // Fast cache-only GetById. Tries all cache entries for own-property and prototype // chain lookups. On cache hit, writes the result to the dst operand and returns 0. // On miss, returns 1 (caller should use full slow path). -i64 asm_try_get_by_id_cache(Interpreter* interp, u32 pc) +i64 asm_try_get_by_id_cache(VM* vm, u32 pc) { - auto* bytecode = interp->current_executable().bytecode.data(); + auto* bytecode = vm->current_executable().bytecode.data(); auto& insn = *reinterpret_cast(&bytecode[pc]); - auto base = interp->get(insn.base()); + auto base = vm->get(insn.base()); if (!base.is_object()) [[unlikely]] return 1; auto& object = base.as_object(); @@ -994,7 +991,7 @@ i64 asm_try_get_by_id_cache(Interpreter* interp, u32 pc) auto value = cached_prototype->get_direct(entry.property_offset); if (value.is_accessor()) [[unlikely]] return 1; - interp->set(insn.dst(), value); + vm->set(insn.dst(), value); return 0; } else if (&shape == entry.shape) { if (shape.is_dictionary() @@ -1003,65 +1000,65 @@ i64 asm_try_get_by_id_cache(Interpreter* interp, u32 pc) auto value = object.get_direct(entry.property_offset); if (value.is_accessor()) [[unlikely]] return 1; - interp->set(insn.dst(), value); + vm->set(insn.dst(), value); return 0; } } return 1; } -i64 asm_slow_path_get_binding(Interpreter* interp, u32 pc) +i64 asm_slow_path_get_binding(VM* vm, u32 pc) { - return slow_path_throwing(*interp, pc); + return slow_path_throwing(*vm, pc); } -i64 asm_slow_path_initialize_lexical_binding(Interpreter* interp, u32 pc) +i64 asm_slow_path_initialize_lexical_binding(VM* vm, u32 pc) { - return slow_path_throwing(*interp, pc); + return slow_path_throwing(*vm, pc); } -i64 asm_slow_path_set_lexical_binding(Interpreter* interp, u32 pc) +i64 asm_slow_path_set_lexical_binding(VM* vm, u32 pc) { - return slow_path_throwing(*interp, pc); + return slow_path_throwing(*vm, pc); } -i64 asm_slow_path_bitwise_not(Interpreter* interp, u32 pc) +i64 asm_slow_path_bitwise_not(VM* vm, u32 pc) { - return slow_path_throwing(*interp, pc); + return slow_path_throwing(*vm, pc); } -i64 asm_slow_path_unary_plus(Interpreter* interp, u32 pc) +i64 asm_slow_path_unary_plus(VM* vm, u32 pc) { - return slow_path_throwing(*interp, pc); + return slow_path_throwing(*vm, pc); } -i64 asm_slow_path_throw_if_tdz(Interpreter* interp, u32 pc) +i64 asm_slow_path_throw_if_tdz(VM* vm, u32 pc) { - return slow_path_throwing(*interp, pc); + return slow_path_throwing(*vm, pc); } -i64 asm_slow_path_throw_if_not_object(Interpreter* interp, u32 pc) +i64 asm_slow_path_throw_if_not_object(VM* vm, u32 pc) { - return slow_path_throwing(*interp, pc); + return slow_path_throwing(*vm, pc); } -i64 asm_slow_path_throw_if_nullish(Interpreter* interp, u32 pc) +i64 asm_slow_path_throw_if_nullish(VM* vm, u32 pc) { - return slow_path_throwing(*interp, pc); + return slow_path_throwing(*vm, pc); } // Fast path for GetByValue on typed arrays. // Returns 0 on success (result stored in dst), 1 on miss (fall to slow path). -i64 asm_try_get_by_value_typed_array(Interpreter* interp, u32 pc) +i64 asm_try_get_by_value_typed_array(VM* vm, u32 pc) { - auto* bytecode = interp->current_executable().bytecode.data(); + auto* bytecode = vm->current_executable().bytecode.data(); auto& insn = *reinterpret_cast(&bytecode[pc]); - auto base = interp->get(insn.base()); + auto base = vm->get(insn.base()); if (!base.is_object()) [[unlikely]] return 1; - auto property = interp->get(insn.property()); + auto property = vm->get(insn.property()); if (!property.is_non_negative_int32()) [[unlikely]] return 1; @@ -1079,12 +1076,12 @@ i64 asm_try_get_by_value_typed_array(Interpreter* interp, u32 pc) auto length = array_length.length(); if (index >= length) [[unlikely]] { - interp->set(insn.dst(), js_undefined()); + vm->set(insn.dst(), js_undefined()); return 0; } if (!is_valid_integer_index(typed_array, CanonicalIndex { CanonicalIndex::Type::Index, index })) [[unlikely]] { - interp->set(insn.dst(), js_undefined()); + vm->set(insn.dst(), js_undefined()); return 0; } @@ -1122,22 +1119,22 @@ i64 asm_try_get_by_value_typed_array(Interpreter* interp, u32 pc) return 1; } - interp->set(insn.dst(), result); + vm->set(insn.dst(), result); return 0; } // Fast path for PutByValue on typed arrays. // Returns 0 on success, 1 on miss (fall to slow path). -i64 asm_try_put_by_value_typed_array(Interpreter* interp, u32 pc) +i64 asm_try_put_by_value_typed_array(VM* vm, u32 pc) { - auto* bytecode = interp->current_executable().bytecode.data(); + auto* bytecode = vm->current_executable().bytecode.data(); auto& insn = *reinterpret_cast(&bytecode[pc]); - auto base = interp->get(insn.base()); + auto base = vm->get(insn.base()); if (!base.is_object()) [[unlikely]] return 1; - auto property = interp->get(insn.property()); + auto property = vm->get(insn.property()); if (!property.is_non_negative_int32()) [[unlikely]] return 1; @@ -1160,7 +1157,7 @@ i64 asm_try_put_by_value_typed_array(Interpreter* interp, u32 pc) auto* buffer = typed_array.viewed_array_buffer(); auto* data = buffer->buffer().data() + typed_array.byte_offset(); - auto value = interp->get(insn.src()); + auto value = vm->get(insn.src()); if (value.is_int32()) { auto int_val = value.as_i32(); @@ -1206,80 +1203,80 @@ i64 asm_try_put_by_value_typed_array(Interpreter* interp, u32 pc) return 1; } -i64 asm_slow_path_instance_of(Interpreter* interp, u32 pc) +i64 asm_slow_path_instance_of(VM* vm, u32 pc) { - return slow_path_throwing(*interp, pc); + return slow_path_throwing(*vm, pc); } -i64 asm_slow_path_resolve_this_binding(Interpreter* interp, u32 pc) +i64 asm_slow_path_resolve_this_binding(VM* vm, u32 pc) { - return slow_path_throwing(*interp, pc); + return slow_path_throwing(*vm, pc); } // Direct handler for GetPrivateById: bypasses Reference indirection. -i64 asm_slow_path_get_private_by_id(Interpreter* interp, u32 pc) +i64 asm_slow_path_get_private_by_id(VM* vm, u32 pc) { - interp->running_execution_context().program_counter = pc; - auto* bytecode = interp->current_executable().bytecode.data(); + vm->running_execution_context().program_counter = pc; + auto* bytecode = vm->current_executable().bytecode.data(); auto& insn = *reinterpret_cast(&bytecode[pc]); - auto base_value = interp->get(insn.base()); - auto& vm = interp->vm(); + auto base_value = vm->get(insn.base()); + auto& current_vm = *vm; if (!base_value.is_object()) [[unlikely]] { - auto object = base_value.to_object(vm); + auto object = base_value.to_object(current_vm); if (object.is_error()) - return handle_asm_exception(*interp, pc, object.error_value()); - auto const& name = interp->get_identifier(insn.property()); - auto private_name = make_private_reference(vm, base_value, name); - auto result = private_name.get_value(vm); + return handle_asm_exception(*vm, pc, object.error_value()); + auto const& name = current_vm.get_identifier(insn.property()); + auto private_name = make_private_reference(current_vm, base_value, name); + auto result = private_name.get_value(current_vm); if (result.is_error()) [[unlikely]] - return handle_asm_exception(*interp, pc, result.error_value()); - interp->set(insn.dst(), result.release_value()); + return handle_asm_exception(*vm, pc, result.error_value()); + vm->set(insn.dst(), result.release_value()); return static_cast(pc + sizeof(Op::GetPrivateById)); } - auto const& name = interp->get_identifier(insn.property()); - auto private_environment = vm.running_execution_context().private_environment; + auto const& name = current_vm.get_identifier(insn.property()); + auto private_environment = current_vm.running_execution_context().private_environment; VERIFY(private_environment); auto private_name = private_environment->resolve_private_identifier(name); auto result = base_value.as_object().private_get(private_name); if (result.is_error()) [[unlikely]] - return handle_asm_exception(*interp, pc, result.error_value()); - interp->set(insn.dst(), result.release_value()); + return handle_asm_exception(*vm, pc, result.error_value()); + vm->set(insn.dst(), result.release_value()); return static_cast(pc + sizeof(Op::GetPrivateById)); } // Direct handler for PutPrivateById: bypasses Reference indirection. -i64 asm_slow_path_put_private_by_id(Interpreter* interp, u32 pc) +i64 asm_slow_path_put_private_by_id(VM* vm, u32 pc) { - interp->running_execution_context().program_counter = pc; - auto* bytecode = interp->current_executable().bytecode.data(); + vm->running_execution_context().program_counter = pc; + auto* bytecode = vm->current_executable().bytecode.data(); auto& insn = *reinterpret_cast(&bytecode[pc]); - auto base_value = interp->get(insn.base()); - auto& vm = interp->vm(); - auto value = interp->get(insn.src()); + auto base_value = vm->get(insn.base()); + auto& current_vm = *vm; + auto value = vm->get(insn.src()); if (!base_value.is_object()) [[unlikely]] { - auto object = base_value.to_object(vm); + auto object = base_value.to_object(current_vm); if (object.is_error()) - return handle_asm_exception(*interp, pc, object.error_value()); - auto const& name = interp->get_identifier(insn.property()); - auto private_reference = make_private_reference(vm, object.release_value(), name); - auto result = private_reference.put_value(vm, value); + return handle_asm_exception(*vm, pc, object.error_value()); + auto const& name = current_vm.get_identifier(insn.property()); + auto private_reference = make_private_reference(current_vm, object.release_value(), name); + auto result = private_reference.put_value(current_vm, value); if (result.is_error()) [[unlikely]] - return handle_asm_exception(*interp, pc, result.error_value()); + return handle_asm_exception(*vm, pc, result.error_value()); return static_cast(pc + sizeof(Op::PutPrivateById)); } - auto const& name = interp->get_identifier(insn.property()); - auto private_environment = vm.running_execution_context().private_environment; + auto const& name = current_vm.get_identifier(insn.property()); + auto private_environment = current_vm.running_execution_context().private_environment; VERIFY(private_environment); auto private_name = private_environment->resolve_private_identifier(name); auto result = base_value.as_object().private_set(private_name, value); if (result.is_error()) [[unlikely]] - return handle_asm_exception(*interp, pc, result.error_value()); + return handle_asm_exception(*vm, pc, result.error_value()); return static_cast(pc + sizeof(Op::PutPrivateById)); } @@ -1299,18 +1296,18 @@ u64 asm_helper_math_exp(u64 encoded_value) u64 asm_helper_empty_string(u64) { - return bit_cast(Value(&Interpreter::vm().empty_string())); + return bit_cast(Value(&VM::the().empty_string())); } u64 asm_helper_single_ascii_character_string(u64 encoded_value) { - return bit_cast(Value(&Interpreter::vm().single_ascii_character_string(static_cast(encoded_value)))); + return bit_cast(Value(&VM::the().single_ascii_character_string(static_cast(encoded_value)))); } u64 asm_helper_single_utf16_code_unit_string(u64 encoded_value) { char16_t code_unit = static_cast(encoded_value); - return bit_cast(Value(PrimitiveString::create(Interpreter::vm(), Utf16View(&code_unit, 1)))); + return bit_cast(Value(PrimitiveString::create(VM::the(), Utf16View(&code_unit, 1)))); } } // extern "C" diff --git a/Libraries/LibJS/Bytecode/AsmInterpreter/AsmInterpreter.h b/Libraries/LibJS/Bytecode/AsmInterpreter/AsmInterpreter.h index 2d667c2865..5147be1274 100644 --- a/Libraries/LibJS/Bytecode/AsmInterpreter/AsmInterpreter.h +++ b/Libraries/LibJS/Bytecode/AsmInterpreter/AsmInterpreter.h @@ -8,14 +8,16 @@ #include -namespace JS::Bytecode { +namespace JS { -class Interpreter; +class VM; +namespace Bytecode { class AsmInterpreter { public: - static void run(Interpreter&, size_t entry_point); + static void run(VM&, size_t entry_point); static bool is_available(); }; } +} diff --git a/Libraries/LibJS/Bytecode/AsmInterpreter/gen_asm_offsets.cpp b/Libraries/LibJS/Bytecode/AsmInterpreter/gen_asm_offsets.cpp index 57a73a2bd6..58a380f11c 100644 --- a/Libraries/LibJS/Bytecode/AsmInterpreter/gen_asm_offsets.cpp +++ b/Libraries/LibJS/Bytecode/AsmInterpreter/gen_asm_offsets.cpp @@ -12,7 +12,6 @@ #include #include #include -#include #include #include #include @@ -25,6 +24,7 @@ #include #include #include +#include #define EMIT_OFFSET(name, type, member) \ outln("const " #name " = {}", offsetof(type, member)) @@ -139,9 +139,9 @@ int main() EMIT_OFFSET(REALM_GLOBAL_OBJECT, Realm, m_global_object); EMIT_OFFSET(REALM_GLOBAL_DECLARATIVE_ENVIRONMENT, Realm, m_global_declarative_environment); - // Interpreter layout - outln("\n# Interpreter layout"); - EMIT_OFFSET(INTERPRETER_RUNNING_EXECUTION_CONTEXT, Interpreter, m_running_execution_context); + // VM layout + outln("\n# VM layout"); + EMIT_OFFSET(VM_RUNNING_EXECUTION_CONTEXT, VM, m_running_execution_context); // IndexedStorageKind enum values outln("\n# IndexedStorageKind enum values"); diff --git a/Libraries/LibJS/Bytecode/Debug.h b/Libraries/LibJS/Bytecode/Debug.h new file mode 100644 index 0000000000..97c9944ea1 --- /dev/null +++ b/Libraries/LibJS/Bytecode/Debug.h @@ -0,0 +1,15 @@ +/* + * Copyright (c) 2026-present, the Ladybird developers. + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#pragma once + +#include + +namespace JS::Bytecode { + +JS_API extern bool g_dump_bytecode; + +} diff --git a/Libraries/LibJS/Bytecode/Interpreter.cpp b/Libraries/LibJS/Bytecode/Interpreter.cpp index bf6b05785d..72514f7ef0 100644 --- a/Libraries/LibJS/Bytecode/Interpreter.cpp +++ b/Libraries/LibJS/Bytecode/Interpreter.cpp @@ -12,9 +12,9 @@ #include #include #include +#include #include #include -#include #include #include #include @@ -44,14 +44,17 @@ #include #include #include +#include #include #include #include #include -namespace JS::Bytecode { +namespace JS { -bool g_dump_bytecode = false; +using namespace Bytecode; + +bool Bytecode::g_dump_bytecode = false; ALWAYS_INLINE static ThrowCompletionOr loosely_inequals(VM& vm, Value src1, Value src2) { @@ -89,11 +92,7 @@ ALWAYS_INLINE static ThrowCompletionOr strict_equals(VM&, Value src1, Valu return is_strictly_equal(src1, src2); } -Interpreter::Interpreter() = default; - -Interpreter::~Interpreter() = default; - -ALWAYS_INLINE Value Interpreter::do_yield(Value value, Optional