@@ -470,6 +470,10 @@ struct InstructionTranslator<Context: TranslatorContext>: InstructionVisitor {
470470            return  makeValueSource ( self . values [ height -  1  -  depth] ) 
471471        } 
472472
473+         func  peekType( depth:  Int )  ->  MetaValue  { 
474+             return  self . values [ height -  1  -  depth] . type
475+         } 
476+ 
473477        private  func  makeValueSource( _ value:  MetaValueOnStack )  ->  ValueSource  { 
474478            let  source :  ValueSource 
475479            switch  value { 
@@ -987,17 +991,29 @@ struct InstructionTranslator<Context: TranslatorContext>: InstructionVisitor {
987991            case  . local( let  localIndex) : 
988992                // Re-push local variables to the stack
989993                _ =  try   valueStack. pushLocal ( localIndex,  locals:  & locals) 
990-             case  . vreg: 
994+             case  . vreg,   nil : 
991995                _ =  valueStack. push ( type) 
992-             case  nil : 
993-                 _ =  valueStack. push ( . unknown) 
994996            case  . const( let  index,  let  type) : 
995997                valueStack. pushConst ( index,  type:  type) 
996998            } 
997999        } 
9981000        return  stackHeight
9991001    } 
10001002
1003+     private  func  checkStackTop( _ valueTypes:  [ ValueType ] )  throws  { 
1004+         for  (stackDepth,  type)    in  valueTypes. reversed ( ) . enumerated ( )  { 
1005+             guard  try   checkBeforePop ( typeHint:  type)  else  {  return  } 
1006+             let  actual  =  valueStack. peekType ( depth:  stackDepth) 
1007+             switch  actual { 
1008+             case  . some( let  actualType) : 
1009+                 guard  actualType ==  type else  { 
1010+                     throw  ValidationError ( " Expected  \( type)  on the stack top but got  \( actualType) " ) 
1011+                 } 
1012+             case  . unknown:  break 
1013+             } 
1014+         } 
1015+     } 
1016+ 
10011017    private  mutating  func  visitReturnLike( )  throws  { 
10021018        var  copies :  [ ( source:  VReg ,  dest:  VReg ) ]  =  [ ] 
10031019        for  (index,  resultType)    in  self . type. results. enumerated ( ) . reversed ( )  { 
@@ -1308,10 +1324,11 @@ struct InstructionTranslator<Context: TranslatorContext>: InstructionVisitor {
13081324    } 
13091325
13101326    mutating  func  visitBrIf( relativeDepth:  UInt32 )  throws  ->  Output  { 
1311-         guard  let  condition =  try   popVRegOperand ( . i32)  else  {  return  } 
1312- 
13131327        let  frame  =  try   controlStack. branchTarget ( relativeDepth:  relativeDepth) 
1328+         let  condition  =  try   popVRegOperand ( . i32) 
1329+ 
13141330        if  frame. copyCount ==  0  { 
1331+             guard  let  condition else  {  return  } 
13151332            // Optimization where we don't need copying values when the branch taken
13161333            iseqBuilder. emitWithLabel ( Instruction . brIf,  frame. continuation)  {  _,  selfPC,  continuation in 
13171334                let  relativeOffset  =  continuation. offsetFromHead -  selfPC. offsetFromHead
@@ -1323,37 +1340,39 @@ struct InstructionTranslator<Context: TranslatorContext>: InstructionVisitor {
13231340        } 
13241341        preserveOnStack ( depth:  valueStack. height -  frame. stackHeight) 
13251342
1326-         // If branch taken, fallthrough to landing pad, copy stack values
1327-         // then branch to the actual place
1328-         // If branch not taken, branch to the next of the landing pad
1329-         //
1330-         // (block (result i32)
1331-         //   (i32.const 42)
1332-         //   (i32.const 24)
1333-         //   (local.get 0)
1334-         //   (br_if 0) ------+
1335-         //   (local.get 1)   |
1336-         // )         <-------+
1337-         //
1338-         // [0x00] (i32.const 42 reg:0)
1339-         // [0x01] (i32.const 24 reg:1)
1340-         // [0x02] (local.get 0 result=reg:2)
1341-         // [0x03] (br_if_z offset=+0x3 cond=reg:2) --+
1342-         // [0x04] (stack.copy reg:1 -> reg:0)        |
1343-         // [0x05] (br offset=+0x2) --------+         |
1344-         // [0x06] (local.get 1 reg:2) <----|---------+
1345-         // [0x07] ...              <-------+
1346-         let  onBranchNotTaken  =  iseqBuilder. allocLabel ( ) 
1347-         iseqBuilder. emitWithLabel ( Instruction . brIfNot,  onBranchNotTaken)  {  _,  conditionCheckAt,  continuation in 
1348-             let  relativeOffset  =  continuation. offsetFromHead -  conditionCheckAt. offsetFromHead
1349-             return  Instruction . BrIfOperand ( condition:  LVReg ( condition) ,  offset:  Int32 ( relativeOffset) ) 
1350-         } 
1351-         try   copyOnBranch ( targetFrame:  frame) 
1352-         try   emitBranch ( Instruction . br,  relativeDepth:  relativeDepth)  {  offset,  copyCount,  popCount in 
1353-             return  offset
1343+         if  let  condition { 
1344+             // If branch taken, fallthrough to landing pad, copy stack values
1345+             // then branch to the actual place
1346+             // If branch not taken, branch to the next of the landing pad
1347+             //
1348+             // (block (result i32)
1349+             //   (i32.const 42)
1350+             //   (i32.const 24)
1351+             //   (local.get 0)
1352+             //   (br_if 0) ------+
1353+             //   (local.get 1)   |
1354+             // )         <-------+
1355+             //
1356+             // [0x00] (i32.const 42 reg:0)
1357+             // [0x01] (i32.const 24 reg:1)
1358+             // [0x02] (local.get 0 result=reg:2)
1359+             // [0x03] (br_if_z offset=+0x3 cond=reg:2) --+
1360+             // [0x04] (stack.copy reg:1 -> reg:0)        |
1361+             // [0x05] (br offset=+0x2) --------+         |
1362+             // [0x06] (local.get 1 reg:2) <----|---------+
1363+             // [0x07] ...              <-------+
1364+             let  onBranchNotTaken  =  iseqBuilder. allocLabel ( ) 
1365+             iseqBuilder. emitWithLabel ( Instruction . brIfNot,  onBranchNotTaken)  {  _,  conditionCheckAt,  continuation in 
1366+                 let  relativeOffset  =  continuation. offsetFromHead -  conditionCheckAt. offsetFromHead
1367+                 return  Instruction . BrIfOperand ( condition:  LVReg ( condition) ,  offset:  Int32 ( relativeOffset) ) 
1368+             } 
1369+             try   copyOnBranch ( targetFrame:  frame) 
1370+             try   emitBranch ( Instruction . br,  relativeDepth:  relativeDepth)  {  offset,  copyCount,  popCount in 
1371+                 return  offset
1372+             } 
1373+             try   iseqBuilder. pinLabelHere ( onBranchNotTaken) 
13541374        } 
13551375        try   popPushValues ( frame. copyTypes) 
1356-         try   iseqBuilder. pinLabelHere ( onBranchNotTaken) 
13571376    } 
13581377
13591378    mutating  func  visitBrTable( targets:  WasmParser . BrTable )  throws  ->  Output  { 
@@ -1413,7 +1432,7 @@ struct InstructionTranslator<Context: TranslatorContext>: InstructionVisitor {
14131432            guard  frame. copyTypes. count ==  defaultFrame. copyTypes. count else  { 
14141433                throw  ValidationError ( " Expected the same copy types for all branches in `br_table` but got  \( frame. copyTypes)  and  \( defaultFrame. copyTypes) " ) 
14151434            } 
1416-             try   popPushValues ( frame. copyTypes) 
1435+             try   checkStackTop ( frame. copyTypes) 
14171436
14181437            do  { 
14191438                let  relativeOffset  =  iseqBuilder. insertingPC. offsetFromHead -  brTableAt. offsetFromHead
0 commit comments