diff --git a/src/de/inetsoftware/jwebassembly/module/WasmCodeBuilder.java b/src/de/inetsoftware/jwebassembly/module/WasmCodeBuilder.java index a7139c4..b24008a 100644 --- a/src/de/inetsoftware/jwebassembly/module/WasmCodeBuilder.java +++ b/src/de/inetsoftware/jwebassembly/module/WasmCodeBuilder.java @@ -374,24 +374,35 @@ public abstract class WasmCodeBuilder { instr = dup2 && type != ValueType.i64 && type != ValueType.f64 ? // findInstructionThatPushValue( 2, javaCodePos ) : null; + int slot2; + if( instr != null ) { + slot2 = getPossibleSlot( instr ); + if( slot2 < 0 ) { + slot2 = getTempVariable( instr.getPushValueType(), javaCodePos, javaCodePos + 1 ); + if( slot < 0 ) { + slot = getTempVariable( type, javaCodePos, javaCodePos + 1 ); + instructions.add( new WasmLoadStoreInstruction( VariableOperator.set, slot, localVariables, javaCodePos, lineNumber ) ); + } else { + instructions.add( new WasmBlockInstruction( WasmBlockOperator.DROP, null, javaCodePos, lineNumber ) ); + } + instructions.add( new WasmLoadStoreInstruction( VariableOperator.tee, slot2, localVariables, javaCodePos, lineNumber ) ); + instructions.add( new WasmLoadStoreInstruction( VariableOperator.get, slot, localVariables, javaCodePos, lineNumber ) ); + } + } else { + slot2 = -1; // for compiler only + } + //alternate we need to create a new locale variable if( slot < 0 ) { - if( instr != null ) { - throw new WasmException( "DUP2 for two slots without variables", lineNumber ); - } slot = getTempVariable( type, javaCodePos, javaCodePos + 1 ); instructions.add( new WasmLoadStoreInstruction( VariableOperator.tee, 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 - // new SyntheticFunctionName( "dup" + storeType, "local.get 0 local.get 0 return", storeType, null, storeType, storeType ), codePos, lineNumber ) } 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 ) ); localVariables.expandUse( slot, javaCodePos ); } + if( instr != null ) { + instructions.add( new WasmLoadStoreInstruction( VariableOperator.get, slot2, localVariables, javaCodePos, lineNumber ) ); + } + instructions.add( new WasmLoadStoreInstruction( VariableOperator.get, slot, localVariables, javaCodePos, lineNumber ) ); } /** diff --git a/test/de/inetsoftware/jwebassembly/runtime/ArrayOperations.java b/test/de/inetsoftware/jwebassembly/runtime/ArrayOperations.java index 6ceb21d..99f8ab1 100644 --- a/test/de/inetsoftware/jwebassembly/runtime/ArrayOperations.java +++ b/test/de/inetsoftware/jwebassembly/runtime/ArrayOperations.java @@ -19,6 +19,7 @@ import java.lang.reflect.Array; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; +import java.util.Objects; import java.util.zip.CRC32; import org.junit.Assume; @@ -64,6 +65,7 @@ public class ArrayOperations extends AbstractBaseTest { addParam( list, script, "copyBack2Front" ); addParam( list, script, "copyFront2Back" ); addParam( list, script, "dup2" ); + addParam( list, script, "dup2FromStack" ); addParam( list, script, "dup_x2" ); addParam( list, script, "byteArrayClassName" ); addParam( list, script, "shortArrayClassName" ); @@ -225,6 +227,17 @@ public class ArrayOperations extends AbstractBaseTest { return sum; } + @Export + static int dup2FromStack() { + int[] data = {1,2,3}; + int i = 0; + + // use dup2 to duplicate the array and the index from stack (not variable) + Objects.requireNonNull( data )[i+1] |= 13; + + return data[1]; + } + @Export static int dup_x2() { Object[] data = {null,null,null};