mirror of
https://github.com/i-net-software/JWebAssembly.git
synced 2025-03-25 07:27:52 +01:00
fix loop detection for nested loops
This commit is contained in:
parent
7823db2708
commit
f52c41ae14
@ -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 doesn’t result in an iteration, instead a br 0 instruction causes the loop to repeat
|
// the loop instruction itself doesn’t 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
|
||||||
|
@ -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;
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user