Handle DUP2 as two dup if used for non 64 bit values

This commit is contained in:
Volker Berlin 2021-05-23 22:12:29 +02:00
parent 534cd19c0f
commit 6520370e02
4 changed files with 57 additions and 14 deletions

View File

@ -310,7 +310,7 @@ class JavaMethodWasmCodeBuilder extends WasmCodeBuilder {
break; break;
case 89: // dup: duplicate the value on top of the stack case 89: // dup: duplicate the value on top of the stack
case 92: // dup2 case 92: // dup2
addDupInstruction( codePos, lineNumber ); addDupInstruction( op == 92, codePos, lineNumber );
break; break;
case 90: // dup_x1 case 90: // dup_x1
case 93: // dup2_x1 case 93: // dup2_x1

View File

@ -20,6 +20,8 @@ import java.util.ArrayDeque;
import java.util.List; import java.util.List;
import java.util.NoSuchElementException; import java.util.NoSuchElementException;
import javax.annotation.Nonnull;
import de.inetsoftware.jwebassembly.WasmException; import de.inetsoftware.jwebassembly.WasmException;
import de.inetsoftware.jwebassembly.module.WasmInstruction.Type; import de.inetsoftware.jwebassembly.module.WasmInstruction.Type;
import de.inetsoftware.jwebassembly.wasm.AnyType; import de.inetsoftware.jwebassembly.wasm.AnyType;
@ -42,6 +44,7 @@ class StackInspector {
* the current code position, important to follow jumps in the code * the current code position, important to follow jumps in the code
* @return details of the stack position * @return details of the stack position
*/ */
@Nonnull
static StackValue findInstructionThatPushValue( List<WasmInstruction> instructions, int count, int javaCodePos ) { static StackValue findInstructionThatPushValue( List<WasmInstruction> instructions, int count, int javaCodePos ) {
// because there can be jumps (GOTO) we can analyze the stack only forward. If we iterate backward we will not see that we are in a jump. // because there can be jumps (GOTO) we can analyze the stack only forward. If we iterate backward we will not see that we are in a jump.
ArrayDeque<StackValue> stack = new ArrayDeque<>(); ArrayDeque<StackValue> stack = new ArrayDeque<>();

View File

@ -218,6 +218,7 @@ public abstract class WasmCodeBuilder {
* current code position for which the stack is inspected * current code position for which the stack is inspected
* @return the instruction * @return the instruction
*/ */
@Nonnull
private WasmInstruction findInstructionThatPushValue( int count, int javaCodePos ) { private WasmInstruction findInstructionThatPushValue( int count, int javaCodePos ) {
return StackInspector.findInstructionThatPushValue( instructions, count, javaCodePos ).instr; return StackInspector.findInstructionThatPushValue( instructions, count, javaCodePos ).instr;
} }
@ -332,36 +333,62 @@ public abstract class WasmCodeBuilder {
} }
/** /**
* Create a WasmDupInstruction. * Get a possible slot from the instruction
* *
* @param javaCodePos * @param instr
* the code position/offset in the Java method * the instruction
* @param lineNumber * @return the slot or -1 if there no slot
* the line number in the Java source code
*/ */
protected void addDupInstruction( int javaCodePos, int lineNumber ) { private static int getPossibleSlot( @Nonnull WasmInstruction instr ) {
WasmInstruction instr = findInstructionThatPushValue( 1, javaCodePos );
AnyType type = instr.getPushValueType();
int slot = -1;
// if it is a GET to a local variable then we can use it // if it is a GET to a local variable then we can use it
if( instr.getType() == Type.Local ) { if( instr.getType() == Type.Local ) {
WasmLocalInstruction local1 = (WasmLocalInstruction)instr; WasmLocalInstruction local1 = (WasmLocalInstruction)instr;
switch( local1.getOperator() ) { switch( local1.getOperator() ) {
case get: case get:
case tee: case tee:
slot = local1.getSlot(); return local1.getSlot();
break;
default: default:
} }
} }
return -1;
}
/**
* Create a WasmDupInstruction.
*
* @param dup2
* call from dup2 instruction
* @param javaCodePos
* the code position/offset in the Java method
* @param lineNumber
* the line number in the Java source code
*/
protected void addDupInstruction( boolean dup2, int javaCodePos, int lineNumber ) {
WasmInstruction instr = findInstructionThatPushValue( 1, javaCodePos );
AnyType type = instr.getPushValueType();
int slot = getPossibleSlot( instr );
// occur with:
// int[] data = new int[x];
// data[i] |= any;
instr = dup2 && type != ValueType.i64 && type != ValueType.f64 ? //
findInstructionThatPushValue( 2, javaCodePos ) : null;
//alternate we need to create a new locale variable //alternate we need to create a new locale variable
if( slot < 0 ) { if( slot < 0 ) {
if( instr != null ) {
throw new WasmException( "DUP2 for two slots without variables", lineNumber );
}
slot = getTempVariable( type, javaCodePos, javaCodePos + 1 ); slot = getTempVariable( type, javaCodePos, javaCodePos + 1 );
instructions.add( new WasmLoadStoreInstruction( VariableOperator.tee, slot, localVariables, javaCodePos, lineNumber ) ); instructions.add( new WasmLoadStoreInstruction( VariableOperator.tee, slot, localVariables, javaCodePos, lineNumber ) );
instructions.add( new WasmLoadStoreInstruction( VariableOperator.get, slot, localVariables, javaCodePos, lineNumber ) ); instructions.add( new WasmLoadStoreInstruction( VariableOperator.get, slot, localVariables, javaCodePos, lineNumber ) );
// an alternative solution can be a function call with multiple return values but this seems to be slower // an alternative solution can be a function call with multiple return values but this seems to be slower
// new SyntheticFunctionName( "dup" + storeType, "local.get 0 local.get 0 return", storeType, null, storeType, storeType ), codePos, lineNumber ) // new SyntheticFunctionName( "dup" + storeType, "local.get 0 local.get 0 return", storeType, null, storeType, storeType ), codePos, lineNumber )
} else { } else {
if( instr != null ) {
int slot2 = getPossibleSlot( instr );
instructions.add( new WasmLoadStoreInstruction( VariableOperator.get, slot2, localVariables, javaCodePos, lineNumber ) );
}
instructions.add( new WasmLoadStoreInstruction( VariableOperator.get, slot, localVariables, javaCodePos, lineNumber ) ); instructions.add( new WasmLoadStoreInstruction( VariableOperator.get, slot, localVariables, javaCodePos, lineNumber ) );
localVariables.expandUse( slot, javaCodePos ); localVariables.expandUse( slot, javaCodePos );
} }
@ -861,7 +888,7 @@ public abstract class WasmCodeBuilder {
break; break;
case NEW_DEFAULT: case NEW_DEFAULT:
if( options.useGC() ) { if( options.useGC() ) {
addDupInstruction( javaCodePos, lineNumber ); addDupInstruction( false, javaCodePos, lineNumber );
addConstInstruction( structInst.getStructType().getVTable(), javaCodePos, lineNumber ); addConstInstruction( structInst.getStructType().getVTable(), javaCodePos, lineNumber );
instructions.add( new WasmStructInstruction( StructOperator.SET, typeName, new NamedStorageType( ValueType.i32, "", TypeManager.FIELD_VTABLE ), javaCodePos, lineNumber, types ) ); instructions.add( new WasmStructInstruction( StructOperator.SET, typeName, new NamedStorageType( ValueType.i32, "", TypeManager.FIELD_VTABLE ), javaCodePos, lineNumber, types ) );
break; break;
@ -920,7 +947,7 @@ public abstract class WasmCodeBuilder {
int pos = instructions.size(); int pos = instructions.size();
addStructInstruction( StructOperator.NEW_DEFAULT, lambdaTypeName, null, javaCodePos, lineNumber ); addStructInstruction( StructOperator.NEW_DEFAULT, lambdaTypeName, null, javaCodePos, lineNumber );
if( !options.useGC() ) { if( !options.useGC() ) {
addDupInstruction( javaCodePos, lineNumber ); addDupInstruction( false, javaCodePos, lineNumber );
} }
int slot = ((WasmLocalInstruction)findInstructionThatPushValue( 1, javaCodePos )).getSlot(); int slot = ((WasmLocalInstruction)findInstructionThatPushValue( 1, javaCodePos )).getSlot();

View File

@ -63,6 +63,7 @@ public class ArrayOperations extends AbstractBaseTest {
addParam( list, script, "loopObject" ); addParam( list, script, "loopObject" );
addParam( list, script, "copyBack2Front" ); addParam( list, script, "copyBack2Front" );
addParam( list, script, "copyFront2Back" ); addParam( list, script, "copyFront2Back" );
addParam( list, script, "dup2" );
addParam( list, script, "dup_x2" ); addParam( list, script, "dup_x2" );
addParam( list, script, "byteArrayClassName" ); addParam( list, script, "byteArrayClassName" );
addParam( list, script, "shortArrayClassName" ); addParam( list, script, "shortArrayClassName" );
@ -212,6 +213,18 @@ public class ArrayOperations extends AbstractBaseTest {
return crc.getValue(); return crc.getValue();
} }
@Export
static int dup2() {
int[] data = {1,2,3};
int sum = 0;
for( int i = 0; i < data.length; i++ ) {
data[i] |= 13; // use dup2 to duplicate the array and the index
sum += data[i];
}
return sum;
}
@Export @Export
static int dup_x2() { static int dup_x2() {
Object[] data = {null,null,null}; Object[] data = {null,null,null};