Adds class preordering. Fixes concurrency issues

This commit is contained in:
Alexey Andreev 2013-11-20 18:16:48 +04:00
parent cf6c9b1ba6
commit 04e12562a0
5 changed files with 63 additions and 25 deletions

View File

@ -2,10 +2,7 @@ package org.teavm.classlibgen;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.util.ArrayList; import java.util.*;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.apache.commons.io.IOUtils; import org.apache.commons.io.IOUtils;
import org.teavm.codegen.DefaultAliasProvider; import org.teavm.codegen.DefaultAliasProvider;
import org.teavm.codegen.DefaultNamingStrategy; import org.teavm.codegen.DefaultNamingStrategy;
@ -51,9 +48,7 @@ public class ClasslibTestGenerator {
} }
dependencyChecker.checkDependencies(); dependencyChecker.checkDependencies();
dependencyChecker.cutUnachievableClasses(); dependencyChecker.cutUnachievableClasses();
for (String className : dependencyChecker.getAchievableClasses()) { decompileClasses(dependencyChecker.getAchievableClasses());
decompileClass(className);
}
renderHead(); renderHead();
ClassLoader classLoader = ClasslibTestGenerator.class.getClassLoader(); ClassLoader classLoader = ClasslibTestGenerator.class.getClassLoader();
try (InputStream input = classLoader.getResourceAsStream("org/teavm/classlib/junit-support.js")) { try (InputStream input = classLoader.getResourceAsStream("org/teavm/classlib/junit-support.js")) {
@ -69,11 +64,12 @@ public class ClasslibTestGenerator {
renderFoot(); renderFoot();
} }
private static void decompileClass(String className) { private static void decompileClasses(Collection<String> classNames) {
ClassHolder cls = classSource.getClassHolder(className); List<ClassNode> clsNodes = decompiler.decompile(classNames);
ClassNode clsNode = decompiler.decompile(cls); for (ClassNode clsNode : clsNodes) {
renderer.render(clsNode); renderer.render(clsNode);
} }
}
private static void renderHead() { private static void renderHead() {
System.out.println("<!DOCTYPE html>"); System.out.println("<!DOCTYPE html>");

View File

@ -41,6 +41,7 @@ public class ConcurrentCachedMapper<T, R> implements Mapper<T, R> {
} }
} else { } else {
CountDownLatch latch = oldWrapper.latch; CountDownLatch latch = oldWrapper.latch;
wrapper = oldWrapper;
try { try {
latch.await(); latch.await();
} catch (InterruptedException e) { } catch (InterruptedException e) {

View File

@ -18,6 +18,7 @@ package org.teavm.dependency;
import java.util.Collection; import java.util.Collection;
import java.util.HashSet; import java.util.HashSet;
import java.util.concurrent.*; import java.util.concurrent.*;
import java.util.concurrent.atomic.AtomicReference;
import org.teavm.codegen.ConcurrentCachedMapper; import org.teavm.codegen.ConcurrentCachedMapper;
import org.teavm.codegen.ConcurrentCachedMapper.KeyListener; import org.teavm.codegen.ConcurrentCachedMapper.KeyListener;
import org.teavm.codegen.Mapper; import org.teavm.codegen.Mapper;
@ -36,7 +37,7 @@ public class DependencyChecker {
private ConcurrentCachedMapper<FieldReference, DependencyNode> fieldCache; private ConcurrentCachedMapper<FieldReference, DependencyNode> fieldCache;
private ConcurrentMap<String, Object> achievableClasses = new ConcurrentHashMap<>(); private ConcurrentMap<String, Object> achievableClasses = new ConcurrentHashMap<>();
private ConcurrentMap<String, Object> initializedClasses = new ConcurrentHashMap<>(); private ConcurrentMap<String, Object> initializedClasses = new ConcurrentHashMap<>();
private volatile RuntimeException exceptionOccured; private AtomicReference<RuntimeException> exceptionOccured = new AtomicReference<>();
public DependencyChecker(ClassHolderSource classSource) { public DependencyChecker(ClassHolderSource classSource) {
this(classSource, Runtime.getRuntime().availableProcessors()); this(classSource, Runtime.getRuntime().availableProcessors());
@ -99,21 +100,24 @@ public class DependencyChecker {
} }
void schedule(final Runnable runnable) { void schedule(final Runnable runnable) {
try {
executor.execute(new Runnable() { executor.execute(new Runnable() {
@Override @Override public void run() {
public void run() {
try { try {
runnable.run(); runnable.run();
} catch (RuntimeException e) { } catch (RuntimeException e) {
exceptionOccured = e; exceptionOccured.compareAndSet(null, e);
executor.shutdownNow(); executor.shutdownNow();
} }
} }
}); });
} catch (RejectedExecutionException e) {
throw exceptionOccured.get();
}
} }
public void checkDependencies() { public void checkDependencies() {
exceptionOccured = null; exceptionOccured.set(null);
while (true) { while (true) {
try { try {
if (executor.getActiveCount() == 0 || executor.awaitTermination(1, TimeUnit.SECONDS)) { if (executor.getActiveCount() == 0 || executor.awaitTermination(1, TimeUnit.SECONDS)) {
@ -124,8 +128,9 @@ public class DependencyChecker {
break; break;
} }
} }
if (exceptionOccured != null) { RuntimeException e = exceptionOccured.get();
throw exceptionOccured; if (e != null) {
throw exceptionOccured.get();
} }
} }
@ -144,6 +149,9 @@ public class DependencyChecker {
break; break;
} }
ClassHolder cls = classSource.getClassHolder(className); ClassHolder cls = classSource.getClassHolder(className);
if (cls == null) {
throw new RuntimeException("Class not found: " + className);
}
if (cls.getMethod(clinitDesc) != null) { if (cls.getMethod(clinitDesc) != null) {
attachMethodGraph(new MethodReference(className, clinitDesc)); attachMethodGraph(new MethodReference(className, clinitDesc));
} }

View File

@ -81,6 +81,9 @@ class DependencyGraphBuilder {
return; return;
} }
MethodGraph targetGraph = checker.attachMethodGraph(methodRef); MethodGraph targetGraph = checker.attachMethodGraph(methodRef);
if (targetGraph == null) {
throw new RuntimeException("Method not found: " + methodRef);
}
DependencyNode[] targetParams = targetGraph.getVariableNodes(); DependencyNode[] targetParams = targetGraph.getVariableNodes();
for (int i = 0; i < parameters.length; ++i) { for (int i = 0; i < parameters.length; ++i) {
parameters[i].connect(targetParams[i]); parameters[i].connect(targetParams[i]);

View File

@ -62,6 +62,36 @@ public class Decompiler {
} }
} }
public List<ClassNode> decompile(Collection<String> classNames) {
List<String> sequence = new ArrayList<>();
Set<String> visited = new HashSet<>();
for (String className : classNames) {
orderClasses(className, visited, sequence);
}
List<ClassNode> result = new ArrayList<>();
for (String className : sequence) {
result.add(decompile(classSource.getClassHolder(className)));
}
return result;
}
private void orderClasses(String className, Set<String> visited, List<String> 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) { public ClassNode decompile(ClassHolder cls) {
ClassNode clsNode = new ClassNode(cls.getName(), cls.getParent()); ClassNode clsNode = new ClassNode(cls.getName(), cls.getParent());
for (FieldHolder field : cls.getFields()) { for (FieldHolder field : cls.getFields()) {