fix push/pop value of compare instructions

This commit is contained in:
Volker Berlin 2019-07-23 18:23:59 +02:00
parent 0d58782f75
commit b65027f156
3 changed files with 81 additions and 46 deletions

View File

@ -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<AnyType> 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<WasmInstruction> instructions, int idx, int lineNumber ) {
int handle( int codePosition, List<WasmInstruction> 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<WasmInstruction> instructions ) {
for( int i = size() - 1; i >= 0; i-- ) {
BranchNode branch = get( i );
branch.calculateBlockType( instructions );
}
if( startBlock != null && startBlock.getOperation() == WasmBlockOperator.IF ) {
ArrayDeque<AnyType> 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() );
}
}
}
}

View File

@ -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;
}
}
}

View File

@ -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: