From 9154f4eff984bbef32a0beb2807574c164d91fed Mon Sep 17 00:00:00 2001 From: Alexey Andreev Date: Fri, 16 Jan 2015 17:47:25 +0400 Subject: [PATCH] Add post-processor that reports references to missing items and replaces these references with code that throws error. --- .../java/io/TByteArrayOutputStream.java | 6 +- .../java/lang/ClassNativeGenerator.java | 3 + .../java/lang/TAbstractStringBuilder.java | 9 - .../lang/TArrayIndexOutOfBoundsException.java | 2 +- .../teavm/classlib/java/lang/TBoolean.java | 8 +- .../org/teavm/classlib/java/lang/TByte.java | 9 +- .../classlib/java/lang/TCharSequence.java | 6 +- .../teavm/classlib/java/lang/TCharacter.java | 8 +- .../org/teavm/classlib/java/lang/TClass.java | 1 + .../org/teavm/classlib/java/lang/TDouble.java | 8 +- .../org/teavm/classlib/java/lang/TEnum.java | 5 +- .../org/teavm/classlib/java/lang/TFloat.java | 8 +- .../teavm/classlib/java/lang/TInteger.java | 17 +- .../org/teavm/classlib/java/lang/TLong.java | 18 +- .../java/lang/TNoClassDefFoundError.java | 32 ++ .../java/lang/TNoSuchMethodError.java | 32 ++ .../org/teavm/classlib/java/lang/TObject.java | 6 +- .../org/teavm/classlib/java/lang/TShort.java | 9 +- .../org/teavm/classlib/java/lang/TString.java | 6 +- .../TStringIndexOutOfBoundsException.java | 3 +- .../org/teavm/classlib/java/util/TBitSet.java | 9 +- .../classlib/java/util/logging/TLevel.java | 29 +- .../DefaultProblemTextConsumer.java | 2 +- .../java/org/teavm/diagnostics/Problem.java | 8 +- .../java/org/teavm/javascript/ni/Rename.java | 5 +- .../main/java/org/teavm/model/BasicBlock.java | 11 + .../model/util/MissingItemsProcessor.java | 302 ++++++++++++++++++ .../teavm/tooling/TeaVMProblemRenderer.java | 97 ++++++ .../java/org/teavm/tooling/TeaVMTestTool.java | 9 + .../java/org/teavm/tooling/TeaVMTool.java | 70 +--- .../src/main/java/org/teavm/vm/TeaVM.java | 22 +- .../org/teavm/maven/BuildJavascriptMojo.java | 9 +- 32 files changed, 587 insertions(+), 182 deletions(-) create mode 100644 teavm-classlib/src/main/java/org/teavm/classlib/java/lang/TNoClassDefFoundError.java create mode 100644 teavm-classlib/src/main/java/org/teavm/classlib/java/lang/TNoSuchMethodError.java create mode 100644 teavm-core/src/main/java/org/teavm/model/util/MissingItemsProcessor.java create mode 100644 teavm-core/src/main/java/org/teavm/tooling/TeaVMProblemRenderer.java diff --git a/teavm-classlib/src/main/java/org/teavm/classlib/java/io/TByteArrayOutputStream.java b/teavm-classlib/src/main/java/org/teavm/classlib/java/io/TByteArrayOutputStream.java index f7f1ed768..07c17c87e 100644 --- a/teavm-classlib/src/main/java/org/teavm/classlib/java/io/TByteArrayOutputStream.java +++ b/teavm-classlib/src/main/java/org/teavm/classlib/java/io/TByteArrayOutputStream.java @@ -18,7 +18,6 @@ package org.teavm.classlib.java.io; import org.teavm.classlib.java.lang.TMath; import org.teavm.classlib.java.lang.TString; import org.teavm.classlib.java.util.TArrays; -import org.teavm.javascript.ni.Rename; /** * @@ -62,9 +61,8 @@ public class TByteArrayOutputStream extends TOutputStream { } @Override - @Rename("toString") - public TString toString0() { - return new TString(buf, 0, count); + public String toString() { + return new String(buf, 0, count); } public TString toString(TString charsetName) throws TUnsupportedEncodingException { diff --git a/teavm-classlib/src/main/java/org/teavm/classlib/java/lang/ClassNativeGenerator.java b/teavm-classlib/src/main/java/org/teavm/classlib/java/lang/ClassNativeGenerator.java index 6cdca4a5c..53d7aba14 100644 --- a/teavm-classlib/src/main/java/org/teavm/classlib/java/lang/ClassNativeGenerator.java +++ b/teavm-classlib/src/main/java/org/teavm/classlib/java/lang/ClassNativeGenerator.java @@ -204,6 +204,9 @@ public class ClassNativeGenerator implements Generator, Injector, DependencyPlug case "getDeclaringClass": graph.getResult().propagate(agent.getType("java.lang.Class")); break; + case "getName": + graph.getResult().propagate(agent.getType("java.lang.String")); + break; case "newInstance": agent.linkMethod(new MethodReference(InstantiationException.class, "", void.class), location).use(); diff --git a/teavm-classlib/src/main/java/org/teavm/classlib/java/lang/TAbstractStringBuilder.java b/teavm-classlib/src/main/java/org/teavm/classlib/java/lang/TAbstractStringBuilder.java index 9c81a0eb3..498b5a17b 100644 --- a/teavm-classlib/src/main/java/org/teavm/classlib/java/lang/TAbstractStringBuilder.java +++ b/teavm-classlib/src/main/java/org/teavm/classlib/java/lang/TAbstractStringBuilder.java @@ -18,8 +18,6 @@ package org.teavm.classlib.java.lang; import org.teavm.classlib.impl.charset.UTF16Helper; import org.teavm.classlib.java.io.TSerializable; import org.teavm.classlib.java.util.TArrays; -import org.teavm.javascript.ni.Remove; -import org.teavm.javascript.ni.Rename; /** * @@ -589,13 +587,6 @@ class TAbstractStringBuilder extends TObject implements TSerializable, TCharSequ return buffer.length; } - @Override - @Rename("toString") - public TString toString0() { - return new TString(buffer, 0, length); - } - - @Remove @Override public String toString() { return new String(buffer, 0, length); diff --git a/teavm-classlib/src/main/java/org/teavm/classlib/java/lang/TArrayIndexOutOfBoundsException.java b/teavm-classlib/src/main/java/org/teavm/classlib/java/lang/TArrayIndexOutOfBoundsException.java index 235c88f12..8df905149 100644 --- a/teavm-classlib/src/main/java/org/teavm/classlib/java/lang/TArrayIndexOutOfBoundsException.java +++ b/teavm-classlib/src/main/java/org/teavm/classlib/java/lang/TArrayIndexOutOfBoundsException.java @@ -31,6 +31,6 @@ public class TArrayIndexOutOfBoundsException extends TIndexOutOfBoundsException } public TArrayIndexOutOfBoundsException(int index) { - super(TInteger.toString(index)); + super(TString.wrap(Integer.toString(index))); } } diff --git a/teavm-classlib/src/main/java/org/teavm/classlib/java/lang/TBoolean.java b/teavm-classlib/src/main/java/org/teavm/classlib/java/lang/TBoolean.java index ca5be44ad..afe614825 100644 --- a/teavm-classlib/src/main/java/org/teavm/classlib/java/lang/TBoolean.java +++ b/teavm-classlib/src/main/java/org/teavm/classlib/java/lang/TBoolean.java @@ -17,7 +17,6 @@ package org.teavm.classlib.java.lang; import org.teavm.classlib.java.io.TSerializable; import org.teavm.javascript.ni.GeneratedBy; -import org.teavm.javascript.ni.Rename; /** * @@ -71,13 +70,12 @@ public class TBoolean extends TObject implements TSerializable, TComparable { return new TByte(value); } - public static TString toString(byte value) { - return TString.wrap(new StringBuilder().append(value).toString()); + public static String toString(byte value) { + return new StringBuilder().append(value).toString(); } @Override - @Rename("toString") - public TString toString0() { + public String toString() { return toString(value); } diff --git a/teavm-classlib/src/main/java/org/teavm/classlib/java/lang/TCharSequence.java b/teavm-classlib/src/main/java/org/teavm/classlib/java/lang/TCharSequence.java index 5aa120d51..d20a368ec 100644 --- a/teavm-classlib/src/main/java/org/teavm/classlib/java/lang/TCharSequence.java +++ b/teavm-classlib/src/main/java/org/teavm/classlib/java/lang/TCharSequence.java @@ -15,8 +15,6 @@ */ package org.teavm.classlib.java.lang; -import org.teavm.javascript.ni.Rename; - /** * * @author Alexey Andreev @@ -28,6 +26,6 @@ public interface TCharSequence { TCharSequence subSequence(int start, int end); - @Rename("toString") - TString toString0(); + @Override + String toString(); } diff --git a/teavm-classlib/src/main/java/org/teavm/classlib/java/lang/TCharacter.java b/teavm-classlib/src/main/java/org/teavm/classlib/java/lang/TCharacter.java index b56d5a3d8..032c20fb5 100644 --- a/teavm-classlib/src/main/java/org/teavm/classlib/java/lang/TCharacter.java +++ b/teavm-classlib/src/main/java/org/teavm/classlib/java/lang/TCharacter.java @@ -19,7 +19,6 @@ import org.teavm.classlib.impl.charset.UTF16Helper; import org.teavm.classlib.impl.unicode.UnicodeHelper; import org.teavm.dependency.PluggableDependency; import org.teavm.javascript.ni.GeneratedBy; -import org.teavm.javascript.ni.Rename; /** * @@ -118,8 +117,7 @@ public class TCharacter extends TObject implements TComparable { } @Override - @Rename("toString") - public TString toString0() { + public String toString() { return toString(value); } @@ -136,8 +134,8 @@ public class TCharacter extends TObject implements TComparable { return value; } - public static TString toString(char c) { - return new TString(new char[] { c }); + public static String toString(char c) { + return new String(new char[] { c }); } public static boolean isValidCodePoint(int codePoint) { diff --git a/teavm-classlib/src/main/java/org/teavm/classlib/java/lang/TClass.java b/teavm-classlib/src/main/java/org/teavm/classlib/java/lang/TClass.java index 655a9478e..94152045c 100644 --- a/teavm-classlib/src/main/java/org/teavm/classlib/java/lang/TClass.java +++ b/teavm-classlib/src/main/java/org/teavm/classlib/java/lang/TClass.java @@ -42,6 +42,7 @@ public class TClass extends TObject { @InjectedBy(ClassNativeGenerator.class) public native boolean isAssignableFrom(TClass obj); + @PluggableDependency(ClassNativeGenerator.class) public TString getName() { return name; } diff --git a/teavm-classlib/src/main/java/org/teavm/classlib/java/lang/TDouble.java b/teavm-classlib/src/main/java/org/teavm/classlib/java/lang/TDouble.java index c4c31a5a9..eb085acf8 100644 --- a/teavm-classlib/src/main/java/org/teavm/classlib/java/lang/TDouble.java +++ b/teavm-classlib/src/main/java/org/teavm/classlib/java/lang/TDouble.java @@ -17,7 +17,6 @@ package org.teavm.classlib.java.lang; import org.teavm.javascript.ni.GeneratedBy; import org.teavm.javascript.ni.InjectedBy; -import org.teavm.javascript.ni.Rename; /** * @@ -68,8 +67,8 @@ public class TDouble extends TNumber implements TComparable { return new TDouble(d); } - public static TString toString(double d) { - return TString.wrap(new TStringBuilder().append(d).toString()); + public static String toString(double d) { + return new TStringBuilder().append(d).toString(); } public static TDouble valueOf(TString string) { @@ -190,8 +189,7 @@ public class TDouble extends TNumber implements TComparable { } @Override - @Rename("toString") - public TString toString0() { + public String toString() { return toString(value); } diff --git a/teavm-classlib/src/main/java/org/teavm/classlib/java/lang/TEnum.java b/teavm-classlib/src/main/java/org/teavm/classlib/java/lang/TEnum.java index 1f987b5a0..38d8ca2c6 100644 --- a/teavm-classlib/src/main/java/org/teavm/classlib/java/lang/TEnum.java +++ b/teavm-classlib/src/main/java/org/teavm/classlib/java/lang/TEnum.java @@ -40,9 +40,8 @@ public abstract class TEnum> extends TObject implements TComp } @Override - @Rename("toString") - public TString toString0() { - return name; + public String toString() { + return name.toString(); } @Override diff --git a/teavm-classlib/src/main/java/org/teavm/classlib/java/lang/TFloat.java b/teavm-classlib/src/main/java/org/teavm/classlib/java/lang/TFloat.java index 56ab410de..2a6181ca7 100644 --- a/teavm-classlib/src/main/java/org/teavm/classlib/java/lang/TFloat.java +++ b/teavm-classlib/src/main/java/org/teavm/classlib/java/lang/TFloat.java @@ -16,7 +16,6 @@ package org.teavm.classlib.java.lang; import org.teavm.javascript.ni.GeneratedBy; -import org.teavm.javascript.ni.Rename; /** * @@ -71,13 +70,12 @@ public class TFloat extends TNumber implements TComparable { return new TFloat(d); } - public static TString toString(float d) { - return TString.wrap(new TStringBuilder().append(d).toString()); + public static String toString(float d) { + return new TStringBuilder().append(d).toString(); } @Override - @Rename("toString") - public TString toString0() { + public String toString() { return toString(value); } diff --git a/teavm-classlib/src/main/java/org/teavm/classlib/java/lang/TInteger.java b/teavm-classlib/src/main/java/org/teavm/classlib/java/lang/TInteger.java index f3b99a5b6..144f696e2 100644 --- a/teavm-classlib/src/main/java/org/teavm/classlib/java/lang/TInteger.java +++ b/teavm-classlib/src/main/java/org/teavm/classlib/java/lang/TInteger.java @@ -15,8 +15,6 @@ */ package org.teavm.classlib.java.lang; -import org.teavm.javascript.ni.Rename; - /** * * @author Alexey Andreev @@ -37,26 +35,26 @@ public class TInteger extends TNumber implements TComparable { this(parseInt(s)); } - public static TString toString(int i, int radix) { + public static String toString(int i, int radix) { if (radix < MIN_VALUE || radix > MAX_VALUE) { radix = 10; } - return TString.wrap(new TAbstractStringBuilder(20).append(i, radix).toString()); + return new TAbstractStringBuilder(20).append(i, radix).toString(); } - public static TString toHexString(int i) { + public static String toHexString(int i) { return toString(i, 16); } - public static TString toOctalString(int i) { + public static String toOctalString(int i) { return toString(i, 8); } - public static TString toBinaryString(int i) { + public static String toBinaryString(int i) { return toString(i, 2); } - public static TString toString(int i) { + public static String toString(int i) { return toString(i, 10); } @@ -152,8 +150,7 @@ public class TInteger extends TNumber implements TComparable { } @Override - @Rename("toString") - public TString toString0() { + public String toString() { return toString(value); } diff --git a/teavm-classlib/src/main/java/org/teavm/classlib/java/lang/TLong.java b/teavm-classlib/src/main/java/org/teavm/classlib/java/lang/TLong.java index 286514306..c0ed2b3b6 100644 --- a/teavm-classlib/src/main/java/org/teavm/classlib/java/lang/TLong.java +++ b/teavm-classlib/src/main/java/org/teavm/classlib/java/lang/TLong.java @@ -16,7 +16,6 @@ package org.teavm.classlib.java.lang; import org.teavm.javascript.ni.GeneratedBy; -import org.teavm.javascript.ni.Rename; /** * @@ -174,29 +173,28 @@ public class TLong extends TNumber implements TComparable { return value; } - public static TString toString(long i, int radix) { - return TString.wrap(new TStringBuilder().insert(0, i, radix).toString()); + public static String toString(long i, int radix) { + return new TStringBuilder().insert(0, i, radix).toString(); } - public static TString toHexString(long i) { + public static String toHexString(long i) { return toString(i, 16); } - public static TString toOctalString(long i) { + public static String toOctalString(long i) { return toString(i, 8); } - public static TString toBinaryString(long i) { + public static String toBinaryString(long i) { return toString(i, 2); } - public static TString toString(long value) { - return TString.wrap(new TStringBuilder().append(value).toString()); + public static String toString(long value) { + return new TStringBuilder().append(value).toString(); } @Override - @Rename("toString") - public TString toString0() { + public String toString() { return toString(value); } diff --git a/teavm-classlib/src/main/java/org/teavm/classlib/java/lang/TNoClassDefFoundError.java b/teavm-classlib/src/main/java/org/teavm/classlib/java/lang/TNoClassDefFoundError.java new file mode 100644 index 000000000..d429ef140 --- /dev/null +++ b/teavm-classlib/src/main/java/org/teavm/classlib/java/lang/TNoClassDefFoundError.java @@ -0,0 +1,32 @@ +/* + * Copyright 2015 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.java.lang; + +/** + * + * @author Alexey Andreev + */ +public class TNoClassDefFoundError extends TLinkageError { + private static final long serialVersionUID = -7662272618403764942L; + + public TNoClassDefFoundError() { + super(); + } + + public TNoClassDefFoundError(TString message) { + super(message); + } +} diff --git a/teavm-classlib/src/main/java/org/teavm/classlib/java/lang/TNoSuchMethodError.java b/teavm-classlib/src/main/java/org/teavm/classlib/java/lang/TNoSuchMethodError.java new file mode 100644 index 000000000..c620191ca --- /dev/null +++ b/teavm-classlib/src/main/java/org/teavm/classlib/java/lang/TNoSuchMethodError.java @@ -0,0 +1,32 @@ +/* + * Copyright 2014 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.java.lang; + +/** + * + * @author Alexey Andreev + */ +public class TNoSuchMethodError extends TIncompatibleClassChangeError { + private static final long serialVersionUID = 7907885242472547035L; + + public TNoSuchMethodError() { + super(); + } + + public TNoSuchMethodError(TString message) { + super(message); + } +} diff --git a/teavm-classlib/src/main/java/org/teavm/classlib/java/lang/TObject.java b/teavm-classlib/src/main/java/org/teavm/classlib/java/lang/TObject.java index a74052040..6759d3cc7 100644 --- a/teavm-classlib/src/main/java/org/teavm/classlib/java/lang/TObject.java +++ b/teavm-classlib/src/main/java/org/teavm/classlib/java/lang/TObject.java @@ -49,9 +49,9 @@ public class TObject { return this == other; } - @Rename("toString") - public TString toString0() { - return TString.wrap(getClass().getName() + "@" + TInteger.toHexString(identity())); + @Override + public String toString() { + return getClass().getName() + "@" + TInteger.toHexString(identity()); } @GeneratedBy(ObjectNativeGenerator.class) diff --git a/teavm-classlib/src/main/java/org/teavm/classlib/java/lang/TShort.java b/teavm-classlib/src/main/java/org/teavm/classlib/java/lang/TShort.java index 6f8040860..7920995e1 100644 --- a/teavm-classlib/src/main/java/org/teavm/classlib/java/lang/TShort.java +++ b/teavm-classlib/src/main/java/org/teavm/classlib/java/lang/TShort.java @@ -15,8 +15,6 @@ */ package org.teavm.classlib.java.lang; -import org.teavm.javascript.ni.Rename; - /** * * @author Alexey Andreev @@ -65,13 +63,12 @@ public class TShort extends TNumber implements TComparable { return new TShort(value); } - public static TString toString(short value) { - return TString.wrap(new StringBuilder().append(value).toString()); + public static String toString(short value) { + return new StringBuilder().append(value).toString(); } @Override - @Rename("toString") - public TString toString0() { + public String toString() { return toString(value); } 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 a11ed0585..9d309e31e 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 @@ -25,7 +25,6 @@ import org.teavm.classlib.java.util.TMap; import org.teavm.classlib.java.util.regex.TPattern; import org.teavm.dependency.PluggableDependency; import org.teavm.javascript.ni.InjectedBy; -import org.teavm.javascript.ni.Rename; /** * @@ -458,9 +457,8 @@ public class TString extends TObject implements TSerializable, TComparable */ public class TLevel extends TObject implements TSerializable { - public static final TLevel OFF = new TLevel(TString.wrap("OFF"), TInteger.MAX_VALUE); - public static final TLevel SEVERE = new TLevel(TString.wrap("SEVERE"), 1000); - public static final TLevel WARNING = new TLevel(TString.wrap("WARNING"), 900); - public static final TLevel INFO = new TLevel(TString.wrap("INFO"), 800); - public static final TLevel CONFIG = new TLevel(TString.wrap("CONFIG"), 700); - public static final TLevel FINE = new TLevel(TString.wrap("FINE"), 500); - public static final TLevel FINER = new TLevel(TString.wrap("FINER"), 400); - public static final TLevel FINEST = new TLevel(TString.wrap("FINEST"), 300); - public static final TLevel ALL = new TLevel(TString.wrap("FINEST"), TInteger.MIN_VALUE); - private TString name; + public static final TLevel OFF = new TLevel("OFF", TInteger.MAX_VALUE); + public static final TLevel SEVERE = new TLevel("SEVERE", 1000); + public static final TLevel WARNING = new TLevel("WARNING", 900); + public static final TLevel INFO = new TLevel("INFO", 800); + public static final TLevel CONFIG = new TLevel("CONFIG", 700); + public static final TLevel FINE = new TLevel("FINE", 500); + public static final TLevel FINER = new TLevel("FINER", 400); + public static final TLevel FINEST = new TLevel("FINEST", 300); + public static final TLevel ALL = new TLevel("ALL", TInteger.MIN_VALUE); + private String name; private int value; - protected TLevel(TString name, int value) { + protected TLevel(String name, int value) { this.name = name; this.value = value; } - public TString getName() { + public String getName() { return name; } @Override - @Rename("toString") - public final TString toString0() { + public final String toString() { return name; } diff --git a/teavm-core/src/main/java/org/teavm/diagnostics/DefaultProblemTextConsumer.java b/teavm-core/src/main/java/org/teavm/diagnostics/DefaultProblemTextConsumer.java index 8db0bf46d..b1b45ca41 100644 --- a/teavm-core/src/main/java/org/teavm/diagnostics/DefaultProblemTextConsumer.java +++ b/teavm-core/src/main/java/org/teavm/diagnostics/DefaultProblemTextConsumer.java @@ -24,7 +24,7 @@ import org.teavm.model.MethodReference; * @author Alexey Andreev */ public class DefaultProblemTextConsumer implements ProblemTextConsumer { - private StringBuilder sb; + private StringBuilder sb = new StringBuilder(); public void clear() { sb.setLength(0); diff --git a/teavm-core/src/main/java/org/teavm/diagnostics/Problem.java b/teavm-core/src/main/java/org/teavm/diagnostics/Problem.java index 06a033648..7204922a3 100644 --- a/teavm-core/src/main/java/org/teavm/diagnostics/Problem.java +++ b/teavm-core/src/main/java/org/teavm/diagnostics/Problem.java @@ -62,7 +62,11 @@ public class Problem { break; } consumer.append(text.substring(index, next)); - next = parseParameter(consumer, next); + index = parseParameter(consumer, next); + if (index == next) { + consumer.append("{{"); + index += 2; + } } consumer.append(text.substring(index)); } @@ -89,7 +93,7 @@ public class Problem { default: return index; } - int digitsEnd = passDigits(index); + int digitsEnd = passDigits(next); if (digitsEnd == next) { return index; } diff --git a/teavm-core/src/main/java/org/teavm/javascript/ni/Rename.java b/teavm-core/src/main/java/org/teavm/javascript/ni/Rename.java index 7a3726873..054c10336 100644 --- a/teavm-core/src/main/java/org/teavm/javascript/ni/Rename.java +++ b/teavm-core/src/main/java/org/teavm/javascript/ni/Rename.java @@ -15,10 +15,7 @@ */ package org.teavm.javascript.ni; -import java.lang.annotation.ElementType; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; +import java.lang.annotation.*; /** * diff --git a/teavm-core/src/main/java/org/teavm/model/BasicBlock.java b/teavm-core/src/main/java/org/teavm/model/BasicBlock.java index 2f5dd5e1e..737f7963c 100644 --- a/teavm-core/src/main/java/org/teavm/model/BasicBlock.java +++ b/teavm-core/src/main/java/org/teavm/model/BasicBlock.java @@ -190,6 +190,17 @@ public class BasicBlock implements BasicBlockReader { } } + public void removeIncomingsFrom(BasicBlock predecessor) { + for (Phi phi : getPhis()) { + List incomings = phi.getIncomings(); + for (int i = 0; i < incomings.size(); ++i) { + if (incomings.get(i).getSource() == predecessor) { + incomings.remove(i--); + } + } + } + } + private List immutableTryCatchBlocks = Collections.unmodifiableList(tryCatchBlocks); @Override diff --git a/teavm-core/src/main/java/org/teavm/model/util/MissingItemsProcessor.java b/teavm-core/src/main/java/org/teavm/model/util/MissingItemsProcessor.java new file mode 100644 index 000000000..9c705b390 --- /dev/null +++ b/teavm-core/src/main/java/org/teavm/model/util/MissingItemsProcessor.java @@ -0,0 +1,302 @@ +/* + * Copyright 2015 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.model.util; + +import java.util.ArrayList; +import java.util.List; +import org.teavm.dependency.DependencyInfo; +import org.teavm.diagnostics.Diagnostics; +import org.teavm.model.*; +import org.teavm.model.instructions.*; + +/** + * + * @author Alexey Andreev + */ +public class MissingItemsProcessor { + private DependencyInfo dependencyInfo; + private Diagnostics diagnostics; + private List instructionsToAdd = new ArrayList<>(); + private MethodHolder methodHolder; + private Program program; + + public MissingItemsProcessor(DependencyInfo dependencyInfo, Diagnostics diagnostics) { + this.dependencyInfo = dependencyInfo; + this.diagnostics = diagnostics; + } + + public void processClass(ClassHolder cls) { + for (MethodHolder method : cls.getMethods()) { + if (dependencyInfo.getAchievableMethods().contains(method.getReference()) && method.getProgram() != null) { + processMethod(method); + } + } + } + + public void processMethod(MethodHolder method) { + this.methodHolder = method; + this.program = method.getProgram(); + for (int i = 0; i < program.basicBlockCount(); ++i) { + BasicBlock block = program.basicBlockAt(i); + instructionsToAdd.clear(); + for (int j = 0; j < block.getInstructions().size(); ++j) { + Instruction insn = block.getInstructions().get(j); + insn.acceptVisitor(instructionProcessor); + if (!instructionsToAdd.isEmpty()) { + truncateBlock(block, j); + break; + } + } + } + } + + private void truncateBlock(BasicBlock block, int index) { + InstructionTransitionExtractor transitionExtractor = new InstructionTransitionExtractor(); + if (block.getLastInstruction() != null) { + block.getLastInstruction().acceptVisitor(transitionExtractor); + } + for (BasicBlock successor : transitionExtractor.getTargets()) { + successor.removeIncomingsFrom(block); + } + block.getInstructions().subList(index, block.getInstructions().size()).clear(); + block.getInstructions().addAll(instructionsToAdd); + } + + private void emitExceptionThrow(InstructionLocation location, String exceptionName, String text) { + Variable exceptionVar = program.createVariable(); + ConstructInstruction newExceptionInsn = new ConstructInstruction(); + newExceptionInsn.setType(exceptionName); + newExceptionInsn.setReceiver(exceptionVar); + newExceptionInsn.setLocation(location); + instructionsToAdd.add(newExceptionInsn); + + Variable constVar = program.createVariable(); + StringConstantInstruction constInsn = new StringConstantInstruction(); + constInsn.setConstant(text); + constInsn.setReceiver(constVar); + constInsn.setLocation(location); + instructionsToAdd.add(constInsn); + + InvokeInstruction initExceptionInsn = new InvokeInstruction(); + initExceptionInsn.setInstance(exceptionVar); + initExceptionInsn.setMethod(new MethodReference(exceptionName, "", ValueType.object("java.lang.String"), + ValueType.VOID)); + initExceptionInsn.setType(InvocationType.SPECIAL); + initExceptionInsn.getArguments().add(constVar); + initExceptionInsn.setLocation(location); + instructionsToAdd.add(initExceptionInsn); + + RaiseInstruction raiseInsn = new RaiseInstruction(); + raiseInsn.setException(exceptionVar); + raiseInsn.setLocation(location); + instructionsToAdd.add(raiseInsn); + } + + private boolean checkClass(InstructionLocation location, String className) { + if (!dependencyInfo.getAchievableClasses().contains(className) || + !dependencyInfo.getClass(className).isMissing()) { + return true; + } + diagnostics.error(new CallLocation(methodHolder.getReference(), location), "Class {{c0}} was not found", + className); + emitExceptionThrow(location, NoClassDefFoundError.class.getName(), "Class not found: " + className); + return false; + } + + private boolean checkClass(InstructionLocation location, ValueType type) { + while (type instanceof ValueType.Array) { + type = ((ValueType.Array)type).getItemType(); + } + if (type instanceof ValueType.Object) { + return checkClass(location, ((ValueType.Object)type).getClassName()); + } + return true; + } + + private boolean checkMethod(InstructionLocation location, MethodReference method) { + if (!checkClass(location, method.getClassName())) { + return false; + } + if (!dependencyInfo.getAchievableMethods().contains(method) || !dependencyInfo.getMethod(method).isMissing()) { + return true; + } + diagnostics.error(new CallLocation(methodHolder.getReference(), location), "Method {{m0}} was not found", + method); + emitExceptionThrow(location, NoSuchMethodError.class.getName(), "Method not found: " + method); + return true; + } + + private boolean checkField(InstructionLocation location, FieldReference field) { + if (!checkClass(location, field.getClassName())) { + return false; + } + if (!dependencyInfo.getAchievableFields().contains(field) || !dependencyInfo.getField(field).isMissing()) { + return true; + } + diagnostics.error(new CallLocation(methodHolder.getReference(), location), "Field {{f0}} was not found", + field); + emitExceptionThrow(location, NoSuchFieldError.class.getName(), "Field not found: " + field); + return true; + } + + private InstructionVisitor instructionProcessor = new InstructionVisitor() { + @Override + public void visit(NullCheckInstruction insn) { + } + + @Override + public void visit(InitClassInstruction insn) { + checkClass(insn.getLocation(), insn.getClassName()); + } + + @Override + public void visit(IsInstanceInstruction insn) { + checkClass(insn.getLocation(), insn.getType()); + } + + @Override + public void visit(InvokeInstruction insn) { + checkMethod(insn.getLocation(), insn.getMethod()); + } + + @Override + public void visit(PutElementInstruction insn) { + } + + @Override + public void visit(GetElementInstruction insn) { + } + + @Override + public void visit(UnwrapArrayInstruction insn) { + } + + @Override + public void visit(CloneArrayInstruction insn) { + } + + @Override + public void visit(ArrayLengthInstruction insn) { + } + + @Override + public void visit(PutFieldInstruction insn) { + checkField(insn.getLocation(), insn.getField()); + } + + @Override + public void visit(GetFieldInstruction insn) { + checkField(insn.getLocation(), insn.getField()); + } + + @Override + public void visit(ConstructMultiArrayInstruction insn) { + checkClass(insn.getLocation(), insn.getItemType()); + } + + @Override + public void visit(ConstructInstruction insn) { + checkClass(insn.getLocation(), insn.getType()); + } + + @Override + public void visit(ConstructArrayInstruction insn) { + checkClass(insn.getLocation(), insn.getItemType()); + } + + @Override + public void visit(RaiseInstruction insn) { + } + + @Override + public void visit(ExitInstruction insn) { + } + + @Override + public void visit(SwitchInstruction insn) { + } + + @Override + public void visit(JumpInstruction insn) { + } + + @Override + public void visit(BinaryBranchingInstruction insn) { + } + + @Override + public void visit(BranchingInstruction insn) { + } + + @Override + public void visit(CastIntegerInstruction insn) { + } + + @Override + public void visit(CastNumberInstruction insn) { + } + + @Override + public void visit(CastInstruction insn) { + checkClass(insn.getLocation(), insn.getTargetType()); + } + + @Override + public void visit(AssignInstruction insn) { + } + + @Override + public void visit(NegateInstruction insn) { + } + + @Override + public void visit(BinaryInstruction insn) { + } + + @Override + public void visit(StringConstantInstruction insn) { + } + + @Override + public void visit(DoubleConstantInstruction insn) { + } + + @Override + public void visit(FloatConstantInstruction insn) { + } + + @Override + public void visit(LongConstantInstruction insn) { + } + + @Override + public void visit(IntegerConstantInstruction insn) { + } + + @Override + public void visit(NullConstantInstruction insn) { + } + + @Override + public void visit(ClassConstantInstruction insn) { + checkClass(insn.getLocation(), insn.getConstant()); + } + + @Override + public void visit(EmptyInstruction insn) { + } + }; +} diff --git a/teavm-core/src/main/java/org/teavm/tooling/TeaVMProblemRenderer.java b/teavm-core/src/main/java/org/teavm/tooling/TeaVMProblemRenderer.java new file mode 100644 index 000000000..246edb15b --- /dev/null +++ b/teavm-core/src/main/java/org/teavm/tooling/TeaVMProblemRenderer.java @@ -0,0 +1,97 @@ +/* + * Copyright 2015 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.tooling; + +import java.util.Iterator; +import org.teavm.callgraph.CallGraph; +import org.teavm.callgraph.CallGraphNode; +import org.teavm.callgraph.CallSite; +import org.teavm.diagnostics.DefaultProblemTextConsumer; +import org.teavm.diagnostics.Problem; +import org.teavm.model.CallLocation; +import org.teavm.model.InstructionLocation; +import org.teavm.model.MethodReference; +import org.teavm.vm.TeaVM; + +/** + * + * @author Alexey Andreev + */ +public final class TeaVMProblemRenderer { + private TeaVMProblemRenderer() { + } + + public static void describeProblems(TeaVM vm, TeaVMToolLog log) { + CallGraph cg = vm.getDependencyInfo().getCallGraph(); + DefaultProblemTextConsumer consumer = new DefaultProblemTextConsumer(); + for (Problem problem : vm.getProblemProvider().getProblems()) { + consumer.clear(); + problem.render(consumer); + StringBuilder sb = new StringBuilder(); + sb.append(consumer.getText()); + renderCallStack(cg, problem.getLocation(), sb); + String problemText = sb.toString(); + switch (problem.getSeverity()) { + case ERROR: + log.error(problemText); + break; + case WARNING: + log.warning(problemText); + break; + } + } + } + + private static void renderCallStack(CallGraph cg, CallLocation location, StringBuilder sb) { + if (location == null) { + return; + } + sb.append("\n at "); + renderCallLocation(location.getMethod(), location.getSourceLocation(), sb); + if (location.getMethod() != null) { + CallGraphNode node = cg.getNode(location.getMethod()); + while (true) { + Iterator callSites = node.getCallerCallSites().iterator(); + if (!callSites.hasNext()) { + break; + } + CallSite callSite = callSites.next(); + sb.append("\n at "); + renderCallLocation(callSite.getCaller().getMethod(), callSite.getLocation(), sb); + node = callSite.getCaller(); + } + } + } + + private static void renderCallLocation(MethodReference method, InstructionLocation location, StringBuilder sb) { + if (method != null) { + sb.append(method); + } else { + sb.append("unknown method"); + } + sb.append(' '); + if (location != null) { + sb.append("("); + String fileName = location.getFileName(); + if (fileName != null) { + sb.append(fileName.substring(fileName.lastIndexOf('/') + 1)); + sb.append(':'); + } + sb.append(location.getLine()); + sb.append(')'); + } + } +} diff --git a/teavm-core/src/main/java/org/teavm/tooling/TeaVMTestTool.java b/teavm-core/src/main/java/org/teavm/tooling/TeaVMTestTool.java index 47545e2a5..cc7867722 100644 --- a/teavm-core/src/main/java/org/teavm/tooling/TeaVMTestTool.java +++ b/teavm-core/src/main/java/org/teavm/tooling/TeaVMTestTool.java @@ -372,6 +372,15 @@ public class TeaVMTestTool { String sourceMapsFileName = targetName.substring(targetName.lastIndexOf('/') + 1) + ".map"; innerWriter.append("\n//# sourceMappingURL=").append(sourceMapsFileName); } + if (!vm.getProblemProvider().getProblems().isEmpty()) { + if (vm.getProblemProvider().getSevereProblems().isEmpty()) { + log.warning("Test built with warnings: " + methodRef); + TeaVMProblemRenderer.describeProblems(vm, log); + } else { + log.warning("Test built with errors: " + methodRef); + TeaVMProblemRenderer.describeProblems(vm, log); + } + } } if (sourceMapsGenerated) { DebugInformation debugInfo = debugInfoBuilder.getDebugInformation(); diff --git a/teavm-core/src/main/java/org/teavm/tooling/TeaVMTool.java b/teavm-core/src/main/java/org/teavm/tooling/TeaVMTool.java index 5ad2eba26..ba71cd4ba 100644 --- a/teavm-core/src/main/java/org/teavm/tooling/TeaVMTool.java +++ b/teavm-core/src/main/java/org/teavm/tooling/TeaVMTool.java @@ -22,13 +22,8 @@ import org.teavm.cache.DiskCachedClassHolderSource; import org.teavm.cache.DiskProgramCache; import org.teavm.cache.DiskRegularMethodNodeCache; import org.teavm.cache.FileSymbolTable; -import org.teavm.callgraph.CallGraph; -import org.teavm.callgraph.CallGraphNode; -import org.teavm.callgraph.CallSite; import org.teavm.debugging.information.DebugInformation; import org.teavm.debugging.information.DebugInformationBuilder; -import org.teavm.diagnostics.DefaultProblemTextConsumer; -import org.teavm.diagnostics.Problem; import org.teavm.diagnostics.ProblemProvider; import org.teavm.javascript.RenderingContext; import org.teavm.model.*; @@ -304,10 +299,10 @@ public class TeaVMTool { log.info("JavaScript file successfully built"); } else if (problemProvider.getSevereProblems().isEmpty()) { log.info("JavaScript file built with warnings"); - describeProblems(vm); + TeaVMProblemRenderer.describeProblems(vm, log); } else { log.info("JavaScript file built with errors"); - describeProblems(vm); + TeaVMProblemRenderer.describeProblems(vm, log); } if (debugInformationGenerated) { DebugInformation debugInfo = debugEmitter.getDebugInformation(); @@ -359,67 +354,6 @@ public class TeaVMTool { } } - private void describeProblems(TeaVM vm) { - CallGraph cg = vm.getDependencyInfo().getCallGraph(); - DefaultProblemTextConsumer consumer = new DefaultProblemTextConsumer(); - for (Problem problem : vm.getProblemProvider().getProblems()) { - consumer.clear(); - problem.render(consumer); - StringBuilder sb = new StringBuilder(); - sb.append(consumer.getText()); - renderCallStack(cg, problem.getLocation(), sb); - String problemText = sb.toString(); - switch (problem.getSeverity()) { - case ERROR: - log.error(problemText); - break; - case WARNING: - log.warning(problemText); - break; - } - } - } - - private void renderCallStack(CallGraph cg, CallLocation location, StringBuilder sb) { - if (location == null) { - return; - } - sb.append("\n at "); - renderCallLocation(location.getMethod(), location.getSourceLocation(), sb); - if (location.getMethod() != null) { - CallGraphNode node = cg.getNode(location.getMethod()); - while (true) { - Iterator callSites = node.getCallerCallSites().iterator(); - if (!callSites.hasNext()) { - break; - } - CallSite callSite = callSites.next(); - sb.append("\n at "); - renderCallLocation(node.getMethod(), callSite.getLocation(), sb); - node = callSite.getCaller(); - } - } - } - - private void renderCallLocation(MethodReference method, InstructionLocation location, StringBuilder sb) { - if (method != null) { - sb.append(method); - } else { - sb.append("unknown method"); - } - sb.append(' '); - if (location != null) { - sb.append("("); - String fileName = location.getFileName(); - if (fileName != null) { - sb.append(fileName.substring(fileName.lastIndexOf('/') + 1)); - sb.append(':'); - } - sb.append(location.getLine()); - sb.append(')'); - } - } - private void copySourceFiles() { if (vm.getWrittenClasses() == null) { return; diff --git a/teavm-core/src/main/java/org/teavm/vm/TeaVM.java b/teavm-core/src/main/java/org/teavm/vm/TeaVM.java index d110ee2fc..8e24aaf6a 100644 --- a/teavm-core/src/main/java/org/teavm/vm/TeaVM.java +++ b/teavm-core/src/main/java/org/teavm/vm/TeaVM.java @@ -29,10 +29,7 @@ import org.teavm.javascript.ast.ClassNode; import org.teavm.javascript.ni.Generator; import org.teavm.javascript.ni.Injector; import org.teavm.model.*; -import org.teavm.model.util.ListingBuilder; -import org.teavm.model.util.ModelUtils; -import org.teavm.model.util.ProgramUtils; -import org.teavm.model.util.RegisterAllocator; +import org.teavm.model.util.*; import org.teavm.optimization.*; import org.teavm.vm.spi.RendererListener; import org.teavm.vm.spi.TeaVMHost; @@ -344,6 +341,21 @@ public class TeaVM implements TeaVMHost, ServiceRepository { internDep.use(); dependencyChecker.linkMethod(new MethodReference(String.class, "length", int.class), null).use(); dependencyChecker.linkMethod(new MethodReference(Object.class, "clone", Object.class), null).use(); + MethodDependency exceptionCons = dependencyChecker.linkMethod(new MethodReference( + NoClassDefFoundError.class, "", String.class, void.class), null); + exceptionCons.use(); + exceptionCons.getVariable(0).propagate(dependencyChecker.getType(NoClassDefFoundError.class.getName())); + exceptionCons.getVariable(1).propagate(dependencyChecker.getType("java.lang.String")); + exceptionCons = dependencyChecker.linkMethod(new MethodReference(NoSuchFieldError.class, "", + String.class, void.class), null); + exceptionCons.use(); + exceptionCons.getVariable(0).propagate(dependencyChecker.getType(NoSuchFieldError.class.getName())); + exceptionCons.getVariable(1).propagate(dependencyChecker.getType("java.lang.String")); + exceptionCons = dependencyChecker.linkMethod(new MethodReference(NoSuchMethodError.class, "", + String.class, void.class), null); + exceptionCons.use(); + exceptionCons.getVariable(0).propagate(dependencyChecker.getType(NoSuchMethodError.class.getName())); + exceptionCons.getVariable(1).propagate(dependencyChecker.getType("java.lang.String")); dependencyChecker.processDependencies(); if (wasCancelled() || !diagnostics.getSevereProblems().isEmpty()) { return; @@ -438,6 +450,7 @@ public class TeaVM implements TeaVMHost, ServiceRepository { reportPhase(TeaVMPhase.LINKING, dependency.getAchievableClasses().size()); Linker linker = new Linker(); MutableClassHolderSource cutClasses = new MutableClassHolderSource(); + MissingItemsProcessor missingItemsProcessor = new MissingItemsProcessor(dependency, diagnostics); if (wasCancelled()) { return cutClasses; } @@ -445,6 +458,7 @@ public class TeaVM implements TeaVMHost, ServiceRepository { for (String className : dependency.getAchievableClasses()) { ClassHolder cls = ModelUtils.copyClass(dependency.getClassSource().get(className)); cutClasses.putClassHolder(cls); + missingItemsProcessor.processClass(cls); linker.link(dependency, cls); progressListener.progressReached(++index); } diff --git a/teavm-maven/teavm-maven-plugin/src/main/java/org/teavm/maven/BuildJavascriptMojo.java b/teavm-maven/teavm-maven-plugin/src/main/java/org/teavm/maven/BuildJavascriptMojo.java index f60c77f63..720ea0686 100644 --- a/teavm-maven/teavm-maven-plugin/src/main/java/org/teavm/maven/BuildJavascriptMojo.java +++ b/teavm-maven/teavm-maven-plugin/src/main/java/org/teavm/maven/BuildJavascriptMojo.java @@ -112,6 +112,9 @@ public class BuildJavascriptMojo extends AbstractMojo { @Parameter private MethodAlias[] methodAliases; + @Parameter + private boolean stopOnErrors = true; + private TeaVMTool tool = new TeaVMTool(); public void setProject(MavenProject project) { @@ -198,6 +201,10 @@ public class BuildJavascriptMojo extends AbstractMojo { this.incremental = incremental; } + public void setStopOnErrors(boolean stopOnErrors) { + this.stopOnErrors = stopOnErrors; + } + public File getCacheDirectory() { return cacheDirectory; } @@ -247,7 +254,7 @@ public class BuildJavascriptMojo extends AbstractMojo { tool.setSourceMapsFileGenerated(sourceMapsGenerated); tool.setSourceFilesCopied(sourceFilesCopied); tool.generate(); - if (!tool.getProblemProvider().getSevereProblems().isEmpty()) { + if (stopOnErrors && !tool.getProblemProvider().getSevereProblems().isEmpty()) { throw new MojoExecutionException("Build error"); } } catch (RuntimeException e) {