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 14251082e..a54bf56ef 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.AtomicInteger; import java.util.concurrent.atomic.AtomicReference; import org.teavm.common.ConcurrentCachedMapper; import org.teavm.common.Mapper; @@ -40,6 +41,8 @@ public class DependencyChecker { private ConcurrentMap achievableClasses = new ConcurrentHashMap<>(); private ConcurrentMap initializedClasses = new ConcurrentHashMap<>(); private AtomicReference exceptionOccured = new AtomicReference<>(); + private AtomicInteger activeTaskCount = new AtomicInteger(0); + private final Object activeTaskMonitor = new Object(); public DependencyChecker(ClassHolderSource classSource, ClassLoader classLoader) { this(classSource, classLoader, Runtime.getRuntime().availableProcessors()); @@ -103,15 +106,22 @@ public class DependencyChecker { } void schedule(final Runnable runnable) { + activeTaskCount.incrementAndGet(); try { executor.execute(new Runnable() { @Override public void run() { try { runnable.run(); } catch (RuntimeException e) { + activeTaskMonitor.notifyAll(); exceptionOccured.compareAndSet(null, e); executor.shutdownNow(); } + if (activeTaskCount.decrementAndGet() == 0) { + synchronized (activeTaskMonitor) { + activeTaskMonitor.notifyAll(); + } + } } }); } catch (RejectedExecutionException e) { @@ -120,11 +130,13 @@ public class DependencyChecker { } public void checkDependencies() { - exceptionOccured.set(null); while (true) { + if (activeTaskCount.get() == 0 || exceptionOccured.get() != null) { + break; + } try { - if (executor.getActiveCount() == 0 || executor.awaitTermination(2, TimeUnit.MILLISECONDS)) { - break; + synchronized (activeTaskMonitor) { + activeTaskMonitor.wait(); } } catch (InterruptedException e) { Thread.currentThread().interrupt(); @@ -138,8 +150,8 @@ public class DependencyChecker { executor.shutdown(); } - void achieveClass(String className) { - achievableClasses.put(className, dummyValue); + boolean achieveClass(String className) { + return achievableClasses.putIfAbsent(className, dummyValue) == null; } public MethodGraph attachMethodGraph(MethodReference methodRef) { @@ -152,6 +164,8 @@ public class DependencyChecker { if (initializedClasses.putIfAbsent(className, clinitDesc) != null) { break; } + achieveClass(className); + achieveInterfaces(className); ClassHolder cls = classSource.getClassHolder(className); if (cls == null) { throw new RuntimeException("Class not found: " + className); @@ -163,6 +177,18 @@ public class DependencyChecker { } } + private void achieveInterfaces(String className) { + ClassHolder cls = classSource.getClassHolder(className); + if (cls == null) { + throw new RuntimeException("Class not found: " + className); + } + for (String iface : cls.getInterfaces()) { + if (achieveClass(iface)) { + achieveInterfaces(iface); + } + } + } + private MethodGraph createMethodGraph(final MethodReference methodRef) { initClass(methodRef.getClassName()); ClassHolder cls = classSource.getClassHolder(methodRef.getClassName()); @@ -202,7 +228,6 @@ public class DependencyChecker { @Override public void run() { DependencyGraphBuilder graphBuilder = new DependencyGraphBuilder(DependencyChecker.this); graphBuilder.buildGraph(currentMethod, graph); - achieveClass(methodRef.getClassName()); } }); return graph; diff --git a/teavm-core/src/main/java/org/teavm/javascript/JavascriptBuilder.java b/teavm-core/src/main/java/org/teavm/javascript/JavascriptBuilder.java index fef3c10bf..93d4eefc8 100644 --- a/teavm-core/src/main/java/org/teavm/javascript/JavascriptBuilder.java +++ b/teavm-core/src/main/java/org/teavm/javascript/JavascriptBuilder.java @@ -69,7 +69,6 @@ public class JavascriptBuilder { } public void build(Appendable writer) throws RenderingException { - Decompiler decompiler = new Decompiler(classSource, classLoader); AliasProvider aliasProvider = minifying ? new MinifyingAliasProvider() : new DefaultAliasProvider(); DefaultNamingStrategy naming = new DefaultNamingStrategy(aliasProvider, classSource); naming.setMinifying(minifying); @@ -83,6 +82,7 @@ public class JavascriptBuilder { ValueType.arrayOf(ValueType.CHARACTER), ValueType.VOID))); dependencyChecker.checkDependencies(); ListableClassHolderSource classSet = dependencyChecker.cutUnachievableClasses(); + Decompiler decompiler = new Decompiler(classSet, classLoader); ClassSetOptimizer optimizer = new ClassSetOptimizer(); optimizer.optimizeAll(classSet); renderer.renderRuntime();