From 56fdf9018d6a77759a558bac9ec0eb4006b4b71c Mon Sep 17 00:00:00 2001 From: Volker Berlin Date: Sun, 6 Jan 2019 16:29:26 +0100 Subject: [PATCH] write the struct type into the type section --- .../binary/BinaryModuleWriter.java | 15 ++++- .../jwebassembly/binary/FunctionType.java | 16 ++++-- .../module/JavaMethodWasmCodeBuilder.java | 10 ++-- .../jwebassembly/module/ModuleGenerator.java | 45 ++++++++++++++- .../jwebassembly/module/ModuleWriter.java | 17 +++++- .../jwebassembly/module/TypeManager.java | 57 ++++++++----------- .../jwebassembly/module/WasmCodeBuilder.java | 10 ++-- .../module/WasmStructInstruction.java | 29 +++++++--- .../jwebassembly/text/TextModuleWriter.java | 29 +++++++++- 9 files changed, 164 insertions(+), 64 deletions(-) diff --git a/src/de/inetsoftware/jwebassembly/binary/BinaryModuleWriter.java b/src/de/inetsoftware/jwebassembly/binary/BinaryModuleWriter.java index 10260b2..9a7f322 100644 --- a/src/de/inetsoftware/jwebassembly/binary/BinaryModuleWriter.java +++ b/src/de/inetsoftware/jwebassembly/binary/BinaryModuleWriter.java @@ -1,5 +1,5 @@ /* - * Copyright 2017 - 2018 Volker Berlin (i-net software) + * Copyright 2017 - 2019 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. @@ -35,6 +35,7 @@ import de.inetsoftware.jwebassembly.module.FunctionName; import de.inetsoftware.jwebassembly.module.ModuleWriter; import de.inetsoftware.jwebassembly.module.ValueTypeConvertion; import de.inetsoftware.jwebassembly.wasm.ArrayOperator; +import de.inetsoftware.jwebassembly.wasm.NamedStorageType; import de.inetsoftware.jwebassembly.wasm.NumericOperator; import de.inetsoftware.jwebassembly.wasm.StorageType; import de.inetsoftware.jwebassembly.wasm.StructOperator; @@ -58,7 +59,7 @@ public class BinaryModuleWriter extends ModuleWriter implements InstructionOpcod private WasmOutputStream codeStream = new WasmOutputStream(); - private List functionTypes = new ArrayList<>(); + private List functionTypes = new ArrayList<>(); private Map functions = new LinkedHashMap<>(); @@ -226,6 +227,16 @@ public class BinaryModuleWriter extends ModuleWriter implements InstructionOpcod wasm.writeSection( SectionType.Custom, stream ); } + /** + * {@inheritDoc} + */ + @Override + protected int writeStruct( String typeName, List fields ) throws IOException { + int typeId = functionTypes.size(); + functionTypes.add( new StructType( fields ) ); + return typeId; + } + /** * {@inheritDoc} */ diff --git a/src/de/inetsoftware/jwebassembly/binary/FunctionType.java b/src/de/inetsoftware/jwebassembly/binary/FunctionType.java index 8cc298c..bfa8433 100644 --- a/src/de/inetsoftware/jwebassembly/binary/FunctionType.java +++ b/src/de/inetsoftware/jwebassembly/binary/FunctionType.java @@ -1,5 +1,5 @@ /* - * Copyright 2017 - 2018 Volker Berlin (i-net software) + * Copyright 2017 - 2019 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. @@ -18,7 +18,6 @@ package de.inetsoftware.jwebassembly.binary; import java.io.IOException; import java.util.ArrayList; import java.util.List; -import java.util.Objects; import de.inetsoftware.jwebassembly.wasm.ValueType; @@ -27,7 +26,7 @@ import de.inetsoftware.jwebassembly.wasm.ValueType; * * @author Volker Berlin */ -class FunctionType extends SectionEntry { +class FunctionType extends TypeEntry { final List params = new ArrayList<>(); @@ -37,8 +36,15 @@ class FunctionType extends SectionEntry { * {@inheritDoc} */ @Override - void writeSectionEntry( WasmOutputStream stream ) throws IOException { - stream.writeValueType( ValueType.func ); + ValueType getTypeForm() { + return ValueType.func; + } + + /** + * {@inheritDoc} + */ + @Override + void writeSectionEntryDetails( WasmOutputStream stream ) throws IOException { stream.writeVaruint32( this.params.size() ); for( ValueType valueType : this.params ) { stream.writeValueType( valueType ); diff --git a/src/de/inetsoftware/jwebassembly/module/JavaMethodWasmCodeBuilder.java b/src/de/inetsoftware/jwebassembly/module/JavaMethodWasmCodeBuilder.java index a136e1b..62593be 100644 --- a/src/de/inetsoftware/jwebassembly/module/JavaMethodWasmCodeBuilder.java +++ b/src/de/inetsoftware/jwebassembly/module/JavaMethodWasmCodeBuilder.java @@ -1,5 +1,5 @@ /* - * Copyright 2018 Volker Berlin (i-net software) + * Copyright 2018 - 2019 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. @@ -26,10 +26,8 @@ import de.inetsoftware.classparser.ConstantClass; import de.inetsoftware.classparser.ConstantPool; import de.inetsoftware.classparser.ConstantRef; import de.inetsoftware.jwebassembly.WasmException; -import de.inetsoftware.jwebassembly.module.TypeManager.StructType; import de.inetsoftware.jwebassembly.wasm.ArrayOperator; import de.inetsoftware.jwebassembly.wasm.NumericOperator; -import de.inetsoftware.jwebassembly.wasm.StorageType; import de.inetsoftware.jwebassembly.wasm.StructOperator; import de.inetsoftware.jwebassembly.wasm.ValueType; import de.inetsoftware.jwebassembly.wasm.WasmBlockOperator; @@ -92,7 +90,7 @@ class JavaMethodWasmCodeBuilder extends WasmCodeBuilder { case 0: // nop break; case 1: // aconst_null - addStructInstruction( StructOperator.NULL, ValueType.anyref, codePos ); + addStructInstruction( StructOperator.NULL, null, codePos ); break; case 2: // iconst_m1 case 3: // iconst_0 @@ -261,6 +259,7 @@ class JavaMethodWasmCodeBuilder extends WasmCodeBuilder { case anyref: addCallInstruction( new SyntheticMember( "de/inetsoftware/jwebassembly/module/NativeHelperCode", "dup_anyref", "(Ljava.lang.Object;)Ljava.lang.Object;Ljava.lang.Object;" ), codePos ); break OP; + default: } //$FALL-THROUGH$ case 90: // dup_x1 @@ -546,8 +545,7 @@ class JavaMethodWasmCodeBuilder extends WasmCodeBuilder { //TODO case 186: // invokedynamic case 187: // new String name = ((ConstantClass)constantPool.get( byteCode.readUnsignedShort() )).getName(); - StorageType storageType = new StructType(name); - addStructInstruction( StructOperator.NEW_DEFAULT, storageType, codePos ); + addStructInstruction( StructOperator.NEW_DEFAULT, name, codePos ); break; case 188: // newarray int typeValue = byteCode.readByte(); diff --git a/src/de/inetsoftware/jwebassembly/module/ModuleGenerator.java b/src/de/inetsoftware/jwebassembly/module/ModuleGenerator.java index fb4c81c..776dde5 100644 --- a/src/de/inetsoftware/jwebassembly/module/ModuleGenerator.java +++ b/src/de/inetsoftware/jwebassembly/module/ModuleGenerator.java @@ -1,5 +1,5 @@ /* - * Copyright 2017 - 2018 Volker Berlin (i-net software) + * Copyright 2017 - 2019 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. @@ -19,6 +19,7 @@ import java.io.IOException; import java.io.InputStream; import java.net.URL; import java.net.URLClassLoader; +import java.util.ArrayList; import java.util.List; import java.util.Map; import java.util.function.Consumer; @@ -29,10 +30,14 @@ import javax.annotation.Nullable; import de.inetsoftware.classparser.ClassFile; import de.inetsoftware.classparser.Code; import de.inetsoftware.classparser.CodeInputStream; +import de.inetsoftware.classparser.FieldInfo; import de.inetsoftware.classparser.LocalVariableTable; import de.inetsoftware.classparser.MethodInfo; import de.inetsoftware.jwebassembly.JWebAssembly; import de.inetsoftware.jwebassembly.WasmException; +import de.inetsoftware.jwebassembly.module.TypeManager.StructType; +import de.inetsoftware.jwebassembly.wasm.NamedStorageType; +import de.inetsoftware.jwebassembly.wasm.StorageType; import de.inetsoftware.jwebassembly.wasm.ValueType; import de.inetsoftware.jwebassembly.wasm.ValueTypeParser; import de.inetsoftware.jwebassembly.watparser.WatParser; @@ -134,6 +139,41 @@ public class ModuleGenerator { } } + /** + * Set the StructType into the instruction and write the types/structs if needed. + * + * @param instruction + * the struct instruction + * @throws IOException + * if any I/O error occur + */ + private void setStructType( WasmStructInstruction instruction ) throws IOException { + String name = instruction.getTypeName(); + if( name != null ) { + StructType type = types.valueOf( name ); + if( type.getCode() == Integer.MIN_VALUE ) { + String className = name; + InputStream stream = libraries.getResourceAsStream( className + ".class" ); + if( stream == null ) { + throw new WasmException( "Missing class: " + className, -1 ); + } + ClassFile classFile = new ClassFile( stream ); + ArrayList list = new ArrayList<>(); + FieldInfo[] fields = classFile.getFields(); + for( FieldInfo field : fields ) { + if( field.isStatic() ) { + continue; + } + StorageType fieldtype = new ValueTypeParser( field.getType() ).next(); + list.add( new NamedStorageType( fieldtype, field.getName() ) ); + } + int id = writer.writeStruct( className, list ); + types.useType( type, id ); + } + instruction.setType( type ); + } + } + /** * Iterate over all methods of the classFile and run the handler. * @@ -240,7 +280,8 @@ public class ModuleGenerator { functions.functionCall( ((WasmCallInstruction)instruction).getFunctionName() ); break; case Struct: - types.useType( ((WasmStructInstruction)instruction).getStorageType() ); + setStructType( (WasmStructInstruction)instruction ); + break; default: } instruction.writeTo( writer ); diff --git a/src/de/inetsoftware/jwebassembly/module/ModuleWriter.java b/src/de/inetsoftware/jwebassembly/module/ModuleWriter.java index bc6e4dc..0deb980 100644 --- a/src/de/inetsoftware/jwebassembly/module/ModuleWriter.java +++ b/src/de/inetsoftware/jwebassembly/module/ModuleWriter.java @@ -1,5 +1,5 @@ /* - * Copyright 2017 - 2018 Volker Berlin (i-net software) + * Copyright 2017 - 2019 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. @@ -17,12 +17,14 @@ 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.classparser.Member; import de.inetsoftware.jwebassembly.wasm.ArrayOperator; +import de.inetsoftware.jwebassembly.wasm.NamedStorageType; import de.inetsoftware.jwebassembly.wasm.NumericOperator; import de.inetsoftware.jwebassembly.wasm.StorageType; import de.inetsoftware.jwebassembly.wasm.StructOperator; @@ -44,6 +46,19 @@ public abstract class ModuleWriter implements Closeable { } + /** + * Write a type/struct. + * + * @param typeName + * the name + * @param fields + * the fields + * @return type ID + * @throws IOException + * if any I/O error occur + */ + protected abstract int writeStruct( String typeName, List fields ) throws IOException; + /** * Prepare a imported single function in the prepare phase. * diff --git a/src/de/inetsoftware/jwebassembly/module/TypeManager.java b/src/de/inetsoftware/jwebassembly/module/TypeManager.java index bc5cf54..cf25cc5 100644 --- a/src/de/inetsoftware/jwebassembly/module/TypeManager.java +++ b/src/de/inetsoftware/jwebassembly/module/TypeManager.java @@ -1,5 +1,5 @@ /* - Copyright 2018 Volker Berlin (i-net software) + Copyright 2018 - 2019 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. @@ -36,20 +36,13 @@ class TypeManager { /** * Use the type in the output. * - * @param storageType + * @param type * the reference to a type + * @param id + * the id in the type section of the wasm */ - void useType( StorageType storageType ) { - if( storageType instanceof StructType ) { - StructType type = (StructType)storageType; - StructType existingType = map.get( type.name ); - if( existingType == null ) { - type.code = map.size(); - map.put( type.name, type ); - } else { - type.code = existingType.code; - } - } + void useType( StructType type, int id ) { + type.code = id; } /** @@ -62,6 +55,22 @@ class TypeManager { return map.values(); } + /** + * Get the StructType. If needed an instance is created. + * + * @param name + * the type name + * @return the struct type + */ + StructType valueOf( String name ) { + StructType type = map.get( name ); + if( type == null ) { + type = new StructType(); + map.put( name, type ); + } + return type; + } + /** * A reference to a type. * @@ -69,19 +78,7 @@ class TypeManager { */ static class StructType implements StorageType { - private final String name; - - private int code; - - /** - * Create a reference to type - * - * @param name - * the Java class name - */ - StructType( String name ) { - this.name = name; - } + private int code = Integer.MIN_VALUE; /** * {@inheritDoc} @@ -90,13 +87,5 @@ class TypeManager { public int getCode() { return code; } - - /** - * Get the name of the Java type - * @return the name - */ - public String getName() { - return name; - } } } diff --git a/src/de/inetsoftware/jwebassembly/module/WasmCodeBuilder.java b/src/de/inetsoftware/jwebassembly/module/WasmCodeBuilder.java index 008e2be..a3968a7 100644 --- a/src/de/inetsoftware/jwebassembly/module/WasmCodeBuilder.java +++ b/src/de/inetsoftware/jwebassembly/module/WasmCodeBuilder.java @@ -1,5 +1,5 @@ /* - * Copyright 2018 Volker Berlin (i-net software) + * Copyright 2018 - 2019 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. @@ -231,12 +231,12 @@ public abstract class WasmCodeBuilder { * * @param op * the operation - * @param type - * the array type + * @param typeName + * the type name * @param javaCodePos * the code position/offset in the Java method */ - protected void addStructInstruction( StructOperator op, StorageType type, int javaCodePos ) { - instructions.add( new WasmStructInstruction( op, type, javaCodePos ) ); + protected void addStructInstruction( StructOperator op, String typeName, int javaCodePos ) { + instructions.add( new WasmStructInstruction( op, typeName, javaCodePos ) ); } } diff --git a/src/de/inetsoftware/jwebassembly/module/WasmStructInstruction.java b/src/de/inetsoftware/jwebassembly/module/WasmStructInstruction.java index e234b48..4ec93c9 100644 --- a/src/de/inetsoftware/jwebassembly/module/WasmStructInstruction.java +++ b/src/de/inetsoftware/jwebassembly/module/WasmStructInstruction.java @@ -22,6 +22,7 @@ import javax.annotation.Nonnull; import javax.annotation.Nullable; import de.inetsoftware.jwebassembly.WasmException; +import de.inetsoftware.jwebassembly.module.TypeManager.StructType; import de.inetsoftware.jwebassembly.wasm.StorageType; import de.inetsoftware.jwebassembly.wasm.StructOperator; import de.inetsoftware.jwebassembly.wasm.ValueType; @@ -36,31 +37,43 @@ class WasmStructInstruction extends WasmInstruction { private final StructOperator op; - private final StorageType type; + private final String typeName; + + private StorageType type; /** * Create an instance of numeric operation. * * @param op * the struct operation - * @param type - * the type of the parameters + * @param typeName + * the type name of the parameters * @param javaCodePos * the code position/offset in the Java method */ - WasmStructInstruction( @Nullable StructOperator op, @Nullable StorageType type, int javaCodePos ) { + WasmStructInstruction( @Nullable StructOperator op, @Nullable String typeName, int javaCodePos ) { super( javaCodePos ); this.op = op; - this.type = type; + this.typeName = typeName; } /** - * Get the storage type of this instruction. + * Get the type name of this instruction. * * @return the type */ - StorageType getStorageType() { - return type; + String getTypeName() { + return typeName; + } + + /** + * Set the resolved StructType for the typeName + * + * @param type + * the type + */ + void setType( StructType type ) { + this.type = type; } /** diff --git a/src/de/inetsoftware/jwebassembly/text/TextModuleWriter.java b/src/de/inetsoftware/jwebassembly/text/TextModuleWriter.java index ef67269..bb28897 100644 --- a/src/de/inetsoftware/jwebassembly/text/TextModuleWriter.java +++ b/src/de/inetsoftware/jwebassembly/text/TextModuleWriter.java @@ -1,5 +1,5 @@ /* - * Copyright 2017 - 2018 Volker Berlin (i-net software) + * Copyright 2017 - 2019 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. @@ -18,6 +18,7 @@ package de.inetsoftware.jwebassembly.text; import java.io.IOException; import java.util.HashMap; import java.util.HashSet; +import java.util.List; import javax.annotation.Nonnull; import javax.annotation.Nullable; @@ -28,6 +29,7 @@ import de.inetsoftware.jwebassembly.module.FunctionName; import de.inetsoftware.jwebassembly.module.ModuleWriter; import de.inetsoftware.jwebassembly.module.ValueTypeConvertion; import de.inetsoftware.jwebassembly.wasm.ArrayOperator; +import de.inetsoftware.jwebassembly.wasm.NamedStorageType; import de.inetsoftware.jwebassembly.wasm.NumericOperator; import de.inetsoftware.jwebassembly.wasm.StorageType; import de.inetsoftware.jwebassembly.wasm.StructOperator; @@ -82,6 +84,31 @@ public class TextModuleWriter extends ModuleWriter { output.append( ')' ); } + /** + * {@inheritDoc} + */ + @Override + protected int writeStruct( String typeName, List fields ) throws IOException { + int oldInset = inset; + inset = 1; + newline( output ); + output.append( "(type $" ).append( typeName ).append( " (struct" ); + inset++; + for( NamedStorageType field : fields ) { + newline( output ); + output.append( "(field" ); + if( debugNames && field.name != null ) { + output.append( " $" ).append( field.name ); + } + output.append( ' ' ).append( field.type.toString() ).append( ')' ); + } + inset--; + newline( output ); + output.append( "))" ); + inset = oldInset; + return 0; + } + /** * {@inheritDoc} */