From f2547bd0d204a277b6f2094d62f7cc0e110ce166 Mon Sep 17 00:00:00 2001 From: Volker Berlin Date: Mon, 24 Feb 2020 18:16:36 +0100 Subject: [PATCH] duplicate THIS parameter also for interface calls --- .../jwebassembly/module/ModuleGenerator.java | 4 +- .../module/WasmCallIndirectInstruction.java | 65 ++--------- .../module/WasmCallInterfaceInstruction.java | 35 +++++- .../module/WasmCallVirtualInstruction.java | 110 ++++++++++++++++++ .../jwebassembly/module/WasmCodeBuilder.java | 64 ++++++---- .../jwebassembly/module/WasmInstruction.java | 2 +- 6 files changed, 191 insertions(+), 89 deletions(-) create mode 100644 src/de/inetsoftware/jwebassembly/module/WasmCallVirtualInstruction.java diff --git a/src/de/inetsoftware/jwebassembly/module/ModuleGenerator.java b/src/de/inetsoftware/jwebassembly/module/ModuleGenerator.java index 6f8044c..ab6a8e9 100644 --- a/src/de/inetsoftware/jwebassembly/module/ModuleGenerator.java +++ b/src/de/inetsoftware/jwebassembly/module/ModuleGenerator.java @@ -319,7 +319,7 @@ public class ModuleGenerator { for( WasmInstruction instruction : instructions ) { switch( instruction.getType() ) { case Call: - case CallIndirect: + case CallVirtual: ((WasmCallInstruction)instruction).markAsNeeded( functions ); break; default: @@ -548,7 +548,7 @@ public class ModuleGenerator { } break; case Call: - case CallIndirect: + case CallVirtual: ((WasmCallInstruction)instruction).markAsNeeded( functions ); break; case Struct: diff --git a/src/de/inetsoftware/jwebassembly/module/WasmCallIndirectInstruction.java b/src/de/inetsoftware/jwebassembly/module/WasmCallIndirectInstruction.java index 8039456..2f80142 100644 --- a/src/de/inetsoftware/jwebassembly/module/WasmCallIndirectInstruction.java +++ b/src/de/inetsoftware/jwebassembly/module/WasmCallIndirectInstruction.java @@ -16,17 +16,7 @@ */ package de.inetsoftware.jwebassembly.module; -import java.io.IOException; - -import javax.annotation.Nonnull; - import de.inetsoftware.jwebassembly.module.TypeManager.StructType; -import de.inetsoftware.jwebassembly.wasm.MemoryOperator; -import de.inetsoftware.jwebassembly.wasm.NamedStorageType; -import de.inetsoftware.jwebassembly.wasm.StructOperator; -import de.inetsoftware.jwebassembly.wasm.ValueType; -import de.inetsoftware.jwebassembly.wasm.VariableOperator; -import de.inetsoftware.jwebassembly.wasm.WasmOptions; /** * WasmInstruction for a function call. @@ -34,16 +24,12 @@ import de.inetsoftware.jwebassembly.wasm.WasmOptions; * @author Volker Berlin * */ -class WasmCallIndirectInstruction extends WasmCallInstruction { - - private int virtualFunctionIdx = -1; +abstract class WasmCallIndirectInstruction extends WasmCallInstruction { private final StructType type; private int tempVarIdx; - private final WasmOptions options; - /** * Create an instance of a function call instruction * @@ -55,21 +41,10 @@ class WasmCallIndirectInstruction extends WasmCallInstruction { * the line number in the Java source code * @param types * the type manager - * @param options - * compiler properties */ - WasmCallIndirectInstruction( FunctionName name, int javaCodePos, int lineNumber, TypeManager types, WasmOptions options ) { + WasmCallIndirectInstruction( FunctionName name, int javaCodePos, int lineNumber, TypeManager types ) { super( name, javaCodePos, lineNumber, types, true ); this.type = types.valueOf( name.className ); - this.options = options; - } - - /** - * {@inheritDoc} - */ - @Override - Type getType() { - return Type.CallIndirect; } /** @@ -90,12 +65,12 @@ class WasmCallIndirectInstruction extends WasmCallInstruction { } /** - * {@inheritDoc} + * Get the variable index on which this can be found. + * + * @return the index of the variable */ - @Override - void markAsNeeded( FunctionManager functions ) { - super.markAsNeeded( functions ); - virtualFunctionIdx = functions.getFunctionIndex( getFunctionName() ); + int getVariableIndexOfThis() { + return tempVarIdx; } /** @@ -103,29 +78,5 @@ class WasmCallIndirectInstruction extends WasmCallInstruction { * * @return true, virtual call */ - boolean isVirtual() { - return virtualFunctionIdx > 0; - } - - /** - * {@inheritDoc} - */ - @Override - public void writeTo( @Nonnull ModuleWriter writer ) throws IOException { - if( virtualFunctionIdx < 0 ) { - super.writeTo( writer ); - } else { - // duplicate this on the stack - writer.writeLocal( VariableOperator.get, tempVarIdx ); - - if( options.useGC() ) { - writer.writeStructOperator( StructOperator.GET, type, new NamedStorageType( type, "", "vtable" ), 0 ); // vtable is ever on position 0 - } else { - writer.writeConst( 0, ValueType.i32 ); // vtable is ever on position 0 - writer.writeFunctionCall( WasmCodeBuilder.GET_I32 ); - } - writer.writeMemoryOperator( MemoryOperator.load, ValueType.i32, virtualFunctionIdx * 4, 2 ); - writer.writeVirtualFunctionCall( getFunctionName(), type ); - } - } + abstract boolean isVirtual(); } diff --git a/src/de/inetsoftware/jwebassembly/module/WasmCallInterfaceInstruction.java b/src/de/inetsoftware/jwebassembly/module/WasmCallInterfaceInstruction.java index 4b0c4cb..209de5e 100644 --- a/src/de/inetsoftware/jwebassembly/module/WasmCallInterfaceInstruction.java +++ b/src/de/inetsoftware/jwebassembly/module/WasmCallInterfaceInstruction.java @@ -22,6 +22,12 @@ import javax.annotation.Nonnull; import de.inetsoftware.jwebassembly.WasmException; import de.inetsoftware.jwebassembly.module.TypeManager.StructType; +import de.inetsoftware.jwebassembly.wasm.MemoryOperator; +import de.inetsoftware.jwebassembly.wasm.NamedStorageType; +import de.inetsoftware.jwebassembly.wasm.StructOperator; +import de.inetsoftware.jwebassembly.wasm.ValueType; +import de.inetsoftware.jwebassembly.wasm.VariableOperator; +import de.inetsoftware.jwebassembly.wasm.WasmOptions; /** * WasmInstruction for a function call. @@ -29,7 +35,9 @@ import de.inetsoftware.jwebassembly.module.TypeManager.StructType; * @author Volker Berlin * */ -class WasmCallInterfaceInstruction extends WasmCallInstruction { +class WasmCallInterfaceInstruction extends WasmCallIndirectInstruction { + + private final WasmOptions options; /** * Create an instance of a function call instruction @@ -42,9 +50,12 @@ class WasmCallInterfaceInstruction extends WasmCallInstruction { * the line number in the Java source code * @param types * the type manager + * @param options + * compiler properties */ - WasmCallInterfaceInstruction( FunctionName name, int javaCodePos, int lineNumber, TypeManager types ) { - super( name, javaCodePos, lineNumber, types, true ); + WasmCallInterfaceInstruction( FunctionName name, int javaCodePos, int lineNumber, TypeManager types, WasmOptions options ) { + super( name, javaCodePos, lineNumber, types ); + this.options = options; } /** @@ -55,12 +66,28 @@ class WasmCallInterfaceInstruction extends WasmCallInstruction { return Type.CallInterface; } + /** + * {@inheritDoc} + */ + @Override + boolean isVirtual() { + return true; + } + /** * {@inheritDoc} */ public void writeTo( @Nonnull ModuleWriter writer ) throws IOException { - StructType type = getTypeManager().valueOf( getFunctionName().className ); + FunctionName name = getFunctionName(); + StructType type = getThisType(); int classIndex = type.getClassIndex(); + + //writer.writeLocal( VariableOperator.get, tempVarIdx ); // duplicate this on the stack + writer.writeConst( classIndex, ValueType.i32 ); + //writer.writeConst( functionIndex, ValueType.i32 ); + //writer.writeFunctionCall( callInterface ); // parameters: this, classIndex, functionIndex + + //writer.writeVirtualFunctionCall( name, type ); throw new WasmException( "Interface calls are not supported.", getLineNumber() ); } } diff --git a/src/de/inetsoftware/jwebassembly/module/WasmCallVirtualInstruction.java b/src/de/inetsoftware/jwebassembly/module/WasmCallVirtualInstruction.java new file mode 100644 index 0000000..7510f1d --- /dev/null +++ b/src/de/inetsoftware/jwebassembly/module/WasmCallVirtualInstruction.java @@ -0,0 +1,110 @@ +/* + Copyright 2019 - 2020 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.module.TypeManager.StructType; +import de.inetsoftware.jwebassembly.wasm.MemoryOperator; +import de.inetsoftware.jwebassembly.wasm.NamedStorageType; +import de.inetsoftware.jwebassembly.wasm.StructOperator; +import de.inetsoftware.jwebassembly.wasm.ValueType; +import de.inetsoftware.jwebassembly.wasm.VariableOperator; +import de.inetsoftware.jwebassembly.wasm.WasmOptions; + +/** + * WasmInstruction for a function call. + * + * @author Volker Berlin + * + */ +class WasmCallVirtualInstruction extends WasmCallIndirectInstruction { + + private int virtualFunctionIdx = -1; + + private final WasmOptions options; + + /** + * Create an instance of a function call instruction + * + * @param name + * the function name that should be called + * @param javaCodePos + * the code position/offset in the Java method + * @param lineNumber + * the line number in the Java source code + * @param types + * the type manager + * @param options + * compiler properties + */ + WasmCallVirtualInstruction( FunctionName name, int javaCodePos, int lineNumber, TypeManager types, WasmOptions options ) { + super( name, javaCodePos, lineNumber, types ); + this.options = options; + } + + /** + * {@inheritDoc} + */ + @Override + Type getType() { + return Type.CallVirtual; + } + + /** + * {@inheritDoc} + */ + @Override + void markAsNeeded( FunctionManager functions ) { + super.markAsNeeded( functions ); + virtualFunctionIdx = functions.getFunctionIndex( getFunctionName() ); + } + + /** + * if this call is executed virtual or if is was optimized. + * + * @return true, virtual call + */ + boolean isVirtual() { + return virtualFunctionIdx > 0; + } + + /** + * {@inheritDoc} + */ + @Override + public void writeTo( @Nonnull ModuleWriter writer ) throws IOException { + if( virtualFunctionIdx < 0 ) { + super.writeTo( writer ); + } else { + // duplicate this on the stack + writer.writeLocal( VariableOperator.get, getVariableIndexOfThis() ); + + StructType type = getThisType(); + if( options.useGC() ) { + writer.writeStructOperator( StructOperator.GET, type, new NamedStorageType( type, "", "vtable" ), 0 ); // vtable is ever on position 0 + } else { + writer.writeConst( 0, ValueType.i32 ); // vtable is ever on position 0 + writer.writeFunctionCall( WasmCodeBuilder.GET_I32 ); + } + writer.writeMemoryOperator( MemoryOperator.load, ValueType.i32, virtualFunctionIdx * 4, 2 ); + writer.writeVirtualFunctionCall( getFunctionName(), type ); + } + } +} diff --git a/src/de/inetsoftware/jwebassembly/module/WasmCodeBuilder.java b/src/de/inetsoftware/jwebassembly/module/WasmCodeBuilder.java index 41c7f74..b7cfbda 100644 --- a/src/de/inetsoftware/jwebassembly/module/WasmCodeBuilder.java +++ b/src/de/inetsoftware/jwebassembly/module/WasmCodeBuilder.java @@ -472,6 +472,43 @@ public abstract class WasmCodeBuilder { instructions.add( instruction ); } + /** + * Add indirect call to the instruction. + * + * @param indirectCall + * the instruction + */ + private void addCallIndirectInstruction( WasmCallIndirectInstruction indirectCall ) { + // For access to the vtable the THIS parameter must be duplicated on stack before the function parameters + + // find the instruction that this push on stack + int count = indirectCall.getPopCount(); + int idx = findPushInstruction( count, false ); + WasmInstruction instr = instructions.get( idx ); + int varIndex = -1; + // if it is a GET to a local variable then we can use it + if( instr.getType() == Type.Local ) { + WasmLocalInstruction local1 = (WasmLocalInstruction)instr; + if( local1.getOperator() == VariableOperator.get ) { + varIndex = local1.getIndex(); + } + } + //alternate we need to create a new locale variable + if( varIndex < 0 ) { + int javaCodePos = indirectCall.getCodePosition(); + varIndex = getTempVariable( indirectCall.getThisType(), instr.getCodePosition(), javaCodePos + 1 ); + idx = count == 1 ? instructions.size() : findPushInstruction( count - 1, false ); + instructions.add( idx, new DupThis( indirectCall, varIndex, javaCodePos ) ); + } + indirectCall.setVariableIndexOfThis( varIndex ); + instructions.add( indirectCall ); + if( !options.useGC() ) { + // for later access of the vtable + functions.markAsNeeded( GET_I32 ); + functions.markAsImport( GET_I32, GET_I32.getAnnotation() ); + } + } + /** * Add a virtual/method function call. * @@ -483,28 +520,7 @@ public abstract class WasmCodeBuilder { * the line number in the Java source code */ protected void addCallVirtualInstruction( FunctionName name, int javaCodePos, int lineNumber ) { - WasmCallIndirectInstruction virtualCall = new WasmCallIndirectInstruction( name, javaCodePos, lineNumber, types, options ); - int count = virtualCall.getPopCount(); - int idx = findPushInstruction( count, false ); - WasmInstruction instr = instructions.get( idx ); - int varIndex = -1; - if( instr.getType() == Type.Local ) { - WasmLocalInstruction local1 = (WasmLocalInstruction)instr; - if( local1.getOperator() == VariableOperator.get ) { - varIndex = local1.getIndex(); - } - } - if( varIndex < 0 ) { - varIndex = getTempVariable( virtualCall.getThisType(), instr.getCodePosition(), javaCodePos + 1 ); - idx = count == 1 ? instructions.size() : findPushInstruction( count - 1, false ); - instructions.add( idx, new DupThis( virtualCall, varIndex, javaCodePos ) ); - } - virtualCall.setVariableIndexOfThis( varIndex ); - instructions.add( virtualCall ); - if( !options.useGC() ) { - functions.markAsNeeded( GET_I32 ); - functions.markAsImport( GET_I32, GET_I32.getAnnotation() ); - } + addCallIndirectInstruction( new WasmCallVirtualInstruction( name, javaCodePos, lineNumber, types, options ) ); } /** @@ -517,9 +533,7 @@ public abstract class WasmCodeBuilder { * the line number in the Java source code */ protected void addCallInterfaceInstruction( FunctionName name, int javaCodePos, int lineNumber ) { - WasmCallInterfaceInstruction interfaceCall = new WasmCallInterfaceInstruction( name, javaCodePos, lineNumber, types ); - - instructions.add( interfaceCall ); + addCallIndirectInstruction( new WasmCallInterfaceInstruction( name, javaCodePos, lineNumber, types, options ) ); } /** diff --git a/src/de/inetsoftware/jwebassembly/module/WasmInstruction.java b/src/de/inetsoftware/jwebassembly/module/WasmInstruction.java index f857d55..a2886ba 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, Memory, Block, Numeric, Nop, Call, CallIndirect, CallInterface, Array, Struct, Dup, DupThis; + Const, Convert, Local, Global, Table, Memory, Block, Numeric, Nop, Call, CallVirtual, CallInterface, Array, Struct, Dup, DupThis; } private int javaCodePos;