fix loop detection for nested loops

This commit is contained in:
Volker Berlin 2022-03-13 14:16:31 +01:00
parent 7823db2708
commit f52c41ae14
3 changed files with 96 additions and 74 deletions

View File

@ -203,9 +203,18 @@ class BranchManager {
// if a condition form outside of the loop point inside the loop then it must be conditional return and a jump to the loop condition.
for( int n = b - 1; n >= 0; n-- ) {
ParsedBlock prevBlock = parsedOperations.get( n );
if( prevBlock.op == JavaBlockOperator.IF && prevBlock.startPosition < start && prevBlock.endPosition > start
&& prevBlock.endPosition < parsedBlock.startPosition ) {
prevBlock.endPosition = start;
switch( prevBlock.op ) {
case IF:
if( prevBlock.startPosition < start && prevBlock.endPosition > start && prevBlock.endPosition < parsedBlock.startPosition ) {
prevBlock.endPosition = start;
}
break;
case LOOP:
if( start == prevBlock.nextPosition ) {
loop.startPosition = prevBlock.startPosition;
}
break;
default:
}
}
}
@ -543,31 +552,16 @@ class BranchManager {
}
if( branch == null ) {
if( startBlock.endPosition > parent.endPos ) {
// we jump outside the parent. This is like a conditional break.
//TODO should be BR_IF
branch = new BranchNode( startPos - 1, startPos, WasmBlockOperator.IF, WasmBlockOperator.END, ValueType.empty );
parent.add( branch );
breakOperations.add( new BreakBlock( branch, startPos, startBlock.endPosition ) );
return;
}
branch = new BranchNode( startPos - 1, 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 like a conditional break
//TODO should be BR_IF
breakOperations.add( new BreakBlock( branch, endPos, startBlock.endPosition ) );
return;
}
}
}
startBlock.negateCompare();
@ -1062,21 +1056,22 @@ class BranchManager {
* @param parsedOperations
* the not consumed operations in the parent branch
*/
private void calculateGoto ( BranchNode parent, ParsedBlock gotoBlock, List<ParsedBlock> parsedOperations ) {
private void calculateGoto ( @Nonnull BranchNode parent, @Nonnull ParsedBlock gotoBlock, List<ParsedBlock> parsedOperations ) {
int jump = gotoBlock.endPosition; // jump position of the GOTO
int start = gotoBlock.startPosition;
if( start > jump ) {
// back jump to a previous position like in loops
int deep = 0;
while( parent != null ) {
if( parent.startOp == WasmBlockOperator.LOOP && parent.startPos == jump ) {
BranchNode node = parent;
do {
if( node.startOp == WasmBlockOperator.LOOP && node.startPos == jump ) {
// the loop instruction itself doesnt result in an iteration, instead a br 0 instruction causes the loop to repeat
parent.add( new BranchNode( start, start, WasmBlockOperator.BR, null, deep ) ); // continue to the start of the loop
return;
}
parent = parent.parent;
node = node.parent;
deep++;
}
} while( node != null );
throw new WasmException( "GOTO code without target loop/block. Jump from " + start + " to " + jump, gotoBlock.lineNumber );
} else {
if( gotoBlock.nextPosition == jump ) {
@ -1384,6 +1379,12 @@ class BranchManager {
parent = parent.parent;
}
if( parent != null && parent.startOp == WasmBlockOperator.LOOP ) {
// a break in a LOOP is only a continue, we need to break to the outer block
deep++;
parent = parent.parent;
}
if( parent != null && parent.elseEndPos > gotoEndPos ) {
// check if we break into an ELSE block which is possible in Java with a GOTO, occur with concatenated conditional operators

View File

@ -25,6 +25,7 @@ import de.inetsoftware.jwebassembly.ScriptEngine;
import de.inetsoftware.jwebassembly.WasmRule;
import de.inetsoftware.jwebassembly.api.annotation.Export;
@SuppressWarnings( { "javadoc", "null", "rawtypes", "cast", "boxing", "unused" } )
public class ControlFlowOperators extends AbstractBaseTest {
@ClassRule
@ -55,6 +56,7 @@ public class ControlFlowOperators extends AbstractBaseTest {
addParam( list, script, "whileLoopInElse_13" );
addParam( list, script, "whileLoopInElseAfterReturn" );
addParam( list, script, "whileLoopAfterIfWithReturn" );
addParam( list, script, "whileLoopInsideLoop" );
addParam( list, script, "forLoop" );
addParam( list, script, "conditionalOperator" );
addParam( list, script, "conditionalOperator2" );
@ -414,6 +416,26 @@ public class ControlFlowOperators extends AbstractBaseTest {
return result;
}
@Export
public static int whileLoopInsideLoop() {
int i = 15;
MAIN: while( true ) {
while( i >= 9 ) {
i--;
}
int start = i;
while( i > start ) {
if( true ) {
i--;
continue MAIN;
}
}
return start;
}
}
@Export
static int forLoop() {
int a = 0;

View File

@ -29,10 +29,10 @@ import org.junit.runners.Parameterized.Parameters;
import de.inetsoftware.jwebassembly.ScriptEngine;
import de.inetsoftware.jwebassembly.WasmRule;
import de.inetsoftware.jwebassembly.api.annotation.Export;
import de.inetsoftware.jwebassembly.runtime.StructsGC.Abc2;
import de.inetsoftware.jwebassembly.web.DOMString;
import de.inetsoftware.jwebassembly.web.JSObject;
@SuppressWarnings( { "javadoc", "null", "rawtypes", "cast", "boxing" } )
public class StructsNonGC extends AbstractBaseTest {
@ClassRule
@ -76,12 +76,11 @@ public class StructsNonGC extends AbstractBaseTest {
addParam( list, script, "lambda1" );
addParam( list, script, "lambda2" );
addParam( list, script, "lambda3" );
// TODO too many classes are loaded that are currently not yet compilable
// addParam( list, script, "simpleName_Object" );
// addParam( list, script, "simpleName_Anonymous" );
// addParam( list, script, "simpleName_Array" );
// addParam( list, script, "simpleName_InnerClass" );
// addParam( list, script, "simpleName_LocalClass" );
addParam( list, script, "simpleName_Object" );
addParam( list, script, "simpleName_Anonymous" );
addParam( list, script, "simpleName_Array" );
addParam( list, script, "simpleName_InnerClass" );
addParam( list, script, "simpleName_LocalClass" );
addParam( list, script, "isPrimitive_int" );
addParam( list, script, "isPrimitive_Object" );
}
@ -251,42 +250,41 @@ public class StructsNonGC extends AbstractBaseTest {
return JSObject.domString( clazz.getName() );
}
// TODO too many classes are loaded that are currently not yet compilable
// @Export
// static DOMString simpleName_Object() {
// Object obj = new Object();
// Class clazz = obj.getClass();
// return JSObject.domString( clazz.getSimpleName() );
// }
//
// @Export
// static DOMString simpleName_Anonymous() {
// Object obj = new Object() {};
// Class clazz = obj.getClass();
// return JSObject.domString( clazz.getSimpleName() );
// }
//
// @Export
// static DOMString simpleName_Array() {
// Object obj = new Object[0];
// Class clazz = obj.getClass();
// return JSObject.domString( clazz.getSimpleName() );
// }
//
// @Export
// static DOMString simpleName_InnerClass() {
// Class clazz = TestClass.class;
// return JSObject.domString( clazz.getSimpleName() );
// }
//
// @Export
// static DOMString simpleName_LocalClass() {
// class Foobar {}
// Object obj = new Foobar();
// Class clazz = obj.getClass();
// return JSObject.domString( clazz.getSimpleName() );
// }
//
@Export
static DOMString simpleName_Object() {
Object obj = new Object();
Class clazz = obj.getClass();
return JSObject.domString( clazz.getSimpleName() );
}
@Export
static DOMString simpleName_Anonymous() {
Object obj = new Object() {};
Class clazz = obj.getClass();
return JSObject.domString( clazz.getSimpleName() );
}
@Export
static DOMString simpleName_Array() {
Object obj = new Object[0];
Class clazz = obj.getClass();
return JSObject.domString( clazz.getSimpleName() );
}
@Export
static DOMString simpleName_InnerClass() {
Class clazz = TestClass.class;
return JSObject.domString( clazz.getSimpleName() );
}
@Export
static DOMString simpleName_LocalClass() {
class Foobar {}
Object obj = new Foobar();
Class clazz = obj.getClass();
return JSObject.domString( clazz.getSimpleName() );
}
@Export
static boolean getComponentType() {
Class<?> clazz = byte.class;
@ -385,6 +383,7 @@ public class StructsNonGC extends AbstractBaseTest {
static class Abc2 extends Abc {
Abc2 abc;
@Override
void bar() {
a = 3;
}