diff --git a/teavm-classlib/src/main/java/org/teavm/classlibgen/ClasslibTestGenerator.java b/teavm-classlib/src/main/java/org/teavm/classlibgen/ClasslibTestGenerator.java index 228b81642..290ec68ff 100644 --- a/teavm-classlib/src/main/java/org/teavm/classlibgen/ClasslibTestGenerator.java +++ b/teavm-classlib/src/main/java/org/teavm/classlibgen/ClasslibTestGenerator.java @@ -2,10 +2,7 @@ package org.teavm.classlibgen; import java.io.IOException; import java.io.InputStream; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; +import java.util.*; import org.apache.commons.io.IOUtils; import org.teavm.codegen.DefaultAliasProvider; import org.teavm.codegen.DefaultNamingStrategy; @@ -51,9 +48,7 @@ public class ClasslibTestGenerator { } dependencyChecker.checkDependencies(); dependencyChecker.cutUnachievableClasses(); - for (String className : dependencyChecker.getAchievableClasses()) { - decompileClass(className); - } + decompileClasses(dependencyChecker.getAchievableClasses()); renderHead(); ClassLoader classLoader = ClasslibTestGenerator.class.getClassLoader(); try (InputStream input = classLoader.getResourceAsStream("org/teavm/classlib/junit-support.js")) { @@ -69,10 +64,11 @@ public class ClasslibTestGenerator { renderFoot(); } - private static void decompileClass(String className) { - ClassHolder cls = classSource.getClassHolder(className); - ClassNode clsNode = decompiler.decompile(cls); - renderer.render(clsNode); + private static void decompileClasses(Collection classNames) { + List clsNodes = decompiler.decompile(classNames); + for (ClassNode clsNode : clsNodes) { + renderer.render(clsNode); + } } private static void renderHead() { diff --git a/teavm-core/src/main/java/org/teavm/codegen/ConcurrentCachedMapper.java b/teavm-core/src/main/java/org/teavm/codegen/ConcurrentCachedMapper.java index 10f6e2dec..0d70cc45a 100644 --- a/teavm-core/src/main/java/org/teavm/codegen/ConcurrentCachedMapper.java +++ b/teavm-core/src/main/java/org/teavm/codegen/ConcurrentCachedMapper.java @@ -41,6 +41,7 @@ public class ConcurrentCachedMapper implements Mapper { } } else { CountDownLatch latch = oldWrapper.latch; + wrapper = oldWrapper; try { latch.await(); } catch (InterruptedException e) { diff --git a/teavm-core/src/main/java/org/teavm/dependency/DependencyChecker.java b/teavm-core/src/main/java/org/teavm/dependency/DependencyChecker.java index e767d6fca..a8f6c0db5 100644 --- a/teavm-core/src/main/java/org/teavm/dependency/DependencyChecker.java +++ b/teavm-core/src/main/java/org/teavm/dependency/DependencyChecker.java @@ -18,6 +18,7 @@ package org.teavm.dependency; import java.util.Collection; import java.util.HashSet; import java.util.concurrent.*; +import java.util.concurrent.atomic.AtomicReference; import org.teavm.codegen.ConcurrentCachedMapper; import org.teavm.codegen.ConcurrentCachedMapper.KeyListener; import org.teavm.codegen.Mapper; @@ -36,7 +37,7 @@ public class DependencyChecker { private ConcurrentCachedMapper fieldCache; private ConcurrentMap achievableClasses = new ConcurrentHashMap<>(); private ConcurrentMap initializedClasses = new ConcurrentHashMap<>(); - private volatile RuntimeException exceptionOccured; + private AtomicReference exceptionOccured = new AtomicReference<>(); public DependencyChecker(ClassHolderSource classSource) { this(classSource, Runtime.getRuntime().availableProcessors()); @@ -99,21 +100,24 @@ public class DependencyChecker { } void schedule(final Runnable runnable) { - executor.execute(new Runnable() { - @Override - public void run() { - try { - runnable.run(); - } catch (RuntimeException e) { - exceptionOccured = e; - executor.shutdownNow(); + try { + executor.execute(new Runnable() { + @Override public void run() { + try { + runnable.run(); + } catch (RuntimeException e) { + exceptionOccured.compareAndSet(null, e); + executor.shutdownNow(); + } } - } - }); + }); + } catch (RejectedExecutionException e) { + throw exceptionOccured.get(); + } } public void checkDependencies() { - exceptionOccured = null; + exceptionOccured.set(null); while (true) { try { if (executor.getActiveCount() == 0 || executor.awaitTermination(1, TimeUnit.SECONDS)) { @@ -124,8 +128,9 @@ public class DependencyChecker { break; } } - if (exceptionOccured != null) { - throw exceptionOccured; + RuntimeException e = exceptionOccured.get(); + if (e != null) { + throw exceptionOccured.get(); } } @@ -144,6 +149,9 @@ public class DependencyChecker { break; } ClassHolder cls = classSource.getClassHolder(className); + if (cls == null) { + throw new RuntimeException("Class not found: " + className); + } if (cls.getMethod(clinitDesc) != null) { attachMethodGraph(new MethodReference(className, clinitDesc)); } diff --git a/teavm-core/src/main/java/org/teavm/dependency/DependencyGraphBuilder.java b/teavm-core/src/main/java/org/teavm/dependency/DependencyGraphBuilder.java index 4a2d758b8..297308b66 100644 --- a/teavm-core/src/main/java/org/teavm/dependency/DependencyGraphBuilder.java +++ b/teavm-core/src/main/java/org/teavm/dependency/DependencyGraphBuilder.java @@ -81,6 +81,9 @@ class DependencyGraphBuilder { return; } MethodGraph targetGraph = checker.attachMethodGraph(methodRef); + if (targetGraph == null) { + throw new RuntimeException("Method not found: " + methodRef); + } DependencyNode[] targetParams = targetGraph.getVariableNodes(); for (int i = 0; i < parameters.length; ++i) { parameters[i].connect(targetParams[i]); diff --git a/teavm-core/src/main/java/org/teavm/javascript/Decompiler.java b/teavm-core/src/main/java/org/teavm/javascript/Decompiler.java index 98441fa70..988173763 100644 --- a/teavm-core/src/main/java/org/teavm/javascript/Decompiler.java +++ b/teavm-core/src/main/java/org/teavm/javascript/Decompiler.java @@ -62,6 +62,36 @@ public class Decompiler { } } + public List decompile(Collection classNames) { + List sequence = new ArrayList<>(); + Set visited = new HashSet<>(); + for (String className : classNames) { + orderClasses(className, visited, sequence); + } + List result = new ArrayList<>(); + for (String className : sequence) { + result.add(decompile(classSource.getClassHolder(className))); + } + return result; + } + + private void orderClasses(String className, Set visited, List order) { + if (!visited.add(className)) { + return; + } + ClassHolder cls = classSource.getClassHolder(className); + if (cls == null) { + throw new IllegalArgumentException("Class not found: " + className); + } + if (cls.getParent() != null) { + orderClasses(cls.getParent(), visited, order); + } + for (String iface : cls.getInterfaces()) { + orderClasses(iface, visited, order); + } + order.add(className); + } + public ClassNode decompile(ClassHolder cls) { ClassNode clsNode = new ClassNode(cls.getName(), cls.getParent()); for (FieldHolder field : cls.getFields()) {