From 02696a64881a10c6d2994b7ace2f43807ddb542c Mon Sep 17 00:00:00 2001 From: Volker Berlin Date: Tue, 25 Feb 2020 18:05:12 +0100 Subject: [PATCH] use a synthetic function call to calculate the function id of a virtual call. --- .../jwebassembly/JWebAssembly.java | 2 +- .../binary/BinaryModuleWriter.java | 2 +- .../jwebassembly/module/CodeOptimizer.java | 2 +- .../jwebassembly/module/FunctionManager.java | 2 +- .../jwebassembly/module/ModuleGenerator.java | 1 - .../jwebassembly/module/ModuleWriter.java | 1 - .../jwebassembly/module/StringManager.java | 5 ++-- .../jwebassembly/module/TypeManager.java | 25 ++++++++++++++-- .../module/WasmCallInterfaceInstruction.java | 5 ---- .../module/WasmCallVirtualInstruction.java | 10 ++----- .../jwebassembly/module/WasmCodeBuilder.java | 4 +-- .../{wasm => module}/WasmOptions.java | 29 +++++++++++++++---- .../jwebassembly/text/TextModuleWriter.java | 2 +- .../jwebassembly/watparser/WatParser.java | 22 ++++++++++++++ .../jwebassembly/module/WatParserTest.java | 1 - 15 files changed, 79 insertions(+), 34 deletions(-) rename src/de/inetsoftware/jwebassembly/{wasm => module}/WasmOptions.java (79%) diff --git a/src/de/inetsoftware/jwebassembly/JWebAssembly.java b/src/de/inetsoftware/jwebassembly/JWebAssembly.java index ed969dd..537c81f 100644 --- a/src/de/inetsoftware/jwebassembly/JWebAssembly.java +++ b/src/de/inetsoftware/jwebassembly/JWebAssembly.java @@ -40,9 +40,9 @@ import de.inetsoftware.classparser.ClassFile; import de.inetsoftware.jwebassembly.binary.BinaryModuleWriter; import de.inetsoftware.jwebassembly.module.ModuleGenerator; import de.inetsoftware.jwebassembly.module.ModuleWriter; +import de.inetsoftware.jwebassembly.module.WasmOptions; import de.inetsoftware.jwebassembly.module.WasmTarget; import de.inetsoftware.jwebassembly.text.TextModuleWriter; -import de.inetsoftware.jwebassembly.wasm.WasmOptions; /** * The main class of the compiler. diff --git a/src/de/inetsoftware/jwebassembly/binary/BinaryModuleWriter.java b/src/de/inetsoftware/jwebassembly/binary/BinaryModuleWriter.java index 30ed2cc..3b04c45 100644 --- a/src/de/inetsoftware/jwebassembly/binary/BinaryModuleWriter.java +++ b/src/de/inetsoftware/jwebassembly/binary/BinaryModuleWriter.java @@ -32,6 +32,7 @@ import de.inetsoftware.jwebassembly.module.FunctionName; import de.inetsoftware.jwebassembly.module.ModuleWriter; import de.inetsoftware.jwebassembly.module.TypeManager.StructType; import de.inetsoftware.jwebassembly.module.ValueTypeConvertion; +import de.inetsoftware.jwebassembly.module.WasmOptions; import de.inetsoftware.jwebassembly.module.WasmTarget; import de.inetsoftware.jwebassembly.sourcemap.SourceMapWriter; import de.inetsoftware.jwebassembly.sourcemap.SourceMapping; @@ -44,7 +45,6 @@ import de.inetsoftware.jwebassembly.wasm.StructOperator; import de.inetsoftware.jwebassembly.wasm.ValueType; import de.inetsoftware.jwebassembly.wasm.VariableOperator; import de.inetsoftware.jwebassembly.wasm.WasmBlockOperator; -import de.inetsoftware.jwebassembly.wasm.WasmOptions; /** * Module Writer for binary format. http://webassembly.org/docs/binary-encoding/ diff --git a/src/de/inetsoftware/jwebassembly/module/CodeOptimizer.java b/src/de/inetsoftware/jwebassembly/module/CodeOptimizer.java index 3227361..0b46606 100644 --- a/src/de/inetsoftware/jwebassembly/module/CodeOptimizer.java +++ b/src/de/inetsoftware/jwebassembly/module/CodeOptimizer.java @@ -25,7 +25,7 @@ import de.inetsoftware.jwebassembly.wasm.VariableOperator; * * @author Volker Berlin */ -public class CodeOptimizer { +class CodeOptimizer { /** * Optimize the code before writing. diff --git a/src/de/inetsoftware/jwebassembly/module/FunctionManager.java b/src/de/inetsoftware/jwebassembly/module/FunctionManager.java index 2070efb..8b6306e 100644 --- a/src/de/inetsoftware/jwebassembly/module/FunctionManager.java +++ b/src/de/inetsoftware/jwebassembly/module/FunctionManager.java @@ -34,7 +34,7 @@ import de.inetsoftware.jwebassembly.WasmException; * * @author Volker Berlin */ -public class FunctionManager { +class FunctionManager { private final Map states = new LinkedHashMap<>(); diff --git a/src/de/inetsoftware/jwebassembly/module/ModuleGenerator.java b/src/de/inetsoftware/jwebassembly/module/ModuleGenerator.java index b03611c..2136ff2 100644 --- a/src/de/inetsoftware/jwebassembly/module/ModuleGenerator.java +++ b/src/de/inetsoftware/jwebassembly/module/ModuleGenerator.java @@ -46,7 +46,6 @@ import de.inetsoftware.jwebassembly.wasm.AnyType; import de.inetsoftware.jwebassembly.wasm.NamedStorageType; import de.inetsoftware.jwebassembly.wasm.StructOperator; import de.inetsoftware.jwebassembly.wasm.ValueType; -import de.inetsoftware.jwebassembly.wasm.WasmOptions; import de.inetsoftware.jwebassembly.watparser.WatParser; /** diff --git a/src/de/inetsoftware/jwebassembly/module/ModuleWriter.java b/src/de/inetsoftware/jwebassembly/module/ModuleWriter.java index 77d003d..8364794 100644 --- a/src/de/inetsoftware/jwebassembly/module/ModuleWriter.java +++ b/src/de/inetsoftware/jwebassembly/module/ModuleWriter.java @@ -33,7 +33,6 @@ import de.inetsoftware.jwebassembly.wasm.StructOperator; import de.inetsoftware.jwebassembly.wasm.ValueType; import de.inetsoftware.jwebassembly.wasm.VariableOperator; import de.inetsoftware.jwebassembly.wasm.WasmBlockOperator; -import de.inetsoftware.jwebassembly.wasm.WasmOptions; /** * Module Writer base class. diff --git a/src/de/inetsoftware/jwebassembly/module/StringManager.java b/src/de/inetsoftware/jwebassembly/module/StringManager.java index 9011423..0f3a82e 100644 --- a/src/de/inetsoftware/jwebassembly/module/StringManager.java +++ b/src/de/inetsoftware/jwebassembly/module/StringManager.java @@ -27,14 +27,13 @@ import javax.annotation.Nonnull; import de.inetsoftware.jwebassembly.api.annotation.WasmTextCode; import de.inetsoftware.jwebassembly.wasm.ValueType; -import de.inetsoftware.jwebassembly.wasm.WasmOptions; /** * Handle all the constant strings. The constant strings will be write into the data section. * * @author Volker Berlin */ -public class StringManager extends LinkedHashMap { +class StringManager extends LinkedHashMap { /** * Signature of method stringConstant. @@ -54,7 +53,7 @@ public class StringManager extends LinkedHashMap { * @param options * compiler properties and shared managers */ - public StringManager( WasmOptions options ) { + StringManager( WasmOptions options ) { this.functions = options.functions; } diff --git a/src/de/inetsoftware/jwebassembly/module/TypeManager.java b/src/de/inetsoftware/jwebassembly/module/TypeManager.java index 1414f4e..2740394c 100644 --- a/src/de/inetsoftware/jwebassembly/module/TypeManager.java +++ b/src/de/inetsoftware/jwebassembly/module/TypeManager.java @@ -23,6 +23,8 @@ import java.util.LinkedHashMap; import java.util.List; import java.util.Map; +import javax.annotation.Nonnull; + import de.inetsoftware.classparser.ClassFile; import de.inetsoftware.classparser.ClassFile.Type; import de.inetsoftware.classparser.ConstantClass; @@ -34,7 +36,6 @@ import de.inetsoftware.jwebassembly.wasm.AnyType; import de.inetsoftware.jwebassembly.wasm.ArrayType; import de.inetsoftware.jwebassembly.wasm.NamedStorageType; import de.inetsoftware.jwebassembly.wasm.ValueType; -import de.inetsoftware.jwebassembly.wasm.WasmOptions; /** * Manage the written and to write types (classes) @@ -60,7 +61,7 @@ public class TypeManager { * @param options * compiler properties */ - public TypeManager( WasmOptions options ) { + TypeManager( WasmOptions options ) { this.options = options; } @@ -87,7 +88,7 @@ public class TypeManager { * Get the StructType. If needed an instance is created. * * @param name - * the type name + * the type name like java/lang/Object * @return the struct type */ public StructType valueOf( String name ) { @@ -123,6 +124,24 @@ public class TypeManager { return type; } + /** + * Get the FunctionName for a virtual call and mark it as used. The function has 2 parameters (THIS, + * virtualfunctionIndex) and returns the index of the function. + * + * @return the name + */ + @Nonnull + WatCodeSyntheticFunctionName getCallVirtualGC() { + return new WatCodeSyntheticFunctionName( // + "callVirtual", "local.get 0 " // THIS + + "struct.get java/lang/Object .vtable " // vtable is on index 0 + + "local.get 1 " // virtualFunctionIndex + + "i32.add " // + + "i32.load offset=0 align=4 " // + + "return " // + , valueOf( "java/lang/Object" ), ValueType.i32, null, ValueType.i32 ); // + } + /** * A reference to a type. * diff --git a/src/de/inetsoftware/jwebassembly/module/WasmCallInterfaceInstruction.java b/src/de/inetsoftware/jwebassembly/module/WasmCallInterfaceInstruction.java index 209de5e..0d7283d 100644 --- a/src/de/inetsoftware/jwebassembly/module/WasmCallInterfaceInstruction.java +++ b/src/de/inetsoftware/jwebassembly/module/WasmCallInterfaceInstruction.java @@ -22,12 +22,7 @@ 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. diff --git a/src/de/inetsoftware/jwebassembly/module/WasmCallVirtualInstruction.java b/src/de/inetsoftware/jwebassembly/module/WasmCallVirtualInstruction.java index 7510f1d..b940376 100644 --- a/src/de/inetsoftware/jwebassembly/module/WasmCallVirtualInstruction.java +++ b/src/de/inetsoftware/jwebassembly/module/WasmCallVirtualInstruction.java @@ -26,7 +26,6 @@ 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. @@ -96,14 +95,9 @@ class WasmCallVirtualInstruction extends WasmCallIndirectInstruction { // duplicate this on the stack writer.writeLocal( VariableOperator.get, getVariableIndexOfThis() ); + writer.writeConst( virtualFunctionIdx * 4, ValueType.i32 ); + writer.writeFunctionCall( options.getCallVirtual() ); 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 8a4940e..ed864ad 100644 --- a/src/de/inetsoftware/jwebassembly/module/WasmCodeBuilder.java +++ b/src/de/inetsoftware/jwebassembly/module/WasmCodeBuilder.java @@ -44,7 +44,6 @@ import de.inetsoftware.jwebassembly.wasm.ValueType; import de.inetsoftware.jwebassembly.wasm.ValueTypeParser; import de.inetsoftware.jwebassembly.wasm.VariableOperator; import de.inetsoftware.jwebassembly.wasm.WasmBlockOperator; -import de.inetsoftware.jwebassembly.wasm.WasmOptions; /** * Base class for Code Building. @@ -517,6 +516,7 @@ public abstract class WasmCodeBuilder { */ protected void addCallVirtualInstruction( FunctionName name, int javaCodePos, int lineNumber ) { addCallIndirectInstruction( new WasmCallVirtualInstruction( name, javaCodePos, lineNumber, types, options ) ); + options.getCallVirtual(); // mark the function as needed } /** @@ -629,7 +629,7 @@ public abstract class WasmCodeBuilder { } /** - * Add an array operation to the instruction list as marker on the code position. + * Add a struct/object operation to the instruction list. * * @param op * the operation diff --git a/src/de/inetsoftware/jwebassembly/wasm/WasmOptions.java b/src/de/inetsoftware/jwebassembly/module/WasmOptions.java similarity index 79% rename from src/de/inetsoftware/jwebassembly/wasm/WasmOptions.java rename to src/de/inetsoftware/jwebassembly/module/WasmOptions.java index b1fd089..be90bef 100644 --- a/src/de/inetsoftware/jwebassembly/wasm/WasmOptions.java +++ b/src/de/inetsoftware/jwebassembly/module/WasmOptions.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package de.inetsoftware.jwebassembly.wasm; +package de.inetsoftware.jwebassembly.module; import java.util.HashMap; @@ -33,13 +33,13 @@ import de.inetsoftware.jwebassembly.module.TypeManager; */ public class WasmOptions { - public final FunctionManager functions = new FunctionManager(); + final FunctionManager functions = new FunctionManager(); - public final TypeManager types = new TypeManager( this ); + final TypeManager types = new TypeManager( this ); - public final StringManager strings = new StringManager( this ); + final StringManager strings = new StringManager( this ); - public final CodeOptimizer optimizer = new CodeOptimizer(); + final CodeOptimizer optimizer = new CodeOptimizer(); private final boolean debugNames; @@ -55,6 +55,9 @@ public class WasmOptions { */ public FunctionName ref_eq; + + private FunctionName callVirtual; + /** * Create a new instance of options * @@ -108,4 +111,20 @@ public class WasmOptions { public String getSourceMapBase() { return sourceMapBase; } + + /** + * Get the FunctionName for a virtual call and mark it as used. The function has 2 parameters (THIS, + * virtualfunctionIndex) and returns the index of the function. + * + * @return the name + */ + @Nonnull + FunctionName getCallVirtual() { + FunctionName name = callVirtual; + if( name == null ) { + callVirtual = name = types.getCallVirtualGC(); + functions.markAsNeeded( name ); + } + return name; + } } diff --git a/src/de/inetsoftware/jwebassembly/text/TextModuleWriter.java b/src/de/inetsoftware/jwebassembly/text/TextModuleWriter.java index 446d647..2db22dd 100644 --- a/src/de/inetsoftware/jwebassembly/text/TextModuleWriter.java +++ b/src/de/inetsoftware/jwebassembly/text/TextModuleWriter.java @@ -33,6 +33,7 @@ import de.inetsoftware.jwebassembly.module.FunctionName; import de.inetsoftware.jwebassembly.module.ModuleWriter; import de.inetsoftware.jwebassembly.module.TypeManager.StructType; import de.inetsoftware.jwebassembly.module.ValueTypeConvertion; +import de.inetsoftware.jwebassembly.module.WasmOptions; import de.inetsoftware.jwebassembly.module.WasmTarget; import de.inetsoftware.jwebassembly.wasm.AnyType; import de.inetsoftware.jwebassembly.wasm.ArrayOperator; @@ -43,7 +44,6 @@ import de.inetsoftware.jwebassembly.wasm.StructOperator; import de.inetsoftware.jwebassembly.wasm.ValueType; import de.inetsoftware.jwebassembly.wasm.VariableOperator; import de.inetsoftware.jwebassembly.wasm.WasmBlockOperator; -import de.inetsoftware.jwebassembly.wasm.WasmOptions; /** * Module Writer for text format with S-expressions. diff --git a/src/de/inetsoftware/jwebassembly/watparser/WatParser.java b/src/de/inetsoftware/jwebassembly/watparser/WatParser.java index a75cdd7..a3f2e22 100644 --- a/src/de/inetsoftware/jwebassembly/watparser/WatParser.java +++ b/src/de/inetsoftware/jwebassembly/watparser/WatParser.java @@ -28,8 +28,12 @@ import de.inetsoftware.jwebassembly.WasmException; import de.inetsoftware.jwebassembly.module.FunctionName; import de.inetsoftware.jwebassembly.module.ValueTypeConvertion; import de.inetsoftware.jwebassembly.module.WasmCodeBuilder; +import de.inetsoftware.jwebassembly.module.TypeManager.StructType; +import de.inetsoftware.jwebassembly.wasm.AnyType; import de.inetsoftware.jwebassembly.wasm.MemoryOperator; +import de.inetsoftware.jwebassembly.wasm.NamedStorageType; import de.inetsoftware.jwebassembly.wasm.NumericOperator; +import de.inetsoftware.jwebassembly.wasm.StructOperator; import de.inetsoftware.jwebassembly.wasm.ValueType; import de.inetsoftware.jwebassembly.wasm.VariableOperator; import de.inetsoftware.jwebassembly.wasm.WasmBlockOperator; @@ -246,6 +250,24 @@ public class WatParser extends WasmCodeBuilder { case "i32.load8_u": i = addMemoryInstruction( MemoryOperator.load8_u, ValueType.i32, tokens, i, lineNumber ); break; + case "struct.get": + String typeName = get( tokens, ++i ); + String fieldName = get( tokens, ++i ); + NamedStorageType fieldNameType = null; + List fields = getTypeManager().valueOf( typeName ).getFields(); + if( fields != null ) { // field is null on prepare + for( NamedStorageType namedStorageType : fields ) { + if( namedStorageType.getName().equals( fieldName ) ) { + fieldNameType = namedStorageType; + break; + } + } + } + if( fieldNameType == null ) { + fieldNameType = new NamedStorageType( ValueType.anyref, "", fieldName ); + } + addStructInstruction( StructOperator.GET, typeName, fieldNameType, javaCodePos, lineNumber ); + break; default: throw new WasmException( "Unknown WASM token: " + tok, lineNumber ); } diff --git a/test/de/inetsoftware/jwebassembly/module/WatParserTest.java b/test/de/inetsoftware/jwebassembly/module/WatParserTest.java index 8005f8b..c8c55cc 100644 --- a/test/de/inetsoftware/jwebassembly/module/WatParserTest.java +++ b/test/de/inetsoftware/jwebassembly/module/WatParserTest.java @@ -28,7 +28,6 @@ import org.junit.Test; import de.inetsoftware.jwebassembly.WasmException; import de.inetsoftware.jwebassembly.binary.BinaryModuleWriter; import de.inetsoftware.jwebassembly.text.TextModuleWriter; -import de.inetsoftware.jwebassembly.wasm.WasmOptions; import de.inetsoftware.jwebassembly.watparser.WatParser; /**