From 9f0f82bb06ebdb67a82568c795f5c397b5b254fa Mon Sep 17 00:00:00 2001 From: Volker Berlin Date: Sat, 19 Feb 2022 22:15:56 +0100 Subject: [PATCH] Use also RETURN in the BranchManager to calculate the IF THEN ELSE blocks. --- .../jwebassembly/module/BranchManager.java | 100 ++++++++++++------ .../module/JavaBlockOperator.java | 3 +- .../module/JavaMethodWasmCodeBuilder.java | 3 +- .../runtime/ControlFlowOperators.java | 49 +++++++++ 4 files changed, 123 insertions(+), 32 deletions(-) diff --git a/src/de/inetsoftware/jwebassembly/module/BranchManager.java b/src/de/inetsoftware/jwebassembly/module/BranchManager.java index 8441b2d..45d9c34 100644 --- a/src/de/inetsoftware/jwebassembly/module/BranchManager.java +++ b/src/de/inetsoftware/jwebassembly/module/BranchManager.java @@ -100,7 +100,7 @@ class BranchManager { } /** - * Add a new Java block operator to handle from this manager. + * Add a new GOTO operator to handle from this manager. * * @param startPosition * the byte position of the start position @@ -115,6 +115,20 @@ class BranchManager { allParsedOperations.add( new ParsedBlock( JavaBlockOperator.GOTO, startPosition, offset, nextPosition, lineNumber ) ); } + /** + * Add a new RETURN to help analyze structures. + * + * @param startPosition + * the byte position of the start position + * @param nextPosition + * the position of the next instruction + * @param lineNumber + * the current line number + */ + void addReturnOperator( int startPosition, int nextPosition, int lineNumber ) { + allParsedOperations.add( new ParsedBlock( JavaBlockOperator.RETURN, startPosition, 0, nextPosition, lineNumber ) ); + } + /** * Add a new IF operator. * @@ -375,6 +389,9 @@ class BranchManager { case TRY: calculateTry( parent, (TryCatchParsedBlock)parsedBlock, parsedOperations ); break; + case RETURN: + // noting, only use as alternative GOTO + break; default: throw new WasmException( "Unimplemented block code operation: " + parsedBlock.op, parsedBlock.lineNumber ); } @@ -462,35 +479,50 @@ class BranchManager { BranchNode branch = null; for( ; i < parsedOperations.size(); i++ ) { ParsedBlock parsedBlock = parsedOperations.get( i ); - if( parsedBlock.nextPosition == positions.elsePos && parsedBlock.op == JavaBlockOperator.GOTO && parsedBlock.startPosition < parsedBlock.endPosition ) { - parsedOperations.remove( i ); - // end position can not be outside of the parent - endPos = Math.min( parsedBlock.endPosition, parent.endPos ); - - branch = new BranchNode( startPos, positions.elsePos, WasmBlockOperator.IF, null ); - parent.add( branch ); - if( i > 0 ) { - calculate( branch, parsedOperations.subList( 0, i ) ); - i = 0; + if( parsedBlock.nextPosition == positions.elsePos ) { + boolean endPosFound = false; + if( parsedBlock.op == JavaBlockOperator.GOTO && parsedBlock.startPosition < parsedBlock.endPosition ) { + parsedOperations.remove( i ); + endPos = parsedBlock.endPosition; + endPosFound = true; + } else if( parsedBlock.op == JavaBlockOperator.RETURN ) { + for( int k = 0; k < i; k++ ) { + ParsedBlock block = parsedOperations.get( k ); + if( block.op == JavaBlockOperator.IF ) { + endPos = Math.max( endPos, block.endPosition ); + } + } + endPosFound = true; } + if( endPosFound ) { + // end position can not be outside of the parent + endPos = Math.min( endPos, parent.endPos ); - if( addBreakIfLoopContinue( branch, parsedBlock ) ) { - branch.endOp = WasmBlockOperator.END; - endPos = branch.endPos; + branch = new BranchNode( startPos, positions.elsePos, WasmBlockOperator.IF, null ); + parent.add( branch ); + if( i > 0 ) { + calculate( branch, parsedOperations.subList( 0, i ) ); + i = 0; + } + + if( addBreakIfLoopContinue( branch, parsedBlock ) ) { + branch.endOp = WasmBlockOperator.END; + endPos = branch.endPos; + break; + } + // if with block type signature must have an else block + int breakDeep = calculateBreakDeep( parent, endPos ); + if( breakDeep > 0 ) { + branch.endOp = WasmBlockOperator.END; + branch.add( new BranchNode( positions.elsePos, endPos, WasmBlockOperator.BR, null, breakDeep + 1 ) ); + endPos = branch.endPos; + } else { + branch.elseEndPos = endPos; + branch = new BranchNode( positions.elsePos, endPos, WasmBlockOperator.ELSE, WasmBlockOperator.END ); + parent.add( branch ); + } break; } - // if with block type signature must have an else block - int breakDeep = calculateBreakDeep( parent, endPos ); - if( breakDeep > 0 ) { - branch.endOp = WasmBlockOperator.END; - branch.add( new BranchNode( positions.elsePos, endPos, WasmBlockOperator.BR, null, breakDeep + 1 ) ); - endPos = branch.endPos; - } else { - branch.elseEndPos = endPos; - branch = new BranchNode( positions.elsePos, endPos, WasmBlockOperator.ELSE, WasmBlockOperator.END ); - parent.add( branch ); - } - break; } if( parsedBlock.nextPosition >= positions.elsePos ) { break; @@ -562,10 +594,18 @@ class BranchManager { newElsePositionFound = false; for( int j = i; j < parsedOpCount; j++ ) { parsedBlock = parsedOperations.get( j ); - if( parsedBlock.op == JavaBlockOperator.GOTO ) { - if( parsedBlock.nextPosition == endElse ) { - break LOOP; - } + switch( parsedBlock.op ) { + case IF: + break; + case GOTO: + if( parsedBlock.nextPosition == endElse ) { + break LOOP; + } + break; + default: + if( parsedBlock.nextPosition < endElse ) { + break LOOP; + } } } } diff --git a/src/de/inetsoftware/jwebassembly/module/JavaBlockOperator.java b/src/de/inetsoftware/jwebassembly/module/JavaBlockOperator.java index dfd1184..d6cd2d9 100644 --- a/src/de/inetsoftware/jwebassembly/module/JavaBlockOperator.java +++ b/src/de/inetsoftware/jwebassembly/module/JavaBlockOperator.java @@ -1,5 +1,5 @@ /* - Copyright 2018 Volker Berlin (i-net software) + Copyright 2018 - 2022 Volker Berlin (i-net software) Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -28,4 +28,5 @@ public enum JavaBlockOperator { SWITCH, LOOP, TRY, + RETURN, } diff --git a/src/de/inetsoftware/jwebassembly/module/JavaMethodWasmCodeBuilder.java b/src/de/inetsoftware/jwebassembly/module/JavaMethodWasmCodeBuilder.java index d6e8972..3400fa9 100644 --- a/src/de/inetsoftware/jwebassembly/module/JavaMethodWasmCodeBuilder.java +++ b/src/de/inetsoftware/jwebassembly/module/JavaMethodWasmCodeBuilder.java @@ -1,5 +1,5 @@ /* - * Copyright 2018 - 2021 Volker Berlin (i-net software) + * Copyright 2018 - 2022 Volker Berlin (i-net software) * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -593,6 +593,7 @@ class JavaMethodWasmCodeBuilder extends WasmCodeBuilder { type = null; } addBlockInstruction( WasmBlockOperator.RETURN, type, codePos, lineNumber ); + branchManager.addReturnOperator( codePos, byteCode.getCodePosition(), lineNumber ); break; case 178: // getstatic ConstantRef ref = (ConstantRef)constantPool.get( byteCode.readUnsignedShort() ); diff --git a/test/de/inetsoftware/jwebassembly/runtime/ControlFlowOperators.java b/test/de/inetsoftware/jwebassembly/runtime/ControlFlowOperators.java index 6181b1e..ccc8769 100644 --- a/test/de/inetsoftware/jwebassembly/runtime/ControlFlowOperators.java +++ b/test/de/inetsoftware/jwebassembly/runtime/ControlFlowOperators.java @@ -85,6 +85,11 @@ public class ControlFlowOperators extends AbstractBaseTest { addParam( list, script, "conditionalInsideIf_2" ); addParam( list, script, "conditionalInsideIf_3" ); addParam( list, script, "conditionalInsideIf_4" ); + addParam( list, script, "ifWithReturn8" ); + addParam( list, script, "ifWithReturn17" ); + addParam( list, script, "ifWithReturn21" ); + addParam( list, script, "ifWithReturn27" ); + addParam( list, script, "ifWithReturn28" ); addParam( list, script, "stringSwitchNormalFoo" ); addParam( list, script, "stringSwitchNormalBar" ); addParam( list, script, "stringSwitchNormalDefault" ); @@ -684,6 +689,50 @@ public class ControlFlowOperators extends AbstractBaseTest { } } + @Export + static int ifWithReturn8() { + return ifWithReturn( 8, 0 ); + } + + @Export + static int ifWithReturn17() { + return ifWithReturn( 8, 13 ); + } + + @Export + static int ifWithReturn21() { + return ifWithReturn( 8, 5 ); + } + + @Export + static int ifWithReturn27() { + return ifWithReturn( 0, 0 ); + } + + @Export + static int ifWithReturn28() { + return ifWithReturn( 0, 1 ); + } + + private static int ifWithReturn( int a, int b ) { + if( a > 7 ) { + if( b > 1 ) { + if( b == 13 ) { + return 17; + } else { + return 21; + } + } + } else { + if( a == b ) { + return 27; + } else { + return 28; + } + } + return a; + } + @Export static int stringSwitchNormalFoo() { return stringSwitchNormal( "foo" );