From f23128bb13d4e1629fcd279485b83f5ab6207ae0 Mon Sep 17 00:00:00 2001
From: Alexey Andreev <konsoletyper@gmail.com>
Date: Sat, 12 May 2018 23:43:53 +0300
Subject: [PATCH] Wasm backend: fix many tests

---
 .../classlib/java/io/TStreamTokenizer.java    |  3 +-
 .../org/teavm/classlib/java/util/TRandom.java |  6 ++-
 .../org/teavm/backend/wasm/WasmRuntime.java   |  1 +
 .../org/teavm/backend/wasm/WasmTarget.java    | 13 ++----
 .../wasm/generate/WasmClassGenerator.java     | 43 ++++++++++++++++++-
 .../wasm/generate/WasmGenerationVisitor.java  |  2 +-
 .../wasm/intrinsics/PlatformIntrinsic.java    |  2 -
 .../WasmIntrinsicFactoryContext.java          |  4 +-
 .../wasm/render/WasmCRenderingVisitor.java    | 16 ++++++-
 .../model/classes/VirtualTableProvider.java   |  4 +-
 .../org/teavm/backend/wasm/wasm-runtime.c     |  8 ++++
 .../java/org/teavm/platform/Platform.java     |  1 +
 .../platform/plugin/MetadataIntrinsic.java    |  6 +--
 .../classlib/java/io/StreamTokenizerTest.java |  2 +-
 14 files changed, 86 insertions(+), 25 deletions(-)

diff --git a/classlib/src/main/java/org/teavm/classlib/java/io/TStreamTokenizer.java b/classlib/src/main/java/org/teavm/classlib/java/io/TStreamTokenizer.java
index 1f6326357..efe44a142 100644
--- a/classlib/src/main/java/org/teavm/classlib/java/io/TStreamTokenizer.java
+++ b/classlib/src/main/java/org/teavm/classlib/java/io/TStreamTokenizer.java
@@ -234,8 +234,7 @@ public class TStreamTokenizer {
                 }
             }
             peekChar = currentChar;
-            sval = forceLowercase ? word.toString().toLowerCase() : word
-                    .toString();
+            sval = forceLowercase ? word.toString().toLowerCase() : word.toString();
             ttype = TT_WORD;
             return ttype;
         }
diff --git a/classlib/src/main/java/org/teavm/classlib/java/util/TRandom.java b/classlib/src/main/java/org/teavm/classlib/java/util/TRandom.java
index dd31f9f90..20adec1d8 100644
--- a/classlib/src/main/java/org/teavm/classlib/java/util/TRandom.java
+++ b/classlib/src/main/java/org/teavm/classlib/java/util/TRandom.java
@@ -40,7 +40,11 @@ public class TRandom extends TObject implements TSerializable {
     }
 
     protected int next(int bits) {
-        return (int) (nextDouble() * (1L << TMath.min(32, bits)));
+        if (bits == 32) {
+            return (int) (nextDouble() * ((1L << 32) - 1) + Integer.MIN_VALUE);
+        } else {
+            return (int) (nextDouble() * (1L << TMath.min(32, bits)));
+        }
     }
 
     public void nextBytes(byte[] bytes) {
diff --git a/core/src/main/java/org/teavm/backend/wasm/WasmRuntime.java b/core/src/main/java/org/teavm/backend/wasm/WasmRuntime.java
index 35838435e..4cdaddb77 100644
--- a/core/src/main/java/org/teavm/backend/wasm/WasmRuntime.java
+++ b/core/src/main/java/org/teavm/backend/wasm/WasmRuntime.java
@@ -129,6 +129,7 @@ public final class WasmRuntime {
     public static void moveMemoryBlock(Address source, Address target, int count) {
         if (count < 8) {
             slowMemoryMove(source, target, count);
+            return;
         }
         int diff = source.toInt() - target.toInt();
         if (diff == 0) {
diff --git a/core/src/main/java/org/teavm/backend/wasm/WasmTarget.java b/core/src/main/java/org/teavm/backend/wasm/WasmTarget.java
index 0090179aa..d2f9743af 100644
--- a/core/src/main/java/org/teavm/backend/wasm/WasmTarget.java
+++ b/core/src/main/java/org/teavm/backend/wasm/WasmTarget.java
@@ -94,6 +94,7 @@ import org.teavm.model.CallLocation;
 import org.teavm.model.ClassHolder;
 import org.teavm.model.ClassHolderTransformer;
 import org.teavm.model.ClassReader;
+import org.teavm.model.ClassReaderSource;
 import org.teavm.model.ElementModifier;
 import org.teavm.model.FieldReader;
 import org.teavm.model.FieldReference;
@@ -325,7 +326,7 @@ public class WasmTarget implements TeaVMTarget, TeaVMWasmHost {
         context.addIntrinsic(new PlatformClassMetadataIntrinsic());
         context.addIntrinsic(new ClassIntrinsic());
 
-        IntrinsicFactoryContext intrinsicFactoryContext = new IntrinsicFactoryContext(classes);
+        IntrinsicFactoryContext intrinsicFactoryContext = new IntrinsicFactoryContext();
         for (WasmIntrinsicFactory additionalIntrinsicFactory : additionalIntrinsics) {
             context.addIntrinsic(additionalIntrinsicFactory.create(intrinsicFactoryContext));
         }
@@ -416,15 +417,9 @@ public class WasmTarget implements TeaVMTarget, TeaVMWasmHost {
     }
 
     private class IntrinsicFactoryContext implements WasmIntrinsicFactoryContext {
-        private ListableClassReaderSource classSource;
-
-        IntrinsicFactoryContext(ListableClassReaderSource classSource) {
-            this.classSource = classSource;
-        }
-
         @Override
-        public ListableClassReaderSource getClassSource() {
-            return classSource;
+        public ClassReaderSource getClassSource() {
+            return controller.getUnprocessedClassSource();
         }
 
         @Override
diff --git a/core/src/main/java/org/teavm/backend/wasm/generate/WasmClassGenerator.java b/core/src/main/java/org/teavm/backend/wasm/generate/WasmClassGenerator.java
index 9934a5471..301bfdca8 100644
--- a/core/src/main/java/org/teavm/backend/wasm/generate/WasmClassGenerator.java
+++ b/core/src/main/java/org/teavm/backend/wasm/generate/WasmClassGenerator.java
@@ -175,8 +175,10 @@ public class WasmClassGenerator {
             binaryData.data.setInt(CLASS_IS_INSTANCE, functionTable.size());
             binaryData.data.setInt(CLASS_CANARY, RuntimeClass.computeCanary(4, 0));
             functionTable.add(names.forSupertypeFunction(type));
+            binaryData.data.setAddress(CLASS_NAME, stringPool.getStringPointer(type.toString()));
             binaryData.data.setAddress(CLASS_SIMPLE_NAME, 0);
             binaryData.data.setInt(CLASS_INIT, -1);
+            binaryData.data.setAddress(CLASS_PARENT, getClassPointer(ValueType.object("java.lang.Object")));
             binaryData.start = binaryWriter.append(vtableSize > 0 ? wrapper : binaryData.data);
 
             itemBinaryData.data.setAddress(CLASS_ARRAY_TYPE, binaryData.start);
@@ -428,7 +430,11 @@ public class WasmClassGenerator {
             int desiredAlignment = getTypeSize(field.getType());
             if (field.hasModifier(ElementModifier.STATIC)) {
                 DataType type = asDataType(field.getType());
-                data.fieldLayout.put(field.getName(), binaryWriter.append(type.createValue()));
+                DataValue value = type.createValue();
+                if (field.getInitialValue() != null) {
+                    setInitialValue(field.getType(), value, field.getInitialValue());
+                }
+                data.fieldLayout.put(field.getName(), binaryWriter.append(value));
             } else {
                 int offset = align(data.size, desiredAlignment);
                 data.fieldLayout.put(field.getName(), offset);
@@ -440,6 +446,41 @@ public class WasmClassGenerator {
         }
     }
 
+    private void setInitialValue(ValueType type, DataValue data, Object value) {
+        if (value instanceof Number) {
+            switch (((ValueType.Primitive) type).getKind()) {
+                case BYTE:
+                    data.setByte(0, ((Number) value).byteValue());
+                    break;
+                case SHORT:
+                    data.setShort(0, ((Number) value).shortValue());
+                    break;
+                case CHARACTER:
+                    data.setShort(0, ((Number) value).shortValue());
+                    break;
+                case INTEGER:
+                    data.setInt(0, ((Number) value).intValue());
+                    break;
+                case LONG:
+                    data.setLong(0, ((Number) value).longValue());
+                    break;
+                case FLOAT:
+                    data.setFloat(0, ((Number) value).floatValue());
+                    break;
+                case DOUBLE:
+                    data.setDouble(0, ((Number) value).doubleValue());
+                    break;
+                case BOOLEAN:
+                    data.setByte(0, ((Number) value).byteValue());
+                    break;
+            }
+        } else if (value instanceof Boolean) {
+            data.setByte(0, (Boolean) value ? (byte) 1 : 0);
+        } else if (value instanceof String) {
+            data.setAddress(0, stringPool.getStringPointer((String) value));
+        }
+    }
+
     private static DataType asDataType(ValueType type) {
         if (type instanceof ValueType.Primitive) {
             switch (((ValueType.Primitive) type).getKind()) {
diff --git a/core/src/main/java/org/teavm/backend/wasm/generate/WasmGenerationVisitor.java b/core/src/main/java/org/teavm/backend/wasm/generate/WasmGenerationVisitor.java
index cdbe7533e..44ef81ada 100644
--- a/core/src/main/java/org/teavm/backend/wasm/generate/WasmGenerationVisitor.java
+++ b/core/src/main/java/org/teavm/backend/wasm/generate/WasmGenerationVisitor.java
@@ -813,7 +813,7 @@ class WasmGenerationVisitor implements StatementVisitor, ExprVisitor {
 
     private void translateSwitchToWasmSwitch(SwitchStatement statement, WasmExpression condition,
             WasmBlock initialWrapper, WasmBlock defaultTarget, WasmBlock[] targets, int min, int max) {
-        if (min > 0) {
+        if (min != 0) {
             condition = new WasmIntBinary(WasmIntType.INT32, WasmIntBinaryOperation.SUB, condition,
                     new WasmInt32Constant(min));
         }
diff --git a/core/src/main/java/org/teavm/backend/wasm/intrinsics/PlatformIntrinsic.java b/core/src/main/java/org/teavm/backend/wasm/intrinsics/PlatformIntrinsic.java
index 4e11aa14d..826a173a3 100644
--- a/core/src/main/java/org/teavm/backend/wasm/intrinsics/PlatformIntrinsic.java
+++ b/core/src/main/java/org/teavm/backend/wasm/intrinsics/PlatformIntrinsic.java
@@ -34,7 +34,6 @@ public class PlatformIntrinsic implements WasmIntrinsic {
         switch (methodDescriptor.getName()) {
             case "getPlatformObject":
             case "asJavaClass":
-            case "getName":
             case "createQueue":
                 return true;
             default:
@@ -48,7 +47,6 @@ public class PlatformIntrinsic implements WasmIntrinsic {
             case "getPlatformObject":
             case "asJavaClass":
                 return manager.generate(invocation.getArguments().get(0));
-            case "getName":
             case "createQueue":
                 return new WasmInt32Constant(0);
             default:
diff --git a/core/src/main/java/org/teavm/backend/wasm/intrinsics/WasmIntrinsicFactoryContext.java b/core/src/main/java/org/teavm/backend/wasm/intrinsics/WasmIntrinsicFactoryContext.java
index eb682f5df..c9012aef1 100644
--- a/core/src/main/java/org/teavm/backend/wasm/intrinsics/WasmIntrinsicFactoryContext.java
+++ b/core/src/main/java/org/teavm/backend/wasm/intrinsics/WasmIntrinsicFactoryContext.java
@@ -17,10 +17,10 @@ package org.teavm.backend.wasm.intrinsics;
 
 import java.util.Properties;
 import org.teavm.common.ServiceRepository;
-import org.teavm.model.ListableClassReaderSource;
+import org.teavm.model.ClassReaderSource;
 
 public interface WasmIntrinsicFactoryContext {
-    ListableClassReaderSource getClassSource();
+    ClassReaderSource getClassSource();
 
     ClassLoader getClassLoader();
 
diff --git a/core/src/main/java/org/teavm/backend/wasm/render/WasmCRenderingVisitor.java b/core/src/main/java/org/teavm/backend/wasm/render/WasmCRenderingVisitor.java
index 52e01a0e1..219e51db1 100644
--- a/core/src/main/java/org/teavm/backend/wasm/render/WasmCRenderingVisitor.java
+++ b/core/src/main/java/org/teavm/backend/wasm/render/WasmCRenderingVisitor.java
@@ -308,12 +308,24 @@ class WasmCRenderingVisitor implements WasmExpressionVisitor {
 
     @Override
     public void visit(WasmFloat32Constant expression) {
-        value = CExpression.relocatable(Float.toHexString(expression.getValue()) + "F");
+        if (Float.isInfinite(expression.getValue())) {
+            value = CExpression.relocatable(expression.getValue() < 0 ? "-INFINITY" : "INFINITY");
+        } else if (Float.isNaN(expression.getValue())) {
+            value = CExpression.relocatable("NAN");
+        } else {
+            value = CExpression.relocatable(Float.toHexString(expression.getValue()) + "F");
+        }
     }
 
     @Override
     public void visit(WasmFloat64Constant expression) {
-        value = CExpression.relocatable(Double.toHexString(expression.getValue()));
+        if (Double.isInfinite(expression.getValue())) {
+            value = CExpression.relocatable(expression.getValue() < 0 ? "-INFINITY" : "INFINITY");
+        } else if (Double.isNaN(expression.getValue())) {
+            value = CExpression.relocatable("NAN");
+        } else {
+            value = CExpression.relocatable(Double.toHexString(expression.getValue()));
+        }
     }
 
     @Override
diff --git a/core/src/main/java/org/teavm/model/classes/VirtualTableProvider.java b/core/src/main/java/org/teavm/model/classes/VirtualTableProvider.java
index de462e8bc..02fbd2559 100644
--- a/core/src/main/java/org/teavm/model/classes/VirtualTableProvider.java
+++ b/core/src/main/java/org/teavm/model/classes/VirtualTableProvider.java
@@ -78,7 +78,9 @@ public class VirtualTableProvider {
         Set<MethodDescriptor> newDescriptors = virtualMethodMap.get(className);
         if (newDescriptors != null) {
             for (MethodDescriptor method : newDescriptors) {
-                table.entries.put(method, new VirtualTableEntry(table, method, null, table.entries.size()));
+                if (!table.entries.containsKey(method)) {
+                    table.entries.put(method, new VirtualTableEntry(table, method, null, table.entries.size()));
+                }
             }
         }
 
diff --git a/core/src/main/resources/org/teavm/backend/wasm/wasm-runtime.c b/core/src/main/resources/org/teavm/backend/wasm/wasm-runtime.c
index c6963450b..76dd1737a 100644
--- a/core/src/main/resources/org/teavm/backend/wasm/wasm-runtime.c
+++ b/core/src/main/resources/org/teavm/backend/wasm/wasm-runtime.c
@@ -6,7 +6,15 @@
 #include <math.h>
 #include <wchar.h>
 #include <wctype.h>
+#include <time.h>
 
 static inline float TeaVM_getNaN() {
     return NAN;
+}
+
+static int64_t currentTimeMillis() {
+    struct timespec time;
+    clock_gettime(CLOCK_REALTIME, &time);
+
+    return time.tv_sec * 1000 + (int64_t) round(time.tv_nsec / 1000000);
 }
\ No newline at end of file
diff --git a/platform/src/main/java/org/teavm/platform/Platform.java b/platform/src/main/java/org/teavm/platform/Platform.java
index 1b27a767a..a54016694 100644
--- a/platform/src/main/java/org/teavm/platform/Platform.java
+++ b/platform/src/main/java/org/teavm/platform/Platform.java
@@ -227,6 +227,7 @@ public final class Platform {
         return cls.getMetadata().getArrayItem();
     }
 
+    @Unmanaged
     public static String getName(PlatformClass cls) {
         return cls.getMetadata().getName();
     }
diff --git a/platform/src/main/java/org/teavm/platform/plugin/MetadataIntrinsic.java b/platform/src/main/java/org/teavm/platform/plugin/MetadataIntrinsic.java
index da9f32cd5..f89996d3c 100644
--- a/platform/src/main/java/org/teavm/platform/plugin/MetadataIntrinsic.java
+++ b/platform/src/main/java/org/teavm/platform/plugin/MetadataIntrinsic.java
@@ -33,7 +33,7 @@ import org.teavm.backend.wasm.model.expression.WasmExpression;
 import org.teavm.backend.wasm.model.expression.WasmInt32Constant;
 import org.teavm.common.ServiceRepository;
 import org.teavm.model.CallLocation;
-import org.teavm.model.ListableClassReaderSource;
+import org.teavm.model.ClassReaderSource;
 import org.teavm.model.MethodReader;
 import org.teavm.model.MethodReference;
 import org.teavm.platform.metadata.MetadataGenerator;
@@ -41,13 +41,13 @@ import org.teavm.platform.metadata.MetadataProvider;
 import org.teavm.platform.metadata.Resource;
 
 public class MetadataIntrinsic implements WasmIntrinsic {
-    private ListableClassReaderSource classSource;
+    private ClassReaderSource classSource;
     private ClassLoader classLoader;
     private ServiceRepository services;
     private Properties properties;
     private Map<ResourceTypeDescriptor, DataStructure> resourceTypeCache = new HashMap<>();
 
-    public MetadataIntrinsic(ListableClassReaderSource classSource, ClassLoader classLoader,
+    public MetadataIntrinsic(ClassReaderSource classSource, ClassLoader classLoader,
             ServiceRepository services, Properties properties) {
         this.classSource = classSource;
         this.classLoader = classLoader;
diff --git a/tests/src/test/java/org/teavm/classlib/java/io/StreamTokenizerTest.java b/tests/src/test/java/org/teavm/classlib/java/io/StreamTokenizerTest.java
index 7719aa01b..f225aa26f 100644
--- a/tests/src/test/java/org/teavm/classlib/java/io/StreamTokenizerTest.java
+++ b/tests/src/test/java/org/teavm/classlib/java/io/StreamTokenizerTest.java
@@ -287,7 +287,7 @@ public class StreamTokenizerTest {
     public void test_toString() throws IOException {
         setTest("ABC Hello World");
         st.nextToken();
-        assertTrue("toString failed." + st.toString(), st.toString().equals("Token[ABC], line 1"));
+        assertEquals("toString failed.", "Token[ABC], line 1", st.toString());
 
         // Regression test for HARMONY-4070
         byte[] data = new byte[] { (byte) '-' };