support the do while(condition) loop

This commit is contained in:
Volker Berlin 2018-06-02 23:57:04 +02:00
parent 9b3993450e
commit 0c83869a81
3 changed files with 73 additions and 45 deletions

View File

@ -100,14 +100,21 @@ class BranchManger {
*/ */
private void addLoops() { private void addLoops() {
for( ParsedBlock parsedBlock : allParsedOperations ) { for( ParsedBlock parsedBlock : allParsedOperations ) {
if( parsedBlock.op == JavaBlockOperator.GOTO && parsedBlock.startPosition > parsedBlock.endPosition ) { if( parsedBlock.startPosition > parsedBlock.endPosition ) {
int start = parsedBlock.endPosition; switch ( parsedBlock.op ) {
ParsedBlock loop = loops.get( start ); case GOTO: // do while(true) loop; Continue
if( loop == null ) { case IF: // do while(condition) loop
loop = new ParsedBlock( JavaBlockOperator.LOOP, start, 0, parsedBlock.lineNumber ); int start = parsedBlock.endPosition;
loops.put( start, loop ); 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<ParsedBlock> parsedOperations ) { private void caculateIf( BranchNode parent, ParsedBlock startBlock, List<ParsedBlock> parsedOperations ) {
int i = 0; int i = 0;
int endPos = Math.min( startBlock.endPosition, parent.endPos ); 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 int gotoPos = endPos - 3; // 3 - byte size of goto instruction
BranchNode branch = null; BranchNode branch = null;
for( ; i < parsedOperations.size(); i++ ) { for( ; i < parsedOperations.size(); i++ ) {
ParsedBlock parsedBlock = parsedOperations.get( i ); ParsedBlock parsedBlock = parsedOperations.get( i );
if( parsedBlock.startPosition == gotoPos && parsedBlock.op == JavaBlockOperator.GOTO && parsedBlock.startPosition < parsedBlock.endPosition) { if( parsedBlock.startPosition == gotoPos && parsedBlock.op == JavaBlockOperator.GOTO && parsedBlock.startPosition < parsedBlock.endPosition) {
parsedOperations.remove( i ); 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 ); parent.add( branch );
if( i > 0 ) { if( i > 0 ) {
calculate( branch, parsedOperations.subList( 0, i ) ); calculate( branch, parsedOperations.subList( 0, i ) );
@ -177,7 +190,7 @@ class BranchManger {
} }
if( branch == null ) { 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 ); parent.add( branch );
} }

View File

@ -466,7 +466,7 @@ public class ModuleGenerator {
case 165: // if_acmpeq case 165: // if_acmpeq
case 166: // if_acmpne case 166: // if_acmpne
int offset = byteCode.readShort(); int offset = byteCode.readShort();
branchManager.start( JavaBlockOperator.IF, codePosition + 3, offset - 3, lineNumber ); branchManager.start( JavaBlockOperator.IF, codePosition, offset, lineNumber );
break; break;
case 167: // goto case 167: // goto
offset = byteCode.readShort(); offset = byteCode.readShort();
@ -864,40 +864,40 @@ public class ModuleGenerator {
opCompare( ValueType.f64, byteCode ); opCompare( ValueType.f64, byteCode );
break; break;
case 153: // ifeq case 153: // ifeq
opIfCondition( NumericOperator.ne, byteCode ); opIfCondition( NumericOperator.ne, NumericOperator.eq, byteCode );
break; break;
case 154: // ifne case 154: // ifne
opIfCondition( NumericOperator.eq, byteCode ); opIfCondition( NumericOperator.eq, NumericOperator.ne, byteCode );
break; break;
case 155: // iflt case 155: // iflt
opIfCondition( NumericOperator.ge_s, byteCode ); opIfCondition( NumericOperator.ge_s, NumericOperator.lt_s, byteCode );
break; break;
case 156: // ifge case 156: // ifge
opIfCondition( NumericOperator.lt_s, byteCode ); opIfCondition( NumericOperator.lt_s, NumericOperator.ge_s, byteCode );
break; break;
case 157: // ifgt case 157: // ifgt
opIfCondition( NumericOperator.le_s, byteCode ); opIfCondition( NumericOperator.le_s, NumericOperator.gt, byteCode );
break; break;
case 158: // ifle case 158: // ifle
opIfCondition( NumericOperator.gt, byteCode ); opIfCondition( NumericOperator.gt, NumericOperator.le_s, byteCode );
break; break;
case 159: // if_icmpeq case 159: // if_icmpeq
opIfCompareCondition( NumericOperator.ne, byteCode ); opIfCompareCondition( NumericOperator.ne, NumericOperator.eq, byteCode );
break; break;
case 160: // if_icmpne case 160: // if_icmpne
opIfCompareCondition( NumericOperator.eq, byteCode ); opIfCompareCondition( NumericOperator.eq, NumericOperator.ne, byteCode );
break; break;
case 161: // if_icmplt case 161: // if_icmplt
opIfCompareCondition( NumericOperator.ge_s, byteCode ); opIfCompareCondition( NumericOperator.ge_s, NumericOperator.lt_s, byteCode );
break; break;
case 162: // if_icmpge case 162: // if_icmpge
opIfCompareCondition( NumericOperator.lt_s, byteCode ); opIfCompareCondition( NumericOperator.lt_s, NumericOperator.ge_s, byteCode );
break; break;
case 163: // if_icmpgt case 163: // if_icmpgt
opIfCompareCondition( NumericOperator.le_s, byteCode ); opIfCompareCondition( NumericOperator.le_s, NumericOperator.gt, byteCode );
break; break;
case 164: // if_icmple case 164: // if_icmple
opIfCompareCondition( NumericOperator.gt, byteCode ); opIfCompareCondition( NumericOperator.gt, NumericOperator.le_s, byteCode );
break; break;
//TODO case 165: // if_acmpeq //TODO case 165: // if_acmpeq
//TODO case 166: // if_acmpne //TODO case 166: // if_acmpne
@ -1029,37 +1029,40 @@ public class ModuleGenerator {
/** /**
* Handle the if<condition> of the Java byte code. This Java instruction compare the first stack value with value 0. * Handle the if<condition> 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 * 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 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<condition> 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
* The condition for the if block. * The condition for the if block.
* @param continueNumOp
* The condition for the continue of a loop.
* @param byteCode * @param byteCode
* current byte code stream to read the target offset. * current byte code stream to read the target offset.
* @throws IOException * @throws IOException
* if any I/O errors occur. * if any I/O errors occur.
*/ */
private void opIfCompareCondition( NumericOperator numOp, CodeInputStream byteCode ) throws IOException { private void opIfCondition( NumericOperator ifNumOp, NumericOperator continueNumOp, CodeInputStream byteCode ) throws IOException {
byteCode.skip(2); writer.writeConstInt( 0 );
writer.writeNumericOperator( numOp, ValueType.i32 ); opIfCompareCondition( ifNumOp, continueNumOp, byteCode );
}
/**
* Handle the if<condition> 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 );
} }
/** /**

View File

@ -46,6 +46,7 @@ public class ControlFlowOperators extends AbstractBaseTest {
addParam( list, script, "ifCompare" ); addParam( list, script, "ifCompare" );
addParam( list, script, "switchDirect" ); addParam( list, script, "switchDirect" );
addParam( list, script, "endlessLoop" ); addParam( list, script, "endlessLoop" );
addParam( list, script, "doWhileLoop" );
addParam( list, script, "forLoop" ); addParam( list, script, "forLoop" );
} }
return list; return list;
@ -198,6 +199,17 @@ public class ControlFlowOperators extends AbstractBaseTest {
} while( true ); } while( true );
} }
@Export
static double doWhileLoop() {
int a = 0;
double d = 1.01;
do {
d *= 2;
a++;
} while( a < 10 );
return d;
}
@Export @Export
static int forLoop() { static int forLoop() {
int a = 0; int a = 0;