LibJS: Sync AsmInt program counter before slow paths
Move the execution context program counter update from ASM_TRY() to the generated slow-path call boundary. Slow paths still enter C++ with the current bytecode offset visible to stack and source location code, while ASM_TRY() only handles completion unwrapping and exception dispatch.
This commit is contained in:
parent
ad7002ba99
commit
0af548b27d
3 changed files with 28 additions and 11 deletions
|
|
@ -386,6 +386,7 @@ fn generate_fallback_handler(out: &mut String, program: &Program, _pinned: &Pinn
|
|||
// Set up args: x0=vm (x20), w1=pc (ip - pb), x2=instruction (ip)
|
||||
w!(out, " mov x0, x20");
|
||||
w!(out, " sub w1, w21, w26");
|
||||
emit_sync_pc_to_execution_context(out, program);
|
||||
w!(out, " mov x2, x21");
|
||||
w!(out, " bl CSYM(asm_fallback_handler)");
|
||||
// Check for exit (return < 0)
|
||||
|
|
@ -430,6 +431,15 @@ fn emit_state_reload(out: &mut String, program: &Program) {
|
|||
emit_add_imm(out, "x27", "x28", sizeof_execctx);
|
||||
}
|
||||
|
||||
fn emit_sync_pc_to_execution_context(out: &mut String, program: &Program) {
|
||||
let program_counter = program
|
||||
.constants
|
||||
.get("EXECUTION_CONTEXT_PROGRAM_COUNTER")
|
||||
.copied()
|
||||
.expect("EXECUTION_CONTEXT_PROGRAM_COUNTER constant required");
|
||||
emit_str32(out, "w1", "x28", program_counter);
|
||||
}
|
||||
|
||||
/// Emit a dispatch sequence: recompute x21 from w25 + x26, then dispatch.
|
||||
/// Used only by dispatch_current (where DSL code has written to x25 directly).
|
||||
fn emit_dispatch(out: &mut String) {
|
||||
|
|
@ -1347,6 +1357,7 @@ fn emit_instruction(
|
|||
if let Some(Operand::Register(func_name)) = insn.operands.first() {
|
||||
w!(out, " mov x0, x20"); // vm
|
||||
w!(out, " sub w1, w21, w26"); // pc = ip - pb
|
||||
emit_sync_pc_to_execution_context(out, program);
|
||||
w!(out, " mov x2, x21"); // instruction
|
||||
w!(out, " bl CSYM({func_name})");
|
||||
w!(out, " tbnz x0, #63, .Lexit");
|
||||
|
|
|
|||
|
|
@ -309,6 +309,7 @@ fn generate_fallback_handler(out: &mut String, program: &Program, abi: X86_64Abi
|
|||
// Returns >= 0: new pc to dispatch to. Returns < 0: exit.
|
||||
w!(out, ".p2align 4");
|
||||
w!(out, "asm_handler_fallback:");
|
||||
emit_sync_pc_to_execution_context(out, program);
|
||||
emit_vm_pc_instruction_args(out, abi);
|
||||
w!(out, " call CSYM(asm_fallback_handler)");
|
||||
// Check for exit (return < 0)
|
||||
|
|
@ -388,6 +389,15 @@ fn emit_vm_pc_instruction_args(out: &mut String, abi: X86_64Abi) {
|
|||
}
|
||||
}
|
||||
|
||||
fn emit_sync_pc_to_execution_context(out: &mut String, program: &Program) {
|
||||
let program_counter = program
|
||||
.constants
|
||||
.get("EXECUTION_CONTEXT_PROGRAM_COUNTER")
|
||||
.copied()
|
||||
.expect("EXECUTION_CONTEXT_PROGRAM_COUNTER constant required");
|
||||
w!(out, " mov DWORD PTR [rbx + {program_counter}], r13d");
|
||||
}
|
||||
|
||||
fn emit_dispatch(out: &mut String) {
|
||||
w!(out, " movzx eax, BYTE PTR [r14 + r13]");
|
||||
w!(out, " jmp [r12 + rax * 8]");
|
||||
|
|
@ -765,6 +775,7 @@ fn emit_instruction(
|
|||
// context, since exception handling may have unwound inline frames.
|
||||
"call_slow_path" => {
|
||||
if let Some(Operand::Register(func_name)) = insn.operands.first() {
|
||||
emit_sync_pc_to_execution_context(out, program);
|
||||
emit_vm_pc_instruction_args(out, abi);
|
||||
w!(out, " call CSYM({func_name})");
|
||||
// Check for exit (return < 0)
|
||||
|
|
|
|||
|
|
@ -60,7 +60,6 @@ static i64 handle_asm_exception(VM& vm, u32 pc, Value exception)
|
|||
({ \
|
||||
auto& asm_try_vm = (vm); \
|
||||
auto asm_try_pc = (pc); \
|
||||
asm_try_vm.running_execution_context().program_counter = asm_try_pc; \
|
||||
auto&& asm_try_result = (expression); \
|
||||
if (asm_try_result.is_error()) [[unlikely]] \
|
||||
return handle_asm_exception(asm_try_vm, asm_try_pc, asm_try_result.release_error().value()); \
|
||||
|
|
@ -803,18 +802,18 @@ i64 asm_slow_path_decrement(VM* vm, u32 pc, Op::Decrement const* instruction)
|
|||
return static_cast<i64>(instruction->false_target().address()); \
|
||||
}
|
||||
|
||||
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))
|
||||
DEFINE_JUMP_COMPARISON_SLOW_PATH(less_than, LessThan, less_than(*vm, lhs, rhs))
|
||||
DEFINE_JUMP_COMPARISON_SLOW_PATH(greater_than, GreaterThan, greater_than(*vm, lhs, rhs))
|
||||
DEFINE_JUMP_COMPARISON_SLOW_PATH(less_than_equals, LessThanEquals, less_than_equals(*vm, lhs, rhs))
|
||||
DEFINE_JUMP_COMPARISON_SLOW_PATH(greater_than_equals, GreaterThanEquals, greater_than_equals(*vm, lhs, rhs))
|
||||
DEFINE_JUMP_COMPARISON_SLOW_PATH(loosely_equals, LooselyEquals, is_loosely_equal(*vm, lhs, rhs))
|
||||
#undef DEFINE_JUMP_COMPARISON_SLOW_PATH
|
||||
|
||||
i64 asm_slow_path_jump_loosely_inequals(VM* vm, u32 pc, Op::JumpLooselyInequals const* instruction)
|
||||
{
|
||||
auto lhs = vm->get(instruction->lhs());
|
||||
auto rhs = vm->get(instruction->rhs());
|
||||
if (!ASM_TRY(*vm, pc, is_loosely_equal(VM::the(), lhs, rhs)))
|
||||
if (!ASM_TRY(*vm, pc, is_loosely_equal(*vm, lhs, rhs)))
|
||||
return static_cast<i64>(instruction->true_target().address());
|
||||
return static_cast<i64>(instruction->false_target().address());
|
||||
}
|
||||
|
|
@ -2963,8 +2962,6 @@ i64 asm_slow_path_resolve_this_binding(VM* vm, u32 pc, Op::ResolveThisBinding co
|
|||
// Direct handler for GetPrivateById: bypasses Reference indirection.
|
||||
i64 asm_slow_path_get_private_by_id(VM* vm, u32 pc, Op::GetPrivateById const* instruction)
|
||||
{
|
||||
vm->running_execution_context().program_counter = pc;
|
||||
|
||||
auto base_value = vm->get(instruction->base());
|
||||
auto& current_vm = *vm;
|
||||
|
||||
|
|
@ -2989,8 +2986,6 @@ i64 asm_slow_path_get_private_by_id(VM* vm, u32 pc, Op::GetPrivateById const* in
|
|||
// Direct handler for PutPrivateById: bypasses Reference indirection.
|
||||
i64 asm_slow_path_put_private_by_id(VM* vm, u32 pc, Op::PutPrivateById const* instruction)
|
||||
{
|
||||
vm->running_execution_context().program_counter = pc;
|
||||
|
||||
auto base_value = vm->get(instruction->base());
|
||||
auto& current_vm = *vm;
|
||||
auto value = vm->get(instruction->src());
|
||||
|
|
|
|||
Loading…
Reference in a new issue