From 92a878b5bf6efdfa49fc64e3e66aff4180b9a82c Mon Sep 17 00:00:00 2001
From: Volker Berlin <volker.berlin@googlemail.com>
Date: Sat, 8 Apr 2017 18:48:45 +0200
Subject: [PATCH] add support for long const

---
 .../binary/BinaryModuleWriter.java            |  19 +-
 .../jwebassembly/binary/WasmOutputStream.java | 332 +++++++++---------
 .../jwebassembly/module/ModuleWriter.java     |  35 +-
 .../jwebassembly/text/TextModuleWriter.java   |   9 +
 4 files changed, 221 insertions(+), 174 deletions(-)

diff --git a/src/de/inetsoftware/jwebassembly/binary/BinaryModuleWriter.java b/src/de/inetsoftware/jwebassembly/binary/BinaryModuleWriter.java
index d1bbf8a..5e905aa 100644
--- a/src/de/inetsoftware/jwebassembly/binary/BinaryModuleWriter.java
+++ b/src/de/inetsoftware/jwebassembly/binary/BinaryModuleWriter.java
@@ -93,16 +93,16 @@ public class BinaryModuleWriter extends ModuleWriter implements InstructionOpcod
             WasmOutputStream stream = new WasmOutputStream();
             stream.writeVaruint32( count );
             for( FunctionType type : functionTypes ) {
-                stream.writeVarint32( ValueType.func.getCode() );
+                stream.writeVarint( ValueType.func.getCode() );
                 stream.writeVaruint32( type.params.size() );
                 for( ValueType valueType : type.params ) {
-                    stream.writeVarint32( valueType.getCode() );
+                    stream.writeVarint( valueType.getCode() );
                 }
                 if( type.result == null ) {
                     stream.writeVaruint32( 0 );
                 } else {
                     stream.writeVaruint32( 1 );
-                    stream.writeVarint32( type.result.getCode() );
+                    stream.writeVarint( type.result.getCode() );
                 }
             }
             wasm.writeSection( SectionType.Type, stream, null );
@@ -217,7 +217,7 @@ public class BinaryModuleWriter extends ModuleWriter implements InstructionOpcod
         localsStream.writeVaruint32( locals.size() );
         for( ValueType valueType : locals ) {
             localsStream.writeVaruint32( 1 ); // TODO optimize, write the count of same types.
-            localsStream.writeVarint32( valueType.getCode() );
+            localsStream.writeVarint( valueType.getCode() );
         }
         functionsStream.writeVaruint32( localsStream.size() + codeStream.size() + 1 );
         localsStream.writeTo( functionsStream );
@@ -231,7 +231,16 @@ public class BinaryModuleWriter extends ModuleWriter implements InstructionOpcod
     @Override
     protected void writeConstInt( int value ) throws IOException {
         codeStream.write( I32_CONST );
-        codeStream.writeVarint32( value );
+        codeStream.writeVarint( value );
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    protected void writeConstLong( long value ) throws IOException {
+        codeStream.write( I64_CONST );
+        codeStream.writeVarint( value );
     }
 
     /**
diff --git a/src/de/inetsoftware/jwebassembly/binary/WasmOutputStream.java b/src/de/inetsoftware/jwebassembly/binary/WasmOutputStream.java
index ecf82dc..36772fa 100644
--- a/src/de/inetsoftware/jwebassembly/binary/WasmOutputStream.java
+++ b/src/de/inetsoftware/jwebassembly/binary/WasmOutputStream.java
@@ -1,166 +1,166 @@
-/*
- * Copyright 2017 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.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package de.inetsoftware.jwebassembly.binary;
-
-import java.io.ByteArrayOutputStream;
-import java.io.FilterOutputStream;
-import java.io.IOException;
-import java.io.OutputStream;
-import java.nio.charset.StandardCharsets;
-
-import javax.annotation.Nonnegative;
-
-/**
- * @author Volker Berlin
- */
-class WasmOutputStream extends FilterOutputStream {
-
-    /**
-     * Create a in memory stream.
-     */
-    WasmOutputStream() {
-        super( new ByteArrayOutputStream() );
-    }
-
-    /**
-     * Create a wrapped stream.
-     * 
-     * @param output
-     *            the target of data
-     */
-    WasmOutputStream( OutputStream output ) {
-        super( output );
-    }
-
-    /**
-     * Write a integer little endian (ever 4 bytes)
-     * 
-     * @param value
-     *            the value
-     * @throws IOException
-     *             if an I/O error occurs.
-     */
-    void writeInt32( int value ) throws IOException {
-        write( (value >>> 0) & 0xFF );
-        write( (value >>> 8) & 0xFF );
-        write( (value >>> 16) & 0xFF );
-        write( (value >>> 24) & 0xFF );
-    }
-
-    /**
-     * Write an unsigned integer.
-     * 
-     * @param value
-     *            the value
-     * @throws IOException
-     *             if an I/O error occurs.
-     */
-    void writeVaruint32( @Nonnegative int value ) throws IOException {
-        if( value < 0 ) {
-            throw new IOException( "Invalid negative value" );
-        }
-        do {
-            int b = value & 0x7F; // low 7 bits
-            value >>= 7;
-            if( value != 0 ) { /* more bytes to come */
-                b |= 0x80;
-            }
-            write( b );
-        } while( value != 0 );
-    }
-
-    /**
-     * Write an integer value.
-     * 
-     * @param value
-     *            the value
-     * @throws IOException
-     *             if an I/O error occurs.
-     */
-    void writeVarint32( int value ) throws IOException {
-        while( true ) {
-            int b = value & 0x7F;
-            value >>= 7;
-
-            /* sign bit of byte is second high order bit (0x40) */
-            if( (value == 0 && (b & 0x40) == 0) || (value == -1 && (b & 0x40) != 0) ) {
-                write( b );
-                return;
-            } else {
-                write( b | 0x80 );
-            }
-        }
-    }
-
-    /**
-     * Write a section with header and data.
-     * 
-     * @param type
-     *            the name of the section
-     * @param data
-     *            the data of the section
-     * @param name
-     *            the name, must be set if the id == 0
-     * @throws IOException
-     *             if any I/O error occur
-     */
-    void writeSection( SectionType type, WasmOutputStream data, String name ) throws IOException {
-        ByteArrayOutputStream baos = (ByteArrayOutputStream)data.out;
-        int size = baos.size();
-        if( size == 0 ) {
-            return;
-        }
-        writeVaruint32( type.ordinal() );
-        writeVaruint32( size );
-        if( type == SectionType.Custom ) {
-            byte[] bytes = name.getBytes( StandardCharsets.ISO_8859_1 );
-            writeVaruint32( bytes.length );
-            write( bytes );
-        }
-        baos.writeTo( this );
-    }
-
-    /**
-     * Write the data of this stream to the output. Work only for in memory stream.
-     * 
-     * @param output
-     *            the target
-     * @throws IOException
-     *             if any I/O error occur
-     */
-    void writeTo( OutputStream output ) throws IOException {
-        ByteArrayOutputStream baos = (ByteArrayOutputStream)out;
-        baos.writeTo( output );
-    }
-
-    /**
-     * The count of bytes in the stream. Work only for in memory stream.
-     * 
-     * @return the data size
-     */
-    int size() {
-        ByteArrayOutputStream baos = (ByteArrayOutputStream)out;
-        return baos.size();
-    }
-
-    /**
-     * Reset the stream. Work only for in memory stream.
-     */
-    void reset() {
-        ByteArrayOutputStream baos = (ByteArrayOutputStream)out;
-        baos.reset();
-    }
-}
+/*
+ * Copyright 2017 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.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package de.inetsoftware.jwebassembly.binary;
+
+import java.io.ByteArrayOutputStream;
+import java.io.FilterOutputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.nio.charset.StandardCharsets;
+
+import javax.annotation.Nonnegative;
+
+/**
+ * @author Volker Berlin
+ */
+class WasmOutputStream extends FilterOutputStream {
+
+    /**
+     * Create a in memory stream.
+     */
+    WasmOutputStream() {
+        super( new ByteArrayOutputStream() );
+    }
+
+    /**
+     * Create a wrapped stream.
+     * 
+     * @param output
+     *            the target of data
+     */
+    WasmOutputStream( OutputStream output ) {
+        super( output );
+    }
+
+    /**
+     * Write a integer little endian (ever 4 bytes)
+     * 
+     * @param value
+     *            the value
+     * @throws IOException
+     *             if an I/O error occurs.
+     */
+    void writeInt32( int value ) throws IOException {
+        write( (value >>> 0) & 0xFF );
+        write( (value >>> 8) & 0xFF );
+        write( (value >>> 16) & 0xFF );
+        write( (value >>> 24) & 0xFF );
+    }
+
+    /**
+     * Write an unsigned integer.
+     * 
+     * @param value
+     *            the value
+     * @throws IOException
+     *             if an I/O error occurs.
+     */
+    void writeVaruint32( @Nonnegative int value ) throws IOException {
+        if( value < 0 ) {
+            throw new IOException( "Invalid negative value" );
+        }
+        do {
+            int b = value & 0x7F; // low 7 bits
+            value >>= 7;
+            if( value != 0 ) { /* more bytes to come */
+                b |= 0x80;
+            }
+            write( b );
+        } while( value != 0 );
+    }
+
+    /**
+     * Write an integer value.
+     * 
+     * @param value
+     *            the value
+     * @throws IOException
+     *             if an I/O error occurs.
+     */
+    void writeVarint( long value ) throws IOException {
+        while( true ) {
+            int b = (int)value & 0x7F;
+            value >>= 7;
+
+            /* sign bit of byte is second high order bit (0x40) */
+            if( (value == 0 && (b & 0x40) == 0) || (value == -1 && (b & 0x40) != 0) ) {
+                write( b );
+                return;
+            } else {
+                write( b | 0x80 );
+            }
+        }
+    }
+
+    /**
+     * Write a section with header and data.
+     * 
+     * @param type
+     *            the name of the section
+     * @param data
+     *            the data of the section
+     * @param name
+     *            the name, must be set if the id == 0
+     * @throws IOException
+     *             if any I/O error occur
+     */
+    void writeSection( SectionType type, WasmOutputStream data, String name ) throws IOException {
+        ByteArrayOutputStream baos = (ByteArrayOutputStream)data.out;
+        int size = baos.size();
+        if( size == 0 ) {
+            return;
+        }
+        writeVaruint32( type.ordinal() );
+        writeVaruint32( size );
+        if( type == SectionType.Custom ) {
+            byte[] bytes = name.getBytes( StandardCharsets.ISO_8859_1 );
+            writeVaruint32( bytes.length );
+            write( bytes );
+        }
+        baos.writeTo( this );
+    }
+
+    /**
+     * Write the data of this stream to the output. Work only for in memory stream.
+     * 
+     * @param output
+     *            the target
+     * @throws IOException
+     *             if any I/O error occur
+     */
+    void writeTo( OutputStream output ) throws IOException {
+        ByteArrayOutputStream baos = (ByteArrayOutputStream)out;
+        baos.writeTo( output );
+    }
+
+    /**
+     * The count of bytes in the stream. Work only for in memory stream.
+     * 
+     * @return the data size
+     */
+    int size() {
+        ByteArrayOutputStream baos = (ByteArrayOutputStream)out;
+        return baos.size();
+    }
+
+    /**
+     * Reset the stream. Work only for in memory stream.
+     */
+    void reset() {
+        ByteArrayOutputStream baos = (ByteArrayOutputStream)out;
+        baos.reset();
+    }
+}
diff --git a/src/de/inetsoftware/jwebassembly/module/ModuleWriter.java b/src/de/inetsoftware/jwebassembly/module/ModuleWriter.java
index 88b3db0..af2248d 100644
--- a/src/de/inetsoftware/jwebassembly/module/ModuleWriter.java
+++ b/src/de/inetsoftware/jwebassembly/module/ModuleWriter.java
@@ -28,6 +28,7 @@ import de.inetsoftware.classparser.Annotations;
 import de.inetsoftware.classparser.ClassFile;
 import de.inetsoftware.classparser.Code;
 import de.inetsoftware.classparser.CodeInputStream;
+import de.inetsoftware.classparser.ConstantPool;
 import de.inetsoftware.classparser.LineNumberTable;
 import de.inetsoftware.classparser.MethodInfo;
 import de.inetsoftware.jwebassembly.WasmException;
@@ -93,11 +94,11 @@ public abstract class ModuleWriter implements Closeable {
                                     i + 1 == lineNumberTable.size() ? code.getCodeSize()
                                                     : lineNumberTable.getStartOffset( i + 1 );
                     CodeInputStream byteCode = code.getByteCode( offset, nextOffset - offset );
-                    writeCodeChunk( byteCode, lineNumber );
+                    writeCodeChunk( byteCode, lineNumber, method.getConstantPool() );
                 }
             } else {
                 CodeInputStream byteCode = code.getByteCode();
-                writeCodeChunk( byteCode, -1 );
+                writeCodeChunk( byteCode, -1, method.getConstantPool() );
             }
             for( int i = Math.min( paramCount, locals.size() ); i > 0; i-- ) {
                 locals.remove( 0 );
@@ -237,7 +238,7 @@ public abstract class ModuleWriter implements Closeable {
      * @throws WasmException
      *             if some Java code can't converted
      */
-    private void writeCodeChunk( CodeInputStream byteCode, int lineNumber ) throws WasmException {
+    private void writeCodeChunk( CodeInputStream byteCode, int lineNumber, ConstantPool constantPool  ) throws WasmException {
         try {
             while( byteCode.available() > 0 ) {
                 int op = byteCode.readUnsignedByte();
@@ -248,6 +249,9 @@ public abstract class ModuleWriter implements Closeable {
                     case 16: //bipush
                         writeConstInt( byteCode.readByte() );
                         break;
+                    case 20: //ldc2_w
+                        writeConstLong( (Long)constantPool.get( byteCode.readUnsignedShort() ) );
+                        break;
                     case 26: // iload_0
                     case 27: // iload_1
                     case 28: // iload_2
@@ -264,6 +268,7 @@ public abstract class ModuleWriter implements Closeable {
                         writeAddInt();
                         break;
                     case 172: // ireturn
+                    case 173: // lreturn
                     case 177: // return void
                         writeReturn();
                         break;
@@ -286,6 +291,30 @@ public abstract class ModuleWriter implements Closeable {
      */
     protected abstract void writeConstInt( int value ) throws IOException;
 
+    /**
+     * Write a constant long value
+     * 
+     * @param value
+     *            the value
+     * @throws IOException
+     *             if any I/O error occur
+     */
+    protected abstract void writeConstLong( long value ) throws IOException;
+
+    /**
+     * Write or Load a local variable.
+     * 
+     * @param load
+     *            true: if load
+     * @param valueType
+     *            the type of the variable
+     * @param idx
+     *            the idx of the variable
+     * @throws WasmException
+     *             occur a if a variable was used for a different type
+     * @throws IOException
+     *             if any I/O error occur
+     */
     private void writeLoadStore( boolean load, @Nonnull ValueType valueType, @Nonnegative int idx ) throws WasmException, IOException {
         while( locals.size() <= idx ) {
             locals.add( null );
diff --git a/src/de/inetsoftware/jwebassembly/text/TextModuleWriter.java b/src/de/inetsoftware/jwebassembly/text/TextModuleWriter.java
index 151bc45..a273468 100644
--- a/src/de/inetsoftware/jwebassembly/text/TextModuleWriter.java
+++ b/src/de/inetsoftware/jwebassembly/text/TextModuleWriter.java
@@ -111,6 +111,15 @@ public class TextModuleWriter extends ModuleWriter {
         methodOutput.append( "i32.const " ).append( Integer.toString( value ) );
     }
 
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    protected void writeConstLong( long value ) throws IOException {
+        newline( methodOutput );
+        methodOutput.append( "i64.const " ).append( Long.toString( value ) );
+    }
+
     /**
      * {@inheritDoc}
      */