Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[x86-64] Remove abrupt return checking, rely on stack unwinding #243

Merged
merged 1 commit into from
Dec 15, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion src/engine/Tuning.v3
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,6 @@ component FeatureDisable {
def tierUpOsr = false; // tier-up uses on-stack-replacement
def emptyProbes = false; // true => all probes are empty
def emptyStacktraces = false; // true => all stacktraces are empty
def stackUnwind = false; // true => unwinding stack for traps/catch uses returns
}

// Tuning settings for the fast interpreter that have no effect on correctness.
Expand Down
28 changes: 0 additions & 28 deletions src/engine/compiler/SinglePassCompiler.v3
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,6 @@ class SinglePassCompiler(xenv: SpcExecEnv, masm: MacroAssembler, regAlloc: RegAl
var osr_loop_label: MasmLabel;
var osr_entry_label: MasmLabel;
var ret_label: MasmLabel;
var unwind_label: MasmLabel;
var last_probe = 0;
var skip_to_end: bool;

Expand Down Expand Up @@ -132,7 +131,6 @@ class SinglePassCompiler(xenv: SpcExecEnv, masm: MacroAssembler, regAlloc: RegAl
this.func = func;
it.reset(func);
sig = func.sig;
unwind_label = null;
regAlloc.clear();
trap_labels.resize(0);
success = true;
Expand Down Expand Up @@ -168,13 +166,6 @@ class SinglePassCompiler(xenv: SpcExecEnv, masm: MacroAssembler, regAlloc: RegAl
if (skip_to_end) doSkipToEndOfBlock();
}

// Emit epilogue even if no return.
if (unwind_label != null) {
masm.bindLabel(unwind_label);
unwind_label = null;
emitUnwind();
}

// Emit trap labels.
for (i < trap_labels.length) {
var e = trap_labels[i];
Expand Down Expand Up @@ -446,7 +437,6 @@ class SinglePassCompiler(xenv: SpcExecEnv, masm: MacroAssembler, regAlloc: RegAl
emit_compute_vsp(vsp_reg, state.sp + u32.view(whamm_sig.length));
// Call to the entrypoint.
masm.emit_call_r(tmp);
emit_unwind_check();
emit_reload_regs();
if (!probeSpillMode.free_regs) state.emitRestoreAll(resolver);
}
Expand Down Expand Up @@ -618,7 +608,6 @@ class SinglePassCompiler(xenv: SpcExecEnv, masm: MacroAssembler, regAlloc: RegAl
} else {
masm.emit_call_r(tmp);
masm.bindLabel(retpt);
emit_unwind_check();
emit_reload_regs();
state.popArgsAndPushResults(func.sig);
}
Expand Down Expand Up @@ -691,7 +680,6 @@ class SinglePassCompiler(xenv: SpcExecEnv, masm: MacroAssembler, regAlloc: RegAl
} else {
masm.emit_call_r(tmp2);
masm.bindLabel(retpt);
emit_unwind_check();
emit_reload_regs();
state.popArgsAndPushResults(sig);
}
Expand Down Expand Up @@ -728,7 +716,6 @@ class SinglePassCompiler(xenv: SpcExecEnv, masm: MacroAssembler, regAlloc: RegAl
masm.emit_call_r(tmp);

masm.bindLabel(retpt);
emit_unwind_check();
emit_reload_regs();

state.popArgsAndPushResults(sig);
Expand Down Expand Up @@ -1072,7 +1059,6 @@ class SinglePassCompiler(xenv: SpcExecEnv, masm: MacroAssembler, regAlloc: RegAl
emit_load_instance(regs.runtime_arg0);
masm.emit_mov_r_i(regs.runtime_arg1, arg1);
masm.emit_call_runtime_op(op);
if (canTrap) emit_unwind_check();
dropN(args);
for (t in results) state.push(typeToKindFlags(t) | TAG_STORED | IS_STORED, NO_REG, 0);
emit_reload_regs();
Expand All @@ -1086,7 +1072,6 @@ class SinglePassCompiler(xenv: SpcExecEnv, masm: MacroAssembler, regAlloc: RegAl
masm.emit_mov_r_i(regs.runtime_arg1, arg1);
masm.emit_mov_r_i(regs.runtime_arg2, arg2);
masm.emit_call_runtime_op(op);
if (canTrap) emit_unwind_check();
dropN(args);
for (t in results) state.push(typeToKindFlags(t) | TAG_STORED | IS_STORED, NO_REG, 0);
emit_reload_regs();
Expand Down Expand Up @@ -1167,13 +1152,6 @@ class SinglePassCompiler(xenv: SpcExecEnv, masm: MacroAssembler, regAlloc: RegAl
// Return to caller
masm.emit_mov_r_i(regs.ret_throw, 0);
// Deallocate stack frame
if (unwind_label != null) {
masm.bindLabel(unwind_label);
unwind_label = null;
}
emitUnwind();
}
def emitUnwind() {
masm.emit_addw_r_i(regs.sp, frame.frameSize);
masm.emit_ret();
}
Expand Down Expand Up @@ -1287,12 +1265,6 @@ class SinglePassCompiler(xenv: SpcExecEnv, masm: MacroAssembler, regAlloc: RegAl
//====================================================================
// codegen operations
//====================================================================
def emit_unwind_check() {
if (FeatureDisable.stackUnwind) {
if (unwind_label == null) unwind_label = masm.newLabel(func.cur_bytecode.length);
masm.emit_brne_r_i(regs.ret_throw, 0, unwind_label);
}
}
def emit_compute_vsp(dst: Reg, slots: u32) {
masm.emit_mov_r_r(ValueKind.REF, dst, regs.vfp); // XXX: use 3-addr adjustment of VSP (i.e. lea)
if (slots > 0) masm.emit_addw_r_i(dst, int.view(slots) * masm.valuerep.slot_size);
Expand Down
35 changes: 5 additions & 30 deletions src/engine/x86-64/X86_64Interpreter.v3
Original file line number Diff line number Diff line change
Expand Up @@ -273,7 +273,6 @@ class X86_64InterpreterGen(ic: X86_64InterpreterCode, w: DataWriter) {
var resumeStub = X86_64Label.new();
var suspendStub = X86_64Label.new();
var spcEntryLabel = X86_64Label.new();
var abruptRetLabel = X86_64Label.new();
var controlFallThruLabel = X86_64Label.new();
var controlTransferLabel = X86_64Label.new();
var controlSkipSidetableAndDispatchLabel = X86_64Label.new();
Expand Down Expand Up @@ -485,10 +484,6 @@ class X86_64InterpreterGen(ic: X86_64InterpreterCode, w: DataWriter) {
// Check if WasmFunction != null, which means host tail-called Wasm
var call_wasm = masm.newLabel(-1);
masm.emit_br_r(r_func, MasmBrCond.REF_NONNULL, call_wasm); // XXX: near jump
if (false) {
// mov [%stack.rsp], %rsp ; possibly unwind stack
masm.emit_mov_r_m(ValueKind.REF, xenv.sp, MasmAddr(r_stack, offsets.X86_64Stack_rsp));
}
// Otherwise return (possibly null) throwable
masm.emit_ret();

Expand Down Expand Up @@ -1057,7 +1052,6 @@ class X86_64InterpreterGen(ic: X86_64InterpreterCode, w: DataWriter) {
genReadUleb32(r_tmp0);
saveCallerIVars();
callRuntime(refRuntimeCall(RT.runtime_THROW), [r_instance, r_tmp0], true);
genAbruptRetCheck(); // TODO: should always fail
restoreCallerIVars();
restoreDispatchTableReg();
genDispatchOrJumpToDispatch();
Expand All @@ -1069,7 +1063,6 @@ class X86_64InterpreterGen(ic: X86_64InterpreterCode, w: DataWriter) {
decrementVsp();
saveCallerIVars();
callRuntime(refRuntimeCall(RT.runtime_THROW_REF), [r_tmp0], true);
genAbruptRetCheck(); // TODO: should always fail
restoreCallerIVars();
restoreDispatchTableReg();
genDispatchOrJumpToDispatch();
Expand Down Expand Up @@ -1179,15 +1172,13 @@ class X86_64InterpreterGen(ic: X86_64InterpreterCode, w: DataWriter) {
} else {
asm.call_rel_far(callReentryLabel);
}
genAbruptRetCheck();
restoreCallerIVars();
if (!FeatureDisable.multiTier) restoreDispatchTableReg();
genDispatchOrJumpToDispatch();

// HostFunction: call into runtime
asm.bind(call_host.label);
asm.call_rel_far(hostCallStubLabel.label);
genAbruptRetCheck();
restoreCallerIVars();
restoreDispatchTableReg();
genJumpToDispatch();
Expand Down Expand Up @@ -1373,7 +1364,6 @@ class X86_64InterpreterGen(ic: X86_64InterpreterCode, w: DataWriter) {
saveCallerIVars();
asm.movd_r_i(r_tmp0, 0);
callRuntime(t.1, [r_instance, r_tmp0, r_tmp1], true);
genAbruptRetCheck();
restoreCallerIVars();
endHandler();
}
Expand Down Expand Up @@ -2602,7 +2592,6 @@ class X86_64InterpreterGen(ic: X86_64InterpreterCode, w: DataWriter) {
genReadUleb32(r_tmp1);
saveCallerIVars();
callRuntime(t.1, [r_instance, r_tmp0, r_tmp1], true);
genAbruptRetCheck();
restoreCallerIVars();
endHandler();
}
Expand Down Expand Up @@ -3211,12 +3200,6 @@ class X86_64InterpreterGen(ic: X86_64InterpreterCode, w: DataWriter) {
if (slots < 0) asm.q.sub_r_i(r_vsp, (0 - slots) * valuerep.slot_size);
else asm.q.add_r_i(r_vsp, slots * valuerep.slot_size);
}
def genAbruptRetCheck() {
if (FeatureDisable.stackUnwind) {
asm.q.cmp_r_i(Target.V3_RET_GPRS[0], 0);
asm.jc_rel_far(C.NZ, abruptRetLabel);
}
}
def saveCallerIVars() {
saveIVar(r_ip);
saveIVar(r_stp);
Expand Down Expand Up @@ -3256,8 +3239,6 @@ class X86_64InterpreterGen(ic: X86_64InterpreterCode, w: DataWriter) {
for (i < dst.length) orderMoves(dst, stk, i);
// emit actual call
asm.callr(int.!((abs - (ic.start + w.pos + 5)))); // TODO: handle 64-bit {abs} with movq_r_l
// check for trap
if (canTrap) genAbruptRetCheck();
restoreDispatchTableReg();
// restore VSP from valueStack.sp
asm.movq_r_m(r_vsp, masm.absPointer(offsets.X86_64Runtime_curStack));
Expand Down Expand Up @@ -3654,8 +3635,6 @@ class X86_64InterpreterGen(ic: X86_64InterpreterCode, w: DataWriter) {
asm.movq_r_m(r_tmp1, m_wasm_func);
// XXX: load runtime arg registers directly
callRuntime(refRuntimeCall(RT.runtime_TRAP), [r_tmp1, r_curpc, r_tmp4], true);
asm.bind(abruptRetLabel);
genPopFrameAndRet();

for (reason in TrapReason) {
if (reason == TrapReason.STACK_OVERFLOW) continue; // must be special
Expand All @@ -3676,14 +3655,14 @@ class X86_64InterpreterGen(ic: X86_64InterpreterCode, w: DataWriter) {
asm.movq_r_m(r_tmp1, m_wasm_func);
asm.movd_r_i(r_tmp4, TrapReason.DIV_BY_ZERO.tag);
callRuntime(refRuntimeCall(RT.runtime_TRAP), [r_tmp1, r_curpc, r_tmp4], true);
asm.jmp_rel_near(abruptRetLabel);
// does not return

// stack overflow cannot call into runtime, because it might be out of stack (!)
var stackoverflow_label = newTrapLabel(TrapReason.STACK_OVERFLOW);
asm.bind(stackoverflow_label);
var trapObj = Pointer.atObject(Execute.trapObjects[TrapReason.STACK_OVERFLOW.tag]);
asm.movq_r_l(Target.V3_RET_GPRS[0], trapObj - Pointer.NULL);
asm.jmp_rel_near(abruptRetLabel);
genPopFrameAndRet();
ic.header.stackOverflowHandlerOffset = stackoverflow_label.pos;
ic.header.oobMemoryHandlerOffset = newTrapLabel(TrapReason.MEM_OUT_OF_BOUNDS).pos;
ic.header.divZeroHandlerOffset = newTrapLabel(TrapReason.DIV_BY_ZERO).pos;
Expand Down Expand Up @@ -3711,13 +3690,9 @@ class X86_64InterpreterGen(ic: X86_64InterpreterCode, w: DataWriter) {
var m_curStack = X86_64Addr.new(null, null, 1, int.view(offsets.X86_64Runtime_curStack - Pointer.NULL));
var done = X86_64Label.new();
// check for error (in %rax)
if (FeatureDisable.stackUnwind) {
genAbruptRetCheck();
} else {
asm.q.cmp_r_i(r_ret_throw, 0);
asm.jc_rel_near(X86_64Conds.Z, done);
callRuntime(refRuntimeCall(RT.runtime_THROW_REF), [r_ret_throw], true);
}
asm.q.cmp_r_i(r_ret_throw, 0);
asm.jc_rel_near(X86_64Conds.Z, done);
callRuntime(refRuntimeCall(RT.runtime_THROW_REF), [r_ret_throw], true);

asm.bind(done);
restoreDispatchTableReg();
Expand Down
10 changes: 4 additions & 6 deletions src/engine/x86-64/X86_64Stack.v3
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,7 @@ class X86_64Stack extends WasmStack {
if (Trace.stack) traceFrames(Strings.format1("stack.throw(%q)", thrown.render), rsp + RETADDR_SIZE);
// Perform a stackwalk, starting from the RSP stored in this object, gathering frames.
var prev_sp = this.rsp;
if (!FeatureDisable.stackUnwind && Exception.?(thrown)) {
if (Exception.?(thrown)) {
var ex = Exception.!(thrown);
var new_sp = walk(findExHandler, ex, prev_sp);
unwind(prev_sp + -RETADDR_SIZE, new_sp);
Expand All @@ -106,11 +106,9 @@ class X86_64Stack extends WasmStack {
var gatherTrace = !FeatureDisable.stacktraces;
var trace = if (gatherTrace, Vector<(WasmFunction, int)>.new());
var return_parent_sp = walk(if(gatherTrace, addFrameToTrace), trace, prev_sp);
if (!FeatureDisable.stackUnwind) {
// Unwind this stack to the return parent stub and overwrite the caller's return IP.
this.vsp = mapping.range.start; // clear value stack
unwind(prev_sp + -RETADDR_SIZE, return_parent_sp);
}
// Unwind this stack to the return parent stub and overwrite the caller's return IP.
this.vsp = mapping.range.start; // clear value stack
unwind(prev_sp + -RETADDR_SIZE, return_parent_sp);

// Append the (reversed) stacktrace to the throwable.
if (trace != null) thrown.prependFrames(ArrayUtil.copyReverse(trace));
Expand Down
Loading