@@ -78,6 +78,20 @@ struct Execution {
78
78
return Backtrace ( symbols: symbols)
79
79
}
80
80
81
+ private func initializeConstSlots(
82
+ sp: Sp , iseq: InstructionSequence ,
83
+ numberOfNonParameterLocals: Int
84
+ ) {
85
+ // Initialize the locals with zeros (all types of value have the same representation)
86
+ sp. initialize ( repeating: UntypedValue . default. storage, count: numberOfNonParameterLocals)
87
+ if let constants = iseq. constants. baseAddress {
88
+ let count = iseq. constants. count
89
+ sp. advanced ( by: numberOfNonParameterLocals) . withMemoryRebound ( to: UntypedValue . self, capacity: count) {
90
+ $0. initialize ( from: constants, count: count)
91
+ }
92
+ }
93
+ }
94
+
81
95
/// Pushes a new call frame to the VM stack.
82
96
@inline ( __always)
83
97
func pushFrame(
@@ -88,17 +102,8 @@ struct Execution {
88
102
spAddend: VReg
89
103
) throws -> Sp {
90
104
let newSp = sp. advanced ( by: Int ( spAddend) )
91
- guard newSp. advanced ( by: iseq. maxStackHeight) < stackEnd else {
92
- throw Trap ( . callStackExhausted)
93
- }
94
- // Initialize the locals with zeros (all types of value have the same representation)
95
- newSp. initialize ( repeating: UntypedValue . default. storage, count: numberOfNonParameterLocals)
96
- if let constants = iseq. constants. baseAddress {
97
- let count = iseq. constants. count
98
- newSp. advanced ( by: numberOfNonParameterLocals) . withMemoryRebound ( to: UntypedValue . self, capacity: count) {
99
- $0. initialize ( from: constants, count: count)
100
- }
101
- }
105
+ try checkStackBoundary ( newSp. advanced ( by: iseq. maxStackHeight) )
106
+ initializeConstSlots ( sp: newSp, iseq: iseq, numberOfNonParameterLocals: numberOfNonParameterLocals)
102
107
newSp. previousSP = sp
103
108
newSp. returnPC = returnPC
104
109
newSp. currentFunction = function
@@ -505,6 +510,11 @@ extension Execution {
505
510
self . trap = ( rawError, sp)
506
511
}
507
512
513
+ @inline ( __always)
514
+ func checkStackBoundary( _ sp: Sp ) throws {
515
+ guard sp < stackEnd else { throw Trap ( . callStackExhausted) }
516
+ }
517
+
508
518
/// Returns the new program counter and stack pointer.
509
519
@inline ( never)
510
520
func invoke(
@@ -524,6 +534,50 @@ extension Execution {
524
534
}
525
535
}
526
536
537
+ @inline ( never)
538
+ func tailInvoke(
539
+ function: InternalFunction ,
540
+ callerInstance: InternalInstance ? ,
541
+ spAddend: VReg ,
542
+ sp: Sp , pc: Pc , md: inout Md , ms: inout Ms
543
+ ) throws -> ( Pc , Sp ) {
544
+ if function. isWasm {
545
+ return try tailInvokeWasmFunction (
546
+ function: function. wasm, callerInstance: callerInstance,
547
+ spAddend: spAddend,
548
+ sp: sp, md: & md, ms: & ms
549
+ )
550
+ } else {
551
+ try invokeHostFunction ( function: function. host, sp: sp, spAddend: spAddend)
552
+ return ( pc, sp)
553
+ }
554
+ }
555
+
556
+ /// Executes the given wasm function while overwriting the current frame.
557
+ ///
558
+ /// Precondition: The frame header must be already resized to be compatible
559
+ /// with the callee's frame header layout.
560
+ @inline ( __always)
561
+ private func tailInvokeWasmFunction(
562
+ function: EntityHandle < WasmFunctionEntity > ,
563
+ callerInstance: InternalInstance ? ,
564
+ spAddend: VReg ,
565
+ sp: Sp , md: inout Md , ms: inout Ms
566
+ ) throws -> ( Pc , Sp ) {
567
+ let iseq = try function. ensureCompiled ( store: store)
568
+ let newSp = sp. advanced ( by: Int ( spAddend) )
569
+ try checkStackBoundary ( newSp. advanced ( by: iseq. maxStackHeight) )
570
+ newSp. currentFunction = function
571
+
572
+ initializeConstSlots ( sp: newSp, iseq: iseq, numberOfNonParameterLocals: function. numberOfNonParameterLocals)
573
+
574
+ Execution . CurrentMemory. mayUpdateCurrentInstance (
575
+ instance: function. instance,
576
+ from: callerInstance, md: & md, ms: & ms
577
+ )
578
+ return ( iseq. baseAddress, newSp)
579
+ }
580
+
527
581
/// Executes the given WebAssembly function.
528
582
@inline ( __always)
529
583
private func invokeWasmFunction(
0 commit comments