diff --git a/src/de/inetsoftware/jwebassembly/module/BranchManger.java b/src/de/inetsoftware/jwebassembly/module/BranchManger.java index 6dca220..f5a9458 100644 --- a/src/de/inetsoftware/jwebassembly/module/BranchManger.java +++ b/src/de/inetsoftware/jwebassembly/module/BranchManger.java @@ -29,6 +29,7 @@ import de.inetsoftware.classparser.Code; import de.inetsoftware.classparser.CodeInputStream; import de.inetsoftware.classparser.TryCatchFinally; import de.inetsoftware.jwebassembly.WasmException; +import de.inetsoftware.jwebassembly.module.WasmInstruction.Type; import de.inetsoftware.jwebassembly.wasm.AnyType; import de.inetsoftware.jwebassembly.wasm.NumericOperator; import de.inetsoftware.jwebassembly.wasm.ValueType; @@ -327,12 +328,10 @@ class BranchManger { calculate( branch, parsedOperations.subList( 0, i ) ); i = 0; } - AnyType blockType = calculateBlockType( startPos, branch.endPos ); - branch.data = blockType; // if with block type signature must have an else block - int breakDeep = blockType == ValueType.empty ? calculateBreakDeep( parent, endPos ) : -1; - if( breakDeep >= 0 ) { + int breakDeep = calculateBreakDeep( parent, endPos ); + if( breakDeep > 0 ) { branch.endOp = WasmBlockOperator.END; branch.add( new BranchNode( elsePos, endPos, WasmBlockOperator.BR, null, breakDeep + 1 ) ); endPos = branch.endPos; @@ -385,39 +384,6 @@ class BranchManger { return deep; } - /** - * Calculate the block type. The value type that is on the stack after the block. - * - * @param startPos - * the start position of the block - * @param endPos - * the end position of the block - * @return the value type - */ - @Nonnull - private AnyType calculateBlockType( int startPos, int endPos ) { - ArrayDeque stack = new ArrayDeque<>(); - stack.push( ValueType.empty ); - for( WasmInstruction instr : instructions ) { - int codePos = instr.getCodePosition(); - if( codePos < startPos ) { - continue; - } - if( codePos >= endPos ) { - break; - } - int popCount = instr.getPopCount(); - for( int p = 0; p < popCount; p++ ) { - stack.pop(); - } - AnyType pushValue = instr.getPushValueType(); - if( pushValue != null ) { - stack.push( pushValue ); - } - } - return stack.pop(); - } - /** * Calculate the blocks of a switch. * @@ -754,6 +720,8 @@ class BranchManger { idx = root.handle( codePosition, instructions, idx, lineNumber ); } root.handle( byteCode.getCodePosition(), instructions, instructions.size(), byteCode.getLineNumber() ); + + root.calculateBlockType( instructions ); } /** @@ -883,15 +851,19 @@ class BranchManger { private final int startPos; - private int endPos; + private int endPos; private final WasmBlockOperator startOp; - private WasmBlockOperator endOp; + private WasmBlockOperator endOp; - private Object data; + private Object data; - private BranchNode parent; + private BranchNode parent; + + private WasmBlockInstruction startBlock; + + private int startIdx; /** * Create a new description. @@ -953,12 +925,14 @@ class BranchManger { * the line number in the Java source code * @return the new index in the instructions */ - int handle( int codePosition, List instructions, int idx, int lineNumber ) { + int handle( int codePosition, List instructions, int idx, int lineNumber ) { if( codePosition < startPos || codePosition > endPos ) { return idx; } if( codePosition == startPos && startOp != null ) { - instructions.add( idx++, new WasmBlockInstruction( startOp, data, codePosition, lineNumber ) ); + startBlock = new WasmBlockInstruction( startOp, data, codePosition, lineNumber ); + instructions.add( idx++, startBlock ); + startIdx = idx; } for( BranchNode branch : this ) { idx = branch.handle( codePosition, instructions, idx, lineNumber ); @@ -968,5 +942,45 @@ class BranchManger { } return idx; } + + /** + * Calculate the block type. The value type that is on the stack after the block. + * + * @param instructions + * the instructions of the function + */ + void calculateBlockType( List instructions ) { + for( int i = size() - 1; i >= 0; i-- ) { + BranchNode branch = get( i ); + branch.calculateBlockType( instructions ); + } + + if( startBlock != null && startBlock.getOperation() == WasmBlockOperator.IF ) { + ArrayDeque stack = new ArrayDeque<>(); + stack.push( ValueType.empty ); + for( int i = startIdx; i < instructions.size(); i++ ) { + WasmInstruction instr = instructions.get( i ); + int codePos = instr.getCodePosition(); + if( codePos >= endPos ) { + break; + } + if( instr.getType() == Type.Block && ((WasmBlockInstruction)instr).getOperation() == WasmBlockOperator.RETURN ) { + while( stack.size() > 1 ) { + stack.pop(); + } + break; + } + int popCount = instr.getPopCount(); + for( int p = 0; p < popCount; p++ ) { + stack.pop(); + } + AnyType pushValue = instr.getPushValueType(); + if( pushValue != null ) { + stack.push( pushValue ); + } + } + startBlock.setData( stack.pop() ); + } + } } } diff --git a/src/de/inetsoftware/jwebassembly/module/WasmBlockInstruction.java b/src/de/inetsoftware/jwebassembly/module/WasmBlockInstruction.java index 490a924..f4f45fc 100644 --- a/src/de/inetsoftware/jwebassembly/module/WasmBlockInstruction.java +++ b/src/de/inetsoftware/jwebassembly/module/WasmBlockInstruction.java @@ -35,7 +35,7 @@ class WasmBlockInstruction extends WasmInstruction { private final WasmBlockOperator op; - private final Object data; + private Object data; /** * Create an instance of block operation. @@ -71,6 +71,16 @@ class WasmBlockInstruction extends WasmInstruction { return op; } + /** + * Set a new value for the data + * + * @param data + * the new value + */ + void setData( Object data ) { + this.data = data; + } + /** * {@inheritDoc} */ @@ -97,6 +107,13 @@ class WasmBlockInstruction extends WasmInstruction { */ @Override int getPopCount() { - return 0; + switch( op ) { + case IF: + case BR_IF: + case DROP: + return 1; + default: + return 0; + } } } diff --git a/src/de/inetsoftware/jwebassembly/module/WasmNumericInstruction.java b/src/de/inetsoftware/jwebassembly/module/WasmNumericInstruction.java index b1b8a3f..08acc35 100644 --- a/src/de/inetsoftware/jwebassembly/module/WasmNumericInstruction.java +++ b/src/de/inetsoftware/jwebassembly/module/WasmNumericInstruction.java @@ -81,7 +81,9 @@ class WasmNumericInstruction extends WasmInstruction { case lt: case le: case ge: - return null; //TODO should this Valuetype.i32? But then tests failed. can be related to the getPopCount() of the block BlockInstaction IF + case ifnull: + case ifnonnull: + return ValueType.i32; default: return valueType; } @@ -93,6 +95,8 @@ class WasmNumericInstruction extends WasmInstruction { @Override int getPopCount() { switch( numOp ) { + case ifnull: + case ifnonnull: case neg: case sqrt: case abs: