From 1ee77584d9a6b97106288d3cb5f55ee5b4ffbd06 Mon Sep 17 00:00:00 2001 From: Volker Berlin Date: Sun, 9 Jun 2019 17:17:47 +0200 Subject: [PATCH] write the vtable of objects to the data section. Use the vtable offset into the data section in the new operation of objects. --- .../binary/BinaryModuleWriter.java | 15 ++++- .../jwebassembly/module/ModuleGenerator.java | 9 ++- .../jwebassembly/module/ModuleWriter.java | 10 ++- .../jwebassembly/module/TypeManager.java | 63 +++++++++++++++---- .../jwebassembly/text/TextModuleWriter.java | 18 ++++-- 5 files changed, 90 insertions(+), 25 deletions(-) diff --git a/src/de/inetsoftware/jwebassembly/binary/BinaryModuleWriter.java b/src/de/inetsoftware/jwebassembly/binary/BinaryModuleWriter.java index 83c9956..a77884f 100644 --- a/src/de/inetsoftware/jwebassembly/binary/BinaryModuleWriter.java +++ b/src/de/inetsoftware/jwebassembly/binary/BinaryModuleWriter.java @@ -31,6 +31,7 @@ import javax.annotation.Nullable; import de.inetsoftware.jwebassembly.JWebAssembly; 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.WasmTarget; import de.inetsoftware.jwebassembly.sourcemap.SourceMapWriter; @@ -442,9 +443,19 @@ public class BinaryModuleWriter extends ModuleWriter implements InstructionOpcod * {@inheritDoc} */ @Override - protected int writeStruct( String typeName, List fields ) throws IOException { + protected int writeStructType( StructType type ) throws IOException { + type.setVTable( dataStream.size() ); + for( FunctionName funcName : type.getMethods() ) { + int functIdx = getFunction( funcName ).id; + // little-endian byte order + dataStream.write( functIdx >>> 0 ); + dataStream.write( functIdx >>> 8 ); + dataStream.write( functIdx >>> 16 ); + dataStream.write( functIdx >>> 24 ); + } + int typeId = functionTypes.size(); - functionTypes.add( new StructTypeEntry( fields ) ); + functionTypes.add( new StructTypeEntry( type.getFields() ) ); return typeId; } diff --git a/src/de/inetsoftware/jwebassembly/module/ModuleGenerator.java b/src/de/inetsoftware/jwebassembly/module/ModuleGenerator.java index 3e808f4..8bddf45 100644 --- a/src/de/inetsoftware/jwebassembly/module/ModuleGenerator.java +++ b/src/de/inetsoftware/jwebassembly/module/ModuleGenerator.java @@ -443,9 +443,14 @@ public class ModuleGenerator { case Struct: WasmStructInstruction instr = (WasmStructInstruction)instruction; if( instr.getOperator() == StructOperator.NEW_DEFAULT ) { - List list = instr.getStructType().getFields(); + StructType structType = instr.getStructType(); + List list = structType.getFields(); for( NamedStorageType storageType : list ) { - writer.writeDefaultValue( storageType.getType() ); + if( TypeManager.VTABLE == storageType.getName() ) { + writer.writeConst( structType.getVTable(), ValueType.i32 ); + } else { + writer.writeDefaultValue( storageType.getType() ); + } } } break; diff --git a/src/de/inetsoftware/jwebassembly/module/ModuleWriter.java b/src/de/inetsoftware/jwebassembly/module/ModuleWriter.java index f5ec237..9cf56d1 100644 --- a/src/de/inetsoftware/jwebassembly/module/ModuleWriter.java +++ b/src/de/inetsoftware/jwebassembly/module/ModuleWriter.java @@ -17,11 +17,11 @@ package de.inetsoftware.jwebassembly.module; import java.io.Closeable; import java.io.IOException; -import java.util.List; import javax.annotation.Nonnull; import javax.annotation.Nullable; +import de.inetsoftware.jwebassembly.module.TypeManager.StructType; import de.inetsoftware.jwebassembly.wasm.AnyType; import de.inetsoftware.jwebassembly.wasm.ArrayOperator; import de.inetsoftware.jwebassembly.wasm.NamedStorageType; @@ -47,15 +47,13 @@ public abstract class ModuleWriter implements Closeable { /** * Write a type/struct. * - * @param typeName - * the name - * @param fields - * the fields + * @param type + * the type to declare/write * @return type ID * @throws IOException * if any I/O error occur */ - protected abstract int writeStruct( String typeName, List fields ) throws IOException; + protected abstract int writeStructType( StructType type ) throws IOException; /** * Mark to write exceptions diff --git a/src/de/inetsoftware/jwebassembly/module/TypeManager.java b/src/de/inetsoftware/jwebassembly/module/TypeManager.java index 4553502..af39216 100644 --- a/src/de/inetsoftware/jwebassembly/module/TypeManager.java +++ b/src/de/inetsoftware/jwebassembly/module/TypeManager.java @@ -42,8 +42,9 @@ import de.inetsoftware.jwebassembly.wasm.ValueType; */ public class TypeManager { - private Map map = new LinkedHashMap<>(); + static final String VTABLE = ".vtable"; + private Map map = new LinkedHashMap<>(); /** * Finish the prepare and write the types. Now no new types and functions should be added. @@ -110,7 +111,7 @@ public class TypeManager { * * @author Volker Berlin */ - static class StructType implements AnyType { + public static class StructType implements AnyType { private final String name; @@ -118,7 +119,12 @@ public class TypeManager { private List fields; - private List methods; + private List methods; + + /** + * The offset to the vtable in the data section. + */ + private int vtableOffset; /** * Create a reference to type @@ -148,7 +154,7 @@ public class TypeManager { fields = new ArrayList<>(); methods = new ArrayList<>(); listStructFields( name, functions, types, libraries ); - code = writer.writeStruct( name, fields ); + code = writer.writeStructType( this ); } /** @@ -176,7 +182,7 @@ public class TypeManager { String superClassName = superClass.getName(); listStructFields( superClassName, functions, types, libraries ); } else { - fields.add( new NamedStorageType( ValueType.i32, className, ".vtable" ) ); + fields.add( new NamedStorageType( ValueType.i32, className, VTABLE ) ); } for( FieldInfo field : classFile.getFields() ) { @@ -187,16 +193,23 @@ public class TypeManager { } for( MethodInfo method : classFile.getMethods() ) { - if( method.isStatic() ) { + if( method.isStatic() || "".equals( method.getName() ) ) { continue; } FunctionName funcName = new FunctionName( method ); if( functions.needToWrite( funcName ) ) { - String signature = funcName.methodName + funcName.signature; - int idx = methods.indexOf( signature ); - if( idx < 0 ) { - idx = methods.size(); - methods.add( signature ); + int idx = 0; + // search if the method is already in our list + for( ; idx < methods.size(); idx++ ) { + FunctionName func = methods.get( idx ); + if( func.methodName.equals( funcName.methodName ) && func.signature.equals( funcName.signature ) ) { + methods.set( idx, funcName ); // use the override method + break; + } + } + if( idx == methods.size() ) { + // if a new method + methods.add( funcName ); } functions.setFunctionIndex( funcName, idx ); } @@ -227,6 +240,34 @@ public class TypeManager { return fields; } + /** + * Get the virtual function/methods + * + * @return the methods + */ + public List getMethods() { + return methods; + } + + /** + * Set the offset of the vtable in the data section + * + * @param vtableOffset + * the offset + */ + public void setVTable( int vtableOffset ) { + this.vtableOffset = vtableOffset; + } + + /** + * Get the vtable offset. + * + * @return the offset + */ + public int getVTable() { + return this.vtableOffset; + } + /** * {@inheritDoc} */ diff --git a/src/de/inetsoftware/jwebassembly/text/TextModuleWriter.java b/src/de/inetsoftware/jwebassembly/text/TextModuleWriter.java index f02278b..c52ff3b 100644 --- a/src/de/inetsoftware/jwebassembly/text/TextModuleWriter.java +++ b/src/de/inetsoftware/jwebassembly/text/TextModuleWriter.java @@ -21,7 +21,6 @@ import java.util.ArrayList; import java.util.HashMap; import java.util.HashSet; import java.util.LinkedHashMap; -import java.util.List; import java.util.Map; import javax.annotation.Nonnull; @@ -31,6 +30,7 @@ import de.inetsoftware.jwebassembly.JWebAssembly; import de.inetsoftware.jwebassembly.WasmException; 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.wasm.AnyType; import de.inetsoftware.jwebassembly.wasm.ArrayOperator; @@ -148,14 +148,24 @@ public class TextModuleWriter extends ModuleWriter { * {@inheritDoc} */ @Override - protected int writeStruct( String typeName, List fields ) throws IOException { + protected int writeStructType( StructType type ) throws IOException { + type.setVTable( dataStream.size() ); + for( FunctionName funcName : type.getMethods() ) { + int functIdx = functions.get( funcName.signatureName ); + // little-endian byte order + dataStream.write( functIdx >>> 0 ); + dataStream.write( functIdx >>> 8 ); + dataStream.write( functIdx >>> 16 ); + dataStream.write( functIdx >>> 24 ); + } + int oldInset = inset; inset = 1; newline( output ); - typeName = normalizeName( typeName ); + String typeName = normalizeName( type.getName() ); output.append( "(type $" ).append( typeName ).append( " (struct" ); inset++; - for( NamedStorageType field : fields ) { + for( NamedStorageType field : type.getFields() ) { newline( output ); output.append( "(field" ); if( debugNames && field.getName() != null ) {