@@ -12,7 +12,7 @@ struct Execution {
12
12
/// The error trap thrown during execution.
13
13
/// This property must not be assigned to be non-nil more than once.
14
14
/// - 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
16
16
17
17
/// Executes the given closure with a new execution state associated with
18
18
/// the given ``Store`` instance.
@@ -26,13 +26,6 @@ struct Execution {
26
26
valueStack. deallocate ( )
27
27
}
28
28
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
- }
36
29
return try body ( & context, valueStack)
37
30
}
38
31
@@ -46,6 +39,7 @@ struct Execution {
46
39
struct FrameIterator : IteratorProtocol {
47
40
struct Element {
48
41
let pc : Pc
42
+ let function : EntityHandle < WasmFunctionEntity > ?
49
43
}
50
44
51
45
/// The stack pointer currently traversed.
@@ -56,29 +50,39 @@ struct Execution {
56
50
}
57
51
58
52
mutating func next( ) -> Element ? {
59
- guard let sp = self . sp else {
53
+ guard let sp = self . sp, let pc = sp . returnPC else {
60
54
// Reached the root frame, whose stack pointer is nil.
61
55
return nil
62
56
}
63
- let pc = sp. returnPC
64
57
self . sp = sp. previousSP
65
- return Element ( pc: pc)
58
+ return Element ( pc: pc, function : sp . currentFunction )
66
59
}
67
60
}
68
61
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)
75
79
}
76
80
77
81
/// Pushes a new call frame to the VM stack.
78
82
@inline ( __always)
79
83
mutating func pushFrame(
80
84
iseq: InstructionSequence ,
81
- instance : InternalInstance ,
85
+ function : EntityHandle < WasmFunctionEntity > ,
82
86
numberOfNonParameterLocals: Int ,
83
87
sp: Sp , returnPC: Pc ,
84
88
spAddend: VReg
@@ -97,7 +101,7 @@ struct Execution {
97
101
}
98
102
newSp. previousSP = sp
99
103
newSp. returnPC = returnPC
100
- newSp. currentInstance = instance
104
+ newSp. currentFunction = function
101
105
return newSp
102
106
}
103
107
@@ -106,7 +110,7 @@ struct Execution {
106
110
mutating func popFrame( sp: inout Sp , pc: inout Pc , md: inout Md , ms: inout Ms ) {
107
111
let oldSp = sp
108
112
sp = oldSp. previousSP. unsafelyUnwrapped
109
- pc = oldSp. returnPC
113
+ pc = oldSp. returnPC. unsafelyUnwrapped
110
114
let toInstance = oldSp. currentInstance. unsafelyUnwrapped
111
115
let fromInstance = sp. currentInstance
112
116
CurrentMemory . mayUpdateCurrentInstance ( instance: toInstance, from: fromInstance, md: & md, ms: & ms)
@@ -222,15 +226,15 @@ extension Sp {
222
226
223
227
// MARK: - Special slots
224
228
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) ) }
228
232
nonmutating set { self [ - 3 ] = UInt64 ( UInt ( bitPattern: newValue? . bitPattern ?? 0 ) ) }
229
233
}
230
234
231
235
/// 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 ] ) ) }
234
238
nonmutating set { self [ - 2 ] = UInt64 ( UInt ( bitPattern: newValue) ) }
235
239
}
236
240
@@ -239,6 +243,10 @@ extension Sp {
239
243
get { return Sp ( bitPattern: UInt ( self [ - 1 ] ) ) }
240
244
nonmutating set { self [ - 1 ] = UInt64 ( UInt ( bitPattern: newValue) ) }
241
245
}
246
+
247
+ fileprivate var currentInstance : InternalInstance ? {
248
+ currentFunction? . instance
249
+ }
242
250
}
243
251
244
252
extension Pc {
@@ -278,7 +286,9 @@ func executeWasm(
278
286
// Advance the stack pointer to be able to reference negative indices
279
287
// for saving slots.
280
288
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
282
292
for (index, argument) in arguments. enumerated ( ) {
283
293
sp [ VReg ( index) ] = UntypedValue ( argument)
284
294
}
@@ -386,8 +396,17 @@ extension Execution {
386
396
var pc = pc
387
397
let handler = pc. read ( wasmkit_tc_exec. self)
388
398
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) )
391
410
}
392
411
}
393
412
@@ -463,11 +482,15 @@ extension Execution {
463
482
defer { stats. dump ( ) }
464
483
#endif
465
484
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) )
471
494
}
472
495
}
473
496
@@ -477,9 +500,9 @@ extension Execution {
477
500
/// It's used only when direct threading is enabled.
478
501
/// - Parameter trap: The error trap thrown during execution.
479
502
@_silgen_name ( " wasmkit_execution_state_set_error " )
480
- mutating func setError( _ trap : UnsafeRawPointer ) {
503
+ mutating func setError( _ rawError : UnsafeRawPointer , sp : Sp ) {
481
504
precondition ( self . trap == nil )
482
- self . trap = trap
505
+ self . trap = ( rawError , sp )
483
506
}
484
507
485
508
/// Returns the new program counter and stack pointer.
@@ -496,7 +519,7 @@ extension Execution {
496
519
497
520
let newSp = try pushFrame (
498
521
iseq: iseq,
499
- instance : function. instance ,
522
+ function : function,
500
523
numberOfNonParameterLocals: function. numberOfNonParameterLocals,
501
524
sp: sp,
502
525
returnPC: pc,
0 commit comments