@@ -310,14 +310,17 @@ struct InstructionTranslator<Context: TranslatorContext>: InstructionVisitor {
310310 var kind : Kind
311311 var reachable : Bool = true
312312
313- var copyCount : UInt16 {
313+ var copyTypes : [ ValueType ] {
314314 switch self . kind {
315315 case . block, . if:
316- return UInt16 ( blockType. results. count )
316+ return blockType. results
317317 case . loop:
318- return UInt16 ( blockType. parameters. count )
318+ return blockType. parameters
319319 }
320320 }
321+ var copyCount : UInt16 {
322+ return UInt16 ( copyTypes. count)
323+ }
321324 }
322325
323326 private var frames : [ ControlFrame ] = [ ]
@@ -893,8 +896,7 @@ struct InstructionTranslator<Context: TranslatorContext>: InstructionVisitor {
893896 ///
894897 /// - Parameter typeHint: A type expected to be popped. Only used for diagnostic purpose.
895898 /// - Returns: `true` if check succeed. `false` if the pop operation is going to be performed in unreachable code path.
896- private func checkBeforePop( typeHint: ValueType ? ) throws -> Bool {
897- let controlFrame = try controlStack. currentFrame ( )
899+ private func checkBeforePop( typeHint: ValueType ? , controlFrame: ControlStack . ControlFrame ) throws -> Bool {
898900 if _slowPath ( valueStack. height <= controlFrame. stackHeight) {
899901 if controlFrame. reachable {
900902 let message : String
@@ -910,6 +912,10 @@ struct InstructionTranslator<Context: TranslatorContext>: InstructionVisitor {
910912 }
911913 return true
912914 }
915+ private func checkBeforePop( typeHint: ValueType ? ) throws -> Bool {
916+ let controlFrame = try controlStack. currentFrame ( )
917+ return try self . checkBeforePop ( typeHint: typeHint, controlFrame: controlFrame)
918+ }
913919 private mutating func ensureOnVReg( _ source: ValueSource ) -> VReg {
914920 // TODO: Copy to stack if source is on preg
915921 // let copyTo = valueStack.stackRegBase + VReg(valueStack.height)
@@ -959,6 +965,27 @@ struct InstructionTranslator<Context: TranslatorContext>: InstructionVisitor {
959965 return try valueStack. pop ( )
960966 }
961967
968+ @discardableResult
969+ private mutating func popPushValues( _ valueTypes: [ ValueType ] ) throws -> Int {
970+ var values : [ ValueSource ? ] = [ ]
971+ for type in valueTypes. reversed ( ) {
972+ values. append ( try popOperand ( type) )
973+ }
974+ let stackHeight = self . valueStack. height
975+ for (type, value) in zip ( valueTypes, values. reversed ( ) ) {
976+ switch value {
977+ case . local( let localIndex) :
978+ // Re-push local variables to the stack
979+ _ = try valueStack. pushLocal ( localIndex, locals: & locals)
980+ case . vreg, nil :
981+ _ = valueStack. push ( type)
982+ case . const( let index, let type) :
983+ valueStack. pushConst ( index, type: type)
984+ }
985+ }
986+ return stackHeight
987+ }
988+
962989 private mutating func visitReturnLike( ) throws {
963990 preserveOnStack ( depth: self . type. results. count)
964991 for (index, resultType) in self . type. results. enumerated ( ) . reversed ( ) {
@@ -1050,22 +1077,7 @@ struct InstructionTranslator<Context: TranslatorContext>: InstructionVisitor {
10501077 mutating func visitBlock( blockType: WasmParser . BlockType ) throws -> Output {
10511078 let blockType = try module. resolveBlockType ( blockType)
10521079 let endLabel = iseqBuilder. allocLabel ( )
1053- var parameters : [ ValueSource ? ] = [ ]
1054- for param in blockType. parameters. reversed ( ) {
1055- parameters. append ( try popOperand ( param) )
1056- }
1057- let stackHeight = self . valueStack. height
1058- for (param, value) in zip ( blockType. parameters, parameters. reversed ( ) ) {
1059- switch value {
1060- case . local( let localIndex) :
1061- // Re-push local variables to the stack
1062- _ = try valueStack. pushLocal ( localIndex, locals: & locals)
1063- case . vreg, nil :
1064- _ = valueStack. push ( param)
1065- case . const( let index, let type) :
1066- valueStack. pushConst ( index, type: type)
1067- }
1068- }
1080+ let stackHeight = try popPushValues ( blockType. parameters)
10691081 controlStack. pushFrame ( ControlStack . ControlFrame ( blockType: blockType, stackHeight: stackHeight, continuation: endLabel, kind: . block) )
10701082 }
10711083
@@ -1158,6 +1170,10 @@ struct InstructionTranslator<Context: TranslatorContext>: InstructionVisitor {
11581170 if case . block( root: true ) = poppedFrame. kind {
11591171 if poppedFrame. reachable {
11601172 try translateReturn ( )
1173+ // TODO: Merge logic with regular block frame
1174+ guard valueStack. height == poppedFrame. stackHeight else {
1175+ throw ValidationError ( " values remaining on stack at end of block " )
1176+ }
11611177 }
11621178 try iseqBuilder. pinLabelHere ( poppedFrame. continuation)
11631179 return
@@ -1173,7 +1189,13 @@ struct InstructionTranslator<Context: TranslatorContext>: InstructionVisitor {
11731189 case . if:
11741190 try iseqBuilder. pinLabelHere ( poppedFrame. continuation)
11751191 }
1176- try valueStack. truncate ( height: poppedFrame. stackHeight)
1192+ for result in poppedFrame. blockType. results. reversed ( ) {
1193+ guard try checkBeforePop ( typeHint: result, controlFrame: poppedFrame) else { continue }
1194+ _ = try valueStack. pop ( result)
1195+ }
1196+ guard valueStack. height == poppedFrame. stackHeight else {
1197+ throw ValidationError ( " values remaining on stack at end of block " )
1198+ }
11771199 for result in poppedFrame. blockType. results {
11781200 _ = valueStack. push ( result)
11791201 }
@@ -1231,6 +1253,9 @@ struct InstructionTranslator<Context: TranslatorContext>: InstructionVisitor {
12311253 try emitBranch ( Instruction . br, relativeDepth: relativeDepth) { offset, copyCount, popCount in
12321254 return offset
12331255 }
1256+ for type in frame. copyTypes. reversed ( ) {
1257+ _ = try popOperand ( type)
1258+ }
12341259 try markUnreachable ( )
12351260 }
12361261
@@ -1279,12 +1304,12 @@ struct InstructionTranslator<Context: TranslatorContext>: InstructionVisitor {
12791304 try emitBranch ( Instruction . br, relativeDepth: relativeDepth) { offset, copyCount, popCount in
12801305 return offset
12811306 }
1307+ try popPushValues ( frame. copyTypes)
12821308 try iseqBuilder. pinLabelHere ( onBranchNotTaken)
12831309 }
12841310
12851311 mutating func visitBrTable( targets: WasmParser . BrTable ) throws -> Output {
12861312 guard let index = try popVRegOperand ( . i32) else { return }
1287- guard try controlStack. currentFrame ( ) . reachable else { return }
12881313
12891314 let defaultFrame = try controlStack. branchTarget ( relativeDepth: targets. defaultIndex)
12901315
0 commit comments