@@ -12,7 +12,7 @@ struct Execution {
1212 /// The error trap thrown during execution.
1313 /// This property must not be assigned to be non-nil more than once.
1414 /// - Note: If the trap is set, it must be released manually.
15- private var trap : UnsafeRawPointer ? = nil
15+ private var trap : ( error : UnsafeRawPointer , sp : Sp ) ? = nil
1616
1717 /// Executes the given closure with a new execution state associated with
1818 /// the given ``Store`` instance.
@@ -26,13 +26,6 @@ struct Execution {
2626 valueStack. deallocate ( )
2727 }
2828 var context = Execution ( store: store, stackEnd: valueStack. advanced ( by: limit) )
29- defer {
30- if let trap = context. trap {
31- // Manually release the error object because the trap is caught in C and
32- // held as a raw pointer.
33- wasmkit_swift_errorRelease ( trap)
34- }
35- }
3629 return try body ( & context, valueStack)
3730 }
3831
@@ -46,6 +39,7 @@ struct Execution {
4639 struct FrameIterator : IteratorProtocol {
4740 struct Element {
4841 let pc : Pc
42+ let function : EntityHandle < WasmFunctionEntity > ?
4943 }
5044
5145 /// The stack pointer currently traversed.
@@ -56,29 +50,39 @@ struct Execution {
5650 }
5751
5852 mutating func next( ) -> Element ? {
59- guard let sp = self . sp else {
53+ guard let sp = self . sp, let pc = sp . returnPC else {
6054 // Reached the root frame, whose stack pointer is nil.
6155 return nil
6256 }
63- let pc = sp. returnPC
6457 self . sp = sp. previousSP
65- return Element ( pc: pc)
58+ return Element ( pc: pc, function : sp . currentFunction )
6659 }
6760 }
6861
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)
62+ static func captureBacktrace( sp: Sp , store: Store ) -> Backtrace {
63+ var frames = FrameIterator ( sp: sp)
64+ var symbols : [ Backtrace . Symbol ? ] = [ ]
65+ while let frame = frames. next ( ) {
66+ guard let function = frame. function else {
67+ symbols. append ( nil )
68+ continue
69+ }
70+ let symbolName = store. nameRegistry. symbolicate ( . wasm( function) )
71+ symbols. append (
72+ Backtrace . Symbol (
73+ function: Function ( handle: . wasm( function) , store: store) ,
74+ name: symbolName
75+ )
76+ )
77+ }
78+ return Backtrace ( symbols: symbols)
7579 }
7680
7781 /// Pushes a new call frame to the VM stack.
7882 @inline ( __always)
7983 mutating func pushFrame(
8084 iseq: InstructionSequence ,
81- instance : InternalInstance ,
85+ function : EntityHandle < WasmFunctionEntity > ,
8286 numberOfNonParameterLocals: Int ,
8387 sp: Sp , returnPC: Pc ,
8488 spAddend: VReg
@@ -97,7 +101,7 @@ struct Execution {
97101 }
98102 newSp. previousSP = sp
99103 newSp. returnPC = returnPC
100- newSp. currentInstance = instance
104+ newSp. currentFunction = function
101105 return newSp
102106 }
103107
@@ -106,7 +110,7 @@ struct Execution {
106110 mutating func popFrame( sp: inout Sp , pc: inout Pc , md: inout Md , ms: inout Ms ) {
107111 let oldSp = sp
108112 sp = oldSp. previousSP. unsafelyUnwrapped
109- pc = oldSp. returnPC
113+ pc = oldSp. returnPC. unsafelyUnwrapped
110114 let toInstance = oldSp. currentInstance. unsafelyUnwrapped
111115 let fromInstance = sp. currentInstance
112116 CurrentMemory . mayUpdateCurrentInstance ( instance: toInstance, from: fromInstance, md: & md, ms: & ms)
@@ -222,15 +226,15 @@ extension Sp {
222226
223227 // MARK: - Special slots
224228
225- /// The current instance of the execution context .
226- fileprivate var currentInstance : InternalInstance ? {
227- get { return InternalInstance ( bitPattern: UInt ( self [ - 3 ] . i64) ) }
229+ /// The current executing function .
230+ fileprivate var currentFunction : EntityHandle < WasmFunctionEntity > ? {
231+ get { return EntityHandle < WasmFunctionEntity > ( bitPattern: UInt ( self [ - 3 ] . i64) ) }
228232 nonmutating set { self [ - 3 ] = UInt64 ( UInt ( bitPattern: newValue? . bitPattern ?? 0 ) ) }
229233 }
230234
231235 /// The return program counter of the current frame.
232- fileprivate var returnPC : Pc {
233- get { return Pc ( bitPattern: UInt ( self [ - 2 ] ) ) ! }
236+ fileprivate var returnPC : Pc ? {
237+ get { return Pc ( bitPattern: UInt ( self [ - 2 ] ) ) }
234238 nonmutating set { self [ - 2 ] = UInt64 ( UInt ( bitPattern: newValue) ) }
235239 }
236240
@@ -239,6 +243,10 @@ extension Sp {
239243 get { return Sp ( bitPattern: UInt ( self [ - 1 ] ) ) }
240244 nonmutating set { self [ - 1 ] = UInt64 ( UInt ( bitPattern: newValue) ) }
241245 }
246+
247+ fileprivate var currentInstance : InternalInstance ? {
248+ currentFunction? . instance
249+ }
242250}
243251
244252extension Pc {
@@ -278,7 +286,9 @@ func executeWasm(
278286 // Advance the stack pointer to be able to reference negative indices
279287 // for saving slots.
280288 let sp = sp. advanced ( by: FrameHeaderLayout . numberOfSavingSlots)
281- sp. previousSP = nil // Mark root stack pointer as nil.
289+ // Mark root stack pointer and current function as nil.
290+ sp. previousSP = nil
291+ sp. currentFunction = nil
282292 for (index, argument) in arguments. enumerated ( ) {
283293 sp [ VReg ( index) ] = UntypedValue ( argument)
284294 }
@@ -386,8 +396,17 @@ extension Execution {
386396 var pc = pc
387397 let handler = pc. read ( wasmkit_tc_exec. self)
388398 wasmkit_tc_start ( handler, sp, pc, md, ms, & self )
389- if let error = self . trap {
390- throw unsafeBitCast ( error, to: Error . self)
399+ if let ( rawError, trappingSp) = self . trap {
400+ let error = unsafeBitCast ( rawError, to: Error . self)
401+ // Manually release the error object because the trap is caught in C and
402+ // held as a raw pointer.
403+ wasmkit_swift_errorRelease ( rawError)
404+
405+ guard let trap = error as? Trap else {
406+ throw error
407+ }
408+ // Attach backtrace if the thrown error is a trap
409+ throw trap. withBacktrace ( Self . captureBacktrace ( sp: trappingSp, store: store. value) )
391410 }
392411 }
393412
@@ -463,11 +482,15 @@ extension Execution {
463482 defer { stats. dump ( ) }
464483 #endif
465484 var opcode = pc. read ( OpcodeID . self)
466- while true {
467- #if EngineStats
468- stats. track ( inst)
469- #endif
470- opcode = try doExecute ( opcode, sp: & sp, pc: & pc, md: & md, ms: & ms)
485+ do {
486+ while true {
487+ #if EngineStats
488+ stats. track ( inst)
489+ #endif
490+ opcode = try doExecute ( opcode, sp: & sp, pc: & pc, md: & md, ms: & ms)
491+ }
492+ } catch let trap as Trap {
493+ throw trap. withBacktrace ( Self . captureBacktrace ( sp: sp, store: store. value) )
471494 }
472495 }
473496
@@ -477,9 +500,9 @@ extension Execution {
477500 /// It's used only when direct threading is enabled.
478501 /// - Parameter trap: The error trap thrown during execution.
479502 @_silgen_name ( " wasmkit_execution_state_set_error " )
480- mutating func setError( _ trap : UnsafeRawPointer ) {
503+ mutating func setError( _ rawError : UnsafeRawPointer , sp : Sp ) {
481504 precondition ( self . trap == nil )
482- self . trap = trap
505+ self . trap = ( rawError , sp )
483506 }
484507
485508 /// Returns the new program counter and stack pointer.
@@ -496,7 +519,7 @@ extension Execution {
496519
497520 let newSp = try pushFrame (
498521 iseq: iseq,
499- instance : function. instance ,
522+ function : function,
500523 numberOfNonParameterLocals: function. numberOfNonParameterLocals,
501524 sp: sp,
502525 returnPC: pc,
0 commit comments