@@ -78,6 +78,20 @@ struct Execution {
7878 return Backtrace ( symbols: symbols)
7979 }
8080
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+
8195 /// Pushes a new call frame to the VM stack.
8296 @inline ( __always)
8397 func pushFrame(
@@ -88,17 +102,8 @@ struct Execution {
88102 spAddend: VReg
89103 ) throws -> Sp {
90104 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)
102107 newSp. previousSP = sp
103108 newSp. returnPC = returnPC
104109 newSp. currentFunction = function
@@ -505,6 +510,11 @@ extension Execution {
505510 self . trap = ( rawError, sp)
506511 }
507512
513+ @inline ( __always)
514+ func checkStackBoundary( _ sp: Sp ) throws {
515+ guard sp < stackEnd else { throw Trap ( . callStackExhausted) }
516+ }
517+
508518 /// Returns the new program counter and stack pointer.
509519 @inline ( never)
510520 func invoke(
@@ -524,6 +534,50 @@ extension Execution {
524534 }
525535 }
526536
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+
527581 /// Executes the given WebAssembly function.
528582 @inline ( __always)
529583 private func invokeWasmFunction(
0 commit comments