Skip to content

Commit

Permalink
[x86-64] Merge interpreter and SPC frame accessors into one base class
Browse files Browse the repository at this point in the history
  • Loading branch information
titzer committed Jul 20, 2023
1 parent 1f82149 commit 330f6b6
Show file tree
Hide file tree
Showing 5 changed files with 34 additions and 68 deletions.
3 changes: 0 additions & 3 deletions src/engine/Probe.v3
Original file line number Diff line number Diff line change
Expand Up @@ -31,9 +31,6 @@ class FrameAccessor {
def func() -> WasmFunction;
// Returns the current program counter.
def pc() -> int;
// Returns {true} if this frame is currently the top executing frame, {false} if the
// frame has called another function, returned, or been unwound.
def isTop() -> bool;
// Returns {true} if this frame has been unwound, either due to returning, or a trap or exception.
// If this frame has been unwound, then
def isUnwound() -> bool;
Expand Down
2 changes: 1 addition & 1 deletion src/engine/v3/V3Interpreter.v3
Original file line number Diff line number Diff line change
Expand Up @@ -1451,7 +1451,7 @@ class V3FrameAccessor(frame: V3Frame) extends FrameAccessor {
}
// Returns {true} if this frame is currently the top executing frame, {false} if the
// frame has called another function or been unwound.
def isTop() -> bool {
private def isTop() -> bool {
return if(!isUnwound(), V3Interpreter.frame == frame);
}
// Returns the call depth of this frame within its segment, with the bottom frame being #0.
Expand Down
31 changes: 0 additions & 31 deletions src/engine/x86-64/X86_64Interpreter.v3
Original file line number Diff line number Diff line change
Expand Up @@ -47,24 +47,6 @@ def dumpFrame(sp: Pointer) {
Trace.OUT.outln();
}

// FrameAccessor for probing and debugging.
class X86_64InterpreterFrameAccessor extends X86_64BaseFrameAccessor {
new(sp: Pointer) super(sp) {
decl = (sp + IVAR_FRAME.FUNC_DECL.disp).load<FuncDecl>();
}

// Returns {true} if this frame has been unwound, either due to returning, a trap, or exception.
def isUnwound() -> bool {
if (FeatureDisable.frameAccess) return false; // TODO: proper is-frame-unwound check
def frame = X86_64MasmRegs.IVAR_FRAME;
return this != (sp + IVAR_FRAME.ACCESSOR.disp).load<X86_64InterpreterFrameAccessor>();
}
// Set the value of a local variable. (dynamically typechecked).
def setLocal(i: int, v: Value);
// Set operand at depth {i}, with 0 being the top of the stack, -1 being one lower, etc. (dynamically typechecked).
def setOperand(i: int, v: Value);
}

// Signal-handling for traps
def ucontext_rip_offset = 168;
def ucontext_rsp_offset = 160;
Expand Down Expand Up @@ -179,19 +161,6 @@ class X86_64InterpreterCode extends RiUserCode {
(/*wf: */ WasmFunction, /*sp: */ Pointer), Throwable>( // param and return types
start + intV3EntryOffset, I);
}
// Get a frame accessor for the probe API.
def getFrameAccessor(sp: Pointer) -> X86_64InterpreterFrameAccessor {
var retip = (sp + -Pointer.SIZE).load<Pointer>();
if (!X86_64Interpreter.inCode(retip)) return null;
if (!FeatureDisable.frameAccess) {
var prev = (sp + IVAR_FRAME.ACCESSOR.disp).load<X86_64InterpreterFrameAccessor>();
if (prev != null) return prev;
var n = X86_64InterpreterFrameAccessor.new(sp);
(sp + IVAR_FRAME.ACCESSOR.disp).store<X86_64InterpreterFrameAccessor>(n);
return n;
}
return X86_64InterpreterFrameAccessor.new(sp);
}
}

def fatal(msg: string) {
Expand Down
39 changes: 33 additions & 6 deletions src/engine/x86-64/X86_64Runtime.v3
Original file line number Diff line number Diff line change
Expand Up @@ -128,8 +128,25 @@ component X86_64Runtime {
var retip = (sp + -Pointer.SIZE).load<Pointer>();
var code = RiRuntime.findUserCode(retip);
match (code) {
x: X86_64InterpreterCode => return x.getFrameAccessor(sp);
x: X86_64SpcCode => return x.getFrameAccessor(retip, sp);
x: X86_64InterpreterCode => {
var prev = (sp + IVAR_FRAME.ACCESSOR.disp).load<X86_64FrameAccessor>();
if (prev != null) return prev;
// Interpreter frames store the {WasmFunction} _and_ {FuncDecl}.
var decl = (sp + IVAR_FRAME.FUNC_DECL.disp).load<FuncDecl>();
var n = X86_64FrameAccessor.new(sp, decl);
(sp + IVAR_FRAME.ACCESSOR.disp).store<X86_64FrameAccessor>(n);
return n;
}
x: X86_64SpcCode => {
var prev = (sp + IVAR_FRAME.ACCESSOR.disp).load<X86_64FrameAccessor>();
if (prev != null) return prev;
// SPC frames only store the {WasmFunction}.
var wf = (sp + IVAR_FRAME.WASM_FUNC.disp).load<WasmFunction>();
// TODO: assert wf.decl == x.decl()
var n = X86_64FrameAccessor.new(sp, wf.decl);
(sp + IVAR_FRAME.ACCESSOR.disp).store<X86_64FrameAccessor>(n);
return n;
}
}
return null;
}
Expand Down Expand Up @@ -415,15 +432,25 @@ component X86_64Runtime {

def RT: X86_64Runtime;

// The base class for fast interpreter and SPC frames, which have a similar layout.
class X86_64BaseFrameAccessor(sp: Pointer) extends FrameAccessor {
// Native frame states used in the implementation of {FrameStateAccessor}. Since a frame
// can be optimized or deoptimized in place, the frame state accessor has to check the
// state for every call.
enum X86_64FrameState {
INVALID, INTERPRETER, SPC, SPC_TRAPS_STUB
}
// Implements access to interpreter and SPC frames.
class X86_64FrameAccessor(sp: Pointer, decl: FuncDecl) extends FrameAccessor {
var cached_depth = -1;
var cached_ip: Pointer;
var cached_pc: int;
var decl: FuncDecl;
var dirty: bool;

// Returns {true} if this frame has been unwound, either due to returning, a trap, or exception.
def isUnwound() -> bool;
def isUnwound() -> bool {
if (FeatureDisable.frameAccess) return false; // TODO: proper is-frame-unwound check
def frame = X86_64MasmRegs.IVAR_FRAME;
return this != (sp + IVAR_FRAME.ACCESSOR.disp).load<X86_64FrameAccessor>();
}
// Returns the Wasm function in this frame.
def func() -> WasmFunction {
checkNotUnwound();
Expand Down
27 changes: 0 additions & 27 deletions src/engine/x86-64/X86_64SinglePassCompiler.v3
Original file line number Diff line number Diff line change
Expand Up @@ -637,15 +637,6 @@ class X86_64SpcCode extends RiUserCode {
RiGc.scanRoot(sp + IVAR_FRAME.INSTANCE.disp);
RiGc.scanRoot(sp + IVAR_FRAME.ACCESSOR.disp);
}
// Get a frame accessor for the probe API.
def getFrameAccessor(retip: Pointer, sp: Pointer) -> X86_64SpcFrameAccessor {
if (retip < start || retip >= end) return null;
var prev = (sp + IVAR_FRAME.ACCESSOR.disp).load<X86_64SpcFrameAccessor>();
if (prev != null) return prev;
var n = X86_64SpcFrameAccessor.new(sp);
(sp + IVAR_FRAME.ACCESSOR.disp).store<X86_64SpcFrameAccessor>(n);
return n;
}
}

// Represents the JITed code for an entire module.
Expand Down Expand Up @@ -807,24 +798,6 @@ class X86_64SpcCompileStub extends RiUserCode {
}
}

// Implements frame accessor for JIT compiled method frames. For SPC, the frame layout is almost
// identical to interpreter frames, so it inherits from the base implementation.
class X86_64SpcFrameAccessor extends X86_64BaseFrameAccessor {
new(sp: Pointer) super(sp) {
var wf = (sp + IVAR_FRAME.WASM_FUNC.disp).load<WasmFunction>();
decl = wf.decl;
}

// Returns {true} if this frame has been unwound, either due to returning, a trap, or exception.
def isUnwound() -> bool {
return this != (sp + IVAR_FRAME.ACCESSOR.disp).load<FrameAccessor>();
}
// Set the value of a local variable. (dynamically typechecked).
def setLocal(i: int, v: Value); // TODO: translate to interpreter frame
// Set operand at depth {i}, with 0 being the top of the stack, -1 being one lower, etc. (dynamically typechecked).
def setOperand(i: int, v: Value); // TODO: translate to interpreter frame
}

type SpcResultForStub(wf: WasmFunction, entrypoint: Pointer, thrown: Throwable) #unboxed { }

// Global functionality associated with the single-pass compiler for X86-64.
Expand Down

0 comments on commit 330f6b6

Please sign in to comment.