write the vtable of objects to the data section. Use the vtable offset into the data section in the new operation of objects.

This commit is contained in:
Volker Berlin 2019-06-09 17:17:47 +02:00
parent 6da4a93918
commit 1ee77584d9
5 changed files with 90 additions and 25 deletions

View File

@ -31,6 +31,7 @@ import javax.annotation.Nullable;
import de.inetsoftware.jwebassembly.JWebAssembly; import de.inetsoftware.jwebassembly.JWebAssembly;
import de.inetsoftware.jwebassembly.module.FunctionName; import de.inetsoftware.jwebassembly.module.FunctionName;
import de.inetsoftware.jwebassembly.module.ModuleWriter; import de.inetsoftware.jwebassembly.module.ModuleWriter;
import de.inetsoftware.jwebassembly.module.TypeManager.StructType;
import de.inetsoftware.jwebassembly.module.ValueTypeConvertion; import de.inetsoftware.jwebassembly.module.ValueTypeConvertion;
import de.inetsoftware.jwebassembly.module.WasmTarget; import de.inetsoftware.jwebassembly.module.WasmTarget;
import de.inetsoftware.jwebassembly.sourcemap.SourceMapWriter; import de.inetsoftware.jwebassembly.sourcemap.SourceMapWriter;
@ -442,9 +443,19 @@ public class BinaryModuleWriter extends ModuleWriter implements InstructionOpcod
* {@inheritDoc} * {@inheritDoc}
*/ */
@Override @Override
protected int writeStruct( String typeName, List<NamedStorageType> 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(); int typeId = functionTypes.size();
functionTypes.add( new StructTypeEntry( fields ) ); functionTypes.add( new StructTypeEntry( type.getFields() ) );
return typeId; return typeId;
} }

View File

@ -443,9 +443,14 @@ public class ModuleGenerator {
case Struct: case Struct:
WasmStructInstruction instr = (WasmStructInstruction)instruction; WasmStructInstruction instr = (WasmStructInstruction)instruction;
if( instr.getOperator() == StructOperator.NEW_DEFAULT ) { if( instr.getOperator() == StructOperator.NEW_DEFAULT ) {
List<NamedStorageType> list = instr.getStructType().getFields(); StructType structType = instr.getStructType();
List<NamedStorageType> list = structType.getFields();
for( NamedStorageType storageType : list ) { 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; break;

View File

@ -17,11 +17,11 @@ package de.inetsoftware.jwebassembly.module;
import java.io.Closeable; import java.io.Closeable;
import java.io.IOException; import java.io.IOException;
import java.util.List;
import javax.annotation.Nonnull; import javax.annotation.Nonnull;
import javax.annotation.Nullable; import javax.annotation.Nullable;
import de.inetsoftware.jwebassembly.module.TypeManager.StructType;
import de.inetsoftware.jwebassembly.wasm.AnyType; import de.inetsoftware.jwebassembly.wasm.AnyType;
import de.inetsoftware.jwebassembly.wasm.ArrayOperator; import de.inetsoftware.jwebassembly.wasm.ArrayOperator;
import de.inetsoftware.jwebassembly.wasm.NamedStorageType; import de.inetsoftware.jwebassembly.wasm.NamedStorageType;
@ -47,15 +47,13 @@ public abstract class ModuleWriter implements Closeable {
/** /**
* Write a type/struct. * Write a type/struct.
* *
* @param typeName * @param type
* the name * the type to declare/write
* @param fields
* the fields
* @return type ID * @return type ID
* @throws IOException * @throws IOException
* if any I/O error occur * if any I/O error occur
*/ */
protected abstract int writeStruct( String typeName, List<NamedStorageType> fields ) throws IOException; protected abstract int writeStructType( StructType type ) throws IOException;
/** /**
* Mark to write exceptions * Mark to write exceptions

View File

@ -42,8 +42,9 @@ import de.inetsoftware.jwebassembly.wasm.ValueType;
*/ */
public class TypeManager { public class TypeManager {
private Map<String, StructType> map = new LinkedHashMap<>(); static final String VTABLE = ".vtable";
private Map<String, StructType> map = new LinkedHashMap<>();
/** /**
* Finish the prepare and write the types. Now no new types and functions should be added. * 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 * @author Volker Berlin
*/ */
static class StructType implements AnyType { public static class StructType implements AnyType {
private final String name; private final String name;
@ -118,7 +119,12 @@ public class TypeManager {
private List<NamedStorageType> fields; private List<NamedStorageType> fields;
private List<String> methods; private List<FunctionName> methods;
/**
* The offset to the vtable in the data section.
*/
private int vtableOffset;
/** /**
* Create a reference to type * Create a reference to type
@ -148,7 +154,7 @@ public class TypeManager {
fields = new ArrayList<>(); fields = new ArrayList<>();
methods = new ArrayList<>(); methods = new ArrayList<>();
listStructFields( name, functions, types, libraries ); 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(); String superClassName = superClass.getName();
listStructFields( superClassName, functions, types, libraries ); listStructFields( superClassName, functions, types, libraries );
} else { } else {
fields.add( new NamedStorageType( ValueType.i32, className, ".vtable" ) ); fields.add( new NamedStorageType( ValueType.i32, className, VTABLE ) );
} }
for( FieldInfo field : classFile.getFields() ) { for( FieldInfo field : classFile.getFields() ) {
@ -187,16 +193,23 @@ public class TypeManager {
} }
for( MethodInfo method : classFile.getMethods() ) { for( MethodInfo method : classFile.getMethods() ) {
if( method.isStatic() ) { if( method.isStatic() || "<init>".equals( method.getName() ) ) {
continue; continue;
} }
FunctionName funcName = new FunctionName( method ); FunctionName funcName = new FunctionName( method );
if( functions.needToWrite( funcName ) ) { if( functions.needToWrite( funcName ) ) {
String signature = funcName.methodName + funcName.signature; int idx = 0;
int idx = methods.indexOf( signature ); // search if the method is already in our list
if( idx < 0 ) { for( ; idx < methods.size(); idx++ ) {
idx = methods.size(); FunctionName func = methods.get( idx );
methods.add( signature ); 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 ); functions.setFunctionIndex( funcName, idx );
} }
@ -227,6 +240,34 @@ public class TypeManager {
return fields; return fields;
} }
/**
* Get the virtual function/methods
*
* @return the methods
*/
public List<FunctionName> 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} * {@inheritDoc}
*/ */

View File

@ -21,7 +21,6 @@ import java.util.ArrayList;
import java.util.HashMap; import java.util.HashMap;
import java.util.HashSet; import java.util.HashSet;
import java.util.LinkedHashMap; import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map; import java.util.Map;
import javax.annotation.Nonnull; import javax.annotation.Nonnull;
@ -31,6 +30,7 @@ import de.inetsoftware.jwebassembly.JWebAssembly;
import de.inetsoftware.jwebassembly.WasmException; import de.inetsoftware.jwebassembly.WasmException;
import de.inetsoftware.jwebassembly.module.FunctionName; import de.inetsoftware.jwebassembly.module.FunctionName;
import de.inetsoftware.jwebassembly.module.ModuleWriter; import de.inetsoftware.jwebassembly.module.ModuleWriter;
import de.inetsoftware.jwebassembly.module.TypeManager.StructType;
import de.inetsoftware.jwebassembly.module.ValueTypeConvertion; import de.inetsoftware.jwebassembly.module.ValueTypeConvertion;
import de.inetsoftware.jwebassembly.wasm.AnyType; import de.inetsoftware.jwebassembly.wasm.AnyType;
import de.inetsoftware.jwebassembly.wasm.ArrayOperator; import de.inetsoftware.jwebassembly.wasm.ArrayOperator;
@ -148,14 +148,24 @@ public class TextModuleWriter extends ModuleWriter {
* {@inheritDoc} * {@inheritDoc}
*/ */
@Override @Override
protected int writeStruct( String typeName, List<NamedStorageType> 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; int oldInset = inset;
inset = 1; inset = 1;
newline( output ); newline( output );
typeName = normalizeName( typeName ); String typeName = normalizeName( type.getName() );
output.append( "(type $" ).append( typeName ).append( " (struct" ); output.append( "(type $" ).append( typeName ).append( " (struct" );
inset++; inset++;
for( NamedStorageType field : fields ) { for( NamedStorageType field : type.getFields() ) {
newline( output ); newline( output );
output.append( "(field" ); output.append( "(field" );
if( debugNames && field.getName() != null ) { if( debugNames && field.getName() != null ) {