diff --git a/src/de/inetsoftware/jwebassembly/module/BranchManger.java b/src/de/inetsoftware/jwebassembly/module/BranchManger.java index a0c1b22..62d5441 100644 --- a/src/de/inetsoftware/jwebassembly/module/BranchManger.java +++ b/src/de/inetsoftware/jwebassembly/module/BranchManger.java @@ -100,14 +100,21 @@ class BranchManger { */ private void addLoops() { for( ParsedBlock parsedBlock : allParsedOperations ) { - if( parsedBlock.op == JavaBlockOperator.GOTO && parsedBlock.startPosition > parsedBlock.endPosition ) { - int start = parsedBlock.endPosition; - ParsedBlock loop = loops.get( start ); - if( loop == null ) { - loop = new ParsedBlock( JavaBlockOperator.LOOP, start, 0, parsedBlock.lineNumber ); - loops.put( start, loop ); + if( parsedBlock.startPosition > parsedBlock.endPosition ) { + switch ( parsedBlock.op ) { + case GOTO: // do while(true) loop; Continue + case IF: // do while(condition) loop + int start = parsedBlock.endPosition; + ParsedBlock loop = loops.get( start ); + if( loop == null ) { + loop = new ParsedBlock( JavaBlockOperator.LOOP, start, 0, parsedBlock.lineNumber ); + loops.put( start, loop ); + } + loop.endPosition = parsedBlock.startPosition + 3; + break; + default: + throw new WasmException( "Unimplemented loop code operation: " + parsedBlock.op, null, parsedBlock.lineNumber ); } - loop.endPosition = parsedBlock.startPosition + 3; } } @@ -155,13 +162,19 @@ class BranchManger { private void caculateIf( BranchNode parent, ParsedBlock startBlock, List parsedOperations ) { int i = 0; int endPos = Math.min( startBlock.endPosition, parent.endPos ); + int startPos = startBlock.startPosition + 3; + if( startPos > endPos ) { + // the condition in a do while(condition) loop + parent.add( new BranchNode( startPos, startPos, WasmBlockOperator.BR_IF, null, 0 ) ); + return; + } int gotoPos = endPos - 3; // 3 - byte size of goto instruction BranchNode branch = null; for( ; i < parsedOperations.size(); i++ ) { ParsedBlock parsedBlock = parsedOperations.get( i ); if( parsedBlock.startPosition == gotoPos && parsedBlock.op == JavaBlockOperator.GOTO && parsedBlock.startPosition < parsedBlock.endPosition) { parsedOperations.remove( i ); - branch = new BranchNode( startBlock.startPosition, startBlock.endPosition, WasmBlockOperator.IF, null ); + branch = new BranchNode( startPos, startBlock.endPosition, WasmBlockOperator.IF, null ); parent.add( branch ); if( i > 0 ) { calculate( branch, parsedOperations.subList( 0, i ) ); @@ -177,7 +190,7 @@ class BranchManger { } if( branch == null ) { - branch = new BranchNode( startBlock.startPosition, endPos, WasmBlockOperator.IF, WasmBlockOperator.END ); + branch = new BranchNode( startPos, endPos, WasmBlockOperator.IF, WasmBlockOperator.END ); parent.add( branch ); } diff --git a/src/de/inetsoftware/jwebassembly/module/ModuleGenerator.java b/src/de/inetsoftware/jwebassembly/module/ModuleGenerator.java index d7172d9..3a9b1b6 100644 --- a/src/de/inetsoftware/jwebassembly/module/ModuleGenerator.java +++ b/src/de/inetsoftware/jwebassembly/module/ModuleGenerator.java @@ -466,7 +466,7 @@ public class ModuleGenerator { case 165: // if_acmpeq case 166: // if_acmpne int offset = byteCode.readShort(); - branchManager.start( JavaBlockOperator.IF, codePosition + 3, offset - 3, lineNumber ); + branchManager.start( JavaBlockOperator.IF, codePosition, offset, lineNumber ); break; case 167: // goto offset = byteCode.readShort(); @@ -864,40 +864,40 @@ public class ModuleGenerator { opCompare( ValueType.f64, byteCode ); break; case 153: // ifeq - opIfCondition( NumericOperator.ne, byteCode ); + opIfCondition( NumericOperator.ne, NumericOperator.eq, byteCode ); break; case 154: // ifne - opIfCondition( NumericOperator.eq, byteCode ); + opIfCondition( NumericOperator.eq, NumericOperator.ne, byteCode ); break; case 155: // iflt - opIfCondition( NumericOperator.ge_s, byteCode ); + opIfCondition( NumericOperator.ge_s, NumericOperator.lt_s, byteCode ); break; case 156: // ifge - opIfCondition( NumericOperator.lt_s, byteCode ); + opIfCondition( NumericOperator.lt_s, NumericOperator.ge_s, byteCode ); break; case 157: // ifgt - opIfCondition( NumericOperator.le_s, byteCode ); + opIfCondition( NumericOperator.le_s, NumericOperator.gt, byteCode ); break; case 158: // ifle - opIfCondition( NumericOperator.gt, byteCode ); + opIfCondition( NumericOperator.gt, NumericOperator.le_s, byteCode ); break; case 159: // if_icmpeq - opIfCompareCondition( NumericOperator.ne, byteCode ); + opIfCompareCondition( NumericOperator.ne, NumericOperator.eq, byteCode ); break; case 160: // if_icmpne - opIfCompareCondition( NumericOperator.eq, byteCode ); + opIfCompareCondition( NumericOperator.eq, NumericOperator.ne, byteCode ); break; case 161: // if_icmplt - opIfCompareCondition( NumericOperator.ge_s, byteCode ); + opIfCompareCondition( NumericOperator.ge_s, NumericOperator.lt_s, byteCode ); break; case 162: // if_icmpge - opIfCompareCondition( NumericOperator.lt_s, byteCode ); + opIfCompareCondition( NumericOperator.lt_s, NumericOperator.ge_s, byteCode ); break; case 163: // if_icmpgt - opIfCompareCondition( NumericOperator.le_s, byteCode ); + opIfCompareCondition( NumericOperator.le_s, NumericOperator.gt, byteCode ); break; case 164: // if_icmple - opIfCompareCondition( NumericOperator.gt, byteCode ); + opIfCompareCondition( NumericOperator.gt, NumericOperator.le_s, byteCode ); break; //TODO case 165: // if_acmpeq //TODO case 166: // if_acmpne @@ -1029,37 +1029,40 @@ public class ModuleGenerator { /** * Handle the if of the Java byte code. This Java instruction compare the first stack value with value 0. - * Important: In Java the condition for the jump to the else block is saved. In WebAssembler we need to use + * Important: In the Java IF expression the condition for the jump to the else block is saved. In WebAssembler we need to use * condition for the if block. The caller of the method must already negate this * - * @param numOp - * The condition for the if block. - * @param byteCode - * current byte code stream to read the taget offset. - * @throws IOException - * if any I/O errors occur. - */ - private void opIfCondition( NumericOperator numOp, CodeInputStream byteCode ) throws IOException { - byteCode.skip(2); - writer.writeConstInt( 0 ); - writer.writeNumericOperator( numOp, ValueType.i32 ); - } - - /** - * Handle the if of the Java byte code. This Java instruction compare the first stack value with value 0. - * Important: In Java the condition for the jump to the else block is saved. In WebAssembler we need to use - * condition for the if block. The caller of the method must already negate this - * - * @param numOp + * @param ifNumOp * The condition for the if block. + * @param continueNumOp + * The condition for the continue of a loop. * @param byteCode * current byte code stream to read the target offset. * @throws IOException * if any I/O errors occur. */ - private void opIfCompareCondition( NumericOperator numOp, CodeInputStream byteCode ) throws IOException { - byteCode.skip(2); - writer.writeNumericOperator( numOp, ValueType.i32 ); + private void opIfCondition( NumericOperator ifNumOp, NumericOperator continueNumOp, CodeInputStream byteCode ) throws IOException { + writer.writeConstInt( 0 ); + opIfCompareCondition( ifNumOp, continueNumOp, byteCode ); + } + + /** + * Handle the if of the Java byte code. This Java instruction compare 2 values from stack. + * Important: In the Java IF expression the condition for the jump to the else block is saved. In WebAssembler we need to use + * condition for the if block. The caller of the method must already negate this. + * + * @param ifNumOp + * The condition for the if block. + * @param continueNumOp + * The condition for the continue of a loop. + * @param byteCode + * current byte code stream to read the target offset. + * @throws IOException + * if any I/O errors occur. + */ + private void opIfCompareCondition( NumericOperator ifNumOp, NumericOperator continueNumOp, CodeInputStream byteCode ) throws IOException { + int offset = byteCode.readShort(); + writer.writeNumericOperator( offset > 0 ? ifNumOp : continueNumOp, ValueType.i32 ); } /** diff --git a/test/de/inetsoftware/jwebassembly/runtime/ControlFlowOperators.java b/test/de/inetsoftware/jwebassembly/runtime/ControlFlowOperators.java index a7321b1..1e3fe1c 100644 --- a/test/de/inetsoftware/jwebassembly/runtime/ControlFlowOperators.java +++ b/test/de/inetsoftware/jwebassembly/runtime/ControlFlowOperators.java @@ -46,6 +46,7 @@ public class ControlFlowOperators extends AbstractBaseTest { addParam( list, script, "ifCompare" ); addParam( list, script, "switchDirect" ); addParam( list, script, "endlessLoop" ); + addParam( list, script, "doWhileLoop" ); addParam( list, script, "forLoop" ); } return list; @@ -198,6 +199,17 @@ public class ControlFlowOperators extends AbstractBaseTest { } while( true ); } + @Export + static double doWhileLoop() { + int a = 0; + double d = 1.01; + do { + d *= 2; + a++; + } while( a < 10 ); + return d; + } + @Export static int forLoop() { int a = 0;