Handle a GOTO instruction that come from a CONTINUE in a loop.

This commit is contained in:
Volker Berlin 2021-11-16 21:28:11 +01:00
parent 296df907b8
commit effd5813c9
2 changed files with 82 additions and 1 deletions

View File

@ -183,6 +183,7 @@ class BranchManger {
loop = new ParsedBlock( JavaBlockOperator.LOOP, start, 0, start, parsedBlock.lineNumber ); loop = new ParsedBlock( JavaBlockOperator.LOOP, start, 0, start, parsedBlock.lineNumber );
loops.put( start, loop ); loops.put( start, loop );
} }
loop.nextPosition = parsedBlock.startPosition; // Jump position for Continue
loop.endPosition = parsedBlock.nextPosition; loop.endPosition = parsedBlock.nextPosition;
break; break;
default: default:
@ -262,7 +263,7 @@ class BranchManger {
for( i = 0; i < instructions.size(); i++ ) { for( i = 0; i < instructions.size(); i++ ) {
WasmInstruction instr = instructions.get( i ); WasmInstruction instr = instructions.get( i );
int codePos = instr.getCodePosition(); int codePos = instr.getCodePosition();
if( codePos == nextPos ) { if( codePos == nextPos && conditionIdx < 0 ) {
conditionIdx = i; conditionIdx = i;
} }
if( codePos >= conditionEnd ) { if( codePos >= conditionEnd ) {
@ -276,6 +277,7 @@ class BranchManger {
} }
gotoBlock.op = JavaBlockOperator.LOOP; gotoBlock.op = JavaBlockOperator.LOOP;
gotoBlock.nextPosition = conditionStart; // Jump position for Continue
gotoBlock.endPosition = conditionEnd; gotoBlock.endPosition = conditionEnd;
instructions.add( i, new WasmBlockInstruction( WasmBlockOperator.BR, 0, conditionNew, gotoBlock.lineNumber ) ); instructions.add( i, new WasmBlockInstruction( WasmBlockOperator.BR, 0, conditionNew, gotoBlock.lineNumber ) );
instructions.add( conditionIdx++, new WasmBlockInstruction( WasmBlockOperator.BR_IF, 1, conditionNew, gotoBlock.lineNumber ) ); instructions.add( conditionIdx++, new WasmBlockInstruction( WasmBlockOperator.BR_IF, 1, conditionNew, gotoBlock.lineNumber ) );
@ -312,6 +314,33 @@ class BranchManger {
} }
} }
/**
* Add a break to the node if the block jump to the continue position of an outer loop.
*
* @param parent
* the container for adding the break
* @param startBlock
* an IF or GOTO block.
* @return true, if the break was added
*/
private boolean addBreakIfLoopContinue( BranchNode parent, ParsedBlock startBlock ) {
BranchNode main = parent;
int endPos = startBlock.endPosition;
int breakDeep = 0;
while( main != null ) {
if( main.startOp == WasmBlockOperator.LOOP && main.continuePos == endPos ) {
// possible operation values here are IF and GOTO
WasmBlockOperator op = startBlock.op == JavaBlockOperator.IF ? WasmBlockOperator.BR_IF : WasmBlockOperator.BR;
int startPos = startBlock.nextPosition;
parent.add( new BranchNode( startPos, startPos, op, null, breakDeep ) );
return true;
}
main = main.parent;
breakDeep++;
}
return false;
}
/** /**
* Calculate the ELSE and END position of an IF control structure. * Calculate the ELSE and END position of an IF control structure.
* *
@ -326,6 +355,10 @@ class BranchManger {
instructions.remove( startBlock.jump ); instructions.remove( startBlock.jump );
IfPositions positions = searchElsePosition( startBlock, parsedOperations ); IfPositions positions = searchElsePosition( startBlock, parsedOperations );
if( addBreakIfLoopContinue( parent, startBlock ) ) {
return;
}
BranchNode main = parent; BranchNode main = parent;
for( int i = 0; i < positions.ifCount; i++ ) { for( int i = 0; i < positions.ifCount; i++ ) {
IfParsedBlock parsedBlock = (IfParsedBlock)parsedOperations.remove( 0 ); IfParsedBlock parsedBlock = (IfParsedBlock)parsedOperations.remove( 0 );
@ -389,6 +422,11 @@ class BranchManger {
i = 0; i = 0;
} }
if( addBreakIfLoopContinue( branch, parsedBlock ) ) {
branch.endOp = WasmBlockOperator.END;
endPos = branch.endPos;
break;
}
// if with block type signature must have an else block // if with block type signature must have an else block
int breakDeep = calculateBreakDeep( parent, endPos ); int breakDeep = calculateBreakDeep( parent, endPos );
if( breakDeep > 0 ) { if( breakDeep > 0 ) {
@ -863,6 +901,29 @@ class BranchManger {
blockInstr.setData( data + 1 ); blockInstr.setData( data + 1 );
} }
} }
patchBrDeepInTree( newNode, 0 );
}
/**
* Patch the existing BR instructions in the tree after a new BLOCK node was injected in the hierarchy. The break position must
* only increment if the old break position is outside of the new BLOCK.
*
* @param newNode
* the new node
* @param deep
* the deep of recursion
*/
private void patchBrDeepInTree( BranchNode newNode, int deep ) {
for( BranchNode node : newNode ) {
if( node.startOp == WasmBlockOperator.BR || node.startOp == WasmBlockOperator.BR_IF ) {
Integer data = (Integer)node.data;
if( data >= deep ) {
node.data = data + 1;
}
} else {
patchBrDeepInTree( node, deep + 1 );
}
}
} }
/** /**
@ -906,6 +967,7 @@ class BranchManger {
return; return;
} }
} }
//breakOperations.add( new BreakBlock( parent, jump ) );
throw new WasmException( "GOTO code without target loop/block. Jump from " + start + " to " + jump, gotoBlock.lineNumber ); throw new WasmException( "GOTO code without target loop/block. Jump from " + start + " to " + jump, gotoBlock.lineNumber );
} }
@ -922,6 +984,7 @@ class BranchManger {
BranchNode blockNode = new BranchNode( loopBlock.startPosition, loopBlock.endPosition, WasmBlockOperator.BLOCK, WasmBlockOperator.END ); BranchNode blockNode = new BranchNode( loopBlock.startPosition, loopBlock.endPosition, WasmBlockOperator.BLOCK, WasmBlockOperator.END );
parent.add( blockNode ); parent.add( blockNode );
BranchNode loopNode = new BranchNode( loopBlock.startPosition, loopBlock.endPosition, WasmBlockOperator.LOOP, WasmBlockOperator.END ); BranchNode loopNode = new BranchNode( loopBlock.startPosition, loopBlock.endPosition, WasmBlockOperator.LOOP, WasmBlockOperator.END );
loopNode.continuePos = loopBlock.nextPosition;
blockNode.add( loopNode ); blockNode.add( loopNode );
int idx = 0; int idx = 0;
@ -1415,6 +1478,9 @@ class BranchManger {
private int elseEndPos; private int elseEndPos;
/** jump position for a CONTINUE in a loop */
private int continuePos;
/** /**
* Create a new description. * Create a new description.
* *

View File

@ -50,6 +50,7 @@ public class ControlFlowOperators extends AbstractBaseTest {
addParam( list, script, "doWhileLoopTwoConditions" ); addParam( list, script, "doWhileLoopTwoConditions" );
addParam( list, script, "doWhileLoopWithBreak" ); addParam( list, script, "doWhileLoopWithBreak" );
addParam( list, script, "whileLoop" ); addParam( list, script, "whileLoop" );
addParam( list, script, "whileLoopWithContinue" );
addParam( list, script, "forLoop" ); addParam( list, script, "forLoop" );
addParam( list, script, "conditionalOperator" ); addParam( list, script, "conditionalOperator" );
addParam( list, script, "conditionalOperator2" ); addParam( list, script, "conditionalOperator2" );
@ -334,6 +335,20 @@ public class ControlFlowOperators extends AbstractBaseTest {
return b; return b;
} }
@Export
public static int whileLoopWithContinue() {
int i = 0;
int value = 0;
while( i < 16 ) {
i++;
if( i > 8 ) {
continue;
}
value |= 1 << i;
}
return value;
}
@Export @Export
static int forLoop() { static int forLoop() {
int a = 0; int a = 0;