From 9ac92316f6cb30b73b9ecafa006192727206384f Mon Sep 17 00:00:00 2001
From: Volker Berlin <volker.berlin@googlemail.com>
Date: Fri, 11 Jan 2019 22:21:59 +0100
Subject: [PATCH] Write the real type of StructType instead anytype

---
 .../binary/BinaryModuleWriter.java            | 14 ++---
 ...nctionType.java => FunctionTypeEntry.java} | 13 +++--
 .../{StructType.java => StructTypeEntry.java} |  6 +-
 .../jwebassembly/module/ModuleGenerator.java  | 57 ++++++++++++-------
 .../jwebassembly/module/ModuleWriter.java     |  2 +-
 .../jwebassembly/module/TypeManager.java      | 36 ++++++++++--
 .../module/WasmCallInstruction.java           |  6 +-
 .../jwebassembly/text/TextModuleWriter.java   | 11 +++-
 .../jwebassembly/wasm/ValueType.java          |  4 +-
 .../jwebassembly/wasm/ValueTypeParser.java    | 30 ++++++++--
 10 files changed, 125 insertions(+), 54 deletions(-)
 rename src/de/inetsoftware/jwebassembly/binary/{FunctionType.java => FunctionTypeEntry.java} (83%)
 rename src/de/inetsoftware/jwebassembly/binary/{StructType.java => StructTypeEntry.java} (93%)

diff --git a/src/de/inetsoftware/jwebassembly/binary/BinaryModuleWriter.java b/src/de/inetsoftware/jwebassembly/binary/BinaryModuleWriter.java
index 9a7f322..b2f2b4b 100644
--- a/src/de/inetsoftware/jwebassembly/binary/BinaryModuleWriter.java
+++ b/src/de/inetsoftware/jwebassembly/binary/BinaryModuleWriter.java
@@ -63,7 +63,7 @@ public class BinaryModuleWriter extends ModuleWriter implements InstructionOpcod
 
     private Map<String, Function>       functions           = new LinkedHashMap<>();
 
-    private List<ValueType>             locals              = new ArrayList<>();
+    private List<StorageType>           locals              = new ArrayList<>();
 
     private Map<String, Global>         globals             = new LinkedHashMap<>();
 
@@ -73,7 +73,7 @@ public class BinaryModuleWriter extends ModuleWriter implements InstructionOpcod
 
     private Function                    function;
 
-    private FunctionType                functionType;
+    private FunctionTypeEntry                functionType;
 
     /**
      * Create new instance.
@@ -233,7 +233,7 @@ public class BinaryModuleWriter extends ModuleWriter implements InstructionOpcod
     @Override
     protected int writeStruct( String typeName, List<NamedStorageType> fields ) throws IOException {
         int typeId = functionTypes.size();
-        functionTypes.add( new StructType( fields ) );
+        functionTypes.add( new StructTypeEntry( fields ) );
         return typeId;
     }
 
@@ -245,7 +245,7 @@ public class BinaryModuleWriter extends ModuleWriter implements InstructionOpcod
         ImportFunction importFunction;
         function = importFunction = new ImportFunction(importModule, importName);
         imports.put( name.signatureName, importFunction );
-        functionType = new FunctionType();
+        functionType = new FunctionTypeEntry();
     }
 
     /**
@@ -278,7 +278,7 @@ public class BinaryModuleWriter extends ModuleWriter implements InstructionOpcod
     @Override
     protected void writeMethodStart( FunctionName name ) throws IOException {
         function = getFunction( name );
-        functionType = new FunctionType();
+        functionType = new FunctionTypeEntry();
         codeStream.reset();
         locals.clear();
     }
@@ -287,7 +287,7 @@ public class BinaryModuleWriter extends ModuleWriter implements InstructionOpcod
      * {@inheritDoc}
      */
     @Override
-    protected void writeMethodParam( String kind, ValueType valueType, @Nullable String name ) throws IOException {
+    protected void writeMethodParam( String kind, StorageType valueType, @Nullable String name ) throws IOException {
         switch( kind ) {
             case "param":
                 functionType.params.add( valueType );
@@ -327,7 +327,7 @@ public class BinaryModuleWriter extends ModuleWriter implements InstructionOpcod
     protected void writeMethodFinish() throws IOException {
         WasmOutputStream localsStream = new WasmOutputStream();
         localsStream.writeVaruint32( locals.size() );
-        for( ValueType valueType : locals ) {
+        for( StorageType valueType : locals ) {
             localsStream.writeVaruint32( 1 ); // TODO optimize, write the count of same types.
             localsStream.writeValueType( valueType );
         }
diff --git a/src/de/inetsoftware/jwebassembly/binary/FunctionType.java b/src/de/inetsoftware/jwebassembly/binary/FunctionTypeEntry.java
similarity index 83%
rename from src/de/inetsoftware/jwebassembly/binary/FunctionType.java
rename to src/de/inetsoftware/jwebassembly/binary/FunctionTypeEntry.java
index bfa8433..0a2fa67 100644
--- a/src/de/inetsoftware/jwebassembly/binary/FunctionType.java
+++ b/src/de/inetsoftware/jwebassembly/binary/FunctionTypeEntry.java
@@ -19,6 +19,7 @@ import java.io.IOException;
 import java.util.ArrayList;
 import java.util.List;
 
+import de.inetsoftware.jwebassembly.wasm.StorageType;
 import de.inetsoftware.jwebassembly.wasm.ValueType;
 
 /**
@@ -26,11 +27,11 @@ import de.inetsoftware.jwebassembly.wasm.ValueType;
  * 
  * @author Volker Berlin
  */
-class FunctionType extends TypeEntry {
+class FunctionTypeEntry extends TypeEntry {
 
-    final List<ValueType> params = new ArrayList<>();
+    final List<StorageType> params = new ArrayList<>();
 
-    final List<ValueType> results = new ArrayList<>();
+    final List<StorageType> results = new ArrayList<>();
 
     /**
      * {@inheritDoc}
@@ -46,11 +47,11 @@ class FunctionType extends TypeEntry {
     @Override
     void writeSectionEntryDetails( WasmOutputStream stream ) throws IOException {
         stream.writeVaruint32( this.params.size() );
-        for( ValueType valueType : this.params ) {
+        for( StorageType valueType : this.params ) {
             stream.writeValueType( valueType );
         }
         stream.writeVaruint32( this.results.size() );
-        for( ValueType valueType : this.results ) {
+        for( StorageType valueType : this.results ) {
             stream.writeValueType( valueType );
         }
     }
@@ -74,7 +75,7 @@ class FunctionType extends TypeEntry {
         if( obj == null || obj.getClass() != getClass() ) {
             return false;
         }
-        FunctionType type = (FunctionType)obj;
+        FunctionTypeEntry type = (FunctionTypeEntry)obj;
         return params.equals( type.params ) && results.equals( type.results );
     }
 }
diff --git a/src/de/inetsoftware/jwebassembly/binary/StructType.java b/src/de/inetsoftware/jwebassembly/binary/StructTypeEntry.java
similarity index 93%
rename from src/de/inetsoftware/jwebassembly/binary/StructType.java
rename to src/de/inetsoftware/jwebassembly/binary/StructTypeEntry.java
index 5e80c07..3964d7d 100644
--- a/src/de/inetsoftware/jwebassembly/binary/StructType.java
+++ b/src/de/inetsoftware/jwebassembly/binary/StructTypeEntry.java
@@ -26,7 +26,7 @@ import de.inetsoftware.jwebassembly.wasm.ValueType;
  * 
  * @author Volker Berlin
  */
-class StructType extends TypeEntry {
+class StructTypeEntry extends TypeEntry {
 
     private final List<NamedStorageType> fields;
 
@@ -36,7 +36,7 @@ class StructType extends TypeEntry {
      * @param fields
      *            the fields of the struct
      */
-    StructType( List<NamedStorageType> fields ) {
+    StructTypeEntry( List<NamedStorageType> fields ) {
         this.fields = fields;
     }
 
@@ -79,7 +79,7 @@ class StructType extends TypeEntry {
         if( obj == null || obj.getClass() != getClass() ) {
             return false;
         }
-        StructType type = (StructType)obj;
+        StructTypeEntry type = (StructTypeEntry)obj;
         return fields.equals( type.fields );
     }
 }
diff --git a/src/de/inetsoftware/jwebassembly/module/ModuleGenerator.java b/src/de/inetsoftware/jwebassembly/module/ModuleGenerator.java
index 776dde5..4b9a950 100644
--- a/src/de/inetsoftware/jwebassembly/module/ModuleGenerator.java
+++ b/src/de/inetsoftware/jwebassembly/module/ModuleGenerator.java
@@ -151,26 +151,43 @@ public class ModuleGenerator {
         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<NamedStorageType> 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 );
+            if( type.getCode() == Integer.MAX_VALUE ) {
+                writeStructType( type );
+            }
+        }
+    }
+
+    /**
+     * Write the struct type
+     * 
+     * @param type
+     *            the type
+     * @throws IOException
+     *             if any I/O error occur
+     */
+    private void writeStructType( StructType type ) throws IOException {
+        String className = type.getName();
+        InputStream stream = libraries.getResourceAsStream( className + ".class" );
+        if( stream == null ) {
+            throw new WasmException( "Missing class: " + className, -1 );
+        }
+        ClassFile classFile = new ClassFile( stream );
+        ArrayList<NamedStorageType> list = new ArrayList<>();
+        FieldInfo[] fields = classFile.getFields();
+        for( FieldInfo field : fields ) {
+            if( field.isStatic() ) {
+                continue;
+            }
+            StorageType fieldtype = new ValueTypeParser( field.getType(), types ).next();
+            list.add( new NamedStorageType( fieldtype, field.getName() ) );
+        }
+        int id = writer.writeStruct( className, list );
+        types.useType( type, id );
+        for( NamedStorageType namedType : list ) {
+            if( namedType.type.getCode() == Integer.MAX_VALUE ) {
+                writeStructType( (StructType)namedType.type );
+            }
         }
     }
 
@@ -338,7 +355,7 @@ public class ModuleGenerator {
             writer.writeMethodParam( "param", ValueType.anyref, "this" );
         }
         ValueTypeParser parser = new ValueTypeParser( signature );
-        ValueType type;
+        StorageType type;
         for( String kind : new String[] {"param","result"}) {
             while( (type = parser.next()) != null ) {
                 String paramName = null;
diff --git a/src/de/inetsoftware/jwebassembly/module/ModuleWriter.java b/src/de/inetsoftware/jwebassembly/module/ModuleWriter.java
index 0deb980..2ca6db8 100644
--- a/src/de/inetsoftware/jwebassembly/module/ModuleWriter.java
+++ b/src/de/inetsoftware/jwebassembly/module/ModuleWriter.java
@@ -107,7 +107,7 @@ public abstract class ModuleWriter implements Closeable {
      * @throws IOException
      *             if any I/O error occur
      */
-    protected abstract void writeMethodParam( String kind, ValueType valueType, @Nullable String name ) throws IOException;
+    protected abstract void writeMethodParam( String kind, StorageType valueType, @Nullable String name ) throws IOException;
 
     /**
      * Finish the function parameter.
diff --git a/src/de/inetsoftware/jwebassembly/module/TypeManager.java b/src/de/inetsoftware/jwebassembly/module/TypeManager.java
index cf25cc5..d7e2990 100644
--- a/src/de/inetsoftware/jwebassembly/module/TypeManager.java
+++ b/src/de/inetsoftware/jwebassembly/module/TypeManager.java
@@ -29,7 +29,7 @@ import de.inetsoftware.jwebassembly.wasm.StorageType;
  * 
  * @author Volker Berlin
  */
-class TypeManager {
+public class TypeManager {
 
     private final Map<String, StructType> map = new LinkedHashMap<>();
 
@@ -62,10 +62,10 @@ class TypeManager {
      *            the type name
      * @return the struct type
      */
-    StructType valueOf( String name ) {
+    public StructType valueOf( String name ) {
         StructType type = map.get( name );
         if( type == null ) {
-            type = new StructType();
+            type = new StructType( name );
             map.put( name, type );
         }
         return type;
@@ -78,7 +78,19 @@ class TypeManager {
      */
     static class StructType implements StorageType {
 
-        private int          code = Integer.MIN_VALUE;
+        private final String name;
+
+        private int          code = Integer.MAX_VALUE;
+
+        /**
+         * Create a reference to type
+         * 
+         * @param name
+         *            the Java class name
+         */
+        StructType( String name ) {
+            this.name = name;
+        }
 
         /**
          * {@inheritDoc}
@@ -87,5 +99,21 @@ class TypeManager {
         public int getCode() {
             return code;
         }
+
+        /**
+         * Get the name of the Java type
+         * @return the name
+         */
+        public String getName() {
+            return name;
+        }
+
+        /**
+         * {@inheritDoc}
+         */
+        @Override
+        public String toString() {
+            return "$" + name;
+        }
     }
 }
diff --git a/src/de/inetsoftware/jwebassembly/module/WasmCallInstruction.java b/src/de/inetsoftware/jwebassembly/module/WasmCallInstruction.java
index e9783ab..0781c12 100644
--- a/src/de/inetsoftware/jwebassembly/module/WasmCallInstruction.java
+++ b/src/de/inetsoftware/jwebassembly/module/WasmCallInstruction.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.
@@ -108,9 +108,9 @@ class WasmCallInstruction extends WasmInstruction {
         while( parser.next() != null ) {
             paramCount++;
         }
-        valueType = parser.next();
+        valueType = (ValueType)parser.next();
         ValueType type;
-        while( (type = parser.next()) != null ) {
+        while( (type = (ValueType)parser.next()) != null ) {
             valueType = type;
             paramCount--;
         }
diff --git a/src/de/inetsoftware/jwebassembly/text/TextModuleWriter.java b/src/de/inetsoftware/jwebassembly/text/TextModuleWriter.java
index b6534e4..8d49640 100644
--- a/src/de/inetsoftware/jwebassembly/text/TextModuleWriter.java
+++ b/src/de/inetsoftware/jwebassembly/text/TextModuleWriter.java
@@ -100,7 +100,14 @@ public class TextModuleWriter extends ModuleWriter {
             if( debugNames && field.name != null ) {
                 output.append( " $" ).append( field.name );
             }
-            output.append( " (mut " ).append( field.type.toString() ).append( "))" );
+            output.append( " (mut " );
+            StorageType type = field.type;
+            if( type.getCode() < 0 ) {
+                output.append( type.toString() );
+            } else {
+                output.append( "(ref " ).append( type.toString() ).append( ')' );
+            }
+            output.append( "))" );
         }
         inset--;
         newline( output );
@@ -145,7 +152,7 @@ public class TextModuleWriter extends ModuleWriter {
      * {@inheritDoc}
      */
     @Override
-    protected void writeMethodParam( String kind, ValueType valueType, @Nullable String name ) throws IOException {
+    protected void writeMethodParam( String kind, StorageType valueType, @Nullable String name ) throws IOException {
         methodOutput.append( " (" ).append( kind );
         if( debugNames && name != null ) {
             methodOutput.append( " $" ).append( name );
diff --git a/src/de/inetsoftware/jwebassembly/wasm/ValueType.java b/src/de/inetsoftware/jwebassembly/wasm/ValueType.java
index e0609c6..1b5a398 100644
--- a/src/de/inetsoftware/jwebassembly/wasm/ValueType.java
+++ b/src/de/inetsoftware/jwebassembly/wasm/ValueType.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.
@@ -61,7 +61,7 @@ public enum ValueType implements StorageType {
      * @return the value type
      */
     public static ValueType getValueType( String javaSignature ) {
-        return new ValueTypeParser( javaSignature ).next();
+        return (ValueType)new ValueTypeParser( javaSignature ).next();
     }
 
 }
diff --git a/src/de/inetsoftware/jwebassembly/wasm/ValueTypeParser.java b/src/de/inetsoftware/jwebassembly/wasm/ValueTypeParser.java
index 90455ac..c527f4c 100644
--- a/src/de/inetsoftware/jwebassembly/wasm/ValueTypeParser.java
+++ b/src/de/inetsoftware/jwebassembly/wasm/ValueTypeParser.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.
@@ -16,6 +16,7 @@
 package de.inetsoftware.jwebassembly.wasm;
 
 import de.inetsoftware.jwebassembly.WasmException;
+import de.inetsoftware.jwebassembly.module.TypeManager;
 
 /**
  * Parser for a Java signature. This can be a method signature or a signature of a field.
@@ -27,14 +28,29 @@ public class ValueTypeParser {
 
     private int          idx;
 
+    private TypeManager  types;
+
     /**
      * Create a new parser.
      * 
      * @param javaSignature
-     *            the Jav signature
+     *            the Java signature
      */
     public ValueTypeParser( String javaSignature ) {
-        sig = javaSignature;
+        this( javaSignature, null );
+    }
+
+    /**
+     * Create a new parser.
+     * 
+     * @param javaSignature
+     *            the Java signature
+     * @param types
+     *            the optional type manager
+     */
+    public ValueTypeParser( String javaSignature, TypeManager types ) {
+        this.sig = javaSignature;
+        this.types = types;
         if( javaSignature.startsWith( "(" ) ) {
             idx++;
         }
@@ -45,7 +61,7 @@ public class ValueTypeParser {
      * 
      * @return next type or null
      */
-    public ValueType next() {
+    public StorageType next() {
         if( idx >= sig.length() ) {
             return null;
         }
@@ -56,8 +72,10 @@ public class ValueTypeParser {
                 next();
                 return ValueType.anyref;
             case 'L':
-                idx = sig.indexOf( ';', idx ) + 1;
-                return ValueType.anyref;
+                int idx2 = sig.indexOf( ';', idx );
+                String name = sig.substring( idx, idx2 );
+                idx = idx2 + 1;
+                return types == null ? ValueType.anyref : types.valueOf( name );
             case 'Z': // boolean
             case 'B': // byte
             case 'C': // char