From 18e35b80e67f21bca81a29452587b2ea6fb4e530 Mon Sep 17 00:00:00 2001 From: Alexey Andreev Date: Fri, 22 Nov 2013 17:19:51 +0400 Subject: [PATCH] Adds some JVM classes. --- .../java/lang/StringNativeGenerator.java | 25 +++++++++ .../java/lang/SystemNativeGenerator.java | 52 +++++++++++++++++++ .../teavm/classlib/java/lang/TException.java | 9 ++++ .../org/teavm/classlib/java/lang/TObject.java | 3 ++ .../classlib/java/lang/TObjectTests.java | 5 ++ .../org/teavm/classlib/java/lang/TString.java | 31 ++++++++++- .../org/teavm/classlib/java/lang/TSystem.java | 19 +++++++ .../classlib/java/lang/TSystemTests.java | 22 ++++++++ .../teavm/classlib/java/lang/TThrowable.java | 2 + .../classlibgen/ClasslibTestGenerator.java | 40 ++++++++------ .../org/teavm/classlib/junit-support.js | 8 ++- .../teavm/codegen/ConcurrentCachedMapper.java | 14 ++--- .../org/teavm/dependency/DependencyNode.java | 18 +++---- .../java/org/teavm/javascript/Renderer.java | 20 +++++++ .../resources/org/teavm/javascript/runtime.js | 40 +++++++------- 15 files changed, 253 insertions(+), 55 deletions(-) create mode 100644 teavm-classlib/src/main/java/org/teavm/classlib/java/lang/StringNativeGenerator.java create mode 100644 teavm-classlib/src/main/java/org/teavm/classlib/java/lang/SystemNativeGenerator.java create mode 100644 teavm-classlib/src/main/java/org/teavm/classlib/java/lang/TException.java create mode 100644 teavm-classlib/src/main/java/org/teavm/classlib/java/lang/TSystem.java create mode 100644 teavm-classlib/src/main/java/org/teavm/classlib/java/lang/TSystemTests.java diff --git a/teavm-classlib/src/main/java/org/teavm/classlib/java/lang/StringNativeGenerator.java b/teavm-classlib/src/main/java/org/teavm/classlib/java/lang/StringNativeGenerator.java new file mode 100644 index 000000000..80c8a4c75 --- /dev/null +++ b/teavm-classlib/src/main/java/org/teavm/classlib/java/lang/StringNativeGenerator.java @@ -0,0 +1,25 @@ +package org.teavm.classlib.java.lang; + +import org.teavm.codegen.SourceWriter; +import org.teavm.javascript.ni.Generator; +import org.teavm.javascript.ni.GeneratorContext; +import org.teavm.model.MethodReference; + +/** + * + * @author Alexey Andreev + */ +public class StringNativeGenerator implements Generator { + @Override + public void generate(GeneratorContext context, SourceWriter writer, MethodReference methodRef) { + switch (methodRef.getName()) { + case "wrap": + generateWrap(context, writer); + break; + } + } + + private void generateWrap(GeneratorContext context, SourceWriter writer) { + writer.append("return ").append(context.getParameterName(1)).newLine(); + } +} diff --git a/teavm-classlib/src/main/java/org/teavm/classlib/java/lang/SystemNativeGenerator.java b/teavm-classlib/src/main/java/org/teavm/classlib/java/lang/SystemNativeGenerator.java new file mode 100644 index 000000000..e7a86748f --- /dev/null +++ b/teavm-classlib/src/main/java/org/teavm/classlib/java/lang/SystemNativeGenerator.java @@ -0,0 +1,52 @@ +package org.teavm.classlib.java.lang; + +import org.teavm.codegen.SourceWriter; +import org.teavm.dependency.DependencyChecker; +import org.teavm.dependency.DependencyNode; +import org.teavm.dependency.DependencyPlugin; +import org.teavm.dependency.MethodGraph; +import org.teavm.javascript.ni.Generator; +import org.teavm.javascript.ni.GeneratorContext; +import org.teavm.model.MethodReference; + +/** + * + * @author Alexey Andreev + */ +public class SystemNativeGenerator implements Generator, DependencyPlugin { + @Override + public void generate(GeneratorContext context, SourceWriter writer, MethodReference methodRef) { + switch (methodRef.getName()) { + case "doArrayCopy": + generateArrayCopy(context, writer); + break; + } + } + + @Override + public void methodAchieved(DependencyChecker checker, MethodReference method) { + switch (method.getName()) { + case "doArrayCopy": + achieveArrayCopy(checker, method); + break; + } + } + + private void generateArrayCopy(GeneratorContext context, SourceWriter writer) { + String src = context.getParameterName(1); + String srcPos = context.getParameterName(2); + String dest = context.getParameterName(3); + String destPos = context.getParameterName(4); + String length = context.getParameterName(5); + writer.append("for (var i = 0; i < " + length + "; i = (i + 1) | 0) {").indent().newLine(); + writer.append(dest + "[" + srcPos + "++] = " + src + "[" + destPos + "++];").newLine(); + writer.outdent().append("}").newLine(); + } + + private void achieveArrayCopy(DependencyChecker checker, MethodReference method) { + MethodGraph graph = checker.attachMethodGraph(method); + DependencyNode src = graph.getVariableNode(1); + DependencyNode dest = graph.getVariableNode(3); + src.getArrayItemNode().connect(dest.getArrayItemNode()); + } +} diff --git a/teavm-classlib/src/main/java/org/teavm/classlib/java/lang/TException.java b/teavm-classlib/src/main/java/org/teavm/classlib/java/lang/TException.java new file mode 100644 index 000000000..21151a6fd --- /dev/null +++ b/teavm-classlib/src/main/java/org/teavm/classlib/java/lang/TException.java @@ -0,0 +1,9 @@ +package org.teavm.classlib.java.lang; + +/** + * + * @author Alexey Andreev + */ +public class TException extends TThrowable { + private static final long serialVersionUID = -2188339106250208952L; +} diff --git a/teavm-classlib/src/main/java/org/teavm/classlib/java/lang/TObject.java b/teavm-classlib/src/main/java/org/teavm/classlib/java/lang/TObject.java index b0a2083c7..935cde39b 100644 --- a/teavm-classlib/src/main/java/org/teavm/classlib/java/lang/TObject.java +++ b/teavm-classlib/src/main/java/org/teavm/classlib/java/lang/TObject.java @@ -31,6 +31,9 @@ public class TObject { @GeneratedBy(ObjectNativeGenerator.class) public native boolean equals(TObject other); + @Rename("toString") + public native TString toString0(); + @Override @GeneratedBy(ObjectNativeGenerator.class) @PluggableDependency(ObjectNativeGenerator.class) diff --git a/teavm-classlib/src/main/java/org/teavm/classlib/java/lang/TObjectTests.java b/teavm-classlib/src/main/java/org/teavm/classlib/java/lang/TObjectTests.java index 12d0bd07f..141fb8809 100644 --- a/teavm-classlib/src/main/java/org/teavm/classlib/java/lang/TObjectTests.java +++ b/teavm-classlib/src/main/java/org/teavm/classlib/java/lang/TObjectTests.java @@ -45,4 +45,9 @@ class TObjectTests { public void properInstanceDetected() { assertTrue(Object.class.isInstance(new Object())); } + + @Test + public void alwaysFails() { + fail(); + } } diff --git a/teavm-classlib/src/main/java/org/teavm/classlib/java/lang/TString.java b/teavm-classlib/src/main/java/org/teavm/classlib/java/lang/TString.java index b421e4f2b..abd5121e6 100644 --- a/teavm-classlib/src/main/java/org/teavm/classlib/java/lang/TString.java +++ b/teavm-classlib/src/main/java/org/teavm/classlib/java/lang/TString.java @@ -1,9 +1,36 @@ package org.teavm.classlib.java.lang; +import org.teavm.javascript.ni.GeneratedBy; + /** - * + * * @author Alexey Andreev */ -public class TString { +public class TString extends TObject { + private char[] characters; + public TString() { + this.characters = new char[0]; + } + + public TString(TString other) { + characters = other.characters; + } + + public TString(char[] characters) { + this.characters = new char[characters.length]; + for (int i = 0; i < characters.length; ++i) { + this.characters[i] = characters[i]; + } + } + + public TString(char[] value, int offset, int count) { + this.characters = new char[count]; + for (int i = 0; i < count; ++i) { + this.characters[i] = value[i + offset]; + } + } + + @GeneratedBy(StringNativeGenerator.class) + public static native TString wrap(String str); } diff --git a/teavm-classlib/src/main/java/org/teavm/classlib/java/lang/TSystem.java b/teavm-classlib/src/main/java/org/teavm/classlib/java/lang/TSystem.java new file mode 100644 index 000000000..2c1d3a335 --- /dev/null +++ b/teavm-classlib/src/main/java/org/teavm/classlib/java/lang/TSystem.java @@ -0,0 +1,19 @@ +package org.teavm.classlib.java.lang; + +import org.teavm.javascript.ni.GeneratedBy; + +/** + * + * @author Alexey Andreev + */ +public final class TSystem extends TObject { + private TSystem() { + } + + public static void arraycopy(Object src, int srcPos, Object dest, int destPos, int length) { + doArrayCopy(src, srcPos, dest, destPos, length); + } + + @GeneratedBy(SystemNativeGenerator.class) + private static native void doArrayCopy(Object src, int srcPos, Object dest, int destPos, int length); +} diff --git a/teavm-classlib/src/main/java/org/teavm/classlib/java/lang/TSystemTests.java b/teavm-classlib/src/main/java/org/teavm/classlib/java/lang/TSystemTests.java new file mode 100644 index 000000000..e40414a47 --- /dev/null +++ b/teavm-classlib/src/main/java/org/teavm/classlib/java/lang/TSystemTests.java @@ -0,0 +1,22 @@ +package org.teavm.classlib.java.lang; + +import static org.junit.Assert.*; +import org.junit.Test; + +/** + * + * @author Alexey Andreev + */ +class TSystemTests { + @Test + public void copiesArray() { + TObject a = new TObject(); + TObject b = new TObject(); + TObject[] src = { a, b, a }; + TObject[] dest = new TObject[3]; + TSystem.arraycopy(src, 0, dest, 0, 3); + assertSame(a, dest[0]); + assertSame(b, dest[1]); + assertSame(a, dest[2]); + } +} diff --git a/teavm-classlib/src/main/java/org/teavm/classlib/java/lang/TThrowable.java b/teavm-classlib/src/main/java/org/teavm/classlib/java/lang/TThrowable.java index 74ecc98c4..3ec6f954b 100644 --- a/teavm-classlib/src/main/java/org/teavm/classlib/java/lang/TThrowable.java +++ b/teavm-classlib/src/main/java/org/teavm/classlib/java/lang/TThrowable.java @@ -6,4 +6,6 @@ package org.teavm.classlib.java.lang; */ public class TThrowable extends Throwable { private static final long serialVersionUID = 2026791432677149320L; + private TString message; + private TThrowable cause; } diff --git a/teavm-classlib/src/main/java/org/teavm/classlibgen/ClasslibTestGenerator.java b/teavm-classlib/src/main/java/org/teavm/classlibgen/ClasslibTestGenerator.java index 290ec68ff..d0d1e3e63 100644 --- a/teavm-classlib/src/main/java/org/teavm/classlibgen/ClasslibTestGenerator.java +++ b/teavm-classlib/src/main/java/org/teavm/classlibgen/ClasslibTestGenerator.java @@ -1,7 +1,9 @@ package org.teavm.classlibgen; +import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; +import java.io.PrintStream; import java.util.*; import org.apache.commons.io.IOUtils; import org.teavm.codegen.DefaultAliasProvider; @@ -19,6 +21,7 @@ import org.teavm.model.resource.ClasspathClassHolderSource; * @author Alexey Andreev */ public class ClasslibTestGenerator { + private static PrintStream out; private static ClasspathClassHolderSource classSource; private static Decompiler decompiler; private static DefaultAliasProvider aliasProvider; @@ -27,9 +30,13 @@ public class ClasslibTestGenerator { private static Renderer renderer; private static List testMethods = new ArrayList<>(); private static Map> groupedMethods = new HashMap<>(); - private static String[] testClasses = { "java.lang.ObjectTests" }; + private static String[] testClasses = { "java.lang.ObjectTests", "java.lang.SystemTests" }; public static void main(String[] args) throws IOException { + out = System.out; + if (args.length > 0) { + out = new PrintStream(new FileOutputStream(args[0])); + } classSource = new ClasspathClassHolderSource(); decompiler = new Decompiler(classSource); aliasProvider = new DefaultAliasProvider(); @@ -52,15 +59,16 @@ public class ClasslibTestGenerator { renderHead(); ClassLoader classLoader = ClasslibTestGenerator.class.getClassLoader(); try (InputStream input = classLoader.getResourceAsStream("org/teavm/classlib/junit-support.js")) { - System.out.println(IOUtils.toString(input)); + out.println(IOUtils.toString(input)); } try (InputStream input = classLoader.getResourceAsStream("org/teavm/javascript/runtime.js")) { - System.out.println(IOUtils.toString(input)); + out.println(IOUtils.toString(input)); } + renderer.renderRuntime(); for (String testClass : testClasses) { renderClassTest(classSource.getClassHolder(testClass)); } - System.out.println(writer); + out.println(writer); renderFoot(); } @@ -72,21 +80,21 @@ public class ClasslibTestGenerator { } private static void renderHead() { - System.out.println(""); - System.out.println(""); - System.out.println(" "); - System.out.println(" TeaVM JUnit tests"); - System.out.println(" "); - System.out.println(" TeaVM JUnit tests"); - System.out.println(" "); - System.out.println(" "); - System.out.println(" "); - System.out.println(" "); - System.out.println(""); + out.println(" "); + out.println(" "); + out.println(""); } private static void renderClassTest(ClassHolder cls) { diff --git a/teavm-classlib/src/main/resources/org/teavm/classlib/junit-support.js b/teavm-classlib/src/main/resources/org/teavm/classlib/junit-support.js index 64245d64f..241e87e70 100644 --- a/teavm-classlib/src/main/resources/org/teavm/classlib/junit-support.js +++ b/teavm-classlib/src/main/resources/org/teavm/classlib/junit-support.js @@ -19,10 +19,14 @@ runTestCase = function(instance, methodName, realMethodName) { } catch (e) { if (e instanceof JUnitAssertionFailure) { statusCell.appendChild(document.createTextNode("assertion failed")); - exceptionCell.appendChild(document.createTextNode(e.stack)); + var exceptionText = document.createElement("pre"); + exceptionText.appendChild(document.createTextNode(e.stack)); + exceptionCell.appendChild(exceptionText); } else { statusCell.appendChild(document.createTextNode("unexpected exception")); - exceptionCell.appendChild(document.createTextNode(e.stack)); + var exceptionText = document.createElement("pre"); + exceptionText.appendChild(document.createTextNode(e.stack)); + exceptionCell.appendChild(exceptionText); } } } diff --git a/teavm-core/src/main/java/org/teavm/codegen/ConcurrentCachedMapper.java b/teavm-core/src/main/java/org/teavm/codegen/ConcurrentCachedMapper.java index 0d70cc45a..c56ddcb02 100644 --- a/teavm-core/src/main/java/org/teavm/codegen/ConcurrentCachedMapper.java +++ b/teavm-core/src/main/java/org/teavm/codegen/ConcurrentCachedMapper.java @@ -40,13 +40,15 @@ public class ConcurrentCachedMapper implements Mapper { listener.keyAdded(preimage); } } else { - CountDownLatch latch = oldWrapper.latch; wrapper = oldWrapper; - try { - latch.await(); - } catch (InterruptedException e) { - Thread.currentThread().interrupt(); - } + } + } + CountDownLatch latch = wrapper.latch; + if (latch != null) { + try { + latch.await(); + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); } } return wrapper.value; diff --git a/teavm-core/src/main/java/org/teavm/dependency/DependencyNode.java b/teavm-core/src/main/java/org/teavm/dependency/DependencyNode.java index e131eaaa0..d6dae6cf0 100644 --- a/teavm-core/src/main/java/org/teavm/dependency/DependencyNode.java +++ b/teavm-core/src/main/java/org/teavm/dependency/DependencyNode.java @@ -76,18 +76,18 @@ public class DependencyNode { arrayItemNodeLatch.countDown(); arrayItemNodeLatch = null; } else { - CountDownLatch latch = arrayItemNodeLatch; - if (latch != null) { - try { - latch.await(); - } catch (InterruptedException e) { - Thread.currentThread().interrupt(); - return result; - } - } result = arrayItemNode.get(); } } + CountDownLatch latch = arrayItemNodeLatch; + if (latch != null) { + try { + latch.await(); + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + return result; + } + } return result; } diff --git a/teavm-core/src/main/java/org/teavm/javascript/Renderer.java b/teavm-core/src/main/java/org/teavm/javascript/Renderer.java index 94fbcf411..b951c186a 100644 --- a/teavm-core/src/main/java/org/teavm/javascript/Renderer.java +++ b/teavm-core/src/main/java/org/teavm/javascript/Renderer.java @@ -45,6 +45,26 @@ public class Renderer implements ExprVisitor, StatementVisitor { return naming; } + public void renderRuntime() { + renderRuntimeCls(); + } + + private void renderRuntimeCls() { + writer.append("$rt_cls = function(cls) {").indent().newLine(); + String classClass = "java.lang.Class"; + writer.append("var cls = cls.classObject;").newLine(); + writer.append("if (cls === undefined) {").newLine().indent(); + MethodReference createMethodRef = new MethodReference(classClass, new MethodDescriptor("createNew", + ValueType.object(classClass))); + writer.append("cls = ").appendClass(classClass).append('.').appendMethod(createMethodRef) + .append("();").newLine(); + writer.append("cls.$data = cls;").newLine(); + writer.append("cls.classObject = cls;").newLine(); + writer.outdent().append("}").newLine(); + writer.append("return cls;").newLine(); + writer.outdent().append("}").newLine(); + } + public void render(ClassNode cls) { writer.appendClass(cls.getName()).append(" = function() {").indent().newLine(); for (FieldNode field : cls.getFields()) { diff --git a/teavm-core/src/main/resources/org/teavm/javascript/runtime.js b/teavm-core/src/main/resources/org/teavm/javascript/runtime.js index ad13d3c9a..9b0a00376 100644 --- a/teavm-core/src/main/resources/org/teavm/javascript/runtime.js +++ b/teavm-core/src/main/resources/org/teavm/javascript/runtime.js @@ -20,6 +20,26 @@ $rt_isAssignable = function(from, to) { } return false; } +$rt_createArray = function(cls, sz) { + var arr = new Array(sz); + arr.$class = $rt_arraycls(cls); + arr.$id = $rt_lastObjectId++; + for (var i = 0; i < sz; i = (i + 1) | 0) { + arr[i] = null; + } + return arr; +} +$rt_arraycls = function(cls) { + if (cls.$array == undefined) { + cls.$array = { + $meta : { item : cls }, + }; + if ($rt.objcls) { + cls.$array.$meta.supertypes = [$rt.objcls()]; + } + } + return cls.$array; +} $rt = { createBooleanArray : function(cls, sz) { @@ -43,15 +63,6 @@ $rt = { } return arr; }, - createArray : function(cls, sz) { - var arr = new Array(sz); - arr.$class = $rt.arraycls(cls); - arr.$id = $rt.lastObjectId++; - for (var i = 0; i < sz; i = (i + 1) | 0) { - arr[i] = null; - } - return arr; - }, createMultiArray : function(cls, dimensions) { for (var i = 1; i < dimensions.length; i = (i + 1) | 0) { cls = $rt.arraycls(cls); @@ -75,17 +86,6 @@ $rt = { $rt.setId(arr, $rt.lastObjectId++); return arr; }, - arraycls : function(cls) { - if (cls.$array == undefined) { - cls.$array = { - $meta : { item : cls }, - }; - if ($rt.objcls) { - cls.$array.$meta.supertypes = [$rt.objcls()]; - } - } - return cls.$array; - }, createcls : function() { return { $meta : {