Further refactoring of dependency checker

This commit is contained in:
konsoletyper 2014-02-19 10:43:13 +04:00
parent da35fbc2a9
commit be89d16e88
20 changed files with 309 additions and 176 deletions

View File

@ -49,10 +49,10 @@ public class CharacterNativeGenerator implements Generator, DependencyPlugin {
} }
@Override @Override
public void methodAchieved(DependencyChecker checker, MethodDependency graph) { public void methodAchieved(DependencyChecker checker, MethodDependency method) {
switch (graph.getReference().getName()) { switch (method.getReference().getName()) {
case "obtainDigitMapping": case "obtainDigitMapping":
achieveObtainDigitMapping(graph); achieveObtainDigitMapping(method);
break; break;
} }
} }
@ -72,7 +72,7 @@ public class CharacterNativeGenerator implements Generator, DependencyPlugin {
.append("\");").softNewLine(); .append("\");").softNewLine();
} }
private void achieveObtainDigitMapping(MethodDependency graph) { private void achieveObtainDigitMapping(MethodDependency method) {
graph.getResult().propagate("java.lang.String"); method.getResult().propagate("java.lang.String");
} }
} }

View File

@ -62,16 +62,16 @@ public class ObjectNativeGenerator implements Generator, Injector, DependencyPlu
} }
@Override @Override
public void methodAchieved(DependencyChecker checker, MethodDependency graph) { public void methodAchieved(DependencyChecker checker, MethodDependency method) {
switch (graph.getReference().getName()) { switch (method.getReference().getName()) {
case "clone": case "clone":
achieveClone(graph); achieveClone(method);
break; break;
case "getClass": case "getClass":
achieveGetClass(checker, graph); achieveGetClass(checker, method);
break; break;
case "wrap": case "wrap":
achieveWrap(graph); achieveWrap(method);
break; break;
} }
} }
@ -87,12 +87,12 @@ public class ObjectNativeGenerator implements Generator, Injector, DependencyPlu
writer.append(".constructor)"); writer.append(".constructor)");
} }
private void achieveGetClass(DependencyChecker checker, MethodDependency graph) { private void achieveGetClass(DependencyChecker checker, MethodDependency method) {
String classClass = "java.lang.Class"; String classClass = "java.lang.Class";
MethodReference initMethod = new MethodReference(classClass, new MethodDescriptor("createNew", MethodReference initMethod = new MethodReference(classClass, new MethodDescriptor("createNew",
ValueType.object(classClass))); ValueType.object(classClass)));
checker.addEntryPoint(initMethod); checker.addEntryPoint(initMethod);
graph.getResult().propagate("java.lang.Class"); method.getResult().propagate("java.lang.Class");
} }
private void generateHashCode(GeneratorContext context, SourceWriter writer) throws IOException { private void generateHashCode(GeneratorContext context, SourceWriter writer) throws IOException {
@ -108,8 +108,8 @@ public class ObjectNativeGenerator implements Generator, Injector, DependencyPlu
writer.append("return copy;").softNewLine(); writer.append("return copy;").softNewLine();
} }
private void achieveClone(MethodDependency graph) { private void achieveClone(MethodDependency method) {
graph.getVariable(0).connect(graph.getResult()); method.getVariable(0).connect(method.getResult());
} }
private void generateWrap(InjectorContext context) throws IOException { private void generateWrap(InjectorContext context) throws IOException {

View File

@ -43,10 +43,10 @@ public class SystemNativeGenerator implements Generator, DependencyPlugin {
} }
@Override @Override
public void methodAchieved(DependencyChecker checker, MethodDependency graph) { public void methodAchieved(DependencyChecker checker, MethodDependency method) {
switch (graph.getReference().getName()) { switch (method.getReference().getName()) {
case "doArrayCopy": case "doArrayCopy":
achieveArrayCopy(graph); achieveArrayCopy(method);
break; break;
} }
} }
@ -66,9 +66,9 @@ public class SystemNativeGenerator implements Generator, DependencyPlugin {
writer.append("return Long_fromNumber(new Date().getTime());").softNewLine(); writer.append("return Long_fromNumber(new Date().getTime());").softNewLine();
} }
private void achieveArrayCopy(MethodDependency graph) { private void achieveArrayCopy(MethodDependency method) {
DependencyNode src = graph.getVariable(1); DependencyNode src = method.getVariable(1);
DependencyNode dest = graph.getVariable(3); DependencyNode dest = method.getVariable(3);
src.getArrayItem().connect(dest.getArrayItem()); src.getArrayItem().connect(dest.getArrayItem());
} }
} }

View File

@ -33,9 +33,9 @@ import org.teavm.model.ValueType;
*/ */
public class ArrayNativeGenerator implements Generator, DependencyPlugin { public class ArrayNativeGenerator implements Generator, DependencyPlugin {
@Override @Override
public void methodAchieved(DependencyChecker checker, MethodDependency graph) { public void methodAchieved(DependencyChecker checker, MethodDependency method) {
if (graph.getReference().getName().equals("getLength")) { if (method.getReference().getName().equals("getLength")) {
achieveGetLength(checker, graph); achieveGetLength(checker, method);
} }
} }
@ -59,8 +59,8 @@ public class ArrayNativeGenerator implements Generator, DependencyPlugin {
writer.append("return " + array + ".data.length;").softNewLine(); writer.append("return " + array + ".data.length;").softNewLine();
} }
private void achieveGetLength(final DependencyChecker checker, final MethodDependency graph) { private void achieveGetLength(final DependencyChecker checker, final MethodDependency method) {
graph.getVariable(1).addConsumer(new DependencyConsumer() { method.getVariable(1).addConsumer(new DependencyConsumer() {
@Override public void consume(String type) { @Override public void consume(String type) {
if (!type.startsWith("[")) { if (!type.startsWith("[")) {
MethodReference cons = new MethodReference("java.lang.IllegalArgumentException", MethodReference cons = new MethodReference("java.lang.IllegalArgumentException",

View File

@ -26,7 +26,7 @@ import org.teavm.model.*;
* *
* @author Alexey Andreev * @author Alexey Andreev
*/ */
public class DependencyChecker implements DependencyInformation { public class DependencyChecker implements DependencyInfo {
private static Object dummyValue = new Object(); private static Object dummyValue = new Object();
static final boolean shouldLog = System.getProperty("org.teavm.logDependencies", "false").equals("true"); static final boolean shouldLog = System.getProperty("org.teavm.logDependencies", "false").equals("true");
private ClassReaderSource classSource; private ClassReaderSource classSource;
@ -34,12 +34,11 @@ public class DependencyChecker implements DependencyInformation {
private FiniteExecutor executor; private FiniteExecutor executor;
private Mapper<MethodReference, MethodReader> methodReaderCache; private Mapper<MethodReference, MethodReader> methodReaderCache;
private Mapper<FieldReference, FieldReader> fieldReaderCache; private Mapper<FieldReference, FieldReader> fieldReaderCache;
private ConcurrentMap<MethodReference, Object> abstractMethods = new ConcurrentHashMap<>();
private ConcurrentMap<MethodReference, DependencyStack> stacks = new ConcurrentHashMap<>(); private ConcurrentMap<MethodReference, DependencyStack> stacks = new ConcurrentHashMap<>();
private ConcurrentMap<FieldReference, DependencyStack> fieldStacks = new ConcurrentHashMap<>(); private ConcurrentMap<FieldReference, DependencyStack> fieldStacks = new ConcurrentHashMap<>();
private ConcurrentMap<String, DependencyStack> classStacks = new ConcurrentHashMap<>(); private ConcurrentMap<String, DependencyStack> classStacks = new ConcurrentHashMap<>();
private ConcurrentCachedMapper<MethodReference, MethodDependency> methodCache; private ConcurrentCachedMapper<MethodReference, MethodDependency> methodCache;
private ConcurrentCachedMapper<FieldReference, DependencyNode> fieldCache; private ConcurrentCachedMapper<FieldReference, FieldDependency> 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 List<DependencyListener> listeners = new ArrayList<>(); private List<DependencyListener> listeners = new ArrayList<>();
@ -75,8 +74,8 @@ public class DependencyChecker implements DependencyInformation {
return createMethodDep(preimage, method, stacks.get(preimage)); return createMethodDep(preimage, method, stacks.get(preimage));
} }
}); });
fieldCache = new ConcurrentCachedMapper<>(new Mapper<FieldReference, DependencyNode>() { fieldCache = new ConcurrentCachedMapper<>(new Mapper<FieldReference, FieldDependency>() {
@Override public DependencyNode map(FieldReference preimage) { @Override public FieldDependency map(FieldReference preimage) {
FieldReader field = fieldReaderCache.map(preimage); FieldReader field = fieldReaderCache.map(preimage);
if (field != null && !field.getReference().equals(preimage)) { if (field != null && !field.getReference().equals(preimage)) {
fieldStacks.put(field.getReference(), fieldStacks.get(preimage)); fieldStacks.put(field.getReference(), fieldStacks.get(preimage));
@ -98,10 +97,10 @@ public class DependencyChecker implements DependencyInformation {
}); });
fieldCache.addKeyListener(new KeyListener<FieldReference>() { fieldCache.addKeyListener(new KeyListener<FieldReference>() {
@Override public void keyAdded(FieldReference key) { @Override public void keyAdded(FieldReference key) {
DependencyNode node = fieldCache.getKnown(key); FieldDependency fieldDep = fieldCache.getKnown(key);
if (!missingFields.containsKey(key)) { if (!fieldDep.isMissing()) {
for (DependencyListener listener : listeners) { for (DependencyListener listener : listeners) {
listener.fieldAchieved(DependencyChecker.this, key, node); listener.fieldAchieved(DependencyChecker.this, fieldDep);
} }
} }
} }
@ -131,8 +130,9 @@ public class DependencyChecker implements DependencyInformation {
if (parameters.length != argumentTypes.length) { if (parameters.length != argumentTypes.length) {
throw new IllegalArgumentException("argumentTypes length does not match the number of method's arguments"); throw new IllegalArgumentException("argumentTypes length does not match the number of method's arguments");
} }
MethodDependency graph = linkMethod(methodRef, DependencyStack.ROOT); MethodDependency method = linkMethod(methodRef, DependencyStack.ROOT);
DependencyNode[] varNodes = graph.getVariables(); method.use();
DependencyNode[] varNodes = method.getVariables();
varNodes[0].propagate(methodRef.getClassName()); varNodes[0].propagate(methodRef.getClassName());
for (int i = 0; i < argumentTypes.length; ++i) { for (int i = 0; i < argumentTypes.length; ++i) {
varNodes[i + 1].propagate(argumentTypes[i]); varNodes[i + 1].propagate(argumentTypes[i]);
@ -183,7 +183,7 @@ public class DependencyChecker implements DependencyInformation {
} }
if (cls.getMethod(clinitDesc) != null) { if (cls.getMethod(clinitDesc) != null) {
MethodReference methodRef = new MethodReference(className, clinitDesc); MethodReference methodRef = new MethodReference(className, clinitDesc);
linkMethod(methodRef, new DependencyStack(methodRef, stack)); linkMethod(methodRef, new DependencyStack(methodRef, stack)).use();
} }
className = cls.getParent(); className = cls.getParent();
} }
@ -264,11 +264,10 @@ public class DependencyChecker implements DependencyInformation {
final MethodDependency dep = new MethodDependency(parameterNodes, paramCount, resultNode, stack, method, final MethodDependency dep = new MethodDependency(parameterNodes, paramCount, resultNode, stack, method,
methodRef); methodRef);
if (method != null) { if (method != null) {
final MethodReader currentMethod = method;
executor.execute(new Runnable() { executor.execute(new Runnable() {
@Override public void run() { @Override public void run() {
DependencyGraphBuilder graphBuilder = new DependencyGraphBuilder(DependencyChecker.this); DependencyGraphBuilder graphBuilder = new DependencyGraphBuilder(DependencyChecker.this);
graphBuilder.buildGraph(currentMethod, dep); graphBuilder.buildGraph(dep);
} }
}); });
} else { } else {
@ -284,10 +283,6 @@ public class DependencyChecker implements DependencyInformation {
return methodCache.caches(methodRef); return methodCache.caches(methodRef);
} }
public boolean isAbstractMethodAchievable(MethodReference methodRef) {
return abstractMethods.containsKey(methodRef);
}
@Override @Override
public Collection<MethodReference> getAchievableMethods() { public Collection<MethodReference> getAchievableMethods() {
return methodCache.getCachedPreimages(); return methodCache.getCachedPreimages();
@ -303,17 +298,17 @@ public class DependencyChecker implements DependencyInformation {
return new HashSet<>(achievableClasses.keySet()); return new HashSet<>(achievableClasses.keySet());
} }
public DependencyNode linkField(FieldReference fieldRef, DependencyStack stack) { public FieldDependency linkField(FieldReference fieldRef, DependencyStack stack) {
fieldStacks.putIfAbsent(fieldRef, stack); fieldStacks.putIfAbsent(fieldRef, stack);
return fieldCache.map(fieldRef); return fieldCache.map(fieldRef);
} }
@Override @Override
public DependencyNode getField(FieldReference fieldRef) { public FieldDependency getField(FieldReference fieldRef) {
return fieldCache.getKnown(fieldRef); return fieldCache.getKnown(fieldRef);
} }
private DependencyNode createFieldNode(FieldReference fieldRef, FieldReader field, DependencyStack stack) { private FieldDependency createFieldNode(FieldReference fieldRef, FieldReader field, DependencyStack stack) {
DependencyNode node = new DependencyNode(this); DependencyNode node = new DependencyNode(this);
if (field == null) { if (field == null) {
missingFields.putIfAbsent(fieldRef, stack); missingFields.putIfAbsent(fieldRef, stack);
@ -324,24 +319,15 @@ public class DependencyChecker implements DependencyInformation {
if (field != null) { if (field != null) {
initClass(fieldRef.getClassName(), stack); initClass(fieldRef.getClassName(), stack);
} }
return node; return new FieldDependency(node, stack, field, fieldRef);
} }
private void activateDependencyPlugin(MethodDependency graph) { private void activateDependencyPlugin(MethodDependency methodDep) {
MethodReference methodRef = graph.getReference(); AnnotationReader depAnnot = methodDep.getMethod().getAnnotations().get(PluggableDependency.class.getName());
ClassReader cls = classSource.get(methodRef.getClassName());
if (cls == null) {
return;
}
MethodReader method = cls.getMethod(methodRef.getDescriptor());
if (method == null) {
return;
}
AnnotationHolder depAnnot = method.getAnnotations().get(PluggableDependency.class.getName());
if (depAnnot == null) { if (depAnnot == null) {
return; return;
} }
ValueType depType = depAnnot.getValues().get("value").getJavaClass(); ValueType depType = depAnnot.getValue("value").getJavaClass();
String depClassName = ((ValueType.Object)depType).getClassName(); String depClassName = ((ValueType.Object)depType).getClassName();
Class<?> depClass; Class<?> depClass;
try { try {
@ -355,26 +341,7 @@ public class DependencyChecker implements DependencyInformation {
} catch (IllegalAccessException | InstantiationException e) { } catch (IllegalAccessException | InstantiationException e) {
throw new RuntimeException("Can't instantiate dependency plugin " + depClassName, e); throw new RuntimeException("Can't instantiate dependency plugin " + depClassName, e);
} }
plugin.methodAchieved(this, graph); plugin.methodAchieved(this, methodDep);
}
public void addAbstractMethod(MethodReference methodRef, DependencyStack stack) {
stacks.putIfAbsent(methodRef, stack);
if (abstractMethods.putIfAbsent(methodRef, methodRef) == null) {
String className = methodRef.getClassName();
while (className != null) {
ClassReader cls = classSource.get(className);
if (cls == null) {
return;
}
MethodReader method = cls.getMethod(methodRef.getDescriptor());
if (method != null) {
abstractMethods.put(methodRef, methodRef);
return;
}
className = cls.getParent();
}
}
} }
public ListableClassHolderSource cutUnachievableClasses(ClassHolderSource classSource) { public ListableClassHolderSource cutUnachievableClasses(ClassHolderSource classSource) {
@ -384,13 +351,12 @@ public class DependencyChecker implements DependencyInformation {
cutClasses.putClassHolder(classHolder); cutClasses.putClassHolder(classHolder);
for (MethodHolder method : classHolder.getMethods().toArray(new MethodHolder[0])) { for (MethodHolder method : classHolder.getMethods().toArray(new MethodHolder[0])) {
MethodReference methodRef = new MethodReference(className, method.getDescriptor()); MethodReference methodRef = new MethodReference(className, method.getDescriptor());
if (!methodCache.getCachedPreimages().contains(methodRef)) { MethodDependency methodDep = getMethod(methodRef);
if (abstractMethods.containsKey(methodRef)) { if (methodDep == null) {
classHolder.removeMethod(method);
} else if (!methodDep.isUsed()) {
method.getModifiers().add(ElementModifier.ABSTRACT); method.getModifiers().add(ElementModifier.ABSTRACT);
method.setProgram(null); method.setProgram(null);
} else {
classHolder.removeMethod(method);
}
} }
} }
for (FieldHolder field : classHolder.getFields().toArray(new FieldHolder[0])) { for (FieldHolder field : classHolder.getFields().toArray(new FieldHolder[0])) {
@ -404,7 +370,7 @@ public class DependencyChecker implements DependencyInformation {
} }
@Override @Override
public DependencyMethodInformation getMethod(MethodReference methodRef) { public MethodDependency getMethod(MethodReference methodRef) {
return methodCache.getKnown(methodRef); return methodCache.getKnown(methodRef);
} }

View File

@ -15,6 +15,7 @@
*/ */
package org.teavm.dependency; package org.teavm.dependency;
import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap; import java.util.concurrent.ConcurrentMap;
@ -32,23 +33,25 @@ class DependencyGraphBuilder {
private DependencyNode resultNode; private DependencyNode resultNode;
private ProgramReader program; private ProgramReader program;
private DependencyStack callerStack; private DependencyStack callerStack;
private List<Runnable> useRunners = new ArrayList<>();
public DependencyGraphBuilder(DependencyChecker dependencyChecker) { public DependencyGraphBuilder(DependencyChecker dependencyChecker) {
this.dependencyChecker = dependencyChecker; this.dependencyChecker = dependencyChecker;
} }
public void buildGraph(MethodReader method, MethodDependency graph) { public void buildGraph(MethodDependency dep) {
MethodReader method = dep.getMethod();
if (method.getProgram() == null || method.getProgram().basicBlockCount() == 0) { if (method.getProgram() == null || method.getProgram().basicBlockCount() == 0) {
return; return;
} }
callerStack = graph.getStack(); callerStack = dep.getStack();
program = method.getProgram(); program = method.getProgram();
if (DependencyChecker.shouldLog) { if (DependencyChecker.shouldLog) {
System.out.println("Method achieved: " + method.getReference()); System.out.println("Method achieved: " + method.getReference());
System.out.println(new ListingBuilder().buildListing(program, " ")); System.out.println(new ListingBuilder().buildListing(program, " "));
} }
resultNode = graph.getResult(); resultNode = dep.getResult();
nodes = graph.getVariables(); nodes = dep.getVariables();
for (int i = 0; i < program.basicBlockCount(); ++i) { for (int i = 0; i < program.basicBlockCount(); ++i) {
BasicBlockReader block = program.basicBlockAt(i); BasicBlockReader block = program.basicBlockAt(i);
block.readAllInstructions(reader); block.readAllInstructions(reader);
@ -58,6 +61,7 @@ class DependencyGraphBuilder {
} }
} }
} }
dep.setUseRunner(new MultipleRunner(useRunners));
} }
private static class VirtualCallPropagationListener implements DependencyConsumer { private static class VirtualCallPropagationListener implements DependencyConsumer {
@ -92,6 +96,7 @@ class DependencyGraphBuilder {
MethodReference methodRef = new MethodReference(className, methodDesc); MethodReference methodRef = new MethodReference(className, methodDesc);
MethodDependency methodDep = checker.linkMethod(methodRef, stack); MethodDependency methodDep = checker.linkMethod(methodRef, stack);
if (!methodDep.isMissing() && knownMethods.putIfAbsent(methodRef, methodRef) == null) { if (!methodDep.isMissing() && knownMethods.putIfAbsent(methodRef, methodRef) == null) {
methodDep.use();
DependencyNode[] targetParams = methodDep.getVariables(); DependencyNode[] targetParams = methodDep.getVariables();
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]);
@ -103,6 +108,30 @@ class DependencyGraphBuilder {
} }
} }
private static class MultipleRunner implements Runnable {
private List<Runnable> parts;
public MultipleRunner(List<Runnable> parts) {
this.parts = parts;
}
@Override public void run() {
for (Runnable part : parts) {
part.run();
}
}
}
private static class TypePropagationRunner implements Runnable {
private DependencyNode node;
private String type;
public TypePropagationRunner(DependencyNode node, String type) {
this.node = node;
this.type = type;
}
@Override public void run() {
node.propagate(type);
}
}
private InstructionReader reader = new InstructionReader() { private InstructionReader reader = new InstructionReader() {
@Override @Override
public void nop() { public void nop() {
@ -110,7 +139,7 @@ class DependencyGraphBuilder {
@Override @Override
public void classConstant(VariableReader receiver, ValueType cst) { public void classConstant(VariableReader receiver, ValueType cst) {
nodes[receiver.getIndex()].propagate("java.lang.Class"); useRunners.add(new TypePropagationRunner(nodes[receiver.getIndex()], "java.lang.Class"));
while (cst instanceof ValueType.Array) { while (cst instanceof ValueType.Array) {
cst = ((ValueType.Array)cst).getItemType(); cst = ((ValueType.Array)cst).getItemType();
} }
@ -141,9 +170,11 @@ class DependencyGraphBuilder {
@Override @Override
public void stringConstant(VariableReader receiver, String cst) { public void stringConstant(VariableReader receiver, String cst) {
nodes[receiver.getIndex()].propagate("java.lang.String"); useRunners.add(new TypePropagationRunner(nodes[receiver.getIndex()], "java.lang.String"));
dependencyChecker.linkMethod(new MethodReference("java.lang.String", new MethodDescriptor( MethodDependency method = dependencyChecker.linkMethod(new MethodReference("java.lang.String",
"<init>", ValueType.arrayOf(ValueType.CHARACTER), ValueType.VOID)), callerStack); new MethodDescriptor("<init>", ValueType.arrayOf(ValueType.CHARACTER), ValueType.VOID)),
callerStack);
method.use();
} }
@Override @Override
@ -211,7 +242,7 @@ class DependencyGraphBuilder {
@Override @Override
public void createArray(VariableReader receiver, ValueType itemType, VariableReader size) { public void createArray(VariableReader receiver, ValueType itemType, VariableReader size) {
nodes[receiver.getIndex()].propagate("[" + itemType); useRunners.add(new TypePropagationRunner(nodes[receiver.getIndex()], "[" + itemType));
} }
@Override @Override
@ -222,27 +253,27 @@ class DependencyGraphBuilder {
sb.append('['); sb.append('[');
} }
sb.append(itemType); sb.append(itemType);
nodes[receiver.getIndex()].propagate(sb.toString()); useRunners.add(new TypePropagationRunner(nodes[receiver.getIndex()], sb.toString()));
} }
@Override @Override
public void create(VariableReader receiver, String type) { public void create(VariableReader receiver, String type) {
nodes[receiver.getIndex()].propagate(type); useRunners.add(new TypePropagationRunner(nodes[receiver.getIndex()], type));
} }
@Override @Override
public void getField(VariableReader receiver, VariableReader instance, FieldReference field, public void getField(VariableReader receiver, VariableReader instance, FieldReference field,
ValueType fieldType) { ValueType fieldType) {
DependencyNode fieldNode = dependencyChecker.linkField(field, callerStack); FieldDependency fieldDep = dependencyChecker.linkField(field, callerStack);
DependencyNode receiverNode = nodes[receiver.getIndex()]; DependencyNode receiverNode = nodes[receiver.getIndex()];
fieldNode.connect(receiverNode); fieldDep.getValue().connect(receiverNode);
} }
@Override @Override
public void putField(VariableReader instance, FieldReference field, VariableReader value) { public void putField(VariableReader instance, FieldReference field, VariableReader value) {
DependencyNode fieldNode = dependencyChecker.linkField(field, callerStack); FieldDependency fieldDep = dependencyChecker.linkField(field, callerStack);
DependencyNode valueNode = nodes[value.getIndex()]; DependencyNode valueNode = nodes[value.getIndex()];
valueNode.connect(fieldNode); valueNode.connect(fieldDep.getValue());
} }
@Override @Override
@ -305,6 +336,7 @@ class DependencyGraphBuilder {
if (methodDep.isMissing()) { if (methodDep.isMissing()) {
return; return;
} }
methodDep.use();
DependencyNode[] targetParams = methodDep.getVariables(); DependencyNode[] targetParams = methodDep.getVariables();
for (int i = 0; i < arguments.size(); ++i) { for (int i = 0; i < arguments.size(); ++i) {
nodes[arguments.get(i).getIndex()].connect(targetParams[i + 1]); nodes[arguments.get(i).getIndex()].connect(targetParams[i + 1]);

View File

@ -23,14 +23,14 @@ import org.teavm.model.MethodReference;
* *
* @author Alexey Andreev <konsoletyper@gmail.com> * @author Alexey Andreev <konsoletyper@gmail.com>
*/ */
public interface DependencyInformation { public interface DependencyInfo {
Collection<MethodReference> getAchievableMethods(); Collection<MethodReference> getAchievableMethods();
Collection<FieldReference> getAchievableFields(); Collection<FieldReference> getAchievableFields();
Collection<String> getAchievableClasses(); Collection<String> getAchievableClasses();
DependencyValueInformation getField(FieldReference fieldRef); FieldDependencyInfo getField(FieldReference fieldRef);
DependencyMethodInformation getMethod(MethodReference methodRef); MethodDependencyInfo getMethod(MethodReference methodRef);
} }

View File

@ -15,8 +15,6 @@
*/ */
package org.teavm.dependency; package org.teavm.dependency;
import org.teavm.model.FieldReference;
/** /**
* *
* @author Alexey Andreev * @author Alexey Andreev
@ -28,5 +26,5 @@ public interface DependencyListener {
void methodAchieved(DependencyChecker dependencyChecker, MethodDependency method); void methodAchieved(DependencyChecker dependencyChecker, MethodDependency method);
void fieldAchieved(DependencyChecker dependencyChecker, FieldReference field, DependencyNode node); void fieldAchieved(DependencyChecker dependencyChecker, FieldDependency field);
} }

View File

@ -24,7 +24,7 @@ import java.util.concurrent.atomic.AtomicReference;
* *
* @author Alexey Andreev * @author Alexey Andreev
*/ */
public class DependencyNode implements DependencyValueInformation { public class DependencyNode implements ValueDependencyInfo {
private DependencyChecker dependencyChecker; private DependencyChecker dependencyChecker;
private static final Object mapValue = new Object(); private static final Object mapValue = new Object();
private ConcurrentMap<DependencyConsumer, Object> followers = new ConcurrentHashMap<>(); private ConcurrentMap<DependencyConsumer, Object> followers = new ConcurrentHashMap<>();

View File

@ -0,0 +1,58 @@
/*
* 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.dependency;
import org.teavm.model.FieldReader;
import org.teavm.model.FieldReference;
/**
*
* @author Alexey Andreev
*/
public class FieldDependency implements FieldDependencyInfo {
private DependencyNode value;
private DependencyStack stack;
private FieldReader field;
private FieldReference reference;
FieldDependency(DependencyNode value, DependencyStack stack, FieldReader field, FieldReference reference) {
this.value = value;
this.stack = stack;
this.field = field;
this.reference = reference;
}
@Override
public DependencyNode getValue() {
return value;
}
public DependencyStack getStack() {
return stack;
}
public FieldReader getField() {
return field;
}
public FieldReference getReference() {
return reference;
}
public boolean isMissing() {
return field == null;
}
}

View File

@ -0,0 +1,24 @@
/*
* 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.dependency;
/**
*
* @author Alexey Andreev
*/
public interface FieldDependencyInfo {
ValueDependencyInfo getValue();
}

View File

@ -16,6 +16,7 @@
package org.teavm.dependency; package org.teavm.dependency;
import java.util.Arrays; import java.util.Arrays;
import java.util.concurrent.atomic.AtomicBoolean;
import org.teavm.model.MethodReader; import org.teavm.model.MethodReader;
import org.teavm.model.MethodReference; import org.teavm.model.MethodReference;
@ -23,13 +24,15 @@ import org.teavm.model.MethodReference;
* *
* @author Alexey Andreev * @author Alexey Andreev
*/ */
public class MethodDependency implements DependencyMethodInformation { public class MethodDependency implements MethodDependencyInfo {
private DependencyNode[] variableNodes; private DependencyNode[] variableNodes;
private int parameterCount; private int parameterCount;
private DependencyNode resultNode; private DependencyNode resultNode;
private DependencyStack stack; private DependencyStack stack;
private MethodReader method; private MethodReader method;
private MethodReference reference; private MethodReference reference;
private AtomicBoolean used = new AtomicBoolean();
private volatile Runnable useRunner;
MethodDependency(DependencyNode[] variableNodes, int parameterCount, DependencyNode resultNode, MethodDependency(DependencyNode[] variableNodes, int parameterCount, DependencyNode resultNode,
DependencyStack stack, MethodReader method, MethodReference reference) { DependencyStack stack, MethodReader method, MethodReference reference) {
@ -81,4 +84,29 @@ public class MethodDependency implements DependencyMethodInformation {
public boolean isMissing() { public boolean isMissing() {
return method == null; return method == null;
} }
@Override
public boolean isUsed() {
return used.get();
}
public void use() {
if (used.compareAndSet(false, true)) {
if (useRunner != null) {
useRunner.run();
useRunner = null;
}
}
}
void setUseRunner(Runnable runner) {
if (isUsed()) {
runner.run();
} else {
useRunner = runner;
if (isUsed()) {
runner.run();
}
}
}
} }

View File

@ -19,14 +19,16 @@ package org.teavm.dependency;
* *
* @author Alexey Andreev <konsoletyper@gmail.com> * @author Alexey Andreev <konsoletyper@gmail.com>
*/ */
public interface DependencyMethodInformation { public interface MethodDependencyInfo {
DependencyValueInformation[] getVariables(); ValueDependencyInfo[] getVariables();
int getVariableCount(); int getVariableCount();
DependencyValueInformation getVariable(int index); ValueDependencyInfo getVariable(int index);
int getParameterCount(); int getParameterCount();
DependencyNode getResult(); DependencyNode getResult();
boolean isUsed();
} }

View File

@ -19,7 +19,7 @@ package org.teavm.dependency;
* *
* @author Alexey Andreev <konsoletyper@gmail.com> * @author Alexey Andreev <konsoletyper@gmail.com>
*/ */
public interface DependencyValueInformation { public interface ValueDependencyInfo {
String[] getTypes(); String[] getTypes();
boolean hasType(String type); boolean hasType(String type);

View File

@ -20,7 +20,7 @@ import java.util.*;
import org.teavm.codegen.*; import org.teavm.codegen.*;
import org.teavm.common.FiniteExecutor; import org.teavm.common.FiniteExecutor;
import org.teavm.dependency.DependencyChecker; import org.teavm.dependency.DependencyChecker;
import org.teavm.dependency.DependencyInformation; import org.teavm.dependency.DependencyInfo;
import org.teavm.dependency.DependencyListener; import org.teavm.dependency.DependencyListener;
import org.teavm.dependency.DependencyStack; import org.teavm.dependency.DependencyStack;
import org.teavm.javascript.ast.ClassNode; import org.teavm.javascript.ast.ClassNode;
@ -120,9 +120,9 @@ public class JavascriptBuilder implements JavascriptBuilderHost {
builder.setMinified(minifying); builder.setMinified(minifying);
SourceWriter sourceWriter = builder.build(writer); SourceWriter sourceWriter = builder.build(writer);
dependencyChecker.linkMethod(new MethodReference("java.lang.Class", new MethodDescriptor("createNew", dependencyChecker.linkMethod(new MethodReference("java.lang.Class", new MethodDescriptor("createNew",
ValueType.object("java.lang.Class"))), DependencyStack.ROOT); ValueType.object("java.lang.Class"))), DependencyStack.ROOT).use();
dependencyChecker.linkMethod(new MethodReference("java.lang.String", new MethodDescriptor("<init>", dependencyChecker.linkMethod(new MethodReference("java.lang.String", new MethodDescriptor("<init>",
ValueType.arrayOf(ValueType.CHARACTER), ValueType.VOID)), DependencyStack.ROOT); ValueType.arrayOf(ValueType.CHARACTER), ValueType.VOID)), DependencyStack.ROOT).use();
executor.complete(); executor.complete();
dependencyChecker.checkForMissingItems(); dependencyChecker.checkForMissingItems();
ListableClassHolderSource classSet = dependencyChecker.cutUnachievableClasses(classSource); ListableClassHolderSource classSet = dependencyChecker.cutUnachievableClasses(classSource);
@ -164,11 +164,12 @@ public class JavascriptBuilder implements JavascriptBuilderHost {
} }
} }
private void devirtualize(ListableClassHolderSource classes, DependencyInformation dependency) { private void devirtualize(ListableClassHolderSource classes, DependencyInfo dependency) {
final Devirtualization devirtualization = new Devirtualization(dependency, classes); final Devirtualization devirtualization = new Devirtualization(dependency, classes);
for (String className : classes.getClassNames()) { for (String className : classes.getClassNames()) {
ClassHolder cls = classes.get(className); ClassHolder cls = classes.get(className);
for (final MethodHolder method : cls.getMethods()) { for (final MethodHolder method : cls.getMethods()) {
if (method.getProgram() != null) {
executor.execute(new Runnable() { executor.execute(new Runnable() {
@Override public void run() { @Override public void run() {
devirtualization.apply(method); devirtualization.apply(method);
@ -177,6 +178,7 @@ public class JavascriptBuilder implements JavascriptBuilderHost {
} }
} }
} }
}
private void allocateRegisters(ListableClassHolderSource classes) { private void allocateRegisters(ListableClassHolderSource classes) {
for (String className : classes.getClassNames()) { for (String className : classes.getClassNames()) {

View File

@ -25,12 +25,13 @@ import org.teavm.model.MethodReference;
public class JavascriptEntryPoint { public class JavascriptEntryPoint {
private String publicName; private String publicName;
MethodReference reference; MethodReference reference;
private MethodDependency graph; private MethodDependency method;
JavascriptEntryPoint(String publicName, MethodReference reference, MethodDependency graph) { JavascriptEntryPoint(String publicName, MethodReference reference, MethodDependency method) {
this.publicName = publicName; this.publicName = publicName;
this.reference = reference; this.reference = reference;
this.graph = graph; this.method = method;
method.use();
} }
String getPublicName() { String getPublicName() {
@ -41,7 +42,7 @@ public class JavascriptEntryPoint {
if (argument > reference.parameterCount()) { if (argument > reference.parameterCount()) {
throw new IllegalArgumentException("Illegal argument #" + argument + " of " + reference.parameterCount()); throw new IllegalArgumentException("Illegal argument #" + argument + " of " + reference.parameterCount());
} }
graph.getVariable(argument).propagate(type); method.getVariable(argument).propagate(type);
return this; return this;
} }
} }

View File

@ -20,7 +20,7 @@ package org.teavm.model;
* @author Alexey Andreev * @author Alexey Andreev
*/ */
public interface AnnotationContainerReader { public interface AnnotationContainerReader {
AnnotationHolder get(String type); AnnotationReader get(String type);
Iterable<? extends AnnotationReader> all(); Iterable<? extends AnnotationReader> all();
} }

View File

@ -17,9 +17,9 @@ package org.teavm.optimization;
import java.util.HashSet; import java.util.HashSet;
import java.util.Set; import java.util.Set;
import org.teavm.dependency.DependencyInformation; import org.teavm.dependency.DependencyInfo;
import org.teavm.dependency.DependencyMethodInformation; import org.teavm.dependency.MethodDependencyInfo;
import org.teavm.dependency.DependencyValueInformation; import org.teavm.dependency.ValueDependencyInfo;
import org.teavm.model.*; import org.teavm.model.*;
import org.teavm.model.instructions.InvocationType; import org.teavm.model.instructions.InvocationType;
import org.teavm.model.instructions.InvokeInstruction; import org.teavm.model.instructions.InvokeInstruction;
@ -29,16 +29,16 @@ import org.teavm.model.instructions.InvokeInstruction;
* @author Alexey Andreev <konsoletyper@gmail.com> * @author Alexey Andreev <konsoletyper@gmail.com>
*/ */
public class Devirtualization { public class Devirtualization {
private DependencyInformation dependency; private DependencyInfo dependency;
private ClassReaderSource classSource; private ClassReaderSource classSource;
public Devirtualization(DependencyInformation dependency, ClassReaderSource classSource) { public Devirtualization(DependencyInfo dependency, ClassReaderSource classSource) {
this.dependency = dependency; this.dependency = dependency;
this.classSource = classSource; this.classSource = classSource;
} }
public void apply(MethodHolder method) { public void apply(MethodHolder method) {
DependencyMethodInformation methodDep = dependency.getMethod(method.getReference()); MethodDependencyInfo methodDep = dependency.getMethod(method.getReference());
if (methodDep == null) { if (methodDep == null) {
return; return;
} }
@ -53,7 +53,7 @@ public class Devirtualization {
if (invoke.getType() != InvocationType.VIRTUAL) { if (invoke.getType() != InvocationType.VIRTUAL) {
continue; continue;
} }
DependencyValueInformation var = methodDep.getVariable(invoke.getInstance().getIndex()); ValueDependencyInfo var = methodDep.getVariable(invoke.getInstance().getIndex());
Set<MethodReference> implementations = getImplementations(var.getTypes(), Set<MethodReference> implementations = getImplementations(var.getTypes(),
invoke.getMethod().getDescriptor()); invoke.getMethod().getDescriptor());
if (implementations.size() == 1) { if (implementations.size() == 1) {

View File

@ -48,44 +48,44 @@ public class JavaScriptBodyDependency implements DependencyListener {
} }
@Override @Override
public void methodAchieved(DependencyChecker dependencyChecker, MethodDependency graph) { public void methodAchieved(DependencyChecker dependencyChecker, MethodDependency method) {
if (graph.isMissing()) { if (method.isMissing()) {
return; return;
} }
AnnotationReader annot = graph.getMethod().getAnnotations().get(JavaScriptBody.class.getName()); AnnotationReader annot = method.getMethod().getAnnotations().get(JavaScriptBody.class.getName());
if (annot != null) { if (annot != null) {
includeDefaultDependencies(dependencyChecker); includeDefaultDependencies(dependencyChecker);
AnnotationValue javacall = annot.getValue("javacall"); AnnotationValue javacall = annot.getValue("javacall");
if (graph.getResult() != null) { if (method.getResult() != null) {
allClassesNode.connect(graph.getResult()); allClassesNode.connect(method.getResult());
allClassesNode.addConsumer(new OneDirectionalConnection(graph.getResult().getArrayItem())); allClassesNode.addConsumer(new OneDirectionalConnection(method.getResult().getArrayItem()));
allClassesNode.addConsumer(new OneDirectionalConnection(graph.getResult().getArrayItem() allClassesNode.addConsumer(new OneDirectionalConnection(method.getResult().getArrayItem()
.getArrayItem())); .getArrayItem()));
} }
for (int i = 0; i < graph.getParameterCount(); ++i) { for (int i = 0; i < method.getParameterCount(); ++i) {
graph.getVariable(i).connect(allClassesNode); method.getVariable(i).connect(allClassesNode);
allClassesNode.addConsumer(new OneDirectionalConnection(graph.getVariable(i).getArrayItem())); allClassesNode.addConsumer(new OneDirectionalConnection(method.getVariable(i).getArrayItem()));
allClassesNode.addConsumer(new OneDirectionalConnection(graph.getVariable(i).getArrayItem() allClassesNode.addConsumer(new OneDirectionalConnection(method.getVariable(i).getArrayItem()
.getArrayItem())); .getArrayItem()));
} }
if (javacall != null && javacall.getBoolean()) { if (javacall != null && javacall.getBoolean()) {
String body = annot.getValue("body").getString(); String body = annot.getValue("body").getString();
new GeneratorJsCallback(dependencyChecker.getClassSource(), dependencyChecker, graph).parse(body); new GeneratorJsCallback(dependencyChecker, method).parse(body);
} }
} }
} }
private void includeDefaultDependencies(DependencyChecker dependencyChecker) { private void includeDefaultDependencies(DependencyChecker dependencyChecker) {
dependencyChecker.linkMethod(JavaScriptConvGenerator.fromJsMethod, DependencyStack.ROOT); dependencyChecker.linkMethod(JavaScriptConvGenerator.fromJsMethod, DependencyStack.ROOT).use();
dependencyChecker.linkMethod(JavaScriptConvGenerator.toJsMethod, DependencyStack.ROOT); dependencyChecker.linkMethod(JavaScriptConvGenerator.toJsMethod, DependencyStack.ROOT).use();
dependencyChecker.linkMethod(JavaScriptConvGenerator.intValueMethod, DependencyStack.ROOT); dependencyChecker.linkMethod(JavaScriptConvGenerator.intValueMethod, DependencyStack.ROOT).use();
dependencyChecker.linkMethod(JavaScriptConvGenerator.valueOfIntMethod, DependencyStack.ROOT); dependencyChecker.linkMethod(JavaScriptConvGenerator.valueOfIntMethod, DependencyStack.ROOT).use();
dependencyChecker.linkMethod(JavaScriptConvGenerator.booleanValueMethod, DependencyStack.ROOT); dependencyChecker.linkMethod(JavaScriptConvGenerator.booleanValueMethod, DependencyStack.ROOT).use();
dependencyChecker.linkMethod(JavaScriptConvGenerator.valueOfBooleanMethod, DependencyStack.ROOT); dependencyChecker.linkMethod(JavaScriptConvGenerator.valueOfBooleanMethod, DependencyStack.ROOT).use();
} }
@Override @Override
public void fieldAchieved(DependencyChecker dependencyChecker, FieldReference field, DependencyNode node) { public void fieldAchieved(DependencyChecker dependencyChecker, FieldDependency fieldDep) {
} }
private static MethodReader findMethod(ClassReaderSource classSource, String clsName, MethodDescriptor desc) { private static MethodReader findMethod(ClassReaderSource classSource, String clsName, MethodDescriptor desc) {
@ -113,27 +113,25 @@ public class JavaScriptBodyDependency implements DependencyListener {
} }
private class GeneratorJsCallback extends JsCallback { private class GeneratorJsCallback extends JsCallback {
private ClassReaderSource classSource;
private DependencyChecker dependencyChecker; private DependencyChecker dependencyChecker;
private MethodDependency caller; private MethodDependency caller;
public GeneratorJsCallback(ClassReaderSource classSource, DependencyChecker dependencyChecker, public GeneratorJsCallback(DependencyChecker dependencyChecker, MethodDependency caller) {
MethodDependency caller) {
this.classSource = classSource;
this.dependencyChecker = dependencyChecker; this.dependencyChecker = dependencyChecker;
this.caller = caller; this.caller = caller;
} }
@Override protected CharSequence callMethod(String ident, String fqn, String method, String params) { @Override protected CharSequence callMethod(String ident, String fqn, String method, String params) {
MethodDescriptor desc = MethodDescriptor.parse(method + params + "V"); MethodDescriptor desc = MethodDescriptor.parse(method + params + "V");
MethodReader reader = findMethod(classSource, fqn, desc); MethodReader reader = findMethod(dependencyChecker.getClassSource(), params, desc);
if (reader != null) { MethodReference ref = reader != null ? reader.getReference() : new MethodReference(fqn, desc);
MethodDependency methodDep = dependencyChecker.linkMethod(ref, caller.getStack());
if (!methodDep.isMissing()) {
if (reader.hasModifier(ElementModifier.STATIC) || reader.hasModifier(ElementModifier.FINAL)) { if (reader.hasModifier(ElementModifier.STATIC) || reader.hasModifier(ElementModifier.FINAL)) {
MethodDependency graph = dependencyChecker.linkMethod(reader.getReference(), caller.getStack()); methodDep.use();
for (int i = 0; i <= graph.getParameterCount(); ++i) { for (int i = 0; i <= methodDep.getParameterCount(); ++i) {
allClassesNode.connect(graph.getVariable(i)); allClassesNode.connect(methodDep.getVariable(i));
} }
} else { } else {
allClassesNode.addConsumer(new VirtualCallbackConsumer(dependencyChecker, allClassesNode.addConsumer(new VirtualCallbackConsumer(dependencyChecker, reader, caller));
reader.getReference(), caller));
} }
} }
return ""; return "";
@ -141,22 +139,46 @@ public class JavaScriptBodyDependency implements DependencyListener {
} }
private class VirtualCallbackConsumer implements DependencyConsumer { private class VirtualCallbackConsumer implements DependencyConsumer {
private String superClass;
private DependencyChecker dependencyChecker; private DependencyChecker dependencyChecker;
private MethodReference superMethod; private MethodReader superMethod;
private ClassReader superClass;
private MethodDependency caller; private MethodDependency caller;
public VirtualCallbackConsumer(DependencyChecker dependencyChecker, MethodReference superMethod, public VirtualCallbackConsumer(DependencyChecker dependencyChecker, MethodReader superMethod,
MethodDependency caller) { MethodDependency caller) {
this.dependencyChecker = dependencyChecker; this.dependencyChecker = dependencyChecker;
this.superMethod = superMethod; this.superMethod = superMethod;
this.caller = caller; this.caller = caller;
this.superClass = dependencyChecker.getClassSource().get(superMethod.getOwnerName());
} }
@Override public void consume(String type) { @Override public void consume(String type) {
MethodReference method = new MethodReference(type, superMethod.getDescriptor()); if (!isAssignableFrom(superClass, type)) {
MethodDependency graph = dependencyChecker.linkMethod(method, caller.getStack()); return;
for (int i = 0; i < graph.getParameterCount(); ++i) { }
allClassesNode.connect(graph.getVariable(i)); MethodReference methodRef = new MethodReference(type, superMethod.getDescriptor());
} MethodDependency method = dependencyChecker.linkMethod(methodRef, caller.getStack());
method.use();
for (int i = 0; i < method.getParameterCount(); ++i) {
allClassesNode.connect(method.getVariable(i));
}
}
private boolean isAssignableFrom(ClassReader supertype, String subtypeName) {
ClassReaderSource classSource = dependencyChecker.getClassSource();
if (supertype.getName().equals(subtypeName)) {
return true;
}
ClassReader subtype = classSource.get(subtypeName);
if (subtype == null) {
return false;
}
if (isAssignableFrom(supertype, subtype.getParent())) {
return true;
}
for (String iface : subtype.getInterfaces()) {
if (isAssignableFrom(supertype, iface)) {
return true;
}
}
return false;
} }
} }
} }

View File

@ -94,11 +94,11 @@ public class JSNativeGenerator implements Generator, Injector, DependencyPlugin
} }
@Override @Override
public void methodAchieved(final DependencyChecker checker, final MethodDependency graph) { public void methodAchieved(final DependencyChecker checker, final MethodDependency method) {
for (int i = 0; i < graph.getReference().parameterCount(); ++i) { for (int i = 0; i < method.getReference().parameterCount(); ++i) {
graph.getVariable(i).addConsumer(new DependencyConsumer() { method.getVariable(i).addConsumer(new DependencyConsumer() {
@Override public void consume(String type) { @Override public void consume(String type) {
achieveFunctorMethods(checker, type, graph); achieveFunctorMethods(checker, type, method);
} }
}); });
} }
@ -111,7 +111,7 @@ public class JSNativeGenerator implements Generator, Injector, DependencyPlugin
ClassReader cls = checker.getClassSource().get(type); ClassReader cls = checker.getClassSource().get(type);
if (cls != null) { if (cls != null) {
for (MethodReader method : cls.getMethods()) { for (MethodReader method : cls.getMethods()) {
checker.linkMethod(method.getReference(), caller.getStack()); checker.linkMethod(method.getReference(), caller.getStack()).use();
} }
} }
} }