diff --git a/teavm-classlib/src/main/java/org/teavm/classlib/java/util/TArrays.java b/teavm-classlib/src/main/java/org/teavm/classlib/java/util/TArrays.java index 410ccfa31..e91ee74c6 100644 --- a/teavm-classlib/src/main/java/org/teavm/classlib/java/util/TArrays.java +++ b/teavm-classlib/src/main/java/org/teavm/classlib/java/util/TArrays.java @@ -1514,7 +1514,7 @@ public class TArrays extends TObject { deepToString(a[0], out, visited); for (int i = 1; i < a.length; ++i) { out.append(TString.wrap(", ")); - deepToString(a[0], out, visited); + deepToString(a[i], out, visited); } } visited.remove(visited.size() - 1); diff --git a/teavm-core/src/main/java/org/teavm/optimization/Devirtualization.java b/teavm-core/src/main/java/org/teavm/optimization/Devirtualization.java index 4bec24cfa..f031a9650 100644 --- a/teavm-core/src/main/java/org/teavm/optimization/Devirtualization.java +++ b/teavm-core/src/main/java/org/teavm/optimization/Devirtualization.java @@ -67,9 +67,12 @@ public class Devirtualization { private Set getImplementations(String[] classNames, MethodReference ref) { Set methods = new HashSet<>(); for (String className : classNames) { + if (className.startsWith("[")) { + className = "java.lang.Object"; + } ClassReader cls = classSource.get(className); if (cls == null || !isAssignable(ref.getClassName(), cls)) { - break; + continue; } MethodDependencyInfo methodDep = dependency.getMethod(new MethodReference(className, ref.getDescriptor())); if (methodDep != null) { diff --git a/teavm-maven-plugin/src/main/java/org/teavm/maven/BuildJavascriptTestMojo.java b/teavm-maven-plugin/src/main/java/org/teavm/maven/BuildJavascriptTestMojo.java index 78206cc91..083deb0b6 100644 --- a/teavm-maven-plugin/src/main/java/org/teavm/maven/BuildJavascriptTestMojo.java +++ b/teavm-maven-plugin/src/main/java/org/teavm/maven/BuildJavascriptTestMojo.java @@ -318,6 +318,7 @@ public class BuildJavascriptTestMojo extends AbstractMojo { .build(); vm.setMinifying(minifying); vm.installPlugins(); + new TestExceptionPlugin().install(vm); for (ClassHolderTransformer transformer : transformerInstances) { vm.add(transformer); } @@ -326,8 +327,11 @@ public class BuildJavascriptTestMojo extends AbstractMojo { try (Writer innerWriter = new OutputStreamWriter(new FileOutputStream(file), "UTF-8")) { MethodReference cons = new MethodReference(methodRef.getClassName(), new MethodDescriptor("", ValueType.VOID)); + MethodReference exceptionMsg = new MethodReference("java.lang.Throwable", "getMessage", + ValueType.object("java.lang.String")); vm.entryPoint("initInstance", cons); vm.entryPoint("runTest", methodRef).withValue(0, cons.getClassName()); + vm.entryPoint("extractException", exceptionMsg); vm.exportType("TestClass", cons.getClassName()); vm.build(innerWriter, new DirectoryBuildTarget(outputDir)); if (!vm.hasMissingItems()) { diff --git a/teavm-maven-plugin/src/main/java/org/teavm/maven/TestExceptionDependency.java b/teavm-maven-plugin/src/main/java/org/teavm/maven/TestExceptionDependency.java new file mode 100644 index 000000000..46a60158d --- /dev/null +++ b/teavm-maven-plugin/src/main/java/org/teavm/maven/TestExceptionDependency.java @@ -0,0 +1,69 @@ +/* + * 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.maven; + +import org.teavm.dependency.*; +import org.teavm.model.ClassReader; +import org.teavm.model.ClassReaderSource; +import org.teavm.model.MethodReference; +import org.teavm.model.ValueType; + +/** + * + * @author Alexey Andreev + */ +class TestExceptionDependency implements DependencyListener { + private MethodReference getMessageRef = new MethodReference("java.lang.Throwable", "getMessage", + ValueType.object("java.lang.String")); + private DependencyNode allClasses; + + @Override + public void started(DependencyChecker dependencyChecker) { + allClasses = dependencyChecker.createNode(); + } + + @Override + public void classAchieved(DependencyChecker dependencyChecker, String className) { + if (isException(dependencyChecker.getClassSource(), className)) { + allClasses.propagate(className); + } + } + + private boolean isException(ClassReaderSource classSource, String className) { + while (className != null) { + if (className.equals("java.lang.Throwable")) { + return true; + } + ClassReader cls = classSource.get(className); + if (cls == null) { + return false; + } + className = cls.getParent(); + } + return false; + } + + @Override + public void methodAchieved(DependencyChecker dependencyChecker, MethodDependency method) { + if (method.getReference().equals(getMessageRef)) { + allClasses.connect(method.getVariable(0)); + } + } + + @Override + public void fieldAchieved(DependencyChecker dependencyChecker, FieldDependency field) { + } +} diff --git a/teavm-maven-plugin/src/main/java/org/teavm/maven/TestExceptionPlugin.java b/teavm-maven-plugin/src/main/java/org/teavm/maven/TestExceptionPlugin.java new file mode 100644 index 000000000..1edf66116 --- /dev/null +++ b/teavm-maven-plugin/src/main/java/org/teavm/maven/TestExceptionPlugin.java @@ -0,0 +1,30 @@ +/* + * 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.maven; + +import org.teavm.vm.spi.TeaVMHost; +import org.teavm.vm.spi.TeaVMPlugin; + +/** + * + * @author Alexey Andreev + */ +public class TestExceptionPlugin implements TeaVMPlugin { + @Override + public void install(TeaVMHost host) { + host.add(new TestExceptionDependency()); + } +} diff --git a/teavm-maven-plugin/src/main/resources/org/teavm/maven/junit-support.js b/teavm-maven-plugin/src/main/resources/org/teavm/maven/junit-support.js index 7baf47358..7be876edb 100644 --- a/teavm-maven-plugin/src/main/resources/org/teavm/maven/junit-support.js +++ b/teavm-maven-plugin/src/main/resources/org/teavm/maven/junit-support.js @@ -221,8 +221,13 @@ JUnitClient.run = function() { message.status = "exception"; 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" + e.stack; + } else { + message.stack = e.stack; } - message.stack = e.stack; } window.parent.postMessage(JSON.stringify(message), "*"); });