Skip to content

Commit 8ef2e77

Browse files
Add frame iterator to support backtrace
1 parent 6493c76 commit 8ef2e77

File tree

1 file changed

+61
-8
lines changed

1 file changed

+61
-8
lines changed

Sources/WasmKit/Execution/Execution.swift

Lines changed: 61 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,39 @@ struct Execution {
3939
/// Gets the current instance from the stack pointer.
4040
@inline(__always)
4141
func currentInstance(sp: Sp) -> InternalInstance {
42-
InternalInstance(bitPattern: UInt(sp[-3].i64)).unsafelyUnwrapped
42+
sp.currentInstance.unsafelyUnwrapped
43+
}
44+
45+
/// An iterator for the call frames in the VM stack.
46+
struct FrameIterator: IteratorProtocol {
47+
struct Element {
48+
let pc: Pc
49+
}
50+
51+
/// The stack pointer currently traversed.
52+
private var sp: Sp?
53+
54+
init(sp: Sp) {
55+
self.sp = sp
56+
}
57+
58+
mutating func next() -> Element? {
59+
guard let sp = self.sp else {
60+
// Reached the root frame, whose stack pointer is nil.
61+
return nil
62+
}
63+
let pc = sp.returnPC
64+
self.sp = sp.previousSP
65+
return Element(pc: pc)
66+
}
67+
}
68+
69+
/// Returns an iterator for the call frames in the VM stack.
70+
///
71+
/// - Parameter sp: The stack pointer of the current frame.
72+
/// - Returns: An iterator for the call frames in the VM stack.
73+
static func frames(sp: Sp) -> FrameIterator {
74+
return FrameIterator(sp: sp)
4375
}
4476

4577
/// Pushes a new call frame to the VM stack.
@@ -63,20 +95,20 @@ struct Execution {
6395
$0.initialize(from: constants, count: count)
6496
}
6597
}
66-
newSp[-1] = UInt64(UInt(bitPattern: sp))
67-
newSp[-2] = UInt64(UInt(bitPattern: returnPC))
68-
newSp[-3] = UInt64(UInt(bitPattern: instance.bitPattern))
98+
newSp.previousSP = sp
99+
newSp.returnPC = returnPC
100+
newSp.currentInstance = instance
69101
return newSp
70102
}
71103

72104
/// Pops the current frame from the VM stack.
73105
@inline(__always)
74106
mutating func popFrame(sp: inout Sp, pc: inout Pc, md: inout Md, ms: inout Ms) {
75107
let oldSp = sp
76-
sp = Sp(bitPattern: UInt(oldSp[-1])).unsafelyUnwrapped
77-
pc = Pc(bitPattern: UInt(oldSp[-2])).unsafelyUnwrapped
78-
let toInstance = InternalInstance(bitPattern: UInt(oldSp[-3])).unsafelyUnwrapped
79-
let fromInstance = InternalInstance(bitPattern: UInt(sp[-3]))
108+
sp = oldSp.previousSP.unsafelyUnwrapped
109+
pc = oldSp.returnPC
110+
let toInstance = oldSp.currentInstance.unsafelyUnwrapped
111+
let fromInstance = sp.currentInstance
80112
CurrentMemory.mayUpdateCurrentInstance(instance: toInstance, from: fromInstance, md: &md, ms: &ms)
81113
}
82114
}
@@ -187,6 +219,26 @@ extension Sp {
187219
get { return Float64(bitPattern: read(index)) }
188220
nonmutating set { write(index, .f64(newValue)) }
189221
}
222+
223+
// MARK: - Special slots
224+
225+
/// The current instance of the execution context.
226+
fileprivate var currentInstance: InternalInstance? {
227+
get { return InternalInstance(bitPattern: UInt(self[-3].i64)) }
228+
nonmutating set { self[-3] = UInt64(UInt(bitPattern: newValue?.bitPattern ?? 0)) }
229+
}
230+
231+
/// The return program counter of the current frame.
232+
fileprivate var returnPC: Pc {
233+
get { return Pc(bitPattern: UInt(self[-2]))! }
234+
nonmutating set { self[-2] = UInt64(UInt(bitPattern: newValue)) }
235+
}
236+
237+
/// The previous stack pointer of the current frame.
238+
fileprivate var previousSP: Sp? {
239+
get { return Sp(bitPattern: UInt(self[-1])) }
240+
nonmutating set { self[-1] = UInt64(UInt(bitPattern: newValue)) }
241+
}
190242
}
191243

192244
extension Pc {
@@ -226,6 +278,7 @@ func executeWasm(
226278
// Advance the stack pointer to be able to reference negative indices
227279
// for saving slots.
228280
let sp = sp.advanced(by: FrameHeaderLayout.numberOfSavingSlots)
281+
sp.previousSP = nil // Mark root stack pointer as nil.
229282
for (index, argument) in arguments.enumerated() {
230283
sp[VReg(index)] = UntypedValue(argument)
231284
}

0 commit comments

Comments
 (0)