Handle Conditional operator inside an if expression

This commit is contained in:
Volker Berlin 2021-10-24 15:29:12 +02:00
parent fec40f1d40
commit 87be1faafe
2 changed files with 128 additions and 4 deletions

View File

@ -62,6 +62,9 @@ class BranchManger {
private TryCatchFinally[] exceptionTable;
private final ArrayList<BreakBlock> breakOperations = new ArrayList<>();
/**
* Create a branch manager.
*
@ -88,7 +91,7 @@ class BranchManger {
allParsedOperations.clear();
root.clear();
loops.clear();
root.endPos = code.getCodeSize();
root.endPos = root.elseEndPos = code.getCodeSize();
exceptionTable = code.getExceptionTable();
for( TryCatchFinally ex : exceptionTable ) {
if ( ex.getStart() == ex.getHandler() ) {
@ -161,6 +164,9 @@ class BranchManger {
List<ParsedBlock> parsedOperations = allParsedOperations;
Collections.sort( parsedOperations );
calculate( root, parsedOperations );
for( BreakBlock breakBlock : breakOperations ) {
calculateBreak( breakBlock );
}
}
/**
@ -393,6 +399,7 @@ class BranchManger {
branch.add( new BranchNode( positions.elsePos, endPos, WasmBlockOperator.BR, null, breakDeep + 1 ) );
endPos = branch.endPos;
} else {
branch.elseEndPos = endPos;
branch = new BranchNode( positions.elsePos, endPos, WasmBlockOperator.ELSE, WasmBlockOperator.END );
parent.add( branch );
}
@ -406,6 +413,29 @@ class BranchManger {
if( branch == null ) {
branch = new BranchNode( startPos, endPos, WasmBlockOperator.IF, WasmBlockOperator.END, ValueType.empty );
parent.add( branch );
if( startBlock.endPosition > parent.endPos ) {
int count = 0;
for( int j = 0; j < instructions.size(); j++ ) {
WasmInstruction instr = instructions.get( j );
int pos = instr.getCodePosition();
if( pos < startPos ) {
continue;
}
if( pos >= endPos ) {
break;
}
if( instr.getType() == Type.Jump ) {
continue;
}
count++;
}
if( count == 0 ) {
// we jump outside the parent and there are no instructions. This is lie a conditional break
//TODO should be BR_IF
breakOperations.add( new BreakBlock( branch, startBlock.endPosition ) );
return;
}
}
}
startBlock.negateCompare();
@ -585,7 +615,7 @@ class BranchManger {
private int calculateBreakDeep( BranchNode parent, int endPos ) {
int deep = -1;
boolean wasLoop = false;
while( parent != null && parent.endPos == endPos && parent.data == null ) {
while( parent != null && parent.elseEndPos <= endPos && parent.data == null ) {
deep++;
wasLoop |= parent.startOp == WasmBlockOperator.LOOP; // only in a loop we need to jump for exit
parent = parent.parent;
@ -1160,6 +1190,43 @@ class BranchManger {
return null;
}
/**
* Add the break to the block hierarchy. Add an extra block if needed and correct the break deep of other
* instructions.
*
* @param breakBlock
* the description of the break.
*/
private void calculateBreak( BreakBlock breakBlock ) {
int deep = -1;
int gotoEndPos = breakBlock.endPosition;
BranchNode branch = breakBlock.branch;
BranchNode parent = branch;
while( parent != null && parent.elseEndPos < gotoEndPos ) {
deep++;
parent = parent.parent;
}
if( parent != null && parent.elseEndPos > gotoEndPos ) {
BranchNode middleNode = new BranchNode( parent.startPos, gotoEndPos, WasmBlockOperator.BLOCK, WasmBlockOperator.END );
for( Iterator<BranchNode> it = parent.iterator(); it.hasNext(); ) {
BranchNode child = it.next();
if( child.endPos > gotoEndPos ) {
continue;
}
middleNode.add( child );
it.remove();
}
parent.add( middleNode );
//deep++;
parent = middleNode;
patchBrDeep( middleNode );
}
BranchNode breakNode = new BranchNode( branch.endPos, branch.endPos, WasmBlockOperator.BR, null, deep + 1 );
branch.add( breakNode );
}
/**
* Check on every instruction position if there any branch is ending
*
@ -1349,6 +1416,8 @@ class BranchManger {
*/
private int startIdx;
private int elseEndPos;
/**
* Create a new description.
*
@ -1381,7 +1450,7 @@ class BranchManger {
*/
BranchNode( int startPos, int endPos, WasmBlockOperator startOp, WasmBlockOperator endOp, Object data ) {
this.startPos = startPos;
this.endPos = endPos;
this.endPos = this.elseEndPos = endPos;
this.startOp = startOp;
this.endOp = endOp;
this.data = data;
@ -1539,4 +1608,27 @@ class BranchManger {
/** The position of the first instruction in the ELSE part. */
private int elsePos;
}
/**
* Described a break to a block that will be added later.
*/
private static class BreakBlock {
private final int endPosition;
private final BranchNode branch;
/**
* Create Break
*
* @param branch
* the parent block which should contain the break
* @param endPosition
* the Jump position
*/
public BreakBlock( BranchNode branch, int endPosition ) {
this.endPosition = endPosition;
this.branch = branch;
}
}
}

View File

@ -74,6 +74,10 @@ public class ControlFlowOperators extends AbstractBaseTest {
addParam( list, script, "ifOrWithMulti" );
addParam( list, script, "ifMultipleInsideThen" );
addParam( list, script, "ifWithConditionalInsideThen" );
addParam( list, script, "conditionalInsideIf_1" );
addParam( list, script, "conditionalInsideIf_2" );
addParam( list, script, "conditionalInsideIf_3" );
addParam( list, script, "conditionalInsideIf_4" );
addParam( list, script, "stringSwitchNormalFoo" );
addParam( list, script, "stringSwitchNormalBar" );
addParam( list, script, "stringSwitchNormalDefault" );
@ -547,7 +551,7 @@ public class ControlFlowOperators extends AbstractBaseTest {
}
@Export
static int ifWithConditionalInsideThen() throws CloneNotSupportedException {
static int ifWithConditionalInsideThen() {
int val = 42;
int result = 0;
if( val > 20 ) {
@ -560,6 +564,34 @@ public class ControlFlowOperators extends AbstractBaseTest {
return result + 13;
}
@Export
static int conditionalInsideIf_1() {
return conditionalInsideIf( null, null, null );
}
@Export
static int conditionalInsideIf_2() {
return conditionalInsideIf( null, null, "foo" );
}
@Export
static int conditionalInsideIf_3() {
return conditionalInsideIf( "foo", null, null );
}
@Export
static int conditionalInsideIf_4() {
return conditionalInsideIf( null, "foo", null );
}
static int conditionalInsideIf( Object a, Object b, Object c ) {
if( (a == null ? b == null : a == b ) ) {
return c == null ? 1 : 2;
} else {
return 3;
}
}
@Export
static int stringSwitchNormalFoo() {
return stringSwitchNormal( "foo" );