diff --git a/src/de/inetsoftware/jwebassembly/module/JavaMethodWasmCodeBuilder.java b/src/de/inetsoftware/jwebassembly/module/JavaMethodWasmCodeBuilder.java index ae09cd1..526ba5e 100644 --- a/src/de/inetsoftware/jwebassembly/module/JavaMethodWasmCodeBuilder.java +++ b/src/de/inetsoftware/jwebassembly/module/JavaMethodWasmCodeBuilder.java @@ -282,14 +282,7 @@ class JavaMethodWasmCodeBuilder extends WasmCodeBuilder { break; case 89: // dup: duplicate the value on top of the stack case 92: // dup2 - // save it in a temporary variable and load it 2 times; optimize will change it to TEE - storeType = findValueTypeFromStack( 1 ); - int idx = getTempVariable( storeType, codePos, codePos + 1 ); - addLoadStoreInstruction( storeType, false, idx, codePos, lineNumber ); - addLoadStoreInstruction( storeType, true, idx, codePos, lineNumber ); - addLoadStoreInstruction( storeType, true, idx, codePos, lineNumber ); -// addCallInstruction( new SyntheticFunctionName( "dup" -// + storeType, "local.get 0 local.get 0 return", storeType, null, storeType, storeType ), codePos, lineNumber ); + addDupInstruction( codePos, lineNumber ); break; case 90: // dup_x1 case 91: // dup_x2 @@ -415,7 +408,7 @@ class JavaMethodWasmCodeBuilder extends WasmCodeBuilder { addNumericInstruction( NumericOperator.xor, ValueType.i64, codePos, lineNumber ); break; case 132: // iinc - idx = byteCode.readUnsignedIndex( wide ); + int idx = byteCode.readUnsignedIndex( wide ); addLoadStoreInstruction( ValueType.i32, true, idx, codePos, lineNumber ); addConstInstruction( (int)(wide ? byteCode.readShort() : byteCode.readByte()), ValueType.i32, codePos, lineNumber ); addNumericInstruction( NumericOperator.add, ValueType.i32, codePos, lineNumber ); diff --git a/src/de/inetsoftware/jwebassembly/module/WasmCodeBuilder.java b/src/de/inetsoftware/jwebassembly/module/WasmCodeBuilder.java index a593fd0..5e81a9c 100644 --- a/src/de/inetsoftware/jwebassembly/module/WasmCodeBuilder.java +++ b/src/de/inetsoftware/jwebassembly/module/WasmCodeBuilder.java @@ -246,7 +246,6 @@ public abstract class WasmCodeBuilder { * @param lineNumber * the line number in the Java source code */ - @Nonnull protected void addLoadStoreInstruction( AnyType valueType, boolean load, @Nonnegative int javaIdx, int javaCodePos, int lineNumber ) { localVariables.use( valueType, javaIdx, javaCodePos ); instructions.add( new WasmLoadStoreInstruction( load, javaIdx, localVariables, javaCodePos, lineNumber ) ); @@ -264,7 +263,6 @@ public abstract class WasmCodeBuilder { * @param lineNumber * the line number in the Java source code */ - @Nonnull protected void addLocalInstruction( VariableOperator op, @Nonnegative int wasmIdx, int javaCodePos, int lineNumber ) { switch( op ) { case set: @@ -275,6 +273,22 @@ public abstract class WasmCodeBuilder { instructions.add( new WasmLocalInstruction( op, wasmIdx, javaCodePos, lineNumber ) ); } + /** + * Create a WasmDupInstruction. + * + * @param javaCodePos + * the code position/offset in the Java method + * @param lineNumber + * the line number in the Java source code + */ + protected void addDupInstruction( int javaCodePos, int lineNumber ) { + AnyType type = findValueTypeFromStack( 1 ); + int idx = getTempVariable( type, javaCodePos, javaCodePos + 1 ); + instructions.add( new WasmDupInstruction( idx, type, 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 ) + } + /** * Add a global instruction * @@ -409,10 +423,11 @@ public abstract class WasmCodeBuilder { if( instr.getType() == Type.Struct ) { WasmStructInstruction struct = (WasmStructInstruction)instr; if( struct.getOperator() == StructOperator.NEW_DEFAULT ) { - instructions.remove( i ); // NEW_DEFAULT - instructions.remove( i ); // SET temp from a dup of the instance reference - instructions.remove( i ); // GET temp from a dup of the instance reference - instructions.remove( i ); // GET temp from a dup of the instance reference + instructions.set( i, new WasmNopInstruction( struct.getCodePosition(), struct.getLineNumber() ) ); // replace NEW_DEFAULT with Nop, Nop because the code position can be needed for the branch manager + instr = instructions.get( ++i ); + if( instr.getType() == Type.Dup ) { + instructions.remove( i ); // dup of the instance reference if it is later assign, missing if the object after the constructor is never assign + } break; } } diff --git a/src/de/inetsoftware/jwebassembly/module/WasmDupInstruction.java b/src/de/inetsoftware/jwebassembly/module/WasmDupInstruction.java new file mode 100644 index 0000000..80b1927 --- /dev/null +++ b/src/de/inetsoftware/jwebassembly/module/WasmDupInstruction.java @@ -0,0 +1,93 @@ +/* + Copyright 2019 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. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + +*/ +package de.inetsoftware.jwebassembly.module; + +import java.io.IOException; + +import javax.annotation.Nonnull; + +import de.inetsoftware.jwebassembly.wasm.AnyType; +import de.inetsoftware.jwebassembly.wasm.VariableOperator; + +/** + * WasmInstruction that emulate the Java dup instruction which duplicate the value on the stack. + * + * @author Volker Berlin + * + */ +class WasmDupInstruction extends WasmInstruction { + + private int idx; + + private AnyType type; + + private LocaleVariableManager localVariables; + + /** + * Create an instance of a dup instruction + * + * @param idx + * the memory/slot idx of the temp variable + * @param type + * the type of the duplicate value + * @param localVariables + * the manager for local variables + * @param javaCodePos + * the code position/offset in the Java method + * @param lineNumber + * the line number in the Java source code + */ + WasmDupInstruction( int idx, AnyType type, LocaleVariableManager localVariables, int javaCodePos, int lineNumber ) { + super( javaCodePos, lineNumber ); + this.idx = idx; + this.type = type; + this.localVariables = localVariables; + } + + /** + * {@inheritDoc} + */ + @Override + Type getType() { + return Type.Dup; + } + + /** + * {@inheritDoc} + */ + public void writeTo( @Nonnull ModuleWriter writer ) throws IOException { + // save it in a temporary variable and load it 2 times; + int index = localVariables.get( idx, getCodePosition() ); + writer.writeLocal( VariableOperator.tee, index ); + writer.writeLocal( VariableOperator.get, index ); + } + + /** + * {@inheritDoc} + */ + AnyType getPushValueType() { + return type; + } + + /** + * {@inheritDoc} + */ + @Override + int getPopCount() { + return 0; + } +} diff --git a/src/de/inetsoftware/jwebassembly/module/WasmInstruction.java b/src/de/inetsoftware/jwebassembly/module/WasmInstruction.java index d7a0a94..81beede 100644 --- a/src/de/inetsoftware/jwebassembly/module/WasmInstruction.java +++ b/src/de/inetsoftware/jwebassembly/module/WasmInstruction.java @@ -35,7 +35,7 @@ abstract class WasmInstruction { * Type of instruction to faster differ as with instanceof. */ static enum Type { - Const, Convert, Local, Global, Table, Block, Numeric, Nop, Call, CallIndirect, Array, Struct, DupThis; + Const, Convert, Local, Global, Table, Block, Numeric, Nop, Call, CallIndirect, Array, Struct, Dup, DupThis; } private int javaCodePos;