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. // 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-- ) { for( int n = b - 1; n >= 0; n-- ) {
ParsedBlock prevBlock = parsedOperations.get( n ); ParsedBlock prevBlock = parsedOperations.get( n );
if( prevBlock.op == JavaBlockOperator.IF && prevBlock.startPosition < start && prevBlock.endPosition > start switch( prevBlock.op ) {
&& prevBlock.endPosition < parsedBlock.startPosition ) { case IF:
prevBlock.endPosition = start; 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( 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 ); branch = new BranchNode( startPos - 1, endPos, WasmBlockOperator.IF, WasmBlockOperator.END, ValueType.empty );
parent.add( branch ); 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(); startBlock.negateCompare();
@ -1062,21 +1056,22 @@ class BranchManager {
* @param parsedOperations * @param parsedOperations
* the not consumed operations in the parent branch * 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 jump = gotoBlock.endPosition; // jump position of the GOTO
int start = gotoBlock.startPosition; int start = gotoBlock.startPosition;
if( start > jump ) { if( start > jump ) {
// back jump to a previous position like in loops // back jump to a previous position like in loops
int deep = 0; int deep = 0;
while( parent != null ) { BranchNode node = parent;
if( parent.startOp == WasmBlockOperator.LOOP && parent.startPos == jump ) { 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 // 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 parent.add( new BranchNode( start, start, WasmBlockOperator.BR, null, deep ) ); // continue to the start of the loop
return; return;
} }
parent = parent.parent; node = node.parent;
deep++; deep++;
} } while( node != null );
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 );
} else { } else {
if( gotoBlock.nextPosition == jump ) { if( gotoBlock.nextPosition == jump ) {
@ -1384,6 +1379,12 @@ class BranchManager {
parent = parent.parent; 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 ) { 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 // 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.WasmRule;
import de.inetsoftware.jwebassembly.api.annotation.Export; import de.inetsoftware.jwebassembly.api.annotation.Export;
@SuppressWarnings( { "javadoc", "null", "rawtypes", "cast", "boxing", "unused" } )
public class ControlFlowOperators extends AbstractBaseTest { public class ControlFlowOperators extends AbstractBaseTest {
@ClassRule @ClassRule
@ -55,6 +56,7 @@ public class ControlFlowOperators extends AbstractBaseTest {
addParam( list, script, "whileLoopInElse_13" ); addParam( list, script, "whileLoopInElse_13" );
addParam( list, script, "whileLoopInElseAfterReturn" ); addParam( list, script, "whileLoopInElseAfterReturn" );
addParam( list, script, "whileLoopAfterIfWithReturn" ); addParam( list, script, "whileLoopAfterIfWithReturn" );
addParam( list, script, "whileLoopInsideLoop" );
addParam( list, script, "forLoop" ); addParam( list, script, "forLoop" );
addParam( list, script, "conditionalOperator" ); addParam( list, script, "conditionalOperator" );
addParam( list, script, "conditionalOperator2" ); addParam( list, script, "conditionalOperator2" );
@ -414,6 +416,26 @@ public class ControlFlowOperators extends AbstractBaseTest {
return result; 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 @Export
static int forLoop() { static int forLoop() {
int a = 0; int a = 0;

View File

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