diff --git a/classlib/src/main/java/org/teavm/classlib/impl/JCLPlugin.java b/classlib/src/main/java/org/teavm/classlib/impl/JCLPlugin.java index c2336042c..c5894b90a 100644 --- a/classlib/src/main/java/org/teavm/classlib/impl/JCLPlugin.java +++ b/classlib/src/main/java/org/teavm/classlib/impl/JCLPlugin.java @@ -90,6 +90,7 @@ public class JCLPlugin implements TeaVMPlugin { } host.add(new NumericClassTransformer()); + host.add(new SystemClassTransformer()); if (!isBootstrap()) { List reflectionSuppliers = new ArrayList<>(); diff --git a/classlib/src/main/java/org/teavm/classlib/impl/SystemClassTransformer.java b/classlib/src/main/java/org/teavm/classlib/impl/SystemClassTransformer.java new file mode 100644 index 000000000..fcf5f98cf --- /dev/null +++ b/classlib/src/main/java/org/teavm/classlib/impl/SystemClassTransformer.java @@ -0,0 +1,70 @@ +/* + * Copyright 2018 Alexey Andreev. + * + * 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 org.teavm.classlib.impl; + +import org.teavm.diagnostics.Diagnostics; +import org.teavm.model.BasicBlock; +import org.teavm.model.ClassHolder; +import org.teavm.model.ClassHolderTransformer; +import org.teavm.model.ClassReaderSource; +import org.teavm.model.FieldReference; +import org.teavm.model.Instruction; +import org.teavm.model.MethodHolder; +import org.teavm.model.MethodReference; +import org.teavm.model.Program; +import org.teavm.model.instructions.GetFieldInstruction; +import org.teavm.model.instructions.InvocationType; +import org.teavm.model.instructions.InvokeInstruction; + +public class SystemClassTransformer implements ClassHolderTransformer { + @Override + public void transformClass(ClassHolder cls, ClassReaderSource innerSource, Diagnostics diagnostics) { + for (MethodHolder method : cls.getMethods()) { + if (method.getProgram() != null) { + transformProgram(method.getProgram()); + } + } + } + + private void transformProgram(Program program) { + for (BasicBlock block : program.getBasicBlocks()) { + for (Instruction insn : block) { + if (!(insn instanceof GetFieldInstruction)) { + continue; + } + + GetFieldInstruction getField = (GetFieldInstruction) insn; + FieldReference field = getField.getField(); + if (field.getClassName().equals("java.lang.System")) { + switch (field.getFieldName()) { + case "err": + case "out": + case "in": { + InvokeInstruction invoke = new InvokeInstruction(); + invoke.setType(InvocationType.SPECIAL); + invoke.setMethod(new MethodReference("java.lang.System", field.getFieldName(), + getField.getFieldType())); + invoke.setReceiver(getField.getReceiver()); + invoke.setLocation(insn.getLocation()); + insn.replace(invoke); + break; + } + } + } + } + } + } +} diff --git a/classlib/src/main/java/org/teavm/classlib/java/lang/SystemNativeGenerator.java b/classlib/src/main/java/org/teavm/classlib/java/lang/SystemNativeGenerator.java index 8e39926d9..4090c0b5f 100644 --- a/classlib/src/main/java/org/teavm/classlib/java/lang/SystemNativeGenerator.java +++ b/classlib/src/main/java/org/teavm/classlib/java/lang/SystemNativeGenerator.java @@ -22,10 +22,8 @@ import org.teavm.backend.javascript.spi.GeneratorContext; import org.teavm.dependency.DependencyAgent; import org.teavm.dependency.DependencyNode; import org.teavm.dependency.DependencyPlugin; -import org.teavm.dependency.FieldDependency; import org.teavm.dependency.MethodDependency; import org.teavm.model.CallLocation; -import org.teavm.model.FieldReference; import org.teavm.model.MethodReference; public class SystemNativeGenerator implements Generator, DependencyPlugin { @@ -38,14 +36,6 @@ public class SystemNativeGenerator implements Generator, DependencyPlugin { case "currentTimeMillis": generateCurrentTimeMillis(writer); break; - case "setOut": - writer.appendStaticField(new FieldReference("java.lang.System", "out")) - .ws().append('=').ws().append(context.getParameterName(1)).append(";").softNewLine(); - break; - case "setErr": - writer.appendStaticField(new FieldReference("java.lang.System", "err")) - .ws().append('=').ws().append(context.getParameterName(1)).append(";").softNewLine(); - break; } } @@ -53,13 +43,7 @@ public class SystemNativeGenerator implements Generator, DependencyPlugin { public void methodReached(DependencyAgent agent, MethodDependency method, CallLocation location) { switch (method.getReference().getName()) { case "doArrayCopy": - achieveArrayCopy(method); - break; - case "setOut": - achieveSetOut(agent, method); - break; - case "setErr": - achieveSetErr(agent, method); + reachArrayCopy(method); break; } } @@ -84,23 +68,12 @@ public class SystemNativeGenerator implements Generator, DependencyPlugin { } private void generateCurrentTimeMillis(SourceWriter writer) throws IOException { - writer.append(writer.getNaming().getNameForClassInit("java.lang.System")).append("();").softNewLine(); writer.append("return Long_fromNumber(new Date().getTime());").softNewLine(); } - private void achieveArrayCopy(MethodDependency method) { + private void reachArrayCopy(MethodDependency method) { DependencyNode src = method.getVariable(1); DependencyNode dest = method.getVariable(3); src.getArrayItem().connect(dest.getArrayItem()); } - - private void achieveSetErr(DependencyAgent agent, MethodDependency method) { - FieldDependency fieldDep = agent.linkField(new FieldReference("java.lang.System", "err"), null); - method.getVariable(1).connect(fieldDep.getValue()); - } - - private void achieveSetOut(DependencyAgent agent, MethodDependency method) { - FieldDependency fieldDep = agent.linkField(new FieldReference("java.lang.System", "out"), null); - method.getVariable(1).connect(fieldDep.getValue()); - } } diff --git a/classlib/src/main/java/org/teavm/classlib/java/lang/TAbstractStringBuilder.java b/classlib/src/main/java/org/teavm/classlib/java/lang/TAbstractStringBuilder.java index 930348a7f..5d29f9f4f 100644 --- a/classlib/src/main/java/org/teavm/classlib/java/lang/TAbstractStringBuilder.java +++ b/classlib/src/main/java/org/teavm/classlib/java/lang/TAbstractStringBuilder.java @@ -19,25 +19,29 @@ import org.teavm.classlib.java.io.TSerializable; import org.teavm.classlib.java.util.TArrays; class TAbstractStringBuilder extends TObject implements TSerializable, TCharSequence { - private static float[] powersOfTen = { 1E1f, 1E2f, 1E4f, 1E8f, 1E16f, 1E32f }; - private static double[] doublePowersOfTen = { 1E1, 1E2, 1E4, 1E8, 1E16, 1E32, 1E64, 1E128, 1E256 }; - private static float[] negPowersOfTen = { 1E-1f, 1E-2f, 1E-4f, 1E-8f, 1E-16f, 1E-32f }; - private static double[] negDoublePowersOfTen = { 1E-1, 1E-2, 1E-4, 1E-8, 1E-16, 1E-32, - 1E-64, 1E-128, 1E-256 }; - private static int[] intPowersOfTen = { 1, 10, 100, 1000, 10000, 100000, 1000000, 10000000, 100000000, - 1000000000 }; - private static long[] longPowersOfTen = { 1, 10, 100, 1000, 10000, 100000, 1000000, 10000000, 100000000, - 1000000000, 10000000000L, 100000000000L, 1000000000000L, 10000000000000L, 100000000000000L, - 1000000000000000L, 10000000000000000L, 100000000000000000L, 1000000000000000000L }; - private static final long[] longLogPowersOfTen = { 1, 10, 100, 10000, 100000000, 10000000000000000L, }; - private static final int FLOAT_DECIMAL_PRECISION = 7; - private static final int DOUBLE_DECIMAL_PRECISION = 16; - private static final float FLOAT_DECIMAL_FACTOR = 1E6f; - private static final double DOUBLE_DECIMAL_FACTOR = 1E15; - private static final int FLOAT_MAX_EXPONENT = 38; - private static final int DOUBLE_MAX_EXPONENT = 308; - private static final int FLOAT_MAX_POS = 1000000; - private static final long DOUBLE_MAX_POS = 1000000000000000L; + static class Constants { + private static float[] powersOfTen = { 1E1f, 1E2f, 1E4f, 1E8f, 1E16f, 1E32f }; + private static double[] doublePowersOfTen = { 1E1, 1E2, 1E4, 1E8, 1E16, 1E32, 1E64, 1E128, 1E256 }; + private static float[] negPowersOfTen = { 1E-1f, 1E-2f, 1E-4f, 1E-8f, 1E-16f, 1E-32f }; + private static double[] negDoublePowersOfTen = { 1E-1, 1E-2, 1E-4, 1E-8, 1E-16, 1E-32, + 1E-64, 1E-128, 1E-256 }; + private static int[] intPowersOfTen = { 1, 10, 100, 1000, 10000, 100000, 1000000, 10000000, 100000000, + 1000000000 }; + private static long[] longPowersOfTen = { 1, 10, 100, 1000, 10000, 100000, 1000000, 10000000, 100000000, + 1000000000, 10000000000L, 100000000000L, 1000000000000L, 10000000000000L, 100000000000000L, + 1000000000000000L, 10000000000000000L, 100000000000000000L, 1000000000000000000L }; + private static final long[] longLogPowersOfTen = { 1, 10, 100, 10000, 100000000, 10000000000000000L, }; + + private static final int FLOAT_DECIMAL_PRECISION = 7; + private static final int DOUBLE_DECIMAL_PRECISION = 16; + private static final float FLOAT_DECIMAL_FACTOR = 1E6f; + private static final double DOUBLE_DECIMAL_FACTOR = 1E15; + private static final int FLOAT_MAX_EXPONENT = 38; + private static final int DOUBLE_MAX_EXPONENT = 308; + private static final int FLOAT_MAX_POS = 1000000; + private static final long DOUBLE_MAX_POS = 1000000000000000L; + } + char[] buffer; private int length; @@ -243,27 +247,27 @@ class TAbstractStringBuilder extends TObject implements TSerializable, TCharSequ int bit = 32; exp = 0; float digit = 1; - for (int i = powersOfTen.length - 1; i >= 0; --i) { - if ((exp | bit) <= FLOAT_MAX_EXPONENT && powersOfTen[i] * digit <= value) { - digit *= powersOfTen[i]; + for (int i = Constants.powersOfTen.length - 1; i >= 0; --i) { + if ((exp | bit) <= Constants.FLOAT_MAX_EXPONENT && Constants.powersOfTen[i] * digit <= value) { + digit *= Constants.powersOfTen[i]; exp |= bit; } bit >>= 1; } - mantissa = (int) ((value / (digit / FLOAT_DECIMAL_FACTOR)) + 0.5f); + mantissa = (int) ((value / (digit / Constants.FLOAT_DECIMAL_FACTOR)) + 0.5f); } else { int bit = 32; exp = 0; float digit = 1; - for (int i = negPowersOfTen.length - 1; i >= 0; --i) { - if ((exp | bit) <= 38 && negPowersOfTen[i] * digit * 10 > value) { - digit *= negPowersOfTen[i]; + for (int i = Constants.negPowersOfTen.length - 1; i >= 0; --i) { + if ((exp | bit) <= 38 && Constants.negPowersOfTen[i] * digit * 10 > value) { + digit *= Constants.negPowersOfTen[i]; exp |= bit; } bit >>= 1; } exp = -exp; - mantissa = (int) (((value * FLOAT_MAX_POS) / digit) + 0.5f); + mantissa = (int) (((value * Constants.FLOAT_MAX_POS) / digit) + 0.5f); while (mantissa >= 10000000) { mantissa /= 10; @@ -272,7 +276,7 @@ class TAbstractStringBuilder extends TObject implements TSerializable, TCharSequ } // Remove trailing zeros - digits = FLOAT_DECIMAL_PRECISION; + digits = Constants.FLOAT_DECIMAL_PRECISION; int zeros = trailingDecimalZeros(mantissa); if (zeros > 0) { digits -= zeros; @@ -285,7 +289,7 @@ class TAbstractStringBuilder extends TObject implements TSerializable, TCharSequ digits = Math.max(digits, intPart + 1); exp = 0; } else if (exp < 0) { - mantissa /= intPowersOfTen[-exp]; + mantissa /= Constants.intPowersOfTen[-exp]; digits -= exp; exp = 0; } @@ -312,7 +316,7 @@ class TAbstractStringBuilder extends TObject implements TSerializable, TCharSequ if (negative) { buffer[target++] = '-'; } - int pos = FLOAT_MAX_POS; + int pos = Constants.FLOAT_MAX_POS; for (int i = 0; i < digits; ++i) { int intDigit; if (pos > 0) { @@ -402,31 +406,31 @@ class TAbstractStringBuilder extends TObject implements TSerializable, TCharSequ int bit = 256; exp = 0; double digit = 1; - for (int i = doublePowersOfTen.length - 1; i >= 0; --i) { - if ((exp | bit) <= DOUBLE_MAX_EXPONENT && doublePowersOfTen[i] * digit <= value) { - digit *= doublePowersOfTen[i]; + for (int i = Constants.doublePowersOfTen.length - 1; i >= 0; --i) { + if ((exp | bit) <= Constants.DOUBLE_MAX_EXPONENT && Constants.doublePowersOfTen[i] * digit <= value) { + digit *= Constants.doublePowersOfTen[i]; exp |= bit; } bit >>= 1; } - mantissa = (long) (((value / digit) * DOUBLE_DECIMAL_FACTOR) + 0.5); + mantissa = (long) (((value / digit) * Constants.DOUBLE_DECIMAL_FACTOR) + 0.5); } else { int bit = 256; exp = 0; double digit = 1; - for (int i = negDoublePowersOfTen.length - 1; i >= 0; --i) { - if ((exp | bit) <= 324 && negDoublePowersOfTen[i] * digit * 10 > value) { + for (int i = Constants.negDoublePowersOfTen.length - 1; i >= 0; --i) { + if ((exp | bit) <= 324 && Constants.negDoublePowersOfTen[i] * digit * 10 > value) { exp |= bit; if (exp == 324) { - value /= negDoublePowersOfTen[i]; + value /= Constants.negDoublePowersOfTen[i]; } else { - digit *= negDoublePowersOfTen[i]; + digit *= Constants.negDoublePowersOfTen[i]; } } bit >>= 1; } exp = -exp; - mantissa = (long) (((value * DOUBLE_MAX_POS) / digit) + 0.5); + mantissa = (long) (((value * Constants.DOUBLE_MAX_POS) / digit) + 0.5); while (mantissa >= 10000000000000000L) { mantissa /= 10; @@ -435,7 +439,7 @@ class TAbstractStringBuilder extends TObject implements TSerializable, TCharSequ } // Remove trailing zeros - digits = DOUBLE_DECIMAL_PRECISION; + digits = Constants.DOUBLE_DECIMAL_PRECISION; int zeros = trailingDecimalZeros(mantissa); if (zeros > 0) { digits -= zeros; @@ -448,7 +452,7 @@ class TAbstractStringBuilder extends TObject implements TSerializable, TCharSequ digits = Math.max(digits, intPart + 1); exp = 0; } else if (exp < 0) { - mantissa /= longPowersOfTen[-exp]; + mantissa /= Constants.longPowersOfTen[-exp]; digits -= exp; exp = 0; } @@ -478,7 +482,7 @@ class TAbstractStringBuilder extends TObject implements TSerializable, TCharSequ if (negative) { buffer[target++] = '-'; } - long pos = DOUBLE_MAX_POS; + long pos = Constants.DOUBLE_MAX_POS; for (int i = 0; i < digits; ++i) { int intDigit; if (pos > 0) { @@ -541,10 +545,10 @@ class TAbstractStringBuilder extends TObject implements TSerializable, TCharSequ long zeros = 1; int result = 0; int bit = 16; - for (int i = longLogPowersOfTen.length - 1; i >= 0; --i) { - if (n % (zeros * longLogPowersOfTen[i]) == 0) { + for (int i = Constants.longLogPowersOfTen.length - 1; i >= 0; --i) { + if (n % (zeros * Constants.longLogPowersOfTen[i]) == 0) { result |= bit; - zeros *= longLogPowersOfTen[i]; + zeros *= Constants.longLogPowersOfTen[i]; } bit >>>= 1; } diff --git a/classlib/src/main/java/org/teavm/classlib/java/lang/TString.java b/classlib/src/main/java/org/teavm/classlib/java/lang/TString.java index b58c7be6b..069be2bac 100644 --- a/classlib/src/main/java/org/teavm/classlib/java/lang/TString.java +++ b/classlib/src/main/java/org/teavm/classlib/java/lang/TString.java @@ -36,7 +36,6 @@ public class TString extends TObject implements TSerializable, TComparable CASE_INSENSITIVE_ORDER = (o1, o2) -> o1.compareToIgnoreCase(o2); private char[] characters; private transient int hashCode; - private static TMap pool = new THashMap<>(); public TString() { this.characters = new char[0]; @@ -633,10 +632,10 @@ public class TString extends TObject implements TSerializable, TComparable pool = new THashMap<>(); + } } diff --git a/classlib/src/main/java/org/teavm/classlib/java/lang/TSystem.java b/classlib/src/main/java/org/teavm/classlib/java/lang/TSystem.java index de67e7102..eec71f071 100644 --- a/classlib/src/main/java/org/teavm/classlib/java/lang/TSystem.java +++ b/classlib/src/main/java/org/teavm/classlib/java/lang/TSystem.java @@ -23,7 +23,6 @@ import org.teavm.classlib.java.io.TConsole; import org.teavm.classlib.java.io.TInputStream; import org.teavm.classlib.java.io.TPrintStream; import org.teavm.classlib.java.lang.reflect.TArray; -import org.teavm.dependency.PluggableDependency; import org.teavm.interop.Address; import org.teavm.interop.DelegateTo; import org.teavm.interop.Import; @@ -34,14 +33,35 @@ import org.teavm.runtime.RuntimeArray; import org.teavm.runtime.RuntimeClass; public final class TSystem extends TObject { - public static final TPrintStream out = new TPrintStream(new TConsoleOutputStreamStdout(), false); - public static final TPrintStream err = new TPrintStream(new TConsoleOutputStreamStderr(), false); - public static final TInputStream in = new TConsoleInputStream(); + private static TPrintStream outCache; + private static TPrintStream errCache; + private static TInputStream inCache; private static Properties properties; private TSystem() { } + public static TPrintStream out() { + if (outCache == null) { + new TPrintStream(new TConsoleOutputStreamStdout(), false); + } + return outCache; + } + + public static TPrintStream err() { + if (errCache == null) { + errCache = new TPrintStream(new TConsoleOutputStreamStderr(), false); + } + return errCache; + } + + public static TInputStream in() { + if (inCache == null) { + inCache = new TConsoleInputStream(); + } + return inCache; + } + public static TConsole console() { return null; } @@ -177,13 +197,13 @@ public final class TSystem extends TObject { return (String) properties.remove(key); } - @GeneratedBy(SystemNativeGenerator.class) - @PluggableDependency(SystemNativeGenerator.class) - public static native void setErr(TPrintStream err); + public static void setErr(TPrintStream err) { + errCache = err; + } - @GeneratedBy(SystemNativeGenerator.class) - @PluggableDependency(SystemNativeGenerator.class) - public static native void setOut(TPrintStream err); + public static void setOut(TPrintStream out) { + outCache = out; + } @DelegateTo("gcLowLevel") public static void gc() { diff --git a/classlib/src/main/java/org/teavm/classlib/java/lang/TThrowable.java b/classlib/src/main/java/org/teavm/classlib/java/lang/TThrowable.java index a7c90e59a..d584f5d4e 100644 --- a/classlib/src/main/java/org/teavm/classlib/java/lang/TThrowable.java +++ b/classlib/src/main/java/org/teavm/classlib/java/lang/TThrowable.java @@ -150,7 +150,7 @@ public class TThrowable extends RuntimeException { @Override public void printStackTrace() { - printStackTrace(TSystem.err); + printStackTrace(TSystem.err()); } public void printStackTrace(TPrintStream stream) { diff --git a/classlib/src/main/java/org/teavm/classlib/java/nio/charset/TCharset.java b/classlib/src/main/java/org/teavm/classlib/java/nio/charset/TCharset.java index 90c4b1465..fee92a1b8 100644 --- a/classlib/src/main/java/org/teavm/classlib/java/nio/charset/TCharset.java +++ b/classlib/src/main/java/org/teavm/classlib/java/nio/charset/TCharset.java @@ -24,11 +24,6 @@ public abstract class TCharset implements Comparable { private String canonicalName; private String[] aliases; private Set aliasSet; - private static final Map charsets = new HashMap<>(); - - static { - charsets.put("UTF-8", new TUTF8Charset()); - } protected TCharset(String canonicalName, String[] aliases) { checkCanonicalName(canonicalName); @@ -73,7 +68,7 @@ public abstract class TCharset implements Comparable { throw new IllegalArgumentException("charsetName is null"); } checkCanonicalName(charsetName); - TCharset charset = charsets.get(charsetName.toUpperCase()); + TCharset charset = Charsets.value.get(charsetName.toUpperCase()); if (charset == null) { throw new TUnsupportedCharsetException(charsetName); } @@ -81,10 +76,9 @@ public abstract class TCharset implements Comparable { } public static TCharset defaultCharset() { - return charsets.get("UTF-8"); + return Charsets.value.get("UTF-8"); } - public final String name() { return canonicalName; } @@ -144,4 +138,12 @@ public abstract class TCharset implements Comparable { public final int compareTo(TCharset that) { return canonicalName.compareToIgnoreCase(that.canonicalName); } + + static class Charsets { + private static final Map value = new HashMap<>(); + + static { + value.put("UTF-8", new TUTF8Charset()); + } + } } diff --git a/core/src/main/java/org/teavm/backend/javascript/JavaScriptTarget.java b/core/src/main/java/org/teavm/backend/javascript/JavaScriptTarget.java index 44093d292..bfe199804 100644 --- a/core/src/main/java/org/teavm/backend/javascript/JavaScriptTarget.java +++ b/core/src/main/java/org/teavm/backend/javascript/JavaScriptTarget.java @@ -21,6 +21,7 @@ import java.io.IOException; import java.io.OutputStream; import java.io.OutputStreamWriter; import java.io.Writer; +import java.nio.charset.StandardCharsets; import java.text.DecimalFormat; import java.text.NumberFormat; import java.util.ArrayList; @@ -67,6 +68,7 @@ import org.teavm.model.ClassHolder; import org.teavm.model.ClassHolderTransformer; import org.teavm.model.ClassReaderSource; import org.teavm.model.ElementModifier; +import org.teavm.model.FieldReference; import org.teavm.model.ListableClassHolderSource; import org.teavm.model.ListableClassReaderSource; import org.teavm.model.MethodHolder; @@ -215,26 +217,9 @@ public class JavaScriptTarget implements TeaVMTarget, TeaVMJavaScriptHost { dep.getVariable(1).propagate(dependencyAnalyzer.getType("[C")); dep.use(); - dep = dependencyAnalyzer.linkMethod(new MethodReference(String.class, "getChars", int.class, int.class, - char[].class, int.class, void.class), null); - dep.getVariable(0).propagate(stringType); - dep.getVariable(3).propagate(dependencyAnalyzer.getType("[C")); - dep.use(); - - MethodDependency internDep = dependencyAnalyzer.linkMethod(new MethodReference(String.class, "intern", - String.class), null); - internDep.getVariable(0).propagate(stringType); - internDep.use(); - - dep = dependencyAnalyzer.linkMethod(new MethodReference(String.class, "length", int.class), null); - dep.getVariable(0).propagate(stringType); - dep.use(); + dependencyAnalyzer.linkField(new FieldReference(String.class.getName(), "characters"), null); dependencyAnalyzer.linkMethod(new MethodReference(Object.class, "clone", Object.class), null).use(); - dependencyAnalyzer.linkMethod(new MethodReference(Thread.class, "currentThread", Thread.class), null).use(); - dependencyAnalyzer.linkMethod(new MethodReference(Thread.class, "getMainThread", Thread.class), null).use(); - dependencyAnalyzer.linkMethod( - new MethodReference(Thread.class, "setCurrentThread", Thread.class, void.class), null).use(); MethodDependency exceptionCons = dependencyAnalyzer.linkMethod(new MethodReference( NoClassDefFoundError.class, "", String.class, void.class), null); @@ -281,7 +266,7 @@ public class JavaScriptTarget implements TeaVMTarget, TeaVMJavaScriptHost { @Override public void emit(ListableClassHolderSource classes, BuildTarget target, String outputName) { try (OutputStream output = target.createResource(outputName); - Writer writer = new OutputStreamWriter(output, "UTF-8")) { + Writer writer = new OutputStreamWriter(output, StandardCharsets.UTF_8)) { emit(classes, writer, target); } catch (IOException e) { throw new RenderingException(e); @@ -322,7 +307,7 @@ public class JavaScriptTarget implements TeaVMTarget, TeaVMJavaScriptHost { renderingContext.setMinifying(minifying); Renderer renderer = new Renderer(sourceWriter, asyncMethods, asyncFamilyMethods, controller.getDiagnostics(), renderingContext); - RuntimeRenderer runtimeRenderer = new RuntimeRenderer(naming, sourceWriter); + RuntimeRenderer runtimeRenderer = new RuntimeRenderer(classes, naming, sourceWriter); renderer.setProperties(controller.getProperties()); renderer.setMinifying(minifying); if (debugEmitter != null) { @@ -358,6 +343,15 @@ public class JavaScriptTarget implements TeaVMTarget, TeaVMJavaScriptHost { renderer.renderStringConstants(); renderer.renderCompatibilityStubs(); + if (renderer.isLongLibraryUsed()) { + runtimeRenderer.renderHandWrittenRuntime("long.js"); + } + if (renderer.isThreadLibraryUsed()) { + runtimeRenderer.renderHandWrittenRuntime("thread.js"); + } else { + runtimeRenderer.renderHandWrittenRuntime("simpleThread.js"); + } + for (Map.Entry entry : controller.getEntryPoints().entrySet()) { sourceWriter.append("").append(entry.getKey()).ws().append("=").ws(); diff --git a/core/src/main/java/org/teavm/backend/javascript/rendering/Renderer.java b/core/src/main/java/org/teavm/backend/javascript/rendering/Renderer.java index 93505ecd6..da3febc07 100644 --- a/core/src/main/java/org/teavm/backend/javascript/rendering/Renderer.java +++ b/core/src/main/java/org/teavm/backend/javascript/rendering/Renderer.java @@ -77,6 +77,9 @@ public class Renderer implements RenderingManager { private int stringPoolSize; private int metadataSize; + private boolean longLibraryUsed; + private boolean threadLibraryUsed; + public Renderer(SourceWriter writer, Set asyncMethods, Set asyncFamilyMethods, Diagnostics diagnostics, RenderingContext context) { this.naming = context.getNaming(); @@ -90,6 +93,14 @@ public class Renderer implements RenderingManager { this.context = context; } + public boolean isLongLibraryUsed() { + return longLibraryUsed; + } + + public boolean isThreadLibraryUsed() { + return threadLibraryUsed; + } + public int getStringPoolSize() { return stringPoolSize; } @@ -752,6 +763,8 @@ public class Renderer implements RenderingManager { writer.newLine(); debugEmitter.emitMethod(null); + + longLibraryUsed |= statementRenderer.isLongLibraryUsed(); } private void renderAsyncPrologue() throws IOException { @@ -831,6 +844,7 @@ public class Renderer implements RenderingManager { @Override public void visit(AsyncMethodNode methodNode) { + threadLibraryUsed = true; try { statementRenderer.setAsync(true); this.async = true; diff --git a/core/src/main/java/org/teavm/backend/javascript/rendering/RuntimeRenderer.java b/core/src/main/java/org/teavm/backend/javascript/rendering/RuntimeRenderer.java index e96d2e611..308cb3053 100644 --- a/core/src/main/java/org/teavm/backend/javascript/rendering/RuntimeRenderer.java +++ b/core/src/main/java/org/teavm/backend/javascript/rendering/RuntimeRenderer.java @@ -26,22 +26,38 @@ import org.mozilla.javascript.ast.AstRoot; import org.teavm.backend.javascript.codegen.NamingException; import org.teavm.backend.javascript.codegen.NamingStrategy; import org.teavm.backend.javascript.codegen.SourceWriter; +import org.teavm.model.ClassReader; +import org.teavm.model.ClassReaderSource; +import org.teavm.model.FieldReference; +import org.teavm.model.MethodDescriptor; import org.teavm.model.MethodReference; import org.teavm.model.ValueType; import org.teavm.vm.RenderingException; public class RuntimeRenderer { + private static final String STRING_CLASS = String.class.getName(); + private static final String THREAD_CLASS = Thread.class.getName(); + + private static final MethodReference NPE_INIT_METHOD = new MethodReference(NullPointerException.class, + "", void.class); + private static final MethodDescriptor STRING_INTERN_METHOD = new MethodDescriptor("intern", + String.class, String.class); + private static final MethodDescriptor CURRENT_THREAD_METHOD = new MethodDescriptor("currentThread", + Thread.class); + + private final ClassReaderSource classSource; private final NamingStrategy naming; private final SourceWriter writer; - public RuntimeRenderer(NamingStrategy naming, SourceWriter writer) { + public RuntimeRenderer(ClassReaderSource classSource, NamingStrategy naming, SourceWriter writer) { + this.classSource = classSource; this.naming = naming; this.writer = writer; } public void renderRuntime() throws RenderingException { try { - renderHandWrittenRuntime(); + renderHandWrittenRuntime("runtime.js"); renderSetCloneMethod(); renderRuntimeCls(); renderRuntimeString(); @@ -60,22 +76,22 @@ public class RuntimeRenderer { } } - private void renderHandWrittenRuntime() throws IOException { - AstRoot ast = parseRuntime(); + public void renderHandWrittenRuntime(String name) throws IOException { + AstRoot ast = parseRuntime(name); ast.visit(new StringConstantElimination()); AstWriter astWriter = new AstWriter(writer); astWriter.hoist(ast); astWriter.print(ast); } - private AstRoot parseRuntime() throws IOException { + private AstRoot parseRuntime(String name) throws IOException { CompilerEnvirons env = new CompilerEnvirons(); env.setRecoverFromErrors(true); env.setLanguageVersion(Context.VERSION_1_8); JSParser factory = new JSParser(env); ClassLoader loader = RuntimeRenderer.class.getClassLoader(); - try (InputStream input = loader.getResourceAsStream("org/teavm/backend/javascript/runtime.js"); + try (InputStream input = loader.getResourceAsStream("org/teavm/backend/javascript/" + name); Reader reader = new InputStreamReader(input, StandardCharsets.UTF_8)) { return factory.parse(reader, null, 0); } @@ -113,29 +129,21 @@ public class RuntimeRenderer { } private void renderRuntimeUnwrapString() throws IOException { - MethodReference stringLen = new MethodReference(String.class, "length", int.class); - MethodReference getChars = new MethodReference(String.class, "getChars", int.class, int.class, - char[].class, int.class, void.class); + FieldReference stringChars = new FieldReference(STRING_CLASS, "characters"); writer.append("function $rt_ustr(str) {").indent().softNewLine(); writer.append("if (str === null) {").indent().softNewLine(); writer.append("return null;").softNewLine(); writer.outdent().append("}").softNewLine(); - writer.append("var result = \"\";").softNewLine(); - writer.append("var sz = ").appendMethodBody(stringLen).append("(str);").softNewLine(); - writer.append("var array = $rt_createCharArray(sz);").softNewLine(); - writer.appendMethodBody(getChars).append("(str, 0, sz, array, 0);").softNewLine(); - writer.append("for (var i = 0; i < sz; i = (i + 1) | 0) {").indent().softNewLine(); - writer.append("result += String.fromCharCode(array.data[i]);").softNewLine(); - writer.outdent().append("}").softNewLine(); - writer.append("return result;").softNewLine(); + + writer.append("return String.fromCharCode.apply(null, str.").appendField(stringChars) + .append(".data);").softNewLine(); writer.outdent().append("}").newLine(); } private void renderRuntimeNullCheck() throws IOException { writer.append("function $rt_nullCheck(val) {").indent().softNewLine(); writer.append("if (val === null) {").indent().softNewLine(); - writer.append("$rt_throw(").append(naming.getNameForInit(new MethodReference(NullPointerException.class, - "", void.class))).append("());").softNewLine(); + writer.append("$rt_throw(").append(naming.getNameForInit(NPE_INIT_METHOD)).append("());").softNewLine(); writer.outdent().append("}").softNewLine(); writer.append("return val;").softNewLine(); writer.outdent().append("}").newLine(); @@ -143,8 +151,14 @@ public class RuntimeRenderer { private void renderRuntimeIntern() throws IOException { writer.append("function $rt_intern(str) {").indent().softNewLine(); - writer.append("return ").appendMethodBody(new MethodReference(String.class, "intern", String.class)) - .append("(str);").softNewLine(); + ClassReader stringCls = classSource.get(STRING_CLASS); + if (stringCls != null && stringCls.getMethod(STRING_INTERN_METHOD) != null) { + writer.append("return ").appendMethodBody(new MethodReference(String.class, "intern", String.class)) + .append("(str);").softNewLine(); + } else { + writer.append("return str;").softNewLine(); + } + writer.outdent().append("}").newLine(); } @@ -153,14 +167,23 @@ public class RuntimeRenderer { } private void renderRuntimeThreads() throws IOException { + ClassReader threadCls = classSource.get(THREAD_CLASS); + boolean threadUsed = threadCls != null && threadCls.getMethod(CURRENT_THREAD_METHOD) != null; + writer.append("function $rt_getThread()").ws().append("{").indent().softNewLine(); - writer.append("return ").appendMethodBody(Thread.class, "currentThread", Thread.class).append("();") - .softNewLine(); + if (threadUsed) { + writer.append("return ").appendMethodBody(Thread.class, "currentThread", Thread.class).append("();") + .softNewLine(); + } else { + writer.append("return null;").softNewLine(); + } writer.outdent().append("}").newLine(); writer.append("function $rt_setThread(t)").ws().append("{").indent().softNewLine(); - writer.append("return ").appendMethodBody(Thread.class, "setCurrentThread", Thread.class, void.class) - .append("(t);").softNewLine(); + if (threadUsed) { + writer.append("return ").appendMethodBody(Thread.class, "setCurrentThread", Thread.class, void.class) + .append("(t);").softNewLine(); + } writer.outdent().append("}").newLine(); } diff --git a/core/src/main/java/org/teavm/backend/javascript/rendering/StatementRenderer.java b/core/src/main/java/org/teavm/backend/javascript/rendering/StatementRenderer.java index 88d188a8d..cb57946f6 100644 --- a/core/src/main/java/org/teavm/backend/javascript/rendering/StatementRenderer.java +++ b/core/src/main/java/org/teavm/backend/javascript/rendering/StatementRenderer.java @@ -102,6 +102,7 @@ public class StatementRenderer implements ExprVisitor, StatementVisitor { private int currentPart; private List blockIds = new ArrayList<>(); private IntIndexedContainer blockIndexMap = new IntArrayList(); + private boolean longLibraryUsed; public StatementRenderer(RenderingContext context, SourceWriter writer) { this.context = context; @@ -112,6 +113,10 @@ public class StatementRenderer implements ExprVisitor, StatementVisitor { this.debugEmitter = context.getDebugEmitter(); } + public boolean isLongLibraryUsed() { + return longLibraryUsed; + } + public boolean isAsync() { return async; } @@ -621,6 +626,7 @@ public class StatementRenderer implements ExprVisitor, StatementVisitor { @Override public void visit(BinaryExpr expr) { if (expr.getType() == OperationType.LONG) { + longLibraryUsed = true; switch (expr.getOperation()) { case ADD: visitBinaryFunction(expr, "Long_add"); @@ -763,6 +769,7 @@ public class StatementRenderer implements ExprVisitor, StatementVisitor { switch (expr.getOperation()) { case NOT: { if (expr.getType() == OperationType.LONG) { + longLibraryUsed = true; writer.append("Long_not("); precedence = Precedence.min(); expr.getOperand().acceptVisitor(this); @@ -782,6 +789,7 @@ public class StatementRenderer implements ExprVisitor, StatementVisitor { } case NEGATE: if (expr.getType() == OperationType.LONG) { + longLibraryUsed = true; writer.append("Long_neg("); precedence = Precedence.min(); expr.getOperand().acceptVisitor(this); diff --git a/core/src/main/resources/org/teavm/backend/javascript/long.js b/core/src/main/resources/org/teavm/backend/javascript/long.js new file mode 100644 index 000000000..dfe58c1ab --- /dev/null +++ b/core/src/main/resources/org/teavm/backend/javascript/long.js @@ -0,0 +1,478 @@ +/* + * Copyright 2018 Alexey Andreev. + * + * 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. + */ +"use strict"; +function Long_eq(a, b) { + return a.hi === b.hi && a.lo === b.lo; +} +function Long_ne(a, b) { + return a.hi !== b.hi || a.lo !== b.lo; +} +function Long_gt(a, b) { + if (a.hi < b.hi) { + return false; + } + if (a.hi > b.hi) { + return true; + } + var x = a.lo >>> 1; + var y = b.lo >>> 1; + if (x !== y) { + return x > y; + } + return (a.lo & 1) > (b.lo & 1); +} +function Long_ge(a, b) { + if (a.hi < b.hi) { + return false; + } + if (a.hi > b.hi) { + return true; + } + var x = a.lo >>> 1; + var y = b.lo >>> 1; + if (x !== y) { + return x >= y; + } + return (a.lo & 1) >= (b.lo & 1); +} +function Long_lt(a, b) { + if (a.hi > b.hi) { + return false; + } + if (a.hi < b.hi) { + return true; + } + var x = a.lo >>> 1; + var y = b.lo >>> 1; + if (x !== y) { + return x < y; + } + return (a.lo & 1) < (b.lo & 1); +} +function Long_le(a, b) { + if (a.hi > b.hi) { + return false; + } + if (a.hi < b.hi) { + return true; + } + var x = a.lo >>> 1; + var y = b.lo >>> 1; + if (x !== y) { + return x <= y; + } + return (a.lo & 1) <= (b.lo & 1); +} + +function Long_add(a, b) { + if (a.hi === (a.lo >> 31) && b.hi === (b.lo >> 31)) { + return Long_fromNumber(a.lo + b.lo); + } else if (Math.abs(a.hi) < Long_MAX_NORMAL && Math.abs(b.hi) < Long_MAX_NORMAL) { + return Long_fromNumber(Long_toNumber(a) + Long_toNumber(b)); + } + var a_lolo = a.lo & 0xFFFF; + var a_lohi = a.lo >>> 16; + var a_hilo = a.hi & 0xFFFF; + var a_hihi = a.hi >>> 16; + var b_lolo = b.lo & 0xFFFF; + var b_lohi = b.lo >>> 16; + var b_hilo = b.hi & 0xFFFF; + var b_hihi = b.hi >>> 16; + + var lolo = (a_lolo + b_lolo) | 0; + var lohi = (a_lohi + b_lohi + (lolo >> 16)) | 0; + var hilo = (a_hilo + b_hilo + (lohi >> 16)) | 0; + var hihi = (a_hihi + b_hihi + (hilo >> 16)) | 0; + return new Long((lolo & 0xFFFF) | ((lohi & 0xFFFF) << 16), (hilo & 0xFFFF) | ((hihi & 0xFFFF) << 16)); +} +function Long_inc(a) { + var lo = (a.lo + 1) | 0; + var hi = a.hi; + if (lo === 0) { + hi = (hi + 1) | 0; + } + return new Long(lo, hi); +} +function Long_dec(a) { + var lo = (a.lo - 1) | 0; + var hi = a.hi; + if (lo === -1) { + hi = (hi - 1) | 0; + } + return new Long(lo, hi); +} +function Long_neg(a) { + return Long_inc(new Long(a.lo ^ 0xFFFFFFFF, a.hi ^ 0xFFFFFFFF)); +} +function Long_sub(a, b) { + if (a.hi === (a.lo >> 31) && b.hi === (b.lo >> 31)) { + return Long_fromNumber(a.lo - b.lo); + } + var a_lolo = a.lo & 0xFFFF; + var a_lohi = a.lo >>> 16; + var a_hilo = a.hi & 0xFFFF; + var a_hihi = a.hi >>> 16; + var b_lolo = b.lo & 0xFFFF; + var b_lohi = b.lo >>> 16; + var b_hilo = b.hi & 0xFFFF; + var b_hihi = b.hi >>> 16; + + var lolo = (a_lolo - b_lolo) | 0; + var lohi = (a_lohi - b_lohi + (lolo >> 16)) | 0; + var hilo = (a_hilo - b_hilo + (lohi >> 16)) | 0; + var hihi = (a_hihi - b_hihi + (hilo >> 16)) | 0; + return new Long((lolo & 0xFFFF) | ((lohi & 0xFFFF) << 16), (hilo & 0xFFFF) | ((hihi & 0xFFFF) << 16)); +} +function Long_compare(a, b) { + var r = a.hi - b.hi; + if (r !== 0) { + return r; + } + r = (a.lo >>> 1) - (b.lo >>> 1); + if (r !== 0) { + return r; + } + return (a.lo & 1) - (b.lo & 1); +} +function Long_isPositive(a) { + return (a.hi & 0x80000000) === 0; +} +function Long_isNegative(a) { + return (a.hi & 0x80000000) !== 0; +} +function Long_mul(a, b) { + var positive = Long_isNegative(a) === Long_isNegative(b); + if (Long_isNegative(a)) { + a = Long_neg(a); + } + if (Long_isNegative(b)) { + b = Long_neg(b); + } + var a_lolo = a.lo & 0xFFFF; + var a_lohi = a.lo >>> 16; + var a_hilo = a.hi & 0xFFFF; + var a_hihi = a.hi >>> 16; + var b_lolo = b.lo & 0xFFFF; + var b_lohi = b.lo >>> 16; + var b_hilo = b.hi & 0xFFFF; + var b_hihi = b.hi >>> 16; + + var lolo = 0; + var lohi = 0; + var hilo = 0; + var hihi = 0; + lolo = (a_lolo * b_lolo) | 0; + lohi = lolo >>> 16; + lohi = ((lohi & 0xFFFF) + a_lohi * b_lolo) | 0; + hilo = (hilo + (lohi >>> 16)) | 0; + lohi = ((lohi & 0xFFFF) + a_lolo * b_lohi) | 0; + hilo = (hilo + (lohi >>> 16)) | 0; + hihi = hilo >>> 16; + hilo = ((hilo & 0xFFFF) + a_hilo * b_lolo) | 0; + hihi = (hihi + (hilo >>> 16)) | 0; + hilo = ((hilo & 0xFFFF) + a_lohi * b_lohi) | 0; + hihi = (hihi + (hilo >>> 16)) | 0; + hilo = ((hilo & 0xFFFF) + a_lolo * b_hilo) | 0; + hihi = (hihi + (hilo >>> 16)) | 0; + hihi = (hihi + a_hihi * b_lolo + a_hilo * b_lohi + a_lohi * b_hilo + a_lolo * b_hihi) | 0; + var result = new Long((lolo & 0xFFFF) | (lohi << 16), (hilo & 0xFFFF) | (hihi << 16)); + return positive ? result : Long_neg(result); +} +function Long_div(a, b) { + if (Math.abs(a.hi) < Long_MAX_NORMAL && Math.abs(b.hi) < Long_MAX_NORMAL) { + return Long_fromNumber(Long_toNumber(a) / Long_toNumber(b)); + } + return Long_divRem(a, b)[0]; +} +function Long_rem(a, b) { + if (Math.abs(a.hi) < Long_MAX_NORMAL && Math.abs(b.hi) < Long_MAX_NORMAL) { + return Long_fromNumber(Long_toNumber(a) % Long_toNumber(b)); + } + return Long_divRem(a, b)[1]; +} +function Long_divRem(a, b) { + if (b.lo === 0 && b.hi === 0) { + throw new Error("Division by zero"); + } + var positive = Long_isNegative(a) === Long_isNegative(b); + if (Long_isNegative(a)) { + a = Long_neg(a); + } + if (Long_isNegative(b)) { + b = Long_neg(b); + } + a = new LongInt(a.lo, a.hi, 0); + b = new LongInt(b.lo, b.hi, 0); + var q = LongInt_div(a, b); + a = new Long(a.lo, a.hi); + q = new Long(q.lo, q.hi); + return positive ? [q, a] : [Long_neg(q), Long_neg(a)]; +} +function Long_shiftLeft16(a) { + return new Long(a.lo << 16, (a.lo >>> 16) | (a.hi << 16)); +} +function Long_shiftRight16(a) { + return new Long((a.lo >>> 16) | (a.hi << 16), a.hi >>> 16); +} +function Long_and(a, b) { + return new Long(a.lo & b.lo, a.hi & b.hi); +} +function Long_or(a, b) { + return new Long(a.lo | b.lo, a.hi | b.hi); +} +function Long_xor(a, b) { + return new Long(a.lo ^ b.lo, a.hi ^ b.hi); +} +function Long_shl(a, b) { + b &= 63; + if (b === 0) { + return a; + } else if (b < 32) { + return new Long(a.lo << b, (a.lo >>> (32 - b)) | (a.hi << b)); + } else if (b === 32) { + return new Long(0, a.lo); + } else { + return new Long(0, a.lo << (b - 32)); + } +} +function Long_shr(a, b) { + b &= 63; + if (b === 0) { + return a; + } else if (b < 32) { + return new Long((a.lo >>> b) | (a.hi << (32 - b)), a.hi >> b); + } else if (b === 32) { + return new Long(a.hi, a.hi >> 31); + } else { + return new Long((a.hi >> (b - 32)), a.hi >> 31); + } +} +function Long_shru(a, b) { + b &= 63; + if (b === 0) { + return a; + } else if (b < 32) { + return new Long((a.lo >>> b) | (a.hi << (32 - b)), a.hi >>> b); + } else if (b === 32) { + return new Long(a.hi, 0); + } else { + return new Long((a.hi >>> (b - 32)), 0); + } +} + +// Represents a mutable 80-bit unsigned integer +function LongInt(lo, hi, sup) { + this.lo = lo; + this.hi = hi; + this.sup = sup; +} +function LongInt_mul(a, b) { + var a_lolo = ((a.lo & 0xFFFF) * b) | 0; + var a_lohi = ((a.lo >>> 16) * b) | 0; + var a_hilo = ((a.hi & 0xFFFF) * b) | 0; + var a_hihi = ((a.hi >>> 16) * b) | 0; + var sup = (a.sup * b) | 0; + + a_lohi = (a_lohi + (a_lolo >>> 16)) | 0; + a_hilo = (a_hilo + (a_lohi >>> 16)) | 0; + a_hihi = (a_hihi + (a_hilo >>> 16)) | 0; + sup = (sup + (a_hihi >>> 16)) | 0; + a.lo = (a_lolo & 0xFFFF) | (a_lohi << 16); + a.hi = (a_hilo & 0xFFFF) | (a_hihi << 16); + a.sup = sup & 0xFFFF; +} +function LongInt_sub(a, b) { + var a_lolo = a.lo & 0xFFFF; + var a_lohi = a.lo >>> 16; + var a_hilo = a.hi & 0xFFFF; + var a_hihi = a.hi >>> 16; + var b_lolo = b.lo & 0xFFFF; + var b_lohi = b.lo >>> 16; + var b_hilo = b.hi & 0xFFFF; + var b_hihi = b.hi >>> 16; + + a_lolo = (a_lolo - b_lolo) | 0; + a_lohi = (a_lohi - b_lohi + (a_lolo >> 16)) | 0; + a_hilo = (a_hilo - b_hilo + (a_lohi >> 16)) | 0; + a_hihi = (a_hihi - b_hihi + (a_hilo >> 16)) | 0; + var sup = (a.sup - b.sup + (a_hihi >> 16)) | 0; + a.lo = (a_lolo & 0xFFFF) | (a_lohi << 16); + a.hi = (a_hilo & 0xFFFF) | (a_hihi << 16); + a.sup = sup; +} +function LongInt_add(a, b) { + var a_lolo = a.lo & 0xFFFF; + var a_lohi = a.lo >>> 16; + var a_hilo = a.hi & 0xFFFF; + var a_hihi = a.hi >>> 16; + var b_lolo = b.lo & 0xFFFF; + var b_lohi = b.lo >>> 16; + var b_hilo = b.hi & 0xFFFF; + var b_hihi = b.hi >>> 16; + + a_lolo = (a_lolo + b_lolo) | 0; + a_lohi = (a_lohi + b_lohi + (a_lolo >> 16)) | 0; + a_hilo = (a_hilo + b_hilo + (a_lohi >> 16)) | 0; + a_hihi = (a_hihi + b_hihi + (a_hilo >> 16)) | 0; + var sup = (a.sup + b.sup + (a_hihi >> 16)) | 0; + a.lo = (a_lolo & 0xFFFF) | (a_lohi << 16); + a.hi = (a_hilo & 0xFFFF) | (a_hihi << 16); + a.sup = sup; +} +function LongInt_inc(a) { + a.lo = (a.lo + 1) | 0; + if (a.lo === 0) { + a.hi = (a.hi + 1) | 0; + if (a.hi === 0) { + a.sup = (a.sup + 1) & 0xFFFF; + } + } +} +function LongInt_dec(a) { + a.lo = (a.lo - 1) | 0; + if (a.lo === -1) { + a.hi = (a.hi - 1) | 0; + if (a.hi === -1) { + a.sup = (a.sup - 1) & 0xFFFF; + } + } +} +function LongInt_ucompare(a, b) { + var r = (a.sup - b.sup); + if (r !== 0) { + return r; + } + r = (a.hi >>> 1) - (b.hi >>> 1); + if (r !== 0) { + return r; + } + r = (a.hi & 1) - (b.hi & 1); + if (r !== 0) { + return r; + } + r = (a.lo >>> 1) - (b.lo >>> 1); + if (r !== 0) { + return r; + } + return (a.lo & 1) - (b.lo & 1); +} +function LongInt_numOfLeadingZeroBits(a) { + var n = 0; + var d = 16; + while (d > 0) { + if ((a >>> d) !== 0) { + a >>>= d; + n = (n + d) | 0; + } + d = (d / 2) | 0; + } + return 31 - n; +} +function LongInt_shl(a, b) { + if (b === 0) { + return; + } + if (b < 32) { + a.sup = ((a.hi >>> (32 - b)) | (a.sup << b)) & 0xFFFF; + a.hi = (a.lo >>> (32 - b)) | (a.hi << b); + a.lo <<= b; + } else if (b === 32) { + a.sup = a.hi & 0xFFFF; + a.hi = a.lo; + a.lo = 0; + } else if (b < 64) { + a.sup = ((a.lo >>> (64 - b)) | (a.hi << (b - 32))) & 0xFFFF; + a.hi = a.lo << b; + a.lo = 0; + } else if (b === 64) { + a.sup = a.lo & 0xFFFF; + a.hi = 0; + a.lo = 0; + } else { + a.sup = (a.lo << (b - 64)) & 0xFFFF; + a.hi = 0; + a.lo = 0; + } +} +function LongInt_shr(a, b) { + if (b === 0) { + return; + } + if (b === 32) { + a.lo = a.hi; + a.hi = a.sup; + a.sup = 0; + } else if (b < 32) { + a.lo = (a.lo >>> b) | (a.hi << (32 - b)); + a.hi = (a.hi >>> b) | (a.sup << (32 - b)); + a.sup >>>= b; + } else if (b === 64) { + a.lo = a.sup; + a.hi = 0; + a.sup = 0; + } else if (b < 64) { + a.lo = (a.hi >>> (b - 32)) | (a.sup << (64 - b)); + a.hi = a.sup >>> (b - 32); + a.sup = 0; + } else { + a.lo = a.sup >>> (b - 64); + a.hi = 0; + a.sup = 0; + } +} +function LongInt_copy(a) { + return new LongInt(a.lo, a.hi, a.sup); +} +function LongInt_div(a, b) { + // Normalize divisor + var bits = b.hi !== 0 ? LongInt_numOfLeadingZeroBits(b.hi) : LongInt_numOfLeadingZeroBits(b.lo) + 32; + var sz = 1 + ((bits / 16) | 0); + var dividentBits = bits % 16; + LongInt_shl(b, bits); + LongInt_shl(a, dividentBits); + var q = new LongInt(0, 0, 0); + while (sz-- > 0) { + LongInt_shl(q, 16); + // Calculate approximate q + var digitA = (a.hi >>> 16) + (0x10000 * a.sup); + var digitB = b.hi >>> 16; + var digit = (digitA / digitB) | 0; + var t = LongInt_copy(b); + LongInt_mul(t, digit); + // Adjust q either down or up + if (LongInt_ucompare(t, a) >= 0) { + while (LongInt_ucompare(t, a) > 0) { + LongInt_sub(t, b); + --digit; + } + } else { + while (true) { + var nextT = LongInt_copy(t); + LongInt_add(nextT, b); + if (LongInt_ucompare(nextT, a) > 0) { + break; + } + t = nextT; + ++digit; + } + } + LongInt_sub(a, t); + q.lo |= digit; + LongInt_shl(a, 16); + } + LongInt_shr(a, bits + 16); + return q; +} diff --git a/core/src/main/resources/org/teavm/backend/javascript/runtime.js b/core/src/main/resources/org/teavm/backend/javascript/runtime.js index 7b57abd59..1579c5f23 100644 --- a/core/src/main/resources/org/teavm/backend/javascript/runtime.js +++ b/core/src/main/resources/org/teavm/backend/javascript/runtime.js @@ -507,99 +507,6 @@ function $rt_s(index) { function $rt_eraseClinit(target) { return target.$clinit = function() {}; } -function TeaVMThread(runner) { - this.status = 3; - this.stack = []; - this.suspendCallback = null; - this.runner = runner; - this.attribute = null; - this.completeCallback = null; -} -TeaVMThread.prototype.push = function() { - for (var i = 0; i < arguments.length; ++i) { - this.stack.push(arguments[i]); - } - return this; -}; -TeaVMThread.prototype.s = TeaVMThread.prototype.push; -TeaVMThread.prototype.pop = function() { - return this.stack.pop(); -}; -TeaVMThread.prototype.l = TeaVMThread.prototype.pop; -TeaVMThread.prototype.isResuming = function() { - return this.status === 2; -}; -TeaVMThread.prototype.isSuspending = function() { - return this.status === 1; -}; -TeaVMThread.prototype.suspend = function(callback) { - this.suspendCallback = callback; - this.status = 1; -}; -TeaVMThread.prototype.start = function(callback) { - if (this.status !== 3) { - throw new Error("Thread already started"); - } - if ($rt_currentNativeThread !== null) { - throw new Error("Another thread is running"); - } - this.status = 0; - this.completeCallback = callback ? callback : function(result) { - if (result instanceof Error) { - throw result; - } - }; - this.run(); -}; -TeaVMThread.prototype.resume = function() { - if ($rt_currentNativeThread !== null) { - throw new Error("Another thread is running"); - } - this.status = 2; - this.run(); -}; -TeaVMThread.prototype.run = function() { - $rt_currentNativeThread = this; - var result; - try { - result = this.runner(); - } catch (e) { - result = e; - } finally { - $rt_currentNativeThread = null; - } - if (this.suspendCallback !== null) { - var self = this; - var callback = this.suspendCallback; - this.suspendCallback = null; - callback(function() { - self.resume(); - }); - } else if (this.status === 0) { - this.completeCallback(result); - } -}; -function $rt_suspending() { - var thread = $rt_nativeThread(); - return thread != null && thread.isSuspending(); -} -function $rt_resuming() { - var thread = $rt_nativeThread(); - return thread != null && thread.isResuming(); -} -function $rt_suspend(callback) { - return $rt_nativeThread().suspend(callback); -} -function $rt_startThread(runner, callback) { - new TeaVMThread(runner).start(callback); -} -var $rt_currentNativeThread = null; -function $rt_nativeThread() { - return $rt_currentNativeThread; -} -function $rt_invalidPointer() { - throw new Error("Invalid recorded state"); -} var $rt_numberConversionView = new DataView(new ArrayBuffer(8)); @@ -716,465 +623,3 @@ function Long_toNumber(val) { } return 0x100000000 * hi + lo; } -function Long_eq(a, b) { - return a.hi === b.hi && a.lo === b.lo; -} -function Long_ne(a, b) { - return a.hi !== b.hi || a.lo !== b.lo; -} -function Long_gt(a, b) { - if (a.hi < b.hi) { - return false; - } - if (a.hi > b.hi) { - return true; - } - var x = a.lo >>> 1; - var y = b.lo >>> 1; - if (x !== y) { - return x > y; - } - return (a.lo & 1) > (b.lo & 1); -} -function Long_ge(a, b) { - if (a.hi < b.hi) { - return false; - } - if (a.hi > b.hi) { - return true; - } - var x = a.lo >>> 1; - var y = b.lo >>> 1; - if (x !== y) { - return x >= y; - } - return (a.lo & 1) >= (b.lo & 1); -} -function Long_lt(a, b) { - if (a.hi > b.hi) { - return false; - } - if (a.hi < b.hi) { - return true; - } - var x = a.lo >>> 1; - var y = b.lo >>> 1; - if (x !== y) { - return x < y; - } - return (a.lo & 1) < (b.lo & 1); -} -function Long_le(a, b) { - if (a.hi > b.hi) { - return false; - } - if (a.hi < b.hi) { - return true; - } - var x = a.lo >>> 1; - var y = b.lo >>> 1; - if (x !== y) { - return x <= y; - } - return (a.lo & 1) <= (b.lo & 1); -} - -function Long_add(a, b) { - if (a.hi === (a.lo >> 31) && b.hi === (b.lo >> 31)) { - return Long_fromNumber(a.lo + b.lo); - } else if (Math.abs(a.hi) < Long_MAX_NORMAL && Math.abs(b.hi) < Long_MAX_NORMAL) { - return Long_fromNumber(Long_toNumber(a) + Long_toNumber(b)); - } - var a_lolo = a.lo & 0xFFFF; - var a_lohi = a.lo >>> 16; - var a_hilo = a.hi & 0xFFFF; - var a_hihi = a.hi >>> 16; - var b_lolo = b.lo & 0xFFFF; - var b_lohi = b.lo >>> 16; - var b_hilo = b.hi & 0xFFFF; - var b_hihi = b.hi >>> 16; - - var lolo = (a_lolo + b_lolo) | 0; - var lohi = (a_lohi + b_lohi + (lolo >> 16)) | 0; - var hilo = (a_hilo + b_hilo + (lohi >> 16)) | 0; - var hihi = (a_hihi + b_hihi + (hilo >> 16)) | 0; - return new Long((lolo & 0xFFFF) | ((lohi & 0xFFFF) << 16), (hilo & 0xFFFF) | ((hihi & 0xFFFF) << 16)); -} -function Long_inc(a) { - var lo = (a.lo + 1) | 0; - var hi = a.hi; - if (lo === 0) { - hi = (hi + 1) | 0; - } - return new Long(lo, hi); -} -function Long_dec(a) { - var lo = (a.lo - 1) | 0; - var hi = a.hi; - if (lo === -1) { - hi = (hi - 1) | 0; - } - return new Long(lo, hi); -} -function Long_neg(a) { - return Long_inc(new Long(a.lo ^ 0xFFFFFFFF, a.hi ^ 0xFFFFFFFF)); -} -function Long_sub(a, b) { - if (a.hi === (a.lo >> 31) && b.hi === (b.lo >> 31)) { - return Long_fromNumber(a.lo - b.lo); - } - var a_lolo = a.lo & 0xFFFF; - var a_lohi = a.lo >>> 16; - var a_hilo = a.hi & 0xFFFF; - var a_hihi = a.hi >>> 16; - var b_lolo = b.lo & 0xFFFF; - var b_lohi = b.lo >>> 16; - var b_hilo = b.hi & 0xFFFF; - var b_hihi = b.hi >>> 16; - - var lolo = (a_lolo - b_lolo) | 0; - var lohi = (a_lohi - b_lohi + (lolo >> 16)) | 0; - var hilo = (a_hilo - b_hilo + (lohi >> 16)) | 0; - var hihi = (a_hihi - b_hihi + (hilo >> 16)) | 0; - return new Long((lolo & 0xFFFF) | ((lohi & 0xFFFF) << 16), (hilo & 0xFFFF) | ((hihi & 0xFFFF) << 16)); -} -function Long_compare(a, b) { - var r = a.hi - b.hi; - if (r !== 0) { - return r; - } - r = (a.lo >>> 1) - (b.lo >>> 1); - if (r !== 0) { - return r; - } - return (a.lo & 1) - (b.lo & 1); -} -function Long_isPositive(a) { - return (a.hi & 0x80000000) === 0; -} -function Long_isNegative(a) { - return (a.hi & 0x80000000) !== 0; -} -function Long_mul(a, b) { - var positive = Long_isNegative(a) === Long_isNegative(b); - if (Long_isNegative(a)) { - a = Long_neg(a); - } - if (Long_isNegative(b)) { - b = Long_neg(b); - } - var a_lolo = a.lo & 0xFFFF; - var a_lohi = a.lo >>> 16; - var a_hilo = a.hi & 0xFFFF; - var a_hihi = a.hi >>> 16; - var b_lolo = b.lo & 0xFFFF; - var b_lohi = b.lo >>> 16; - var b_hilo = b.hi & 0xFFFF; - var b_hihi = b.hi >>> 16; - - var lolo = 0; - var lohi = 0; - var hilo = 0; - var hihi = 0; - lolo = (a_lolo * b_lolo) | 0; - lohi = lolo >>> 16; - lohi = ((lohi & 0xFFFF) + a_lohi * b_lolo) | 0; - hilo = (hilo + (lohi >>> 16)) | 0; - lohi = ((lohi & 0xFFFF) + a_lolo * b_lohi) | 0; - hilo = (hilo + (lohi >>> 16)) | 0; - hihi = hilo >>> 16; - hilo = ((hilo & 0xFFFF) + a_hilo * b_lolo) | 0; - hihi = (hihi + (hilo >>> 16)) | 0; - hilo = ((hilo & 0xFFFF) + a_lohi * b_lohi) | 0; - hihi = (hihi + (hilo >>> 16)) | 0; - hilo = ((hilo & 0xFFFF) + a_lolo * b_hilo) | 0; - hihi = (hihi + (hilo >>> 16)) | 0; - hihi = (hihi + a_hihi * b_lolo + a_hilo * b_lohi + a_lohi * b_hilo + a_lolo * b_hihi) | 0; - var result = new Long((lolo & 0xFFFF) | (lohi << 16), (hilo & 0xFFFF) | (hihi << 16)); - return positive ? result : Long_neg(result); -} -function Long_div(a, b) { - if (Math.abs(a.hi) < Long_MAX_NORMAL && Math.abs(b.hi) < Long_MAX_NORMAL) { - return Long_fromNumber(Long_toNumber(a) / Long_toNumber(b)); - } - return Long_divRem(a, b)[0]; -} -function Long_rem(a, b) { - if (Math.abs(a.hi) < Long_MAX_NORMAL && Math.abs(b.hi) < Long_MAX_NORMAL) { - return Long_fromNumber(Long_toNumber(a) % Long_toNumber(b)); - } - return Long_divRem(a, b)[1]; -} -function Long_divRem(a, b) { - if (b.lo === 0 && b.hi === 0) { - throw new Error("Division by zero"); - } - var positive = Long_isNegative(a) === Long_isNegative(b); - if (Long_isNegative(a)) { - a = Long_neg(a); - } - if (Long_isNegative(b)) { - b = Long_neg(b); - } - a = new LongInt(a.lo, a.hi, 0); - b = new LongInt(b.lo, b.hi, 0); - var q = LongInt_div(a, b); - a = new Long(a.lo, a.hi); - q = new Long(q.lo, q.hi); - return positive ? [q, a] : [Long_neg(q), Long_neg(a)]; -} -function Long_shiftLeft16(a) { - return new Long(a.lo << 16, (a.lo >>> 16) | (a.hi << 16)); -} -function Long_shiftRight16(a) { - return new Long((a.lo >>> 16) | (a.hi << 16), a.hi >>> 16); -} -function Long_and(a, b) { - return new Long(a.lo & b.lo, a.hi & b.hi); -} -function Long_or(a, b) { - return new Long(a.lo | b.lo, a.hi | b.hi); -} -function Long_xor(a, b) { - return new Long(a.lo ^ b.lo, a.hi ^ b.hi); -} -function Long_shl(a, b) { - b &= 63; - if (b === 0) { - return a; - } else if (b < 32) { - return new Long(a.lo << b, (a.lo >>> (32 - b)) | (a.hi << b)); - } else if (b === 32) { - return new Long(0, a.lo); - } else { - return new Long(0, a.lo << (b - 32)); - } -} -function Long_shr(a, b) { - b &= 63; - if (b === 0) { - return a; - } else if (b < 32) { - return new Long((a.lo >>> b) | (a.hi << (32 - b)), a.hi >> b); - } else if (b === 32) { - return new Long(a.hi, a.hi >> 31); - } else { - return new Long((a.hi >> (b - 32)), a.hi >> 31); - } -} -function Long_shru(a, b) { - b &= 63; - if (b === 0) { - return a; - } else if (b < 32) { - return new Long((a.lo >>> b) | (a.hi << (32 - b)), a.hi >>> b); - } else if (b === 32) { - return new Long(a.hi, 0); - } else { - return new Long((a.hi >>> (b - 32)), 0); - } -} - -// Represents a mutable 80-bit unsigned integer -function LongInt(lo, hi, sup) { - this.lo = lo; - this.hi = hi; - this.sup = sup; -} -function LongInt_mul(a, b) { - var a_lolo = ((a.lo & 0xFFFF) * b) | 0; - var a_lohi = ((a.lo >>> 16) * b) | 0; - var a_hilo = ((a.hi & 0xFFFF) * b) | 0; - var a_hihi = ((a.hi >>> 16) * b) | 0; - var sup = (a.sup * b) | 0; - - a_lohi = (a_lohi + (a_lolo >>> 16)) | 0; - a_hilo = (a_hilo + (a_lohi >>> 16)) | 0; - a_hihi = (a_hihi + (a_hilo >>> 16)) | 0; - sup = (sup + (a_hihi >>> 16)) | 0; - a.lo = (a_lolo & 0xFFFF) | (a_lohi << 16); - a.hi = (a_hilo & 0xFFFF) | (a_hihi << 16); - a.sup = sup & 0xFFFF; -} -function LongInt_sub(a, b) { - var a_lolo = a.lo & 0xFFFF; - var a_lohi = a.lo >>> 16; - var a_hilo = a.hi & 0xFFFF; - var a_hihi = a.hi >>> 16; - var b_lolo = b.lo & 0xFFFF; - var b_lohi = b.lo >>> 16; - var b_hilo = b.hi & 0xFFFF; - var b_hihi = b.hi >>> 16; - - a_lolo = (a_lolo - b_lolo) | 0; - a_lohi = (a_lohi - b_lohi + (a_lolo >> 16)) | 0; - a_hilo = (a_hilo - b_hilo + (a_lohi >> 16)) | 0; - a_hihi = (a_hihi - b_hihi + (a_hilo >> 16)) | 0; - var sup = (a.sup - b.sup + (a_hihi >> 16)) | 0; - a.lo = (a_lolo & 0xFFFF) | (a_lohi << 16); - a.hi = (a_hilo & 0xFFFF) | (a_hihi << 16); - a.sup = sup; -} -function LongInt_add(a, b) { - var a_lolo = a.lo & 0xFFFF; - var a_lohi = a.lo >>> 16; - var a_hilo = a.hi & 0xFFFF; - var a_hihi = a.hi >>> 16; - var b_lolo = b.lo & 0xFFFF; - var b_lohi = b.lo >>> 16; - var b_hilo = b.hi & 0xFFFF; - var b_hihi = b.hi >>> 16; - - a_lolo = (a_lolo + b_lolo) | 0; - a_lohi = (a_lohi + b_lohi + (a_lolo >> 16)) | 0; - a_hilo = (a_hilo + b_hilo + (a_lohi >> 16)) | 0; - a_hihi = (a_hihi + b_hihi + (a_hilo >> 16)) | 0; - var sup = (a.sup + b.sup + (a_hihi >> 16)) | 0; - a.lo = (a_lolo & 0xFFFF) | (a_lohi << 16); - a.hi = (a_hilo & 0xFFFF) | (a_hihi << 16); - a.sup = sup; -} -function LongInt_inc(a) { - a.lo = (a.lo + 1) | 0; - if (a.lo === 0) { - a.hi = (a.hi + 1) | 0; - if (a.hi === 0) { - a.sup = (a.sup + 1) & 0xFFFF; - } - } -} -function LongInt_dec(a) { - a.lo = (a.lo - 1) | 0; - if (a.lo === -1) { - a.hi = (a.hi - 1) | 0; - if (a.hi === -1) { - a.sup = (a.sup - 1) & 0xFFFF; - } - } -} -function LongInt_ucompare(a, b) { - var r = (a.sup - b.sup); - if (r !== 0) { - return r; - } - r = (a.hi >>> 1) - (b.hi >>> 1); - if (r !== 0) { - return r; - } - r = (a.hi & 1) - (b.hi & 1); - if (r !== 0) { - return r; - } - r = (a.lo >>> 1) - (b.lo >>> 1); - if (r !== 0) { - return r; - } - return (a.lo & 1) - (b.lo & 1); -} -function LongInt_numOfLeadingZeroBits(a) { - var n = 0; - var d = 16; - while (d > 0) { - if ((a >>> d) !== 0) { - a >>>= d; - n = (n + d) | 0; - } - d = (d / 2) | 0; - } - return 31 - n; -} -function LongInt_shl(a, b) { - if (b === 0) { - return; - } - if (b < 32) { - a.sup = ((a.hi >>> (32 - b)) | (a.sup << b)) & 0xFFFF; - a.hi = (a.lo >>> (32 - b)) | (a.hi << b); - a.lo <<= b; - } else if (b === 32) { - a.sup = a.hi & 0xFFFF; - a.hi = a.lo; - a.lo = 0; - } else if (b < 64) { - a.sup = ((a.lo >>> (64 - b)) | (a.hi << (b - 32))) & 0xFFFF; - a.hi = a.lo << b; - a.lo = 0; - } else if (b === 64) { - a.sup = a.lo & 0xFFFF; - a.hi = 0; - a.lo = 0; - } else { - a.sup = (a.lo << (b - 64)) & 0xFFFF; - a.hi = 0; - a.lo = 0; - } -} -function LongInt_shr(a, b) { - if (b === 0) { - return; - } - if (b === 32) { - a.lo = a.hi; - a.hi = a.sup; - a.sup = 0; - } else if (b < 32) { - a.lo = (a.lo >>> b) | (a.hi << (32 - b)); - a.hi = (a.hi >>> b) | (a.sup << (32 - b)); - a.sup >>>= b; - } else if (b === 64) { - a.lo = a.sup; - a.hi = 0; - a.sup = 0; - } else if (b < 64) { - a.lo = (a.hi >>> (b - 32)) | (a.sup << (64 - b)); - a.hi = a.sup >>> (b - 32); - a.sup = 0; - } else { - a.lo = a.sup >>> (b - 64); - a.hi = 0; - a.sup = 0; - } -} -function LongInt_copy(a) { - return new LongInt(a.lo, a.hi, a.sup); -} -function LongInt_div(a, b) { - // Normalize divisor - var bits = b.hi !== 0 ? LongInt_numOfLeadingZeroBits(b.hi) : LongInt_numOfLeadingZeroBits(b.lo) + 32; - var sz = 1 + ((bits / 16) | 0); - var dividentBits = bits % 16; - LongInt_shl(b, bits); - LongInt_shl(a, dividentBits); - var q = new LongInt(0, 0, 0); - while (sz-- > 0) { - LongInt_shl(q, 16); - // Calculate approximate q - var digitA = (a.hi >>> 16) + (0x10000 * a.sup); - var digitB = b.hi >>> 16; - var digit = (digitA / digitB) | 0; - var t = LongInt_copy(b); - LongInt_mul(t, digit); - // Adjust q either down or up - if (LongInt_ucompare(t, a) >= 0) { - while (LongInt_ucompare(t, a) > 0) { - LongInt_sub(t, b); - --digit; - } - } else { - while (true) { - var nextT = LongInt_copy(t); - LongInt_add(nextT, b); - if (LongInt_ucompare(nextT, a) > 0) { - break; - } - t = nextT; - ++digit; - } - } - LongInt_sub(a, t); - q.lo |= digit; - LongInt_shl(a, 16); - } - LongInt_shr(a, bits + 16); - return q; -} diff --git a/core/src/main/resources/org/teavm/backend/javascript/simpleThread.js b/core/src/main/resources/org/teavm/backend/javascript/simpleThread.js new file mode 100644 index 000000000..12803bade --- /dev/null +++ b/core/src/main/resources/org/teavm/backend/javascript/simpleThread.js @@ -0,0 +1,41 @@ +/* + * Copyright 2018 Alexey Andreev. + * + * 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. + */ +"use strict"; + +function $rt_startThread(runner, callback) { + var result; + try { + result = runner(); + } catch (e) { + result = e; + } + if (typeof callback !== 'undefined') { + callback(result); + } else if (e instanceof Error) { + throw e; + } +} +function $rt_suspending() { + return false; +} +function $rt_resuming() { + return false; +} +function $rt_nativeThread() { + return null; +} +function $rt_invalidPointer() { +} \ No newline at end of file diff --git a/core/src/main/resources/org/teavm/backend/javascript/thread.js b/core/src/main/resources/org/teavm/backend/javascript/thread.js new file mode 100644 index 000000000..8666667b8 --- /dev/null +++ b/core/src/main/resources/org/teavm/backend/javascript/thread.js @@ -0,0 +1,111 @@ +/* + * Copyright 2018 Alexey Andreev. + * + * 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. + */ +"use strict"; + +function TeaVMThread(runner) { + this.status = 3; + this.stack = []; + this.suspendCallback = null; + this.runner = runner; + this.attribute = null; + this.completeCallback = null; +} +TeaVMThread.prototype.push = function() { + for (var i = 0; i < arguments.length; ++i) { + this.stack.push(arguments[i]); + } + return this; +}; +TeaVMThread.prototype.s = TeaVMThread.prototype.push; +TeaVMThread.prototype.pop = function() { + return this.stack.pop(); +}; +TeaVMThread.prototype.l = TeaVMThread.prototype.pop; +TeaVMThread.prototype.isResuming = function() { + return this.status === 2; +}; +TeaVMThread.prototype.isSuspending = function() { + return this.status === 1; +}; +TeaVMThread.prototype.suspend = function(callback) { + this.suspendCallback = callback; + this.status = 1; +}; +TeaVMThread.prototype.start = function(callback) { + if (this.status !== 3) { + throw new Error("Thread already started"); + } + if ($rt_currentNativeThread !== null) { + throw new Error("Another thread is running"); + } + this.status = 0; + this.completeCallback = callback ? callback : function(result) { + if (result instanceof Error) { + throw result; + } + }; + this.run(); +}; +TeaVMThread.prototype.resume = function() { + if ($rt_currentNativeThread !== null) { + throw new Error("Another thread is running"); + } + this.status = 2; + this.run(); +}; +TeaVMThread.prototype.run = function() { + $rt_currentNativeThread = this; + var result; + try { + result = this.runner(); + } catch (e) { + result = e; + } finally { + $rt_currentNativeThread = null; + } + if (this.suspendCallback !== null) { + var self = this; + var callback = this.suspendCallback; + this.suspendCallback = null; + callback(function() { + self.resume(); + }); + } else if (this.status === 0) { + this.completeCallback(result); + } +}; + +function $rt_suspending() { + var thread = $rt_nativeThread(); + return thread != null && thread.isSuspending(); +} +function $rt_resuming() { + var thread = $rt_nativeThread(); + return thread != null && thread.isResuming(); +} +function $rt_suspend(callback) { + return $rt_nativeThread().suspend(callback); +} +function $rt_startThread(runner, callback) { + new TeaVMThread(runner).start(callback); +} +var $rt_currentNativeThread = null; +function $rt_nativeThread() { + return $rt_currentNativeThread; +} +function $rt_invalidPointer() { + throw new Error("Invalid recorded state"); +} \ No newline at end of file diff --git a/metaprogramming/impl/src/main/java/org/teavm/metaprogramming/impl/UsageGenerator.java b/metaprogramming/impl/src/main/java/org/teavm/metaprogramming/impl/UsageGenerator.java index ff942d430..345fcd82c 100644 --- a/metaprogramming/impl/src/main/java/org/teavm/metaprogramming/impl/UsageGenerator.java +++ b/metaprogramming/impl/src/main/java/org/teavm/metaprogramming/impl/UsageGenerator.java @@ -103,10 +103,14 @@ class UsageGenerator { MethodDependency hashCodeDep = agent.linkMethod(new MethodReference(String.class, "hashCode", int.class), location); + hashCodeDep.getVariable(0).propagate(agent.getType("java.lang.String")); nameDep.getResult().connect(hashCodeDep.getVariable(0)); hashCodeDep.getThrown().connect(methodDep.getThrown()); hashCodeDep.use(); + agent.linkMethod(new MethodReference(Object.class, "hashCode", int.class), null); + agent.linkMethod(new MethodReference(Object.class, "equals", Object.class, boolean.class), null); + return nameDep; } diff --git a/pom.xml b/pom.xml index 195f5d0fa..14e06603a 100644 --- a/pom.xml +++ b/pom.xml @@ -68,7 +68,6 @@ 1.5 9.2.1.v20140609 1.7.7 - 2.47.2 2.6.2 2017.3.5 7.0 @@ -77,7 +76,6 @@ false 1 - true @@ -183,16 +181,6 @@ slf4j-api ${slf4j.version} - - org.seleniumhq.selenium - selenium-java - ${selenium.version} - - - org.seleniumhq.selenium - selenium-remote-driver - ${selenium.version} - com.fasterxml.jackson.core jackson-annotations diff --git a/tests/src/test/js/src/run-tests.js b/tests/src/test/js/src/run-tests.js index 6ed1798e2..d118674b5 100644 --- a/tests/src/test/js/src/run-tests.js +++ b/tests/src/test/js/src/run-tests.js @@ -276,34 +276,27 @@ class TestRunner { function runTeaVM() { return new Promise(resolve => { - $rt_startThread(() => { - const thread = $rt_nativeThread(); - let instance; - if (thread.isResuming()) { - instance = thread.pop(); + main([], result => { + const message = {}; + if (result instanceof Error) { + makeErrorMessage(message, result); + } else { + message.status = "OK"; } - try { - runTest(); - } catch (e) { - resolve({ status: "failed", errorMessage: buildErrorMessage(e) }); - return; - } - if (thread.isSuspending()) { - thread.push(instance); - return; - } - resolve({ status: "OK" }); + resolve(message); }); - function buildErrorMessage(e) { - let stack = e.stack; - if (e.$javaException && e.$javaException.constructor.$meta) { - stack = e.$javaException.constructor.$meta.name + ": "; - const exceptionMessage = extractException(e.$javaException); - stack += exceptionMessage ? $rt_ustr(exceptionMessage) : ""; + function makeErrorMessage(message, e) { + message.status = "failed"; + if (e.$javaException) { + message.className = e.$javaException.constructor.name; + message.message = e.$javaException.getMessage(); + } else { + message.className = Object.getPrototypeOf(e).name; + message.message = e.message; } - stack += "\n" + stack; - return stack; + message.exception = e; + message.stack = e.stack; } }) } diff --git a/tools/core/src/main/resources/org/teavm/tooling/test/junit-client.html b/tools/core/src/main/resources/org/teavm/tooling/test/junit-client.html deleted file mode 100644 index 81ad7fcf4..000000000 --- a/tools/core/src/main/resources/org/teavm/tooling/test/junit-client.html +++ /dev/null @@ -1,25 +0,0 @@ - - - - - - - - - - - \ No newline at end of file diff --git a/tools/core/src/main/resources/org/teavm/tooling/test/junit.html b/tools/core/src/main/resources/org/teavm/tooling/test/junit.html deleted file mode 100644 index b16073ed8..000000000 --- a/tools/core/src/main/resources/org/teavm/tooling/test/junit.html +++ /dev/null @@ -1,52 +0,0 @@ - - - - - TeaVM JUnit tests - - - - - - - -
-
Total tests: - -
-
Failed:
-
-
-
- -
-
-
-
-
- - - \ No newline at end of file diff --git a/tools/core/src/main/resources/org/teavm/tooling/test/res/class_obj.png b/tools/core/src/main/resources/org/teavm/tooling/test/res/class_obj.png deleted file mode 100644 index c57c2d00f..000000000 Binary files a/tools/core/src/main/resources/org/teavm/tooling/test/res/class_obj.png and /dev/null differ diff --git a/tools/core/src/main/resources/org/teavm/tooling/test/res/control-000-small.png b/tools/core/src/main/resources/org/teavm/tooling/test/res/control-000-small.png deleted file mode 100644 index 40a7bf9d8..000000000 Binary files a/tools/core/src/main/resources/org/teavm/tooling/test/res/control-000-small.png and /dev/null differ diff --git a/tools/core/src/main/resources/org/teavm/tooling/test/res/junit-client.js b/tools/core/src/main/resources/org/teavm/tooling/test/res/junit-client.js deleted file mode 100644 index f22da3d0c..000000000 --- a/tools/core/src/main/resources/org/teavm/tooling/test/res/junit-client.js +++ /dev/null @@ -1,78 +0,0 @@ -"use strict"; -var JUnitClient = {}; -JUnitClient.run = function() { - var handler = function(event) { - switch (event.data.command) { - case "runTest": - window.removeEventListener("message", handler); - $rt_startThread(function() { - JUnitClient.runTest(); - }); - break; - } - }; - window.addEventListener("message", handler); - window.parent.postMessage("ready", "*"); -}; -JUnitClient.runTest = function() { - var thread = $rt_nativeThread(); - var instance; - var ptr = 0; - var message; - if (thread.isResuming()) { - ptr = thread.pop(); - instance = thread.pop(); - } - loop: while (true) { switch (ptr) { - case 0: - try { - runTest(); - } catch (e) { - message = {}; - JUnitClient.makeErrorMessage(message, e); - break loop; - } - if (thread.isSuspending()) { - thread.push(instance); - thread.push(ptr); - return; - } - message = {}; - message.status = "ok"; - break loop; - }} - window.parent.postMessage(message, "*"); -}; -JUnitClient.makeErrorMessage = function(message, e) { - message.status = "exception"; - var stack = e.stack; - if (e.$javaException && e.$javaException.constructor.$meta) { - message.exception = e.$javaException.constructor.$meta.name; - message.stack = e.$javaException.constructor.$meta.name + ": "; - var exceptionMessage = extractException(e.$javaException); - message.stack += exceptionMessage ? $rt_ustr(exceptionMessage) : ""; - } - message.stack += "\n" + stack; -}; -JUnitClient.reportError = function(error) { - var handler = function() { - window.removeEventListener("message", handler); - var message = { status : "exception", stack : error }; - window.parent.postMessage(message, "*"); - }; - window.addEventListener("message", handler); -}; -JUnitClient.loadScript = function(scriptPath) { - var script = document.createElement("script"); - script.src = scriptPath; - document.body.appendChild(script); -}; -window.addEventListener("message", function(event) { - var data = event.data; - switch (data.command) { - case "loadScript": - JUnitClient.loadScript(data.script); - break; - } -}); -window.parent.postMessage("loaded", "*"); \ No newline at end of file diff --git a/tools/core/src/main/resources/org/teavm/tooling/test/res/junit-support.js b/tools/core/src/main/resources/org/teavm/tooling/test/res/junit-support.js deleted file mode 100644 index b6ab86c10..000000000 --- a/tools/core/src/main/resources/org/teavm/tooling/test/res/junit-support.js +++ /dev/null @@ -1,362 +0,0 @@ -/* - * Copyright 2013 Alexey Andreev. - * - * 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. - */ -"use strict"; -function JUnitServer() { - this.tree = new Tree(document.getElementById("test-tree")); - this.totalTimeSpent = 0; - this.expectedExceptions = []; - this.frame = null; - this.tests = []; - this.currentTestNode = null; - this.testCaseCount = 0; - this.progressElem = document.getElementById("progress-bar-content"); - this.runCount = 0; - this.failCount = 0; - this.traceElem = document.getElementById("test-trace"); - this.failedElem = document.getElementById("failed-test-count"); - this.totalTimeElem = document.getElementById("total-time"); - var self = this; - this.tree.addSelectionListener(function(node) { - while (self.traceElem.firstChild) { - self.traceElem.removeChild(self.traceElem.firstChild); - } - if (node.error) { - var pre = document.createElement("pre"); - pre.appendChild(document.createTextNode(node.error)); - self.traceElem.appendChild(pre); - } - }); -} -JUnitServer.prototype = {}; -JUnitServer.prototype.handleEvent = function(message, callback) { - if (message.status === "ok") { - if (this.expectedExceptions.length > 0) { - this.currentTestNode.success = false; - this.currentTestNode.error = "Expected exception not thrown"; - this.failCount++; - } else { - this.currentTestNode.success = true; - } - } else if (message.status === "exception") { - if (message.exception && this.isExpectedException(message.exception)) { - this.currentTestNode.success = true; - } else { - this.currentTestNode.success = false; - this.currentTestNode.error = message.stack; - this.failCount++; - } - } - this.currentTestNode.indicator.className = "complete-indicator " + - (this.currentTestNode.success ? "successfull" : "failed"); - this.runCount++; - this.progressElem.style.width = (100 * this.runCount / this.testCaseCount).toFixed(2) + "%"; - document.body.removeChild(this.frame); - self.frame = null; - callback(); -}; -JUnitServer.prototype.isExpectedException = function(ex) { - for (var i = 0; i < this.expectedExceptions.length; ++i) { - if (this.expectedExceptions[i] === ex) { - return true; - } - } - return false; -}; -JUnitServer.prototype.loadCode = function(path, additionalScripts, callback) { - this.frame = document.createElement("iframe"); - this.frame.src = "junit-client.html"; - document.body.appendChild(this.frame); - var sequence = []; - sequence.push(path); - for (var i = 0; i < additionalScripts.length; ++i) { - sequence.push(additionalScripts[i]); - } - var self = this; - var handler = function() { - window.removeEventListener("message", handler); - self.loadScripts(sequence, callback); - }; - window.addEventListener("message", handler); -}; -JUnitServer.prototype.loadScripts = function(scripts, callback) { - for (var i = 0; i < scripts.length; ++i) { - this.frame.contentWindow.postMessage({ command : "loadScript", "script" : scripts[i] }, "*"); - } - var handler = function() { - window.removeEventListener("message", handler); - callback(); - }; - window.addEventListener("message", handler); -}; -JUnitServer.prototype.runTest = function(node, callback) { - node.indicator.className = "complete-indicator in-progress"; - var startTime = new Date().getTime(); - if (node.testCase) { - this.expectedExceptions = node.testCase.expected; - this.currentTestNode = node; - var self = this; - this.loadCode(node.testCase.script, node.testCase.additionalScripts, function() { - function messageHandler(event) { - window.removeEventListener("message", messageHandler); - var timeSpent = new Date().getTime() - startTime; - node.timeIndicator.appendChild(document.createTextNode("(" + (timeSpent / 1000).toFixed(3) + ")")); - self.handleEvent(event.data, callback); - } - window.addEventListener("message", messageHandler); - self.frame.contentWindow.postMessage({ command : "runTest" }, "*"); - }); - } else { - var self = this; - var nodes = node.getNodes(); - this.runTestFromList(nodes, 0, function() { - node.success = true; - for (var i = 0; i < nodes.length; ++i) { - if (!nodes[i].success) { - node.success = false; - break; - } - } - node.indicator.className = "complete-indicator " + (node.success ? "successfull" : "failed"); - if (!node.success) { - node.open(); - } - var timeSpent = new Date().getTime() - startTime; - node.timeIndicator.appendChild(document.createTextNode( - "(" + (timeSpent / 1000).toFixed(3) + ")")); - callback(); - }); - } -}; -JUnitServer.prototype.readTests = function(tests) { - var groups = this.groupTests(tests); - var groupNames = []; - for (var groupName in groups) { - groupNames.push(groupName); - } - groupNames.sort(); - this.tests = []; - for (var i = 0; i < groupNames.length; ++i) { - var groupName = groupNames[i]; - var group = groups[groupName]; - var pkgNode = this.createNode(this.tree, "package", groupName); - group.sort(); - for (var j = 0; j < group.length; ++j) { - var test = group[j]; - var simpleName = test.name.substring(groupName.length + 1); - var testNode = this.createNode(pkgNode, "test", simpleName); - var methods = test.methods.slice(); - methods.sort(); - for (var k = 0; k < methods.length; ++k) { - var method = methods[k]; - var caseNode = this.createNode(testNode, "case", method.name); - caseNode.testCase = method; - ++this.testCaseCount; - } - } - } - document.getElementById("test-count").appendChild(document.createTextNode(this.testCaseCount)); - return this; -}; -JUnitServer.prototype.createNode = function(parent, className, name) { - var elem = document.createElement("div"); - elem.className = className; - elem.appendChild(document.createTextNode(name)); - var node = parent.add(elem); - node.indicator = document.createElement("div"); - node.indicator.className = "complete-indicator"; - elem.appendChild(node.indicator); - node.timeIndicator = document.createElement("span"); - node.timeIndicator.className = "time-indicator"; - elem.appendChild(node.timeIndicator); - return node; -}; -JUnitServer.prototype.groupTests = function(tests) { - var groups = {}; - for (var i = 0; i < tests.length; ++i) { - var test = tests[i]; - var pkg = test.name.substring(0, test.name.lastIndexOf('.')); - var group = groups[pkg]; - if (!group) { - group = []; - groups[pkg] = group; - } - group.push(test); - } - return groups; -}; -JUnitServer.prototype.runAllTests = function(callback) { - this.cleanupTests(); - var self = this; - var startTime = new Date().getTime(); - this.runTestFromList(this.tree.getNodes(), 0, function() { - self.failedElem.appendChild(document.createTextNode(self.failCount)); - var totalTime = new Date().getTime() - startTime; - self.totalTimeElem.appendChild(document.createTextNode("(" + - (totalTime / 1000).toFixed(3) + ")")); - callback(); - }); -}; -JUnitServer.prototype.runTestFromList = function(nodes, index, callback) { - if (index < nodes.length) { - var node = nodes[index]; - var self = this; - this.runTest(node, function() { - self.runTestFromList(nodes, index + 1, callback); - }); - } else { - callback(); - } -}; -JUnitServer.prototype.cleanupTests = function() { - if (this.failedElem.firstChild) { - this.failedElem.removeChild(this.failedElem.firstChild); - } - if (this.totalTimeElem.firstChild) { - this.totalTimeElem.removeChild(this.totalTimeElem.firstChild); - } - this.runCount = 0; - this.failCount = 0; - this.progressElem.style.width = "0%"; - var nodes = this.tree.getNodes(); - for (var i = 0; i < nodes.length; ++i) { - this.cleanupNode(nodes[i]); - } -}; -JUnitServer.prototype.cleanupNode = function(node) { - delete node.error; - node.indicator.className = "complete-indicator"; - if (node.timeIndicator.firstChild) { - node.timeIndicator.removeChild(node.timeIndicator.firstChild); - } - var nodes = node.getNodes(); - for (var i = 0; i < nodes.length; ++i) { - this.cleanupNode(nodes[i]); - } -}; - -function Tree(container) { - this.container = container; - this.nodes = []; - this.selectedNode = null; - this.selectionListeners = []; -} -Tree.prototype.createNode = function(content) { - var elem = document.createElement("div"); - elem.className = "tree-node"; - var contentElem = document.createElement("div"); - contentElem.className = "tree-node-content"; - elem.appendChild(contentElem); - contentElem.appendChild(content); - var buttonElem = document.createElement("div"); - buttonElem.className = "tree-node-button closed"; - buttonElem.style.display = "none"; - elem.appendChild(buttonElem); - var childrenElem = document.createElement("div"); - childrenElem.className = "tree-node-children closed"; - childrenElem.style.display = "none"; - elem.appendChild(childrenElem); - return new TreeNode(elem, contentElem, buttonElem, childrenElem, this); -}; -Tree.prototype.add = function(content) { - var node = this.createNode(content); - this.container.appendChild(node.elem); - this.nodes.push(node); - return node; -}; -Tree.prototype.getNodes = function() { - return this.nodes; -}; -Tree.prototype.addSelectionListener = function(listener) { - this.selectionListeners.push(listener); -}; -function TreeNode(elem, content, button, children, tree) { - this.elem = elem; - this.content = content; - this.button = button; - this.children = children; - this.opened = false; - this.parent = null; - this.nodes = []; - this.tree = tree; - var self = this; - this.button.onclick = function() { - self.toggle(); - }; - this.content.onclick = function() { - self.select(); - } -} -TreeNode.prototype.add = function(content) { - var node = this.tree.createNode(content); - this.children.appendChild(node.elem); - this.button.style.display = ""; - this.children.style.display = ""; - this.content.className = "tree-node-content"; - node.parent = this; - this.nodes.push(node); - return node; -}; -TreeNode.prototype.isOpened = function() { - return this.opened; -}; -TreeNode.prototype.open = function() { - if (this.isOpened()) { - return; - } - this.opened = true; - this.children.className = "tree-node-children opened"; - this.button.className = "tree-node-button opened"; -}; -TreeNode.prototype.close = function() { - if (!this.isOpened()) { - return; - } - this.opened = false; - this.children.className = "tree-node-children closed"; - this.button.className = "tree-node-button closed"; -}; -TreeNode.prototype.toggle = function() { - if (this.isOpened()) { - this.close(); - } else { - this.open(); - } -}; -TreeNode.prototype.getNodes = function() { - return this.nodes; -}; -TreeNode.prototype.getParent = function() { - return this.parent; -}; -TreeNode.prototype.getTree = function() { - return this.tree; -}; -TreeNode.prototype.isSelected = function() { - return this.tree.selectedNode === this; -}; -TreeNode.prototype.select = function() { - if (this.isSelected()) { - return; - } - if (this.tree.selectedNode != null) { - this.tree.selectedNode.content.className = "tree-node-content"; - } - this.content.className = "tree-node-content selected"; - this.tree.selectedNode = this; - for (var i = 0; i < this.tree.selectionListeners.length; ++i) { - this.tree.selectionListeners[i](this); - } -}; \ No newline at end of file diff --git a/tools/core/src/main/resources/org/teavm/tooling/test/res/junit.css b/tools/core/src/main/resources/org/teavm/tooling/test/res/junit.css deleted file mode 100644 index 28997f74c..000000000 --- a/tools/core/src/main/resources/org/teavm/tooling/test/res/junit.css +++ /dev/null @@ -1,185 +0,0 @@ -/* - * Copyright 2013 Alexey Andreev. - * - * 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. - */ -iframe { - width: 1px; - height: 1px; - padding: 0; - margin: 0; - border-style: none; -} -* { - font-family: sans-serif; - font-size: 10pt; -} -html, body { - position: absolute; - left: 0; - right: 0; - top: 0; - bottom: 0; - padding: 0; - margin: 0; -} -.test-header { - position: absolute; - top: 0; - right: 0; - left: 0; - height: 40px; - border-bottom-color: gray; - border-bottom-width: 1px; - border-bottom-style: solid; -} -.test-count, .failed-test-count { - position: absolute; - top: 0; - bottom: 0; - line-height: 40px; - padding: 0; - margin: 0; - vertical-align: middle; -} -.test-count { - left: 5px; - width: 200px; -} -.failed-test-count { - left: 205px; - width: 130px; -} -#start-button { - display: block; - position: absolute; - left: 340px; - top: 6px; - bottom: 6px; - width: 70px; -} -.progress-bar { - position: absolute; - left: 420px; - right: 20px; - top: 5px; - height: 30px; - border-color: grey; - border-radius: 2px; - border-width: 1px; - border-style: solid; -} -#progress-bar-content { - position: absolute; - background-color: green; - left: 0; - top: 0; - bottom: 0; - width: 0; -} -#test-tree { - position: absolute; - top: 41px; - bottom: 0; - left: 0; - width: 50%; - border-right-color: grey; - border-right-width: 1px; - border-right-style: solid; - overflow: auto; -} -#test-trace { - position: absolute; - top: 41px; - bottom: 0; - left: 50%; - right: 0; - overflow: auto; -} -.tree-node { - position: relative; -} -.tree-node-content { - margin-left: 18px; - cursor: default; - white-space: nowrap; -} -.tree-node-content.selected { - background-color: rgb(160,160,255); -} -.tree-node-children { - padding-left: 18px; -} -.tree-node-children.closed { - display: none; -} -.tree-node-button { - position: absolute; - cursor: pointer; - left: 0; - top: 0; - width: 16px; - height: 16px; - background-repeat: no-repeat; - background-position: 0 0; -} -.tree-node-button.opened { - background-image: url(toggle-small.png); -} -.tree-node-button.closed { - background-image: url(toggle-small-expand.png); -} -.package, .test, .case { - min-height: 18px; - padding-left: 20px; - background-position: 2px 1px; - background-repeat: no-repeat; - position: relative; -} -.package { - background-image: url(package_obj.png); -} -.test { - background-image: url(class_obj.png); -} -.case { - background-image: url(methpub_obj.png); -} -.complete-indicator { - position: absolute; - left: -4px; - top: 5px; - width: 16px; - height: 16px; - background-position: 0 0; - background-repeat: no-repeat; - display: none; -} -.complete-indicator.successfull { - display: block; - background-image: url(tick-small.png); -} -.complete-indicator.failed { - display: block; - background-image: url(tick-small-red.png); -} -.complete-indicator.in-progress { - display: block; - background-image: url(control-000-small.png); -} -.time-indicator { - font-size: 9pt; - font-style: italic; - color: rgb(0,80,160); - padding-left: 0.5em; -} \ No newline at end of file diff --git a/tools/core/src/main/resources/org/teavm/tooling/test/res/methpub_obj.png b/tools/core/src/main/resources/org/teavm/tooling/test/res/methpub_obj.png deleted file mode 100644 index 300419528..000000000 Binary files a/tools/core/src/main/resources/org/teavm/tooling/test/res/methpub_obj.png and /dev/null differ diff --git a/tools/core/src/main/resources/org/teavm/tooling/test/res/package_obj.png b/tools/core/src/main/resources/org/teavm/tooling/test/res/package_obj.png deleted file mode 100644 index 0afea5b86..000000000 Binary files a/tools/core/src/main/resources/org/teavm/tooling/test/res/package_obj.png and /dev/null differ diff --git a/tools/core/src/main/resources/org/teavm/tooling/test/res/tick-small-red.png b/tools/core/src/main/resources/org/teavm/tooling/test/res/tick-small-red.png deleted file mode 100644 index 5b95ec59e..000000000 Binary files a/tools/core/src/main/resources/org/teavm/tooling/test/res/tick-small-red.png and /dev/null differ diff --git a/tools/core/src/main/resources/org/teavm/tooling/test/res/tick-small.png b/tools/core/src/main/resources/org/teavm/tooling/test/res/tick-small.png deleted file mode 100644 index 1c0ffff6d..000000000 Binary files a/tools/core/src/main/resources/org/teavm/tooling/test/res/tick-small.png and /dev/null differ diff --git a/tools/core/src/main/resources/org/teavm/tooling/test/res/toggle-small-expand.png b/tools/core/src/main/resources/org/teavm/tooling/test/res/toggle-small-expand.png deleted file mode 100644 index 79c5ff7e8..000000000 Binary files a/tools/core/src/main/resources/org/teavm/tooling/test/res/toggle-small-expand.png and /dev/null differ diff --git a/tools/core/src/main/resources/org/teavm/tooling/test/res/toggle-small.png b/tools/core/src/main/resources/org/teavm/tooling/test/res/toggle-small.png deleted file mode 100644 index f783a6f2c..000000000 Binary files a/tools/core/src/main/resources/org/teavm/tooling/test/res/toggle-small.png and /dev/null differ diff --git a/tools/junit/src/main/java/org/teavm/junit/RhinoResultParser.java b/tools/junit/src/main/java/org/teavm/junit/RhinoResultParser.java index aa6d7010d..d73f543d6 100644 --- a/tools/junit/src/main/java/org/teavm/junit/RhinoResultParser.java +++ b/tools/junit/src/main/java/org/teavm/junit/RhinoResultParser.java @@ -36,14 +36,15 @@ import org.teavm.model.MethodReference; final class RhinoResultParser { private static Pattern pattern = Pattern.compile("(([A-Za-z_$]+)\\(\\))?@.+:([0-9]+)"); private static Pattern lineSeparator = Pattern.compile("\\r\\n|\r|\n"); - private File debugFile; private DebugInformation debugInformation; private String[] script; RhinoResultParser(File debugFile) { - debugInformation = debugFile != null ? getDebugInformation(debugFile) : null; - script = getScript(new File(debugFile.getParentFile(), - debugFile.getName().substring(0, debugFile.getName().length() - 9))); + if (debugFile != null) { + debugInformation = getDebugInformation(debugFile); + script = getScript(new File(debugFile.getParentFile(), + debugFile.getName().substring(0, debugFile.getName().length() - 9))); + } } void parseResult(Scriptable result, TestRunCallback callback) { @@ -57,8 +58,6 @@ final class RhinoResultParser { callback.complete(); break; case "exception": { - DebugInformation debugInformation = debugFile != null ? getDebugInformation(debugFile) : null; - String className = String.valueOf(result.get("className", result)); if (debugInformation != null) { String decodedName = debugInformation.getClassNameByJsName(className); diff --git a/tools/maven/plugin/pom.xml b/tools/maven/plugin/pom.xml index 4f9926dcd..38348ec41 100644 --- a/tools/maven/plugin/pom.xml +++ b/tools/maven/plugin/pom.xml @@ -57,14 +57,6 @@ commons-io commons-io
- - org.seleniumhq.selenium - selenium-java - - - org.seleniumhq.selenium - selenium-remote-driver - com.fasterxml.jackson.core jackson-databind