mirror of
https://github.com/Eaglercraft-TeaVM-Fork/eagler-teavm.git
synced 2024-12-22 08:14:09 -08:00
Adds displaying of full dependency stack for each missing item
This commit is contained in:
parent
6c903a916c
commit
ee28309008
|
@ -21,6 +21,7 @@ import org.teavm.classlib.impl.unicode.UnicodeSupport;
|
|||
import org.teavm.codegen.SourceWriter;
|
||||
import org.teavm.dependency.DependencyChecker;
|
||||
import org.teavm.dependency.DependencyPlugin;
|
||||
import org.teavm.dependency.MethodGraph;
|
||||
import org.teavm.javascript.ni.Generator;
|
||||
import org.teavm.javascript.ni.GeneratorContext;
|
||||
import org.teavm.model.MethodReference;
|
||||
|
@ -48,10 +49,10 @@ public class CharacterNativeGenerator implements Generator, DependencyPlugin {
|
|||
}
|
||||
|
||||
@Override
|
||||
public void methodAchieved(DependencyChecker checker, MethodReference method) {
|
||||
switch (method.getName()) {
|
||||
public void methodAchieved(DependencyChecker checker, MethodGraph graph) {
|
||||
switch (graph.getReference().getName()) {
|
||||
case "obtainDigitMapping":
|
||||
achieveObtainDigitMapping(checker, method);
|
||||
achieveObtainDigitMapping(graph);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -71,7 +72,7 @@ public class CharacterNativeGenerator implements Generator, DependencyPlugin {
|
|||
.append("\");").softNewLine();
|
||||
}
|
||||
|
||||
private void achieveObtainDigitMapping(DependencyChecker checker, MethodReference method) {
|
||||
checker.attachMethodGraph(method).getResult().propagate("java.lang.String");
|
||||
private void achieveObtainDigitMapping(MethodGraph graph) {
|
||||
graph.getResult().propagate("java.lang.String");
|
||||
}
|
||||
}
|
||||
|
|
|
@ -61,16 +61,16 @@ public class ObjectNativeGenerator implements Generator, Injector, DependencyPlu
|
|||
}
|
||||
|
||||
@Override
|
||||
public void methodAchieved(DependencyChecker checker, MethodReference method) {
|
||||
switch (method.getDescriptor().getName()) {
|
||||
public void methodAchieved(DependencyChecker checker, MethodGraph graph) {
|
||||
switch (graph.getReference().getName()) {
|
||||
case "clone":
|
||||
achieveClone(checker, method);
|
||||
achieveClone(graph);
|
||||
break;
|
||||
case "getClass":
|
||||
achieveGetClass(checker, method);
|
||||
achieveGetClass(checker, graph);
|
||||
break;
|
||||
case "wrap":
|
||||
achieveWrap(checker, method);
|
||||
achieveWrap(graph);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -86,12 +86,12 @@ public class ObjectNativeGenerator implements Generator, Injector, DependencyPlu
|
|||
writer.append(".constructor)");
|
||||
}
|
||||
|
||||
private void achieveGetClass(DependencyChecker checker, MethodReference method) {
|
||||
private void achieveGetClass(DependencyChecker checker, MethodGraph graph) {
|
||||
String classClass = "java.lang.Class";
|
||||
MethodReference initMethod = new MethodReference(classClass, new MethodDescriptor("createNew",
|
||||
ValueType.object(classClass)));
|
||||
checker.addEntryPoint(initMethod);
|
||||
checker.attachMethodGraph(method).getResult().propagate("java.lang.Class");
|
||||
graph.getResult().propagate("java.lang.Class");
|
||||
}
|
||||
|
||||
private void generateHashCode(GeneratorContext context, SourceWriter writer) throws IOException {
|
||||
|
@ -107,8 +107,7 @@ public class ObjectNativeGenerator implements Generator, Injector, DependencyPlu
|
|||
writer.append("return copy;").softNewLine();
|
||||
}
|
||||
|
||||
private void achieveClone(DependencyChecker checker, MethodReference method) {
|
||||
MethodGraph graph = checker.attachMethodGraph(method);
|
||||
private void achieveClone(MethodGraph graph) {
|
||||
graph.getVariable(0).connect(graph.getResult());
|
||||
}
|
||||
|
||||
|
@ -116,8 +115,7 @@ public class ObjectNativeGenerator implements Generator, Injector, DependencyPlu
|
|||
context.writeExpr(context.getArgument(0));
|
||||
}
|
||||
|
||||
private void achieveWrap(DependencyChecker checker, MethodReference method) {
|
||||
MethodGraph graph = checker.attachMethodGraph(method);
|
||||
private void achieveWrap(MethodGraph graph) {
|
||||
graph.getVariable(1).connect(graph.getResult());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -43,10 +43,10 @@ public class SystemNativeGenerator implements Generator, DependencyPlugin {
|
|||
}
|
||||
|
||||
@Override
|
||||
public void methodAchieved(DependencyChecker checker, MethodReference method) {
|
||||
switch (method.getName()) {
|
||||
public void methodAchieved(DependencyChecker checker, MethodGraph graph) {
|
||||
switch (graph.getReference().getName()) {
|
||||
case "doArrayCopy":
|
||||
achieveArrayCopy(checker, method);
|
||||
achieveArrayCopy(graph);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -66,8 +66,7 @@ public class SystemNativeGenerator implements Generator, DependencyPlugin {
|
|||
writer.append("return Long_fromNumber(new Date().getTime());").softNewLine();
|
||||
}
|
||||
|
||||
private void achieveArrayCopy(DependencyChecker checker, MethodReference method) {
|
||||
MethodGraph graph = checker.attachMethodGraph(method);
|
||||
private void achieveArrayCopy(MethodGraph graph) {
|
||||
DependencyNode src = graph.getVariable(1);
|
||||
DependencyNode dest = graph.getVariable(3);
|
||||
src.getArrayItem().connect(dest.getArrayItem());
|
||||
|
|
|
@ -33,9 +33,9 @@ import org.teavm.model.ValueType;
|
|||
*/
|
||||
public class ArrayNativeGenerator implements Generator, DependencyPlugin {
|
||||
@Override
|
||||
public void methodAchieved(DependencyChecker checker, MethodReference method) {
|
||||
if (method.getName().equals("getLength")) {
|
||||
achieveGetLength(checker, method);
|
||||
public void methodAchieved(DependencyChecker checker, MethodGraph graph) {
|
||||
if (graph.getReference().getName().equals("getLength")) {
|
||||
achieveGetLength(checker, graph);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -59,8 +59,7 @@ public class ArrayNativeGenerator implements Generator, DependencyPlugin {
|
|||
writer.append("return " + array + ".data.length;").softNewLine();
|
||||
}
|
||||
|
||||
private void achieveGetLength(final DependencyChecker checker, MethodReference methodRef) {
|
||||
final MethodGraph graph = checker.attachMethodGraph(methodRef);
|
||||
private void achieveGetLength(final DependencyChecker checker, final MethodGraph graph) {
|
||||
graph.getVariable(1).addConsumer(new DependencyConsumer() {
|
||||
@Override public void consume(String type) {
|
||||
if (!type.startsWith("[")) {
|
||||
|
|
|
@ -33,14 +33,17 @@ public class DependencyChecker implements DependencyInformation {
|
|||
private ClassLoader classLoader;
|
||||
private FiniteExecutor executor;
|
||||
private ConcurrentMap<MethodReference, Object> abstractMethods = new ConcurrentHashMap<>();
|
||||
private ConcurrentMap<MethodReference, DependencyStack> stacks = new ConcurrentHashMap<>();
|
||||
private ConcurrentMap<FieldReference, DependencyStack> fieldStacks = new ConcurrentHashMap<>();
|
||||
private ConcurrentMap<String, DependencyStack> classStacks = new ConcurrentHashMap<>();
|
||||
private ConcurrentCachedMapper<MethodReference, MethodGraph> methodCache;
|
||||
private ConcurrentCachedMapper<FieldReference, DependencyNode> fieldCache;
|
||||
private ConcurrentMap<String, Object> achievableClasses = new ConcurrentHashMap<>();
|
||||
private ConcurrentMap<String, Object> initializedClasses = new ConcurrentHashMap<>();
|
||||
private List<DependencyListener> listeners = new ArrayList<>();
|
||||
Set<MethodReference> missingMethods = new HashSet<>();
|
||||
Set<String> missingClasses = new HashSet<>();
|
||||
Set<FieldReference> missingFields = new HashSet<>();
|
||||
ConcurrentMap<MethodReference, DependencyStack> missingMethods = new ConcurrentHashMap<>();
|
||||
ConcurrentMap<String, DependencyStack> missingClasses = new ConcurrentHashMap<>();
|
||||
ConcurrentMap<FieldReference, DependencyStack> missingFields = new ConcurrentHashMap<>();
|
||||
|
||||
public DependencyChecker(ClassHolderSource classSource, ClassLoader classLoader) {
|
||||
this(classSource, classLoader, new SimpleFiniteExecutor());
|
||||
|
@ -52,26 +55,28 @@ public class DependencyChecker implements DependencyInformation {
|
|||
this.executor = executor;
|
||||
methodCache = new ConcurrentCachedMapper<>(new Mapper<MethodReference, MethodGraph>() {
|
||||
@Override public MethodGraph map(MethodReference preimage) {
|
||||
return createMethodGraph(preimage);
|
||||
return createMethodGraph(preimage, stacks.get(preimage));
|
||||
}
|
||||
});
|
||||
fieldCache = new ConcurrentCachedMapper<>(new Mapper<FieldReference, DependencyNode>() {
|
||||
@Override public DependencyNode map(FieldReference preimage) {
|
||||
return createFieldNode(preimage);
|
||||
return createFieldNode(preimage, fieldStacks.get(preimage));
|
||||
}
|
||||
});
|
||||
methodCache.addKeyListener(new KeyListener<MethodReference>() {
|
||||
@Override public void keyAdded(MethodReference key) {
|
||||
MethodGraph graph = methodCache.getKnown(key);
|
||||
for (DependencyListener listener : listeners) {
|
||||
listener.methodAchieved(DependencyChecker.this, key);
|
||||
listener.methodAchieved(DependencyChecker.this, graph);
|
||||
}
|
||||
activateDependencyPlugin(key);
|
||||
activateDependencyPlugin(graph);
|
||||
}
|
||||
});
|
||||
fieldCache.addKeyListener(new KeyListener<FieldReference>() {
|
||||
@Override public void keyAdded(FieldReference key) {
|
||||
DependencyNode node = fieldCache.getKnown(key);
|
||||
for (DependencyListener listener : listeners) {
|
||||
listener.fieldAchieved(DependencyChecker.this, key);
|
||||
listener.fieldAchieved(DependencyChecker.this, key, node);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
@ -100,7 +105,7 @@ public class DependencyChecker implements DependencyInformation {
|
|||
if (parameters.length != argumentTypes.length) {
|
||||
throw new IllegalArgumentException("argumentTypes length does not match the number of method's arguments");
|
||||
}
|
||||
MethodGraph graph = attachMethodGraph(methodRef);
|
||||
MethodGraph graph = attachMethodGraph(methodRef, DependencyStack.ROOT);
|
||||
DependencyNode[] varNodes = graph.getVariables();
|
||||
varNodes[0].propagate(methodRef.getClassName());
|
||||
for (int i = 0; i < argumentTypes.length; ++i) {
|
||||
|
@ -120,7 +125,8 @@ public class DependencyChecker implements DependencyInformation {
|
|||
return executor;
|
||||
}
|
||||
|
||||
boolean achieveClass(String className) {
|
||||
boolean achieveClass(String className, DependencyStack stack) {
|
||||
classStacks.putIfAbsent(className, stack);
|
||||
boolean result = achievableClasses.putIfAbsent(className, dummyValue) == null;
|
||||
if (result) {
|
||||
for (DependencyListener listener : listeners) {
|
||||
|
@ -130,49 +136,56 @@ public class DependencyChecker implements DependencyInformation {
|
|||
return result;
|
||||
}
|
||||
|
||||
public MethodGraph attachMethodGraph(MethodReference methodRef) {
|
||||
public MethodGraph attachMethodGraph(MethodReference methodRef, DependencyStack stack) {
|
||||
stacks.putIfAbsent(methodRef, stack);
|
||||
return methodCache.map(methodRef);
|
||||
}
|
||||
|
||||
public void initClass(String className) {
|
||||
public void initClass(String className, DependencyStack stack) {
|
||||
classStacks.putIfAbsent(className, stack);
|
||||
MethodDescriptor clinitDesc = new MethodDescriptor("<clinit>", ValueType.VOID);
|
||||
while (className != null) {
|
||||
if (initializedClasses.putIfAbsent(className, clinitDesc) != null) {
|
||||
break;
|
||||
}
|
||||
achieveClass(className);
|
||||
achieveInterfaces(className);
|
||||
achieveClass(className, stack);
|
||||
achieveInterfaces(className, stack);
|
||||
ClassHolder cls = classSource.get(className);
|
||||
if (cls == null) {
|
||||
missingClasses.add(className);
|
||||
missingClasses.put(className, stack);
|
||||
return;
|
||||
}
|
||||
if (cls.getMethod(clinitDesc) != null) {
|
||||
attachMethodGraph(new MethodReference(className, clinitDesc));
|
||||
MethodReference methodRef = new MethodReference(className, clinitDesc);
|
||||
attachMethodGraph(methodRef, new DependencyStack(methodRef, stack));
|
||||
}
|
||||
className = cls.getParent();
|
||||
}
|
||||
}
|
||||
|
||||
private void achieveInterfaces(String className) {
|
||||
private void achieveInterfaces(String className, DependencyStack stack) {
|
||||
classStacks.putIfAbsent(className, stack);
|
||||
ClassHolder cls = classSource.get(className);
|
||||
if (cls == null) {
|
||||
missingClasses.add(className);
|
||||
missingClasses.put(className, stack);
|
||||
return;
|
||||
}
|
||||
for (String iface : cls.getInterfaces()) {
|
||||
if (achieveClass(iface)) {
|
||||
achieveInterfaces(iface);
|
||||
if (achieveClass(iface, stack)) {
|
||||
achieveInterfaces(iface, stack);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private MethodGraph createMethodGraph(final MethodReference methodRef) {
|
||||
initClass(methodRef.getClassName());
|
||||
private MethodGraph createMethodGraph(final MethodReference methodRef, DependencyStack stack) {
|
||||
if (stack == null) {
|
||||
stack = DependencyStack.ROOT;
|
||||
}
|
||||
initClass(methodRef.getClassName(), stack);
|
||||
ClassHolder cls = classSource.get(methodRef.getClassName());
|
||||
MethodHolder method;
|
||||
if (cls == null) {
|
||||
missingClasses.add(methodRef.getClassName());
|
||||
missingClasses.put(methodRef.getClassName(), stack);
|
||||
method = null;
|
||||
} else {
|
||||
method = cls.getMethod(methodRef.getDescriptor());
|
||||
|
@ -180,11 +193,11 @@ public class DependencyChecker implements DependencyInformation {
|
|||
while (cls != null) {
|
||||
method = cls.getMethod(methodRef.getDescriptor());
|
||||
if (method != null) {
|
||||
return methodCache.map(new MethodReference(cls.getName(), methodRef.getDescriptor()));
|
||||
return attachMethodGraph(method.getReference(), stack);
|
||||
}
|
||||
cls = cls.getParent() != null ? classSource.get(cls.getParent()) : null;
|
||||
}
|
||||
missingMethods.add(methodRef);
|
||||
missingMethods.put(methodRef, stack);
|
||||
}
|
||||
}
|
||||
ValueType[] arguments = methodRef.getParameterTypes();
|
||||
|
@ -206,7 +219,8 @@ public class DependencyChecker implements DependencyInformation {
|
|||
resultNode.setTag(methodRef + ":RESULT");
|
||||
}
|
||||
}
|
||||
final MethodGraph graph = new MethodGraph(parameterNodes, paramCount, resultNode);
|
||||
stack = new DependencyStack(methodRef, stack);
|
||||
final MethodGraph graph = new MethodGraph(parameterNodes, paramCount, resultNode, stack, methodRef);
|
||||
if (method != null) {
|
||||
final MethodHolder currentMethod = method;
|
||||
executor.execute(new Runnable() {
|
||||
|
@ -242,27 +256,32 @@ public class DependencyChecker implements DependencyInformation {
|
|||
return new HashSet<>(achievableClasses.keySet());
|
||||
}
|
||||
|
||||
@Override
|
||||
public DependencyNode getField(FieldReference fieldRef) {
|
||||
public DependencyNode attachFieldNode(FieldReference fieldRef, DependencyStack stack) {
|
||||
fieldStacks.putIfAbsent(fieldRef, stack);
|
||||
return fieldCache.map(fieldRef);
|
||||
}
|
||||
|
||||
private DependencyNode createFieldNode(FieldReference fieldRef) {
|
||||
initClass(fieldRef.getClassName());
|
||||
@Override
|
||||
public DependencyNode getField(FieldReference fieldRef) {
|
||||
return fieldCache.getKnown(fieldRef);
|
||||
}
|
||||
|
||||
private DependencyNode createFieldNode(FieldReference fieldRef, DependencyStack stack) {
|
||||
initClass(fieldRef.getClassName(), stack);
|
||||
ClassHolder cls = classSource.get(fieldRef.getClassName());
|
||||
if (cls == null) {
|
||||
missingClasses.add(fieldRef.getClassName());
|
||||
missingClasses.put(fieldRef.getClassName(), stack);
|
||||
} else {
|
||||
FieldHolder field = cls.getField(fieldRef.getFieldName());
|
||||
if (field == null) {
|
||||
while (cls != null) {
|
||||
field = cls.getField(fieldRef.getFieldName());
|
||||
if (field != null) {
|
||||
return fieldCache.map(new FieldReference(cls.getName(), fieldRef.getFieldName()));
|
||||
return attachFieldNode(new FieldReference(cls.getName(), fieldRef.getFieldName()), stack);
|
||||
}
|
||||
cls = cls.getParent() != null ? classSource.get(cls.getParent()) : null;
|
||||
}
|
||||
missingFields.add(fieldRef);
|
||||
missingFields.put(fieldRef, stack);
|
||||
}
|
||||
}
|
||||
DependencyNode node = new DependencyNode(this);
|
||||
|
@ -272,7 +291,8 @@ public class DependencyChecker implements DependencyInformation {
|
|||
return node;
|
||||
}
|
||||
|
||||
private void activateDependencyPlugin(MethodReference methodRef) {
|
||||
private void activateDependencyPlugin(MethodGraph graph) {
|
||||
MethodReference methodRef = graph.getReference();
|
||||
ClassHolder cls = classSource.get(methodRef.getClassName());
|
||||
if (cls == null) {
|
||||
return;
|
||||
|
@ -299,10 +319,11 @@ public class DependencyChecker implements DependencyInformation {
|
|||
} catch (IllegalAccessException | InstantiationException e) {
|
||||
throw new RuntimeException("Can't instantiate dependency plugin " + depClassName, e);
|
||||
}
|
||||
plugin.methodAchieved(this, methodRef);
|
||||
plugin.methodAchieved(this, graph);
|
||||
}
|
||||
|
||||
public void addAbstractMethod(MethodReference methodRef) {
|
||||
public void addAbstractMethod(MethodReference methodRef, DependencyStack stack) {
|
||||
stacks.putIfAbsent(methodRef, stack);
|
||||
if (abstractMethods.putIfAbsent(methodRef, methodRef) == null) {
|
||||
String className = methodRef.getClassName();
|
||||
while (className != null) {
|
||||
|
@ -356,11 +377,17 @@ public class DependencyChecker implements DependencyInformation {
|
|||
return;
|
||||
}
|
||||
List<String> items = new ArrayList<>();
|
||||
items.addAll(missingClasses);
|
||||
for (MethodReference method : missingMethods) {
|
||||
Map<String, DependencyStack> stackMap = new HashMap<>();
|
||||
for (String cls : missingClasses.keySet()) {
|
||||
stackMap.put(cls, missingClasses.get(cls));
|
||||
items.add(cls);
|
||||
}
|
||||
for (MethodReference method : missingMethods.keySet()) {
|
||||
stackMap.put(method.toString(), missingMethods.get(method));
|
||||
items.add(method.toString());
|
||||
}
|
||||
for (FieldReference field : missingFields) {
|
||||
for (FieldReference field : missingFields.keySet()) {
|
||||
stackMap.put(field.toString(), missingFields.get(field));
|
||||
items.add(field.toString());
|
||||
}
|
||||
Collections.sort(items);
|
||||
|
@ -368,6 +395,15 @@ public class DependencyChecker implements DependencyInformation {
|
|||
sb.append("Can't compile due to the following items missing:\n");
|
||||
for (String item : items) {
|
||||
sb.append(" ").append(item).append("\n");
|
||||
DependencyStack stack = stackMap.get(item);
|
||||
if (stack == null) {
|
||||
sb.append(" at unknown location\n");
|
||||
}
|
||||
while (stack.getMethod() != null) {
|
||||
sb.append(" at " + stack.getMethod() + "\n");
|
||||
stack = stack.getCause();
|
||||
}
|
||||
sb.append('\n');
|
||||
}
|
||||
throw new IllegalStateException(sb.toString());
|
||||
}
|
||||
|
|
|
@ -29,6 +29,7 @@ class DependencyGraphBuilder {
|
|||
private DependencyNode[] nodes;
|
||||
private DependencyNode resultNode;
|
||||
private Program program;
|
||||
private DependencyStack callerStack;
|
||||
|
||||
public DependencyGraphBuilder(DependencyChecker dependencyChecker) {
|
||||
this.dependencyChecker = dependencyChecker;
|
||||
|
@ -38,6 +39,7 @@ class DependencyGraphBuilder {
|
|||
if (method.getProgram().basicBlockCount() == 0) {
|
||||
return;
|
||||
}
|
||||
callerStack = graph.getStack();
|
||||
program = method.getProgram();
|
||||
if (DependencyChecker.shouldLog) {
|
||||
System.out.println("Method achieved: " + method.getReference());
|
||||
|
@ -64,14 +66,17 @@ class DependencyGraphBuilder {
|
|||
private final DependencyChecker checker;
|
||||
private final DependencyNode[] parameters;
|
||||
private final DependencyNode result;
|
||||
private final DependencyStack stack;
|
||||
|
||||
public VirtualCallPropagationListener(DependencyNode node, MethodDescriptor methodDesc,
|
||||
DependencyChecker checker, DependencyNode[] parameters, DependencyNode result) {
|
||||
DependencyChecker checker, DependencyNode[] parameters, DependencyNode result,
|
||||
DependencyStack stack) {
|
||||
this.node = node;
|
||||
this.methodDesc = methodDesc;
|
||||
this.checker = checker;
|
||||
this.parameters = parameters;
|
||||
this.result = result;
|
||||
this.stack = stack;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -88,7 +93,7 @@ class DependencyGraphBuilder {
|
|||
if (method == null) {
|
||||
return;
|
||||
}
|
||||
MethodGraph targetGraph = checker.attachMethodGraph(methodRef);
|
||||
MethodGraph targetGraph = checker.attachMethodGraph(methodRef, stack);
|
||||
DependencyNode[] targetParams = targetGraph.getVariables();
|
||||
for (int i = 0; i < parameters.length; ++i) {
|
||||
parameters[i].connect(targetParams[i]);
|
||||
|
@ -137,7 +142,7 @@ class DependencyGraphBuilder {
|
|||
}
|
||||
|
||||
private void invokeSpecial(InvokeInstruction insn) {
|
||||
MethodGraph targetGraph = dependencyChecker.attachMethodGraph(insn.getMethod());
|
||||
MethodGraph targetGraph = dependencyChecker.attachMethodGraph(insn.getMethod(), callerStack);
|
||||
DependencyNode[] targetParams = targetGraph.getVariables();
|
||||
List<Variable> arguments = insn.getArguments();
|
||||
for (int i = 0; i < arguments.size(); ++i) {
|
||||
|
@ -160,8 +165,8 @@ class DependencyGraphBuilder {
|
|||
actualArgs[0] = nodes[insn.getInstance().getIndex()];
|
||||
DependencyConsumer listener = new VirtualCallPropagationListener(nodes[insn.getInstance().getIndex()],
|
||||
insn.getMethod().getDescriptor(), dependencyChecker, actualArgs,
|
||||
insn.getReceiver() != null ? nodes[insn.getReceiver().getIndex()] : null);
|
||||
dependencyChecker.addAbstractMethod(insn.getMethod());
|
||||
insn.getReceiver() != null ? nodes[insn.getReceiver().getIndex()] : null, callerStack);
|
||||
dependencyChecker.addAbstractMethod(insn.getMethod(), callerStack);
|
||||
nodes[insn.getInstance().getIndex()].addConsumer(listener);
|
||||
}
|
||||
|
||||
|
@ -205,14 +210,14 @@ class DependencyGraphBuilder {
|
|||
|
||||
@Override
|
||||
public void visit(PutFieldInstruction insn) {
|
||||
DependencyNode fieldNode = dependencyChecker.getField(insn.getField());
|
||||
DependencyNode fieldNode = dependencyChecker.attachFieldNode(insn.getField(), callerStack);
|
||||
DependencyNode valueNode = nodes[insn.getValue().getIndex()];
|
||||
valueNode.connect(fieldNode);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(GetFieldInstruction insn) {
|
||||
DependencyNode fieldNode = dependencyChecker.getField(insn.getField());
|
||||
DependencyNode fieldNode = dependencyChecker.attachFieldNode(insn.getField(), callerStack);
|
||||
DependencyNode receiverNode = nodes[insn.getReceiver().getIndex()];
|
||||
fieldNode.connect(receiverNode);
|
||||
}
|
||||
|
@ -298,7 +303,7 @@ class DependencyGraphBuilder {
|
|||
public void visit(StringConstantInstruction insn) {
|
||||
nodes[insn.getReceiver().getIndex()].propagate("java.lang.String");
|
||||
dependencyChecker.attachMethodGraph(new MethodReference("java.lang.String", new MethodDescriptor(
|
||||
"<init>", ValueType.arrayOf(ValueType.CHARACTER), ValueType.VOID)));
|
||||
"<init>", ValueType.arrayOf(ValueType.CHARACTER), ValueType.VOID)), callerStack);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -329,7 +334,7 @@ class DependencyGraphBuilder {
|
|||
type = ((ValueType.Array)type).getItemType();
|
||||
}
|
||||
if (type instanceof ValueType.Object) {
|
||||
dependencyChecker.achieveClass(((ValueType.Object)type).getClassName());
|
||||
dependencyChecker.achieveClass(((ValueType.Object)type).getClassName(), callerStack);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -339,7 +344,7 @@ class DependencyGraphBuilder {
|
|||
|
||||
@Override
|
||||
public void visit(InitClassInstruction insn) {
|
||||
dependencyChecker.initClass(insn.getClassName());
|
||||
dependencyChecker.initClass(insn.getClassName(), callerStack);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
|
|
@ -16,7 +16,6 @@
|
|||
package org.teavm.dependency;
|
||||
|
||||
import org.teavm.model.FieldReference;
|
||||
import org.teavm.model.MethodReference;
|
||||
|
||||
/**
|
||||
*
|
||||
|
@ -27,7 +26,7 @@ public interface DependencyListener {
|
|||
|
||||
void classAchieved(DependencyChecker dependencyChecker, String className);
|
||||
|
||||
void methodAchieved(DependencyChecker dependencyChecker, MethodReference method);
|
||||
void methodAchieved(DependencyChecker dependencyChecker, MethodGraph method);
|
||||
|
||||
void fieldAchieved(DependencyChecker dependencyChecker, FieldReference field);
|
||||
void fieldAchieved(DependencyChecker dependencyChecker, FieldReference field, DependencyNode node);
|
||||
}
|
||||
|
|
|
@ -15,12 +15,10 @@
|
|||
*/
|
||||
package org.teavm.dependency;
|
||||
|
||||
import org.teavm.model.MethodReference;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Alexey Andreev
|
||||
*/
|
||||
public interface DependencyPlugin {
|
||||
void methodAchieved(DependencyChecker checker, MethodReference method);
|
||||
void methodAchieved(DependencyChecker checker, MethodGraph graph);
|
||||
}
|
||||
|
|
|
@ -0,0 +1,67 @@
|
|||
/*
|
||||
* 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.MethodReference;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Alexey Andreev
|
||||
*/
|
||||
public class DependencyStack {
|
||||
public static final DependencyStack ROOT = new DependencyStack();
|
||||
private MethodReference method;
|
||||
private DependencyStack cause;
|
||||
|
||||
private DependencyStack() {
|
||||
}
|
||||
|
||||
public DependencyStack(MethodReference method) {
|
||||
this(method, ROOT);
|
||||
}
|
||||
|
||||
public DependencyStack(MethodReference method, DependencyStack cause) {
|
||||
if (method == null || cause == null) {
|
||||
throw new IllegalArgumentException("Arguments must not be null");
|
||||
}
|
||||
this.method = method;
|
||||
this.cause = cause;
|
||||
}
|
||||
|
||||
public MethodReference getMethod() {
|
||||
return method;
|
||||
}
|
||||
|
||||
public DependencyStack getCause() {
|
||||
return cause;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
DependencyStack stack = this;
|
||||
while (true) {
|
||||
if (stack.method == null) {
|
||||
sb.append(" used by ROOT\n");
|
||||
break;
|
||||
} else {
|
||||
sb.append(" used by " + stack.method);
|
||||
stack = stack.cause;
|
||||
}
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
}
|
|
@ -16,6 +16,7 @@
|
|||
package org.teavm.dependency;
|
||||
|
||||
import java.util.Arrays;
|
||||
import org.teavm.model.MethodReference;
|
||||
|
||||
/**
|
||||
*
|
||||
|
@ -25,11 +26,16 @@ public class MethodGraph implements DependencyMethodInformation {
|
|||
private DependencyNode[] variableNodes;
|
||||
private int parameterCount;
|
||||
private DependencyNode resultNode;
|
||||
private DependencyStack stack;
|
||||
private MethodReference reference;
|
||||
|
||||
MethodGraph(DependencyNode[] variableNodes, int parameterCount, DependencyNode resultNode) {
|
||||
MethodGraph(DependencyNode[] variableNodes, int parameterCount, DependencyNode resultNode,
|
||||
DependencyStack stack, MethodReference reference) {
|
||||
this.variableNodes = Arrays.copyOf(variableNodes, variableNodes.length);
|
||||
this.parameterCount = parameterCount;
|
||||
this.resultNode = resultNode;
|
||||
this.stack = stack;
|
||||
this.reference = reference;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -56,4 +62,12 @@ public class MethodGraph implements DependencyMethodInformation {
|
|||
public DependencyNode getResult() {
|
||||
return resultNode;
|
||||
}
|
||||
|
||||
public DependencyStack getStack() {
|
||||
return stack;
|
||||
}
|
||||
|
||||
public MethodReference getReference() {
|
||||
return reference;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -22,9 +22,12 @@ import org.teavm.common.FiniteExecutor;
|
|||
import org.teavm.dependency.DependencyChecker;
|
||||
import org.teavm.dependency.DependencyInformation;
|
||||
import org.teavm.dependency.DependencyListener;
|
||||
import org.teavm.dependency.DependencyStack;
|
||||
import org.teavm.javascript.ast.ClassNode;
|
||||
import org.teavm.model.*;
|
||||
import org.teavm.model.util.*;
|
||||
import org.teavm.model.util.ListingBuilder;
|
||||
import org.teavm.model.util.ProgramUtils;
|
||||
import org.teavm.model.util.RegisterAllocator;
|
||||
import org.teavm.optimization.ClassSetOptimizer;
|
||||
import org.teavm.optimization.Devirtualization;
|
||||
|
||||
|
@ -88,7 +91,7 @@ public class JavascriptBuilder implements JavascriptBuilderHost {
|
|||
"for method " + ref);
|
||||
}
|
||||
JavascriptEntryPoint entryPoint = new JavascriptEntryPoint(name, ref,
|
||||
dependencyChecker.attachMethodGraph(ref));
|
||||
dependencyChecker.attachMethodGraph(ref, DependencyStack.ROOT));
|
||||
entryPoints.put(name, entryPoint);
|
||||
return entryPoint;
|
||||
}
|
||||
|
@ -117,9 +120,9 @@ public class JavascriptBuilder implements JavascriptBuilderHost {
|
|||
builder.setMinified(minifying);
|
||||
SourceWriter sourceWriter = builder.build(writer);
|
||||
dependencyChecker.attachMethodGraph(new MethodReference("java.lang.Class", new MethodDescriptor("createNew",
|
||||
ValueType.object("java.lang.Class"))));
|
||||
ValueType.object("java.lang.Class"))), DependencyStack.ROOT);
|
||||
dependencyChecker.attachMethodGraph(new MethodReference("java.lang.String", new MethodDescriptor("<init>",
|
||||
ValueType.arrayOf(ValueType.CHARACTER), ValueType.VOID)));
|
||||
ValueType.arrayOf(ValueType.CHARACTER), ValueType.VOID)), DependencyStack.ROOT);
|
||||
executor.complete();
|
||||
dependencyChecker.checkForMissingItems();
|
||||
ListableClassHolderSource classSet = dependencyChecker.cutUnachievableClasses();
|
||||
|
|
|
@ -48,14 +48,13 @@ public class JavaScriptBodyDependency implements DependencyListener {
|
|||
}
|
||||
|
||||
@Override
|
||||
public void methodAchieved(DependencyChecker dependencyChecker, MethodReference methodRef) {
|
||||
ClassHolder cls = dependencyChecker.getClassSource().get(methodRef.getClassName());
|
||||
MethodHolder method = cls.getMethod(methodRef.getDescriptor());
|
||||
public void methodAchieved(DependencyChecker dependencyChecker, MethodGraph graph) {
|
||||
ClassHolder cls = dependencyChecker.getClassSource().get(graph.getReference().getClassName());
|
||||
MethodHolder method = cls.getMethod(graph.getReference().getDescriptor());
|
||||
AnnotationReader annot = method.getAnnotations().get(JavaScriptBody.class.getName());
|
||||
if (annot != null) {
|
||||
includeDefaultDependencies(dependencyChecker);
|
||||
AnnotationValue javacall = annot.getValue("javacall");
|
||||
MethodGraph graph = dependencyChecker.attachMethodGraph(methodRef);
|
||||
if (graph.getResult() != null) {
|
||||
allClassesNode.connect(graph.getResult());
|
||||
allClassesNode.addConsumer(new OneDirectionalConnection(graph.getResult().getArrayItem()));
|
||||
|
@ -70,20 +69,20 @@ public class JavaScriptBodyDependency implements DependencyListener {
|
|||
}
|
||||
if (javacall != null && javacall.getBoolean()) {
|
||||
String body = annot.getValue("body").getString();
|
||||
new GeneratorJsCallback(dependencyChecker.getClassSource(), dependencyChecker).parse(body);
|
||||
new GeneratorJsCallback(dependencyChecker.getClassSource(), dependencyChecker, graph).parse(body);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void includeDefaultDependencies(DependencyChecker dependencyChecker) {
|
||||
dependencyChecker.attachMethodGraph(JavaScriptConvGenerator.fromJsMethod);
|
||||
dependencyChecker.attachMethodGraph(JavaScriptConvGenerator.toJsMethod);
|
||||
dependencyChecker.attachMethodGraph(JavaScriptConvGenerator.intValueMethod);
|
||||
dependencyChecker.attachMethodGraph(JavaScriptConvGenerator.valueOfIntMethod);
|
||||
dependencyChecker.attachMethodGraph(JavaScriptConvGenerator.fromJsMethod, DependencyStack.ROOT);
|
||||
dependencyChecker.attachMethodGraph(JavaScriptConvGenerator.toJsMethod, DependencyStack.ROOT);
|
||||
dependencyChecker.attachMethodGraph(JavaScriptConvGenerator.intValueMethod, DependencyStack.ROOT);
|
||||
dependencyChecker.attachMethodGraph(JavaScriptConvGenerator.valueOfIntMethod, DependencyStack.ROOT);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void fieldAchieved(DependencyChecker dependencyChecker, FieldReference field) {
|
||||
public void fieldAchieved(DependencyChecker dependencyChecker, FieldReference field, DependencyNode node) {
|
||||
}
|
||||
|
||||
private static MethodReader findMethod(ClassReaderSource classSource, String clsName, MethodDescriptor desc) {
|
||||
|
@ -113,21 +112,25 @@ public class JavaScriptBodyDependency implements DependencyListener {
|
|||
private class GeneratorJsCallback extends JsCallback {
|
||||
private ClassReaderSource classSource;
|
||||
private DependencyChecker dependencyChecker;
|
||||
public GeneratorJsCallback(ClassReaderSource classSource, DependencyChecker dependencyChecker) {
|
||||
private MethodGraph caller;
|
||||
public GeneratorJsCallback(ClassReaderSource classSource, DependencyChecker dependencyChecker,
|
||||
MethodGraph caller) {
|
||||
this.classSource = classSource;
|
||||
this.dependencyChecker = dependencyChecker;
|
||||
this.caller = caller;
|
||||
}
|
||||
@Override protected CharSequence callMethod(String ident, String fqn, String method, String params) {
|
||||
MethodDescriptor desc = MethodDescriptor.parse(method + params + "V");
|
||||
MethodReader reader = findMethod(classSource, fqn, desc);
|
||||
if (reader != null) {
|
||||
if (reader.hasModifier(ElementModifier.STATIC) || reader.hasModifier(ElementModifier.FINAL)) {
|
||||
MethodGraph graph = dependencyChecker.attachMethodGraph(reader.getReference());
|
||||
MethodGraph graph = dependencyChecker.attachMethodGraph(reader.getReference(), caller.getStack());
|
||||
for (int i = 0; i <= graph.getParameterCount(); ++i) {
|
||||
allClassesNode.connect(graph.getVariable(i));
|
||||
}
|
||||
} else {
|
||||
allClassesNode.addConsumer(new VirtualCallbackConsumer(classSource, dependencyChecker, desc));
|
||||
allClassesNode.addConsumer(new VirtualCallbackConsumer(classSource, dependencyChecker, desc,
|
||||
caller));
|
||||
}
|
||||
}
|
||||
return "";
|
||||
|
@ -138,16 +141,18 @@ public class JavaScriptBodyDependency implements DependencyListener {
|
|||
private ClassReaderSource classSource;
|
||||
private DependencyChecker dependencyChecker;
|
||||
private MethodDescriptor desc;
|
||||
private MethodGraph caller;
|
||||
public VirtualCallbackConsumer(ClassReaderSource classSource, DependencyChecker dependencyChecker,
|
||||
MethodDescriptor desc) {
|
||||
MethodDescriptor desc, MethodGraph caller) {
|
||||
this.classSource = classSource;
|
||||
this.dependencyChecker = dependencyChecker;
|
||||
this.desc = desc;
|
||||
this.caller = caller;
|
||||
}
|
||||
@Override public void consume(String type) {
|
||||
MethodReader reader = findMethod(classSource, type, desc);
|
||||
if (reader != null) {
|
||||
MethodGraph graph = dependencyChecker.attachMethodGraph(reader.getReference());
|
||||
MethodGraph graph = dependencyChecker.attachMethodGraph(reader.getReference(), caller.getStack());
|
||||
for (int i = 0; i < graph.getParameterCount(); ++i) {
|
||||
allClassesNode.connect(graph.getVariable(i));
|
||||
}
|
||||
|
|
|
@ -97,22 +97,21 @@ public class JSNativeGenerator implements Generator, Injector, DependencyPlugin
|
|||
}
|
||||
|
||||
@Override
|
||||
public void methodAchieved(final DependencyChecker checker, MethodReference method) {
|
||||
MethodGraph graph = checker.attachMethodGraph(method);
|
||||
for (int i = 0; i < method.parameterCount(); ++i) {
|
||||
public void methodAchieved(final DependencyChecker checker, final MethodGraph graph) {
|
||||
for (int i = 0; i < graph.getReference().parameterCount(); ++i) {
|
||||
graph.getVariable(i).addConsumer(new DependencyConsumer() {
|
||||
@Override public void consume(String type) {
|
||||
achieveFunctorMethods(checker, type);
|
||||
achieveFunctorMethods(checker, type, graph);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
private void achieveFunctorMethods(DependencyChecker checker, String type) {
|
||||
private void achieveFunctorMethods(DependencyChecker checker, String type, MethodGraph caller) {
|
||||
ClassHolder cls = checker.getClassSource().get(type);
|
||||
if (cls != null) {
|
||||
for (MethodHolder method : cls.getMethods()) {
|
||||
checker.attachMethodGraph(method.getReference());
|
||||
checker.attachMethodGraph(method.getReference(), caller.getStack());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue
Block a user