-
Notifications
You must be signed in to change notification settings - Fork 43
/
Copy pathWasmStack.v3
152 lines (140 loc) · 5.43 KB
/
WasmStack.v3
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
// Copyright 2023 Wizard authors. All rights reserved.
// See LICENSE for details of Apache 2.0 license.
// An execution stack.
class ExecStack {
def popV(t: ValueType) -> Value;
def popi() -> i32;
def popu() -> u32;
def popl() -> i64;
def popw() -> u64;
def popf() -> float;
def popd() -> double;
def popr() -> Value.Ref;
def popObject() -> Object;
def popN(ts: Range<ValueType>) -> Array<Value>;
def peekK(ts: Range<ValueType>) -> Range<Value>;
def push(val: Value);
def pushi(val: i32);
def pushu(val: u32);
def pushl(val: i64);
def pushw(val: u64);
def pushf(val: float);
def pushd(val: double);
def pushz(val: bool);
def pushN(vs: Range<Value>);
def trap(r: TrapReason) -> Throwable;
def throw(t: Throwable) -> Throwable;
def trap_or<T>(r: (T, TrapReason), push: T -> ()) -> Throwable {
if (r.1 != TrapReason.NONE) return trap(r.1);
push(r.0);
return null;
}
def pusha(size: SizeConstraint, val: u64) {
return if(size.is64, pushw(val), pushu(u32.view(val)));
}
def popa(size: SizeConstraint) -> u64 {
return if(size.is64, popw(), popu());
}
def popStruct() -> HeapStruct {
return HeapStruct.!(popObject());
}
def popArray() -> HeapArray {
return HeapArray.!(popObject());
}
def popFunction() -> Function {
return Function.!(popObject());
}
}
// Represents a stack on which Wasm code can be executed.
class WasmStack extends ExecStack {
var parent: WasmStack;
// Gets the state of this stack.
def state() -> StackState;
// Requires {state == EMPTY}.
// Resets this stack to be {SUSPENDED}, awaiting arguments for {func}.
def reset(func: Function) -> this;
// Requires {state == SUSPENDED}.
// Pushes {args} incrementally onto the value stack and transitions to {state == RESUMABLE}
// when enough arguments are pushed.
def bind(args: Range<Value>) -> this;
// Requires {state == RESUMABLE}.
// Resumes running the Wasm or host code in this stack until that code either returns, throws,
// or suspends itself.
def resume() -> Result;
// Gets a {FrameLoc} for the top of the stack.
def where() -> FrameLoc;
// Gets the caller of a given {FrameLoc}.
def caller(loc: FrameLoc) -> FrameLoc;
// Clears this stack, forcibly removing all its frames.
def clear() -> this;
}
enum StackState {
EMPTY, // contains no frames
SUSPENDED, // contains one or more frames, waiting for inputs
CALL_CHILD, // waiting for child stack to return
RESUMABLE, // all inputs set; can be resumed
RUNNING, // currently running Wasm or host code
RETURNING, // used internally
THROWING, // used internally
}
// An object which provides access to the state of an executing frame.
// A {FrameAccessor} is a stateful object that is materialized lazily by calling {TargetFrame.getAccessor()}
// and cached thereafter. It becomes obsolete after the frame is unwound, either because the function returned,
// or a trap or exception unwound the stack.
class FrameAccessor {
def var metaRef: FrameAccessorRef;
// Returns the Wasm function in this frame.
def func() -> WasmFunction;
// Returns the current program counter.
def pc() -> int;
// Returns {true} if this frame has been unwound, either due to returning, or a trap or exception.
def isUnwound() -> bool;
// Returns the call depth of this frame within its segment, with the bottom frame being #0.
def depth() -> int;
// Get the caller frame, either a wasm or host function or none if called by the engine.
def caller() -> FrameLoc;
// Returns the sidetable pointer (for testing).
def stp() -> int;
// Get the number of local variables in this frame.
def numLocals() -> int;
// Get the value of local variable {i}.
def getLocal(i: int) -> Value;
// Get the number of operand stack elements.
def numOperands() -> int;
// Get operand at depth {i}, with 0 being the top of the stack, -1 being one lower, etc.
def getOperand(i: int) -> Value;
// Convenience method to get the top of the operand stack.
def getTopOfStack() -> Value { return getOperand(0); }
// Get a {FrameWriter} for this frame. Returns {null} if the execution configuration cannot support modifying this frame.
def getWriter() -> FrameWriter;
// Get a {HostObject} that can be passed to Wasm code for this object.
def getMetaRef() -> FrameAccessorRef {
if (metaRef == null) metaRef = FrameAccessorRef.new(this);
return metaRef;
}
}
// An object that provide the ability to modify the state of an executing frame.
// Methods marked "Dirty" modify the frame in a way that is unexpected, and thus can cause the program
// to behave in unintended ways and should be used with care.
class FrameWriter {
// 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);
// Set the value stack pointer (0 = empty).
def setVsp(vsp: u31);
// Set the program counter (and implicitly, the sidetable pointer).
def setPc(pc: u31);
// Push the given values onto the value stack.
def pushVals(vals: Range<Value>);
// Push a single value onto the value stack.
def push(val: Value);
}
// Represents a dynamic location, e.g. the current point of execution during a probe callback.
type DynamicLoc(func: WasmFunction, pc: int, frame: TargetFrame) #unboxed { }
// A location in either Wasm code or a host function.
type FrameLoc { // TODO: #unboxed
case None;
case Wasm(func: WasmFunction, pc: int, frame: TargetFrame);
case Host(func: HostFunction, frame: HostFrame);
}