diff --git a/src/de/inetsoftware/jwebassembly/module/BranchManager.java b/src/de/inetsoftware/jwebassembly/module/BranchManager.java index dd2cb29..34368a3 100644 --- a/src/de/inetsoftware/jwebassembly/module/BranchManager.java +++ b/src/de/inetsoftware/jwebassembly/module/BranchManager.java @@ -154,8 +154,6 @@ class BranchManager { * * @param startPosition * the byte position of the start position - * @param offset - * the relative jump position * @param lineNumber * the current line number * @param keys @@ -165,8 +163,8 @@ class BranchManager { * @param defaultPosition * the code position of the default block */ - void addSwitchOperator( int startPosition, int offset, int lineNumber, int[] keys, int[] positions, int defaultPosition ) { - allParsedOperations.add( new SwitchParsedBlock( startPosition, offset, lineNumber, keys, positions, defaultPosition ) ); + void addSwitchOperator( int startPosition, int lineNumber, @Nullable int[] keys, @Nonnull int[] positions, int defaultPosition ) { + allParsedOperations.add( new SwitchParsedBlock( startPosition, lineNumber, keys, positions, defaultPosition ) ); } /** @@ -224,6 +222,7 @@ class BranchManager { if( loop.endPosition < parsedBlock.nextPosition ) { int nextPosition = parsedBlock.startPosition; // Jump position for Continue int endPosition = parsedBlock.nextPosition; + // if a condition behind the loop points to a position inside the loop, the loop must be extended to avoid overlapping blocks. for( int n = b + 1; n < parsedOperations.size(); n++ ) { ParsedBlock block = parsedOperations.get( n ); @@ -232,6 +231,21 @@ class BranchManager { endPosition = block.nextPosition; } } + + // if there is a structure like a SWITCH that overlap the loop then we must be extended the loop to avoid this. + for( int n = b - 1; n >= 0; n-- ) { + ParsedBlock prevBlock = parsedOperations.get( n ); + switch( prevBlock.op ) { + case SWITCH: + if( start < prevBlock.startPosition && prevBlock.endPosition > endPosition ) { + nextPosition = prevBlock.endPosition; + endPosition = nextPosition; + } + break; + default: + } + } + loop.nextPosition = nextPosition; // Jump position for Continue loop.endPosition = endPosition; } @@ -1600,11 +1614,18 @@ class BranchManager { private int defaultPosition; - public SwitchParsedBlock( int startPosition, int offset, int lineNumber, int[] keys, int[] positions, int defaultPosition ) { - super( JavaBlockOperator.SWITCH, startPosition, offset, startPosition, lineNumber ); + public SwitchParsedBlock( int startPosition, int lineNumber, @Nullable int[] keys, @Nonnull int[] positions, int defaultPosition ) { + super( JavaBlockOperator.SWITCH, startPosition, 0, startPosition, lineNumber ); this.keys = keys; this.positions = positions; this.defaultPosition = defaultPosition; + + // calculate the end position of the switch + int end = defaultPosition; + for( int i = positions.length - 1; i >= 0; i-- ) { + end = Math.max( defaultPosition, positions[i] ); + } + this.endPosition = end; } } diff --git a/src/de/inetsoftware/jwebassembly/module/JavaMethodWasmCodeBuilder.java b/src/de/inetsoftware/jwebassembly/module/JavaMethodWasmCodeBuilder.java index 8fb6313..b4580ff 100644 --- a/src/de/inetsoftware/jwebassembly/module/JavaMethodWasmCodeBuilder.java +++ b/src/de/inetsoftware/jwebassembly/module/JavaMethodWasmCodeBuilder.java @@ -845,7 +845,7 @@ class JavaMethodWasmCodeBuilder extends WasmCodeBuilder { addNumericInstruction( NumericOperator.sub, ValueType.i32, codePos, lineNumber ); } } - branchManager.addSwitchOperator( startPosition, 0, lineNumber, keys, positions, defaultPosition ); + branchManager.addSwitchOperator( startPosition, lineNumber, keys, positions, defaultPosition ); } /** diff --git a/test/de/inetsoftware/jwebassembly/runtime/ControlFlowOperators.java b/test/de/inetsoftware/jwebassembly/runtime/ControlFlowOperators.java index a6f2511..3a2a434 100644 --- a/test/de/inetsoftware/jwebassembly/runtime/ControlFlowOperators.java +++ b/test/de/inetsoftware/jwebassembly/runtime/ControlFlowOperators.java @@ -60,6 +60,7 @@ public class ControlFlowOperators extends AbstractBaseTest { addParam( list, script, "whileLoopAfterIfWithReturn" ); addParam( list, script, "whileLoopInsideLoop" ); addParam( list, script, "whileTrueInsideWhileTrue" ); + addParam( list, script, "whileTrueContinueWithSwitch" ); addParam( list, script, "forLoop" ); addParam( list, script, "conditionalOperator" ); addParam( list, script, "conditionalOperator2" ); @@ -510,6 +511,25 @@ public class ControlFlowOperators extends AbstractBaseTest { return sw; } + @Export + static int whileTrueContinueWithSwitch() { + int sw = 1; + LOOP: + while( true ) { + switch(sw) { + case 1: + sw++; + continue LOOP; + case 5: + return sw; + default: + sw++; + } + break; + } + return sw; + } + @Export static int forLoop() { int a = 0;