From 9d1c9ee93bb791cc92e858445aeb6e8a8d0fad56 Mon Sep 17 00:00:00 2001 From: Volker Berlin Date: Sun, 19 Jun 2022 16:20:17 +0200 Subject: [PATCH] expand a loop if there is a SWICH structure that point outside the loop. #43 --- .../jwebassembly/module/BranchManager.java | 33 +++++++++++++++---- .../module/JavaMethodWasmCodeBuilder.java | 2 +- .../runtime/ControlFlowOperators.java | 20 +++++++++++ 3 files changed, 48 insertions(+), 7 deletions(-) diff --git a/src/de/inetsoftware/jwebassembly/module/BranchManager.java b/src/de/inetsoftware/jwebassembly/module/BranchManager.java index dd2cb296..34368a3f 100644 --- a/src/de/inetsoftware/jwebassembly/module/BranchManager.java +++ b/src/de/inetsoftware/jwebassembly/module/BranchManager.java @@ -154,8 +154,6 @@ void addIfOperator( int startPosition, int offset, int lineNumber, WasmNumericIn * * @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 @@ void addIfOperator( int startPosition, int offset, int lineNumber, WasmNumericIn * @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 @@ private void addLoops( List parsedOperations ) { 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 @@ private void addLoops( List parsedOperations ) { 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 @@ private static class SwitchParsedBlock extends ParsedBlock { 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 8fb6313f..b4580ffe 100644 --- a/src/de/inetsoftware/jwebassembly/module/JavaMethodWasmCodeBuilder.java +++ b/src/de/inetsoftware/jwebassembly/module/JavaMethodWasmCodeBuilder.java @@ -845,7 +845,7 @@ private void writeSwitchCode( CodeInputStream byteCode, boolean isLookupSwitch ) 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 a6f25119..3a2a434c 100644 --- a/test/de/inetsoftware/jwebassembly/runtime/ControlFlowOperators.java +++ b/test/de/inetsoftware/jwebassembly/runtime/ControlFlowOperators.java @@ -60,6 +60,7 @@ public static Collection data() { 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 @@ static int whileTrueInsideWhileTrue() { 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;