diff --git a/teavm-classlib/src/main/java/org/teavm/classlib/java/lang/AbstractStringBuilder.java b/teavm-classlib/src/main/java/org/teavm/classlib/java/lang/TAbstractStringBuilder.java similarity index 57% rename from teavm-classlib/src/main/java/org/teavm/classlib/java/lang/AbstractStringBuilder.java rename to teavm-classlib/src/main/java/org/teavm/classlib/java/lang/TAbstractStringBuilder.java index 0e75edcd3..a45610a78 100644 --- a/teavm-classlib/src/main/java/org/teavm/classlib/java/lang/AbstractStringBuilder.java +++ b/teavm-classlib/src/main/java/org/teavm/classlib/java/lang/TAbstractStringBuilder.java @@ -2,24 +2,25 @@ package org.teavm.classlib.java.lang; import org.teavm.classlib.java.lang.io.TSerializable; import org.teavm.classlib.java.util.TArrays; +import org.teavm.javascript.ni.Rename; /** * * @author Alexey Andreev */ -class AbstractStringBuilder extends TObject implements TSerializable { +class TAbstractStringBuilder extends TObject implements TSerializable { private char[] buffer; private int length; - public AbstractStringBuilder() { + public TAbstractStringBuilder() { this(16); } - public AbstractStringBuilder(int capacity) { + public TAbstractStringBuilder(int capacity) { buffer = new char[capacity]; } - protected AbstractStringBuilder append(TString string) { + protected TAbstractStringBuilder append(TString string) { ensureCapacity(length + string.length()); int j = length; for (int i = 0; i < string.length(); ++i) { @@ -29,13 +30,20 @@ class AbstractStringBuilder extends TObject implements TSerializable { return this; } - protected AbstractStringBuilder append(int value) { + protected TAbstractStringBuilder append(int value) { + boolean positive = true; if (value < 0) { - append('-'); + positive = false; value = -value; } if (value < 10) { - append((char)('0' + value)); + if (!positive) { + ensureCapacity(length + 2); + buffer[length++] = '-'; + } else { + ensureCapacity(length + 1); + } + buffer[length++] = (char)('0' + value); } else { int pos = 10; int sz = 1; @@ -43,7 +51,14 @@ class AbstractStringBuilder extends TObject implements TSerializable { pos *= 10; ++sz; } + if (!positive) { + ++sz; + } ensureCapacity(length + sz); + if (!positive) { + buffer[length++] = '-'; + } + pos /= 10; while (pos > 0) { buffer[length++] = (char)('0' + value / pos); value %= pos; @@ -53,7 +68,7 @@ class AbstractStringBuilder extends TObject implements TSerializable { return this; } - protected AbstractStringBuilder append(char c) { + protected TAbstractStringBuilder append(char c) { ensureCapacity(length + 1); buffer[length++] = c; return this; @@ -65,4 +80,10 @@ class AbstractStringBuilder extends TObject implements TSerializable { } buffer = TArrays.copyOf(buffer, capacity * 2 + 1); } + + @Override + @Rename("toString") + public TString toString0() { + return new TString(buffer, 0, length); + } } diff --git a/teavm-classlib/src/main/java/org/teavm/classlib/java/lang/TMath.java b/teavm-classlib/src/main/java/org/teavm/classlib/java/lang/TMath.java new file mode 100644 index 000000000..387035c9b --- /dev/null +++ b/teavm-classlib/src/main/java/org/teavm/classlib/java/lang/TMath.java @@ -0,0 +1,14 @@ +package org.teavm.classlib.java.lang; + +/** + * + * @author Alexey Andreev + */ +public final class TMath extends TObject { + private TMath() { + } + + public static int min(int a, int b) { + return a < b ? a : b; + } +} 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 7474827ec..f494cb409 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 @@ -9,6 +9,7 @@ import org.teavm.javascript.ni.GeneratedBy; */ public class TString extends TObject implements TSerializable { private char[] characters; + private transient int hashCode; public TString() { this.characters = new char[0]; @@ -47,6 +48,41 @@ public class TString extends TObject implements TSerializable { return new TStringBuilder().append(index).toString0(); } + @Override + public boolean equals(TObject other) { + if (this == other) { + return true; + } + if (!(other instanceof TString)) { + return false; + } + TString str = (TString)other; + if (str.length() != length()) { + return false; + } + for (int i = 0; i < str.length(); ++i) { + if (charAt(i) != str.charAt(i)) { + return false; + } + } + return true; + } + + @Override + public int hashCode() { + if (hashCode == 0) { + hashCode ^= 734262231; + for (char c : characters) { + hashCode = (hashCode << 4) | (hashCode >>> 28); + hashCode ^= 347236277 ^ c; + if (hashCode == 0) { + ++hashCode; + } + } + } + return hashCode; + } + @GeneratedBy(StringNativeGenerator.class) public static native TString wrap(String str); } diff --git a/teavm-classlib/src/main/java/org/teavm/classlib/java/lang/TStringBuilder.java b/teavm-classlib/src/main/java/org/teavm/classlib/java/lang/TStringBuilder.java index 50dae2324..33132c66f 100644 --- a/teavm-classlib/src/main/java/org/teavm/classlib/java/lang/TStringBuilder.java +++ b/teavm-classlib/src/main/java/org/teavm/classlib/java/lang/TStringBuilder.java @@ -4,7 +4,7 @@ package org.teavm.classlib.java.lang; * * @author Alexey Andreev */ -public class TStringBuilder extends AbstractStringBuilder { +public class TStringBuilder extends TAbstractStringBuilder { @Override public TStringBuilder append(TString string) { super.append(string); diff --git a/teavm-classlib/src/main/java/org/teavm/classlib/java/lang/TStringBuilderTests.java b/teavm-classlib/src/main/java/org/teavm/classlib/java/lang/TStringBuilderTests.java new file mode 100644 index 000000000..c84b43059 --- /dev/null +++ b/teavm-classlib/src/main/java/org/teavm/classlib/java/lang/TStringBuilderTests.java @@ -0,0 +1,17 @@ +package org.teavm.classlib.java.lang; + +import static org.junit.Assert.*; +import org.junit.Test; + +/** + * + * @author Alexey Andreev + */ +class TStringBuilderTests { + @Test + public void integerAppended() { + TStringBuilder sb = new TStringBuilder(); + sb.append(23); + assertEquals("23", sb.toString()); + } +} 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 d0d1e3e63..ac3d01776 100644 --- a/teavm-classlib/src/main/java/org/teavm/classlibgen/ClasslibTestGenerator.java +++ b/teavm-classlib/src/main/java/org/teavm/classlibgen/ClasslibTestGenerator.java @@ -30,7 +30,8 @@ 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", "java.lang.SystemTests" }; + private static String[] testClasses = { "java.lang.ObjectTests", "java.lang.SystemTests", + "java.lang.StringBuilderTests" }; public static void main(String[] args) throws IOException { out = System.out; diff --git a/teavm-core/src/main/java/org/teavm/dependency/DependencyChecker.java b/teavm-core/src/main/java/org/teavm/dependency/DependencyChecker.java index a8f6c0db5..e5a454ebd 100644 --- a/teavm-core/src/main/java/org/teavm/dependency/DependencyChecker.java +++ b/teavm-core/src/main/java/org/teavm/dependency/DependencyChecker.java @@ -159,10 +159,20 @@ public class DependencyChecker { } } - private MethodGraph createMethodGraph(MethodReference methodRef) { + private MethodGraph createMethodGraph(final MethodReference methodRef) { initClass(methodRef.getClassName()); ClassHolder cls = classSource.getClassHolder(methodRef.getClassName()); MethodHolder method = cls.getMethod(methodRef.getDescriptor()); + if (method == null) { + while (cls != null) { + method = cls.getMethod(methodRef.getDescriptor()); + if (method != null) { + return methodCache.map(new MethodReference(cls.getName(), methodRef.getDescriptor())); + } + cls = classSource.getClassHolder(cls.getParent()); + } + throw new RuntimeException("Method not found: " + methodRef); + } ValueType[] arguments = method.getParameterTypes(); int paramCount = arguments.length + 1; int varCount = Math.max(paramCount, method.getProgram().variableCount()); @@ -184,10 +194,15 @@ public class DependencyChecker { method.getName() + MethodDescriptor.get(method) + ":RESULT"); } } - MethodGraph graph = new MethodGraph(parameterNodes, paramCount, resultNode, this); - DependencyGraphBuilder graphBuilder = new DependencyGraphBuilder(this); - graphBuilder.buildGraph(method, graph); - achieveClass(methodRef.getClassName()); + final MethodGraph graph = new MethodGraph(parameterNodes, paramCount, resultNode, this); + final MethodHolder currentMethod = method; + executor.submit(new Runnable() { + @Override public void run() { + DependencyGraphBuilder graphBuilder = new DependencyGraphBuilder(DependencyChecker.this); + graphBuilder.buildGraph(currentMethod, graph); + achieveClass(methodRef.getClassName()); + } + }); return graph; } @@ -223,6 +238,9 @@ public class DependencyChecker { private void activateDependencyPlugin(MethodReference methodRef) { ClassHolder cls = classSource.getClassHolder(methodRef.getClassName()); MethodHolder method = cls.getMethod(methodRef.getDescriptor()); + if (method == null) { + return; + } AnnotationHolder depAnnot = method.getAnnotations().get(PluggableDependency.class.getName()); if (depAnnot == null) { return; diff --git a/teavm-core/src/main/java/org/teavm/model/ClassHolder.java b/teavm-core/src/main/java/org/teavm/model/ClassHolder.java index 6f275dcf8..1924c3b85 100644 --- a/teavm-core/src/main/java/org/teavm/model/ClassHolder.java +++ b/teavm-core/src/main/java/org/teavm/model/ClassHolder.java @@ -98,5 +98,6 @@ public class ClassHolder extends ElementHolder { field.getName() + " is not a member of " + getName()); } fields.remove(field.getName()); + field.setOwner(null); } }