diff --git a/src/de/inetsoftware/jwebassembly/binary/BinaryModuleWriter.java b/src/de/inetsoftware/jwebassembly/binary/BinaryModuleWriter.java index a77884f..efec876 100644 --- a/src/de/inetsoftware/jwebassembly/binary/BinaryModuleWriter.java +++ b/src/de/inetsoftware/jwebassembly/binary/BinaryModuleWriter.java @@ -1018,8 +1018,13 @@ public class BinaryModuleWriter extends ModuleWriter implements InstructionOpcod * {@inheritDoc} */ @Override - protected void writeVirtualFunctionCall( FunctionName name, AnyType type, int virtualFunctionIdx ) throws IOException { + protected void writeVirtualFunctionCall( FunctionName name, AnyType type, int virtualFunctionIdx, int tempVarIdx ) throws IOException { callIndirect = true; + + // duplicate this on the stack + writeLocal( VariableOperator.tee, tempVarIdx ); + writeLocal( VariableOperator.get, tempVarIdx ); + codeStream.writeOpCode( STRUCT_GET ); codeStream.writeValueType( type ); codeStream.writeVaruint32( 0 ); // vtable is ever on position 0 diff --git a/src/de/inetsoftware/jwebassembly/module/ModuleWriter.java b/src/de/inetsoftware/jwebassembly/module/ModuleWriter.java index 9cf56d1..418aadc 100644 --- a/src/de/inetsoftware/jwebassembly/module/ModuleWriter.java +++ b/src/de/inetsoftware/jwebassembly/module/ModuleWriter.java @@ -244,10 +244,12 @@ public abstract class ModuleWriter implements Closeable { * the base type that should be called * @param virtualFunctionIdx * the index of the virtual method in the object. If the value < 0 a direct call should be used. + * @param tempVarIdx + * the index of a temporary variable of type "type" to duplicate "this" * @throws IOException * if any I/O error occur */ - protected abstract void writeVirtualFunctionCall( FunctionName name, AnyType type, int virtualFunctionIdx ) throws IOException; + protected abstract void writeVirtualFunctionCall( FunctionName name, AnyType type, int virtualFunctionIdx, int tempVarIdx ) throws IOException; /** * Write a block/branch code diff --git a/src/de/inetsoftware/jwebassembly/module/WasmCallIndirectInstruction.java b/src/de/inetsoftware/jwebassembly/module/WasmCallIndirectInstruction.java index 08d54db..992d9d0 100644 --- a/src/de/inetsoftware/jwebassembly/module/WasmCallIndirectInstruction.java +++ b/src/de/inetsoftware/jwebassembly/module/WasmCallIndirectInstruction.java @@ -30,23 +30,36 @@ import de.inetsoftware.jwebassembly.module.TypeManager.StructType; */ class WasmCallIndirectInstruction extends WasmCallInstruction { - private int virtualFunctionIdx = -1; + private int virtualFunctionIdx = -1; - private StructType type; + private final StructType type; + + private final int tempVar; + + private final LocaleVariableManager localVariables; /** * Create an instance of a function call instruction * * @param name * the function name that should be called + * @param type + * the type with the virtual method/function + * @param tempVar + * the slot of a temporary variable of type "type" to duplicate "this" + * @param localVariables + * the manager for local variables to translate the Java slot of the temporary variable into wasm local + * position * @param javaCodePos * the code position/offset in the Java method * @param lineNumber * the line number in the Java source code */ - WasmCallIndirectInstruction( FunctionName name, @Nonnull StructType type, int javaCodePos, int lineNumber ) { + WasmCallIndirectInstruction( FunctionName name, @Nonnull StructType type, int tempVar, LocaleVariableManager localVariables, int javaCodePos, int lineNumber ) { super( name, javaCodePos, lineNumber ); this.type = type; + this.tempVar = tempVar; + this.localVariables = localVariables; } /** @@ -74,7 +87,8 @@ class WasmCallIndirectInstruction extends WasmCallInstruction { if( virtualFunctionIdx < 0 || true ) { super.writeTo( writer ); } else { - writer.writeVirtualFunctionCall( getFunctionName(), type, virtualFunctionIdx ); + int tempVarIdx = localVariables.get( tempVar, getCodePosition() ); + writer.writeVirtualFunctionCall( getFunctionName(), type, virtualFunctionIdx, tempVarIdx ); } } diff --git a/src/de/inetsoftware/jwebassembly/module/WasmCodeBuilder.java b/src/de/inetsoftware/jwebassembly/module/WasmCodeBuilder.java index 3b4e413..c13b8be 100644 --- a/src/de/inetsoftware/jwebassembly/module/WasmCodeBuilder.java +++ b/src/de/inetsoftware/jwebassembly/module/WasmCodeBuilder.java @@ -285,7 +285,8 @@ public abstract class WasmCodeBuilder { */ protected void addCallVirtualInstruction( FunctionName name, int javaCodePos, int lineNumber ) { StructType type = types.valueOf( name.className ); - instructions.add( new WasmCallIndirectInstruction( name, type, javaCodePos, lineNumber ) ); + int tempVar = localVariables.getTempVariable( type, javaCodePos, javaCodePos + 1 ); + instructions.add( new WasmCallIndirectInstruction( name, type, tempVar, localVariables, javaCodePos, lineNumber ) ); } /** diff --git a/src/de/inetsoftware/jwebassembly/text/TextModuleWriter.java b/src/de/inetsoftware/jwebassembly/text/TextModuleWriter.java index c52ff3b..574065a 100644 --- a/src/de/inetsoftware/jwebassembly/text/TextModuleWriter.java +++ b/src/de/inetsoftware/jwebassembly/text/TextModuleWriter.java @@ -580,8 +580,13 @@ public class TextModuleWriter extends ModuleWriter { * {@inheritDoc} */ @Override - protected void writeVirtualFunctionCall( FunctionName name, AnyType type, int virtualFunctionIdx ) throws IOException { + protected void writeVirtualFunctionCall( FunctionName name, AnyType type, int virtualFunctionIdx, int tempVarIdx ) throws IOException { callIndirect = true; + + // duplicate this on the stack + writeLocal( VariableOperator.tee, tempVarIdx ); + writeLocal( VariableOperator.get, tempVarIdx ); + newline( methodOutput ); methodOutput.append( "struct.get " ).append( normalizeName( type.toString() ) ).append( " 0 ;;vtable" ); // vtable is ever on position 0 newline( methodOutput );