Initial optimization of dependency checker

This commit is contained in:
konsoletyper 2015-03-13 22:09:28 +03:00
parent 1380e7dbf4
commit 2745f1c7f5
14 changed files with 249 additions and 80 deletions

View File

@ -36,14 +36,20 @@ public class DataFlowGraphBuilder implements InstructionReader {
private ObjectIntMap<MethodReference> methodNodes = new ObjectIntOpenHashMap<>(); private ObjectIntMap<MethodReference> methodNodes = new ObjectIntOpenHashMap<>();
private ObjectIntMap<FieldReference> fieldNodes = new ObjectIntOpenHashMap<>(); private ObjectIntMap<FieldReference> fieldNodes = new ObjectIntOpenHashMap<>();
private int[] arrayNodes; private int[] arrayNodes;
private int returnIndex = -1;
private int exceptionIndex;
public void important(int node) { public void important(int node) {
importantNodes.add(node); importantNodes.add(node);
} }
public int[] buildMapping(ProgramReader program, int paramCount) { public int[] buildMapping(ProgramReader program, int paramCount, boolean needsReturn) {
lastIndex = program.variableCount(); lastIndex = program.variableCount();
arrayNodes = new int[lastIndex]; arrayNodes = new int[lastIndex];
if (needsReturn) {
returnIndex = lastIndex++;
}
exceptionIndex = lastIndex++;
Arrays.fill(arrayNodes, -1); Arrays.fill(arrayNodes, -1);
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);
@ -52,6 +58,11 @@ public class DataFlowGraphBuilder implements InstructionReader {
builder.addEdge(incoming.getValue().getIndex(), phi.getReceiver().getIndex()); builder.addEdge(incoming.getValue().getIndex(), phi.getReceiver().getIndex());
} }
} }
for (TryCatchBlockReader tryCatch : block.readTryCatchBlocks()) {
if (tryCatch.getExceptionVariable() != null) {
important(tryCatch.getExceptionVariable().getIndex());
}
}
block.readAllInstructions(this); block.readAllInstructions(this);
} }
Graph graph = builder.build(); Graph graph = builder.build();
@ -76,6 +87,17 @@ public class DataFlowGraphBuilder implements InstructionReader {
importantNodes.add(newCls); importantNodes.add(newCls);
} }
} }
for (int succ : graph.outgoingEdges(i)) {
boolean succImportant = importantNodes.contains(classes.find(succ));
boolean nodeImportant = importantNodes.contains(classes.find(i));
if (succImportant && nodeImportant) {
continue;
}
int newCls = classes.union(succ, i);
if (nodeImportant || succImportant) {
importantNodes.add(newCls);
}
}
} }
int[][] sccs = GraphUtils.findStronglyConnectedComponents(graph, startNodes.getAll()); int[][] sccs = GraphUtils.findStronglyConnectedComponents(graph, startNodes.getAll());
@ -88,7 +110,25 @@ public class DataFlowGraphBuilder implements InstructionReader {
last = last < 0 ? node : classes.union(node, last); last = last < 0 ? node : classes.union(node, last);
} }
} }
return classes.pack(program.variableCount());
int[] classMap = new int[classes.size()];
Arrays.fill(classMap, -1);
int[] result = new int[program.variableCount()];
int classCount = 0;
for (int i = 0; i < program.variableCount(); ++i) {
int cls = classes.find(i);
if (!importantNodes.contains(cls)) {
result[i] = -1;
continue;
}
int packedCls = classMap[cls];
if (packedCls < 0) {
packedCls = classCount++;
classMap[cls] = packedCls;
}
result[i] = packedCls;
}
return result;
} }
@Override @Override
@ -178,14 +218,16 @@ public class DataFlowGraphBuilder implements InstructionReader {
@Override @Override
public void exit(VariableReader valueToReturn) { public void exit(VariableReader valueToReturn) {
if (valueToReturn != null) { if (valueToReturn != null && returnIndex >= 0) {
important(valueToReturn.getIndex()); important(returnIndex);
builder.addEdge(valueToReturn.getIndex(), returnIndex);
} }
} }
@Override @Override
public void raise(VariableReader exception) { public void raise(VariableReader exception) {
important(exception.getIndex()); builder.addEdge(exception.getIndex(), exceptionIndex);
important(exceptionIndex);
} }
@Override @Override
@ -212,13 +254,18 @@ public class DataFlowGraphBuilder implements InstructionReader {
@Override @Override
public void getField(VariableReader receiver, VariableReader instance, FieldReference field, ValueType fieldType) { public void getField(VariableReader receiver, VariableReader instance, FieldReference field, ValueType fieldType) {
if (fieldType instanceof ValueType.Primitive) {
return;
}
int fieldNode = getFieldNode(field); int fieldNode = getFieldNode(field);
builder.addEdge(fieldNode, receiver.getIndex()); builder.addEdge(fieldNode, receiver.getIndex());
} }
@Override @Override
public void putField(VariableReader instance, FieldReference field, VariableReader value) { public void putField(VariableReader instance, FieldReference field, VariableReader value, ValueType fieldType) {
if (fieldType instanceof ValueType.Primitive) {
return;
}
int fieldNode = getFieldNode(field); int fieldNode = getFieldNode(field);
builder.addEdge(value.getIndex(), fieldNode); builder.addEdge(value.getIndex(), fieldNode);
} }
@ -274,9 +321,20 @@ public class DataFlowGraphBuilder implements InstructionReader {
public void invoke(VariableReader receiver, VariableReader instance, MethodReference method, public void invoke(VariableReader receiver, VariableReader instance, MethodReference method,
List<? extends VariableReader> arguments, InvocationType type) { List<? extends VariableReader> arguments, InvocationType type) {
if (receiver != null) { if (receiver != null) {
if (!(method.getReturnType() instanceof ValueType.Primitive)) {
builder.addEdge(getMethodNode(method), receiver.getIndex()); builder.addEdge(getMethodNode(method), receiver.getIndex());
} }
} }
ValueType[] paramTypes = method.getParameterTypes();
for (int i = 0; i < paramTypes.length; ++i) {
if (!(paramTypes[i] instanceof ValueType.Primitive)) {
important(arguments.get(i).getIndex());
}
}
if (instance != null) {
important(instance.getIndex());
}
}
@Override @Override
public void isInstance(VariableReader receiver, VariableReader value, ValueType type) { public void isInstance(VariableReader receiver, VariableReader value, ValueType type) {
@ -293,9 +351,11 @@ public class DataFlowGraphBuilder implements InstructionReader {
@Override @Override
public void monitorEnter(VariableReader objectRef) { public void monitorEnter(VariableReader objectRef) {
important(objectRef.getIndex());
} }
@Override @Override
public void monitorExit(VariableReader objectRef) { public void monitorExit(VariableReader objectRef) {
important(objectRef.getIndex());
} }
} }

View File

@ -62,6 +62,8 @@ public class DependencyChecker implements DependencyInfo {
private Diagnostics diagnostics; private Diagnostics diagnostics;
DefaultCallGraph callGraph = new DefaultCallGraph(); DefaultCallGraph callGraph = new DefaultCallGraph();
private DependencyAgent agent; private DependencyAgent agent;
List<DependencyNode> nodes = new ArrayList<>();
List<BitSet> typeBitSets = new ArrayList<>();
public DependencyChecker(ClassReaderSource classSource, ClassLoader classLoader, ServiceRepository services, public DependencyChecker(ClassReaderSource classSource, ClassLoader classLoader, ServiceRepository services,
Diagnostics diagnostics) { Diagnostics diagnostics) {
@ -128,13 +130,16 @@ public class DependencyChecker implements DependencyInfo {
if (type == null) { if (type == null) {
type = new DependencyType(this, name, types.size()); type = new DependencyType(this, name, types.size());
types.add(type); types.add(type);
typeBitSets.add(new BitSet(nodes.size()));
typeMap.put(name, type); typeMap.put(name, type);
} }
return type; return type;
} }
public DependencyNode createNode() { public DependencyNode createNode() {
return new DependencyNode(this); DependencyNode node = new DependencyNode(this, nodes.size());
nodes.add(node);
return node;
} }
@Override @Override
@ -336,11 +341,9 @@ public class DependencyChecker implements DependencyInfo {
private MethodDependency createMethodDep(MethodReference methodRef, MethodReader method) { private MethodDependency createMethodDep(MethodReference methodRef, MethodReader method) {
ValueType[] arguments = methodRef.getParameterTypes(); ValueType[] arguments = methodRef.getParameterTypes();
int paramCount = arguments.length + 1; int paramCount = arguments.length + 1;
int varCount = Math.max(paramCount, method != null && method.getProgram() != null ? DependencyNode[] parameterNodes = new DependencyNode[arguments.length + 1];
method.getProgram().variableCount() : 0); for (int i = 0; i < parameterNodes.length; ++i) {
DependencyNode[] parameterNodes = new DependencyNode[varCount]; parameterNodes[i] = createNode();
for (int i = 0; i < varCount; ++i) {
parameterNodes[i] = new DependencyNode(this);
if (shouldLog) { if (shouldLog) {
parameterNodes[i].setTag(methodRef + ":" + i); parameterNodes[i].setTag(methodRef + ":" + i);
} }
@ -349,7 +352,7 @@ public class DependencyChecker implements DependencyInfo {
if (methodRef.getDescriptor().getResultType() == ValueType.VOID) { if (methodRef.getDescriptor().getResultType() == ValueType.VOID) {
resultNode = null; resultNode = null;
} else { } else {
resultNode = new DependencyNode(this); resultNode = createNode();
if (shouldLog) { if (shouldLog) {
resultNode.setTag(methodRef + ":RESULT"); resultNode.setTag(methodRef + ":RESULT");
} }
@ -431,7 +434,7 @@ public class DependencyChecker implements DependencyInfo {
} }
private FieldDependency createFieldNode(final FieldReference fieldRef, FieldReader field) { private FieldDependency createFieldNode(final FieldReference fieldRef, FieldReader field) {
DependencyNode node = new DependencyNode(this); DependencyNode node = createNode();
if (shouldLog) { if (shouldLog) {
node.setTag(fieldRef.getClassName() + "#" + fieldRef.getFieldName()); node.setTag(fieldRef.getClassName() + "#" + fieldRef.getFieldName());
} }
@ -501,6 +504,7 @@ public class DependencyChecker implements DependencyInfo {
index = 0; index = 0;
} }
} }
return;
} }
public <T> T getService(Class<T> type) { public <T> T getService(Class<T> type) {

View File

@ -15,6 +15,7 @@
*/ */
package org.teavm.dependency; package org.teavm.dependency;
import java.util.Arrays;
import java.util.HashSet; import java.util.HashSet;
import java.util.List; import java.util.List;
import java.util.Set; import java.util.Set;
@ -48,20 +49,29 @@ class DependencyGraphBuilder {
} }
program = method.getProgram(); program = method.getProgram();
if (DependencyChecker.shouldLog) { if (DependencyChecker.shouldLog) {
System.out.println("Method achieved: " + method.getReference()); System.out.println("Method reached: " + method.getReference());
System.out.println(new ListingBuilder().buildListing(program, " ")); System.out.println(new ListingBuilder().buildListing(program, " "));
} }
resultNode = dep.getResult(); resultNode = dep.getResult();
DependencyNode[] origNodes = dep.getVariables();
DataFlowGraphBuilder dfgBuilder = new DataFlowGraphBuilder(); DataFlowGraphBuilder dfgBuilder = new DataFlowGraphBuilder();
for (int i = 0; i < dep.getParameterCount(); ++i) { for (int i = 0; i < dep.getParameterCount(); ++i) {
dfgBuilder.important(i); dfgBuilder.important(i);
} }
int[] nodeMapping = dfgBuilder.buildMapping(program, dep.getParameterCount()); int[] nodeMapping = dfgBuilder.buildMapping(program, dep.getParameterCount(),
nodes = new DependencyNode[origNodes.length]; !(method.getResultType() instanceof ValueType.Primitive) && method.getResultType() != ValueType.VOID);
int nodeClassCount = 0;
for (int i = 0; i < nodeMapping.length; ++i) {
nodeClassCount = Math.max(nodeClassCount, nodeMapping[i] + 1);
}
DependencyNode[] nodeClasses = Arrays.copyOf(dep.getVariables(), nodeClassCount);
for (int i = dep.getVariableCount(); i < nodeClasses.length; ++i) {
nodeClasses[i] = dependencyChecker.createNode();
}
nodes = new DependencyNode[dep.getMethod().getProgram().variableCount()];
for (int i = 0; i < nodes.length; ++i) { for (int i = 0; i < nodes.length; ++i) {
nodes[i] = origNodes[nodeMapping[i]]; int mappedNode = nodeMapping[i];
nodes[i] = mappedNode >= 0 ? nodeClasses[mappedNode] : null;
} }
dep.setVariables(nodes); dep.setVariables(nodes);
@ -71,9 +81,13 @@ class DependencyGraphBuilder {
block.readAllInstructions(reader); block.readAllInstructions(reader);
for (PhiReader phi : block.readPhis()) { for (PhiReader phi : block.readPhis()) {
for (IncomingReader incoming : phi.readIncomings()) { for (IncomingReader incoming : phi.readIncomings()) {
DependencyNode incomingNode = nodes[incoming.getValue().getIndex()];
DependencyNode receiverNode = nodes[phi.getReceiver().getIndex()];
if (incomingNode != null || receiverNode != null) {
nodes[incoming.getValue().getIndex()].connect(nodes[phi.getReceiver().getIndex()]); nodes[incoming.getValue().getIndex()].connect(nodes[phi.getReceiver().getIndex()]);
} }
} }
}
for (TryCatchBlockReader tryCatch : block.readTryCatchBlocks()) { for (TryCatchBlockReader tryCatch : block.readTryCatchBlocks()) {
if (tryCatch.getExceptionType() != null) { if (tryCatch.getExceptionType() != null) {
dependencyChecker.linkClass(tryCatch.getExceptionType(), new CallLocation(caller.getMethod())); dependencyChecker.linkClass(tryCatch.getExceptionType(), new CallLocation(caller.getMethod()));
@ -169,8 +183,10 @@ class DependencyGraphBuilder {
methodDep.use(); 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) {
if (parameters[i] != null) {
parameters[i].connect(targetParams[i]); parameters[i].connect(targetParams[i]);
} }
}
if (result != null && methodDep.getResult() != null) { if (result != null && methodDep.getResult() != null) {
methodDep.getResult().connect(result); methodDep.getResult().connect(result);
} }
@ -211,7 +227,10 @@ class DependencyGraphBuilder {
@Override @Override
public void classConstant(VariableReader receiver, ValueType cst) { public void classConstant(VariableReader receiver, ValueType cst) {
nodes[receiver.getIndex()].propagate(dependencyChecker.getType("java.lang.Class")); DependencyNode node = nodes[receiver.getIndex()];
if (node != null) {
node.propagate(dependencyChecker.getType("java.lang.Class"));
}
while (cst instanceof ValueType.Array) { while (cst instanceof ValueType.Array) {
cst = ((ValueType.Array)cst).getItemType(); cst = ((ValueType.Array)cst).getItemType();
} }
@ -243,7 +262,10 @@ class DependencyGraphBuilder {
@Override @Override
public void stringConstant(VariableReader receiver, String cst) { public void stringConstant(VariableReader receiver, String cst) {
nodes[receiver.getIndex()].propagate(dependencyChecker.getType("java.lang.String")); DependencyNode node = nodes[receiver.getIndex()];
if (node != null) {
node.propagate(dependencyChecker.getType("java.lang.String"));
}
MethodDependency method = dependencyChecker.linkMethod(new MethodReference(String.class, MethodDependency method = dependencyChecker.linkMethod(new MethodReference(String.class,
"<init>", char[].class, void.class), new CallLocation(caller.getMethod(), currentLocation)); "<init>", char[].class, void.class), new CallLocation(caller.getMethod(), currentLocation));
method.use(); method.use();
@ -262,8 +284,10 @@ class DependencyGraphBuilder {
public void assign(VariableReader receiver, VariableReader assignee) { public void assign(VariableReader receiver, VariableReader assignee) {
DependencyNode valueNode = nodes[assignee.getIndex()]; DependencyNode valueNode = nodes[assignee.getIndex()];
DependencyNode receiverNode = nodes[receiver.getIndex()]; DependencyNode receiverNode = nodes[receiver.getIndex()];
if (valueNode != null && receiverNode != null) {
valueNode.connect(receiverNode); valueNode.connect(receiverNode);
} }
}
@Override @Override
public void cast(VariableReader receiver, VariableReader value, ValueType targetType) { public void cast(VariableReader receiver, VariableReader value, ValueType targetType) {
@ -319,7 +343,10 @@ class DependencyGraphBuilder {
@Override @Override
public void exit(VariableReader valueToReturn) { public void exit(VariableReader valueToReturn) {
if (valueToReturn != null) { if (valueToReturn != null) {
nodes[valueToReturn.getIndex()].connect(resultNode); DependencyNode node = nodes[valueToReturn.getIndex()];
if (node != null) {
node.connect(resultNode);
}
} }
} }
@ -330,7 +357,10 @@ 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(dependencyChecker.getType("[" + itemType)); DependencyNode node = nodes[receiver.getIndex()];
if (node != null) {
node.propagate(dependencyChecker.getType("[" + itemType));
}
String className = extractClassName(itemType); String className = extractClassName(itemType);
if (className != null) { if (className != null) {
dependencyChecker.linkClass(className, new CallLocation(caller.getMethod(), currentLocation)); dependencyChecker.linkClass(className, new CallLocation(caller.getMethod(), currentLocation));
@ -361,6 +391,9 @@ class DependencyGraphBuilder {
sb.append(itemTypeStr); sb.append(itemTypeStr);
DependencyNode node = nodes[receiver.getIndex()]; DependencyNode node = nodes[receiver.getIndex()];
for (int i = 0; i < dimensions.size(); ++i) { for (int i = 0; i < dimensions.size(); ++i) {
if (node == null) {
break;
}
node.propagate(dependencyChecker.getType(sb.substring(i, sb.length()))); node.propagate(dependencyChecker.getType(sb.substring(i, sb.length())));
node = node.getArrayItem(); node = node.getArrayItem();
} }
@ -373,25 +406,37 @@ class DependencyGraphBuilder {
@Override @Override
public void create(VariableReader receiver, String type) { public void create(VariableReader receiver, String type) {
dependencyChecker.linkClass(type, new CallLocation(caller.getMethod(), currentLocation)); dependencyChecker.linkClass(type, new CallLocation(caller.getMethod(), currentLocation));
nodes[receiver.getIndex()].propagate(dependencyChecker.getType(type)); DependencyNode node = nodes[receiver.getIndex()];
if (node != null) {
node.propagate(dependencyChecker.getType(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) {
if (!(fieldType instanceof ValueType.Primitive)) {
FieldDependency fieldDep = dependencyChecker.linkField(field, FieldDependency fieldDep = dependencyChecker.linkField(field,
new CallLocation(caller.getMethod(), currentLocation)); new CallLocation(caller.getMethod(), currentLocation));
DependencyNode receiverNode = nodes[receiver.getIndex()]; DependencyNode receiverNode = nodes[receiver.getIndex()];
if (receiverNode != null) {
fieldDep.getValue().connect(receiverNode); fieldDep.getValue().connect(receiverNode);
}
}
initClass(field.getClassName()); initClass(field.getClassName());
} }
@Override @Override
public void putField(VariableReader instance, FieldReference field, VariableReader value) { public void putField(VariableReader instance, FieldReference field, VariableReader value,
ValueType fieldType) {
if (!(fieldType instanceof ValueType.Primitive)) {
FieldDependency fieldDep = dependencyChecker.linkField(field, FieldDependency fieldDep = dependencyChecker.linkField(field,
new CallLocation(caller.getMethod(), currentLocation)); new CallLocation(caller.getMethod(), currentLocation));
DependencyNode valueNode = nodes[value.getIndex()]; DependencyNode valueNode = nodes[value.getIndex()];
if (valueNode != null) {
valueNode.connect(fieldDep.getValue()); valueNode.connect(fieldDep.getValue());
}
}
initClass(field.getClassName()); initClass(field.getClassName());
} }
@ -403,6 +448,7 @@ class DependencyGraphBuilder {
public void cloneArray(VariableReader receiver, VariableReader array) { public void cloneArray(VariableReader receiver, VariableReader array) {
DependencyNode arrayNode = nodes[array.getIndex()]; DependencyNode arrayNode = nodes[array.getIndex()];
final DependencyNode receiverNode = nodes[receiver.getIndex()]; final DependencyNode receiverNode = nodes[receiver.getIndex()];
if (arrayNode != null && receiverNode != null) {
arrayNode.addConsumer(new DependencyConsumer() { arrayNode.addConsumer(new DependencyConsumer() {
@Override public void consume(DependencyType type) { @Override public void consume(DependencyType type) {
receiverNode.propagate(type); receiverNode.propagate(type);
@ -410,27 +456,34 @@ class DependencyGraphBuilder {
}); });
arrayNode.getArrayItem().connect(receiverNode.getArrayItem()); arrayNode.getArrayItem().connect(receiverNode.getArrayItem());
} }
}
@Override @Override
public void unwrapArray(VariableReader receiver, VariableReader array, ArrayElementType elementType) { public void unwrapArray(VariableReader receiver, VariableReader array, ArrayElementType elementType) {
DependencyNode arrayNode = nodes[array.getIndex()]; DependencyNode arrayNode = nodes[array.getIndex()];
DependencyNode receiverNode = nodes[receiver.getIndex()]; DependencyNode receiverNode = nodes[receiver.getIndex()];
if (arrayNode != null && receiverNode != null) {
arrayNode.connect(receiverNode); arrayNode.connect(receiverNode);
} }
}
@Override @Override
public void getElement(VariableReader receiver, VariableReader array, VariableReader index) { public void getElement(VariableReader receiver, VariableReader array, VariableReader index) {
DependencyNode arrayNode = nodes[array.getIndex()]; DependencyNode arrayNode = nodes[array.getIndex()];
DependencyNode receiverNode = nodes[receiver.getIndex()]; DependencyNode receiverNode = nodes[receiver.getIndex()];
if (arrayNode != null && receiverNode != null) {
arrayNode.getArrayItem().connect(receiverNode); arrayNode.getArrayItem().connect(receiverNode);
} }
}
@Override @Override
public void putElement(VariableReader array, VariableReader index, VariableReader value) { public void putElement(VariableReader array, VariableReader index, VariableReader value) {
DependencyNode valueNode = nodes[value.getIndex()]; DependencyNode valueNode = nodes[value.getIndex()];
DependencyNode arrayNode = nodes[array.getIndex()]; DependencyNode arrayNode = nodes[array.getIndex()];
if (valueNode != null && arrayNode != null) {
valueNode.connect(arrayNode.getArrayItem()); valueNode.connect(arrayNode.getArrayItem());
} }
}
@Override @Override
public void invoke(VariableReader receiver, VariableReader instance, MethodReference method, public void invoke(VariableReader receiver, VariableReader instance, MethodReference method,
@ -460,13 +513,20 @@ class DependencyGraphBuilder {
methodDep.use(); 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]); DependencyNode value = nodes[arguments.get(i).getIndex()];
DependencyNode param = targetParams[i + 1];
if (value != null && param != null) {
value.connect(param);
}
} }
if (instance != null) { if (instance != null) {
nodes[instance.getIndex()].connect(targetParams[0]); nodes[instance.getIndex()].connect(targetParams[0]);
} }
if (methodDep.getResult() != null && receiver != null) { if (methodDep.getResult() != null && receiver != null) {
methodDep.getResult().connect(nodes[receiver.getIndex()]); DependencyNode receiverNode = nodes[receiver.getIndex()];
if (methodDep.getResult() != null && receiverNode != null) {
methodDep.getResult().connect(receiverNode);
}
} }
methodDep.getThrown().addConsumer(currentExceptionConsumer); methodDep.getThrown().addConsumer(currentExceptionConsumer);
initClass(method.getClassName()); initClass(method.getClassName());

View File

@ -23,19 +23,21 @@ import java.util.*;
*/ */
public class DependencyNode implements ValueDependencyInfo { public class DependencyNode implements ValueDependencyInfo {
private DependencyChecker dependencyChecker; private DependencyChecker dependencyChecker;
private Set<DependencyConsumer> followers = new HashSet<>(); private List<DependencyConsumer> followers;
private BitSet types; private BitSet types;
private Map<DependencyNode, DependencyNodeToNodeTransition> transitions = new HashMap<>(); private List<DependencyNodeToNodeTransition> transitions;
private volatile String tag; private volatile String tag;
private DependencyNode arrayItemNode; private DependencyNode arrayItemNode;
private int degree; private int degree;
int index;
DependencyNode(DependencyChecker dependencyChecker) { DependencyNode(DependencyChecker dependencyChecker, int index) {
this(dependencyChecker, 0); this(dependencyChecker, index, 0);
} }
DependencyNode(DependencyChecker dependencyChecker, int degree) { DependencyNode(DependencyChecker dependencyChecker, int index, int degree) {
this.dependencyChecker = dependencyChecker; this.dependencyChecker = dependencyChecker;
this.index = index;
this.degree = degree; this.degree = degree;
} }
@ -54,11 +56,13 @@ public class DependencyNode implements ValueDependencyInfo {
if (DependencyChecker.shouldLog) { if (DependencyChecker.shouldLog) {
System.out.println(tag + " -> " + type.getName()); System.out.println(tag + " -> " + type.getName());
} }
if (followers != null) {
for (DependencyConsumer consumer : followers.toArray(new DependencyConsumer[followers.size()])) { for (DependencyConsumer consumer : followers.toArray(new DependencyConsumer[followers.size()])) {
dependencyChecker.schedulePropagation(consumer, type); dependencyChecker.schedulePropagation(consumer, type);
} }
} }
} }
}
public void propagate(DependencyType[] agentTypes) { public void propagate(DependencyType[] agentTypes) {
DependencyType[] types = new DependencyType[agentTypes.length]; DependencyType[] types = new DependencyType[agentTypes.length];
@ -81,13 +85,22 @@ public class DependencyNode implements ValueDependencyInfo {
System.out.println(tag + " -> " + types[i].getName()); System.out.println(tag + " -> " + types[i].getName());
} }
} }
if (followers != null) {
for (DependencyConsumer consumer : followers.toArray(new DependencyConsumer[followers.size()])) { for (DependencyConsumer consumer : followers.toArray(new DependencyConsumer[followers.size()])) {
dependencyChecker.schedulePropagation(consumer, Arrays.copyOf(types, j)); dependencyChecker.schedulePropagation(consumer, Arrays.copyOf(types, j));
} }
} }
}
public void addConsumer(DependencyConsumer consumer) { public void addConsumer(DependencyConsumer consumer) {
if (followers.add(consumer) && this.types != null) { if (followers == null) {
followers = new ArrayList<>();
}
if (followers.contains(consumer)) {
return;
}
followers.add(consumer);
if (this.types != null) {
List<DependencyType> types = new ArrayList<>(); List<DependencyType> types = new ArrayList<>();
for (int index = this.types.nextSetBit(0); index >= 0; index = this.types.nextSetBit(index + 1)) { for (int index = this.types.nextSetBit(0); index >= 0; index = this.types.nextSetBit(index + 1)) {
types.add(dependencyChecker.types.get(index)); types.add(dependencyChecker.types.get(index));
@ -100,15 +113,27 @@ public class DependencyNode implements ValueDependencyInfo {
if (this == node) { if (this == node) {
return; return;
} }
if (node == null) {
throw new IllegalArgumentException("Node must not be null");
}
if (transitions != null) {
for (DependencyNodeToNodeTransition transition : transitions) {
if (transition.destination == node) {
return;
}
}
}
DependencyNodeToNodeTransition transition = new DependencyNodeToNodeTransition(this, node, filter); DependencyNodeToNodeTransition transition = new DependencyNodeToNodeTransition(this, node, filter);
if (!transitions.containsKey(node)) { if (transitions == null) {
transitions.put(node, transition); transitions = new ArrayList<>();
}
transitions.add(transition);
if (DependencyChecker.shouldLog) { if (DependencyChecker.shouldLog) {
System.out.println("Connecting " + tag + " to " + node.tag); System.out.println("Connecting " + tag + " to " + node.tag);
} }
addConsumer(transition); addConsumer(transition);
} }
}
public void connect(DependencyNode node) { public void connect(DependencyNode node) {
connect(node, null); connect(node, null);
@ -117,7 +142,8 @@ public class DependencyNode implements ValueDependencyInfo {
@Override @Override
public DependencyNode getArrayItem() { public DependencyNode getArrayItem() {
if (arrayItemNode == null) { if (arrayItemNode == null) {
arrayItemNode = new DependencyNode(dependencyChecker, degree + 1); arrayItemNode = new DependencyNode(dependencyChecker, dependencyChecker.nodes.size(), degree + 1);
dependencyChecker.nodes.add(arrayItemNode);
if (DependencyChecker.shouldLog) { if (DependencyChecker.shouldLog) {
arrayItemNode.tag = tag + "["; arrayItemNode.tag = tag + "[";
} }

View File

@ -20,8 +20,8 @@ package org.teavm.dependency;
* @author Alexey Andreev * @author Alexey Andreev
*/ */
class DependencyNodeToNodeTransition implements DependencyConsumer { class DependencyNodeToNodeTransition implements DependencyConsumer {
private DependencyNode source; DependencyNode source;
private DependencyNode destination; DependencyNode destination;
private DependencyTypeFilter filter; private DependencyTypeFilter filter;
public DependencyNodeToNodeTransition(DependencyNode source, DependencyNode destination, public DependencyNodeToNodeTransition(DependencyNode source, DependencyNode destination,

View File

@ -153,7 +153,7 @@ class InstructionReadVisitor implements InstructionVisitor {
@Override @Override
public void visit(PutFieldInstruction insn) { public void visit(PutFieldInstruction insn) {
reader.putField(insn.getInstance(), insn.getField(), insn.getValue()); reader.putField(insn.getInstance(), insn.getField(), insn.getValue(), insn.getFieldType());
} }
@Override @Override

View File

@ -99,6 +99,10 @@ public class MethodReference {
return Arrays.copyOf(signature, signature.length); return Arrays.copyOf(signature, signature.length);
} }
public ValueType getReturnType() {
return signature[signature.length - 1];
}
public String getName() { public String getName() {
return name; return name;
} }

View File

@ -79,7 +79,7 @@ public interface InstructionReader {
void getField(VariableReader receiver, VariableReader instance, FieldReference field, ValueType fieldType); void getField(VariableReader receiver, VariableReader instance, FieldReference field, ValueType fieldType);
void putField(VariableReader instance, FieldReference field, VariableReader value); void putField(VariableReader instance, FieldReference field, VariableReader value, ValueType fieldType);
void arrayLength(VariableReader receiver, VariableReader array); void arrayLength(VariableReader receiver, VariableReader array);

View File

@ -17,6 +17,7 @@ package org.teavm.model.instructions;
import org.teavm.model.FieldReference; import org.teavm.model.FieldReference;
import org.teavm.model.Instruction; import org.teavm.model.Instruction;
import org.teavm.model.ValueType;
import org.teavm.model.Variable; import org.teavm.model.Variable;
/** /**
@ -27,6 +28,7 @@ public class PutFieldInstruction extends Instruction {
private Variable instance; private Variable instance;
private FieldReference field; private FieldReference field;
private Variable value; private Variable value;
private ValueType fieldType;
public Variable getInstance() { public Variable getInstance() {
return instance; return instance;
@ -52,6 +54,14 @@ public class PutFieldInstruction extends Instruction {
this.value = value; this.value = value;
} }
public ValueType getFieldType() {
return fieldType;
}
public void setFieldType(ValueType fieldType) {
this.fieldType = fieldType;
}
@Override @Override
public void acceptVisitor(InstructionVisitor visitor) { public void acceptVisitor(InstructionVisitor visitor) {
visitor.visit(this); visitor.visit(this);

View File

@ -330,7 +330,8 @@ public class AsyncMethodFinder {
} }
@Override @Override
public void putField(VariableReader instance, FieldReference field, VariableReader value) { public void putField(VariableReader instance, FieldReference field, VariableReader value,
ValueType fieldType) {
} }
@Override @Override

View File

@ -280,7 +280,7 @@ public class InstructionStringifier implements InstructionReader {
} }
@Override @Override
public void putField(VariableReader instance, FieldReference field, VariableReader value) { public void putField(VariableReader instance, FieldReference field, VariableReader value, ValueType fieldType) {
if (instance != null) { if (instance != null) {
sb.append("@").append(instance.getIndex()); sb.append("@").append(instance.getIndex());
} else { } else {

View File

@ -398,11 +398,13 @@ public final class ProgramUtils {
} }
@Override @Override
public void putField(VariableReader instance, FieldReference field, VariableReader value) { public void putField(VariableReader instance, FieldReference field, VariableReader value,
ValueType fieldType) {
PutFieldInstruction insnCopy = new PutFieldInstruction(); PutFieldInstruction insnCopy = new PutFieldInstruction();
insnCopy.setField(field); insnCopy.setField(field);
insnCopy.setInstance(instance != null ? copyVar(instance) : null); insnCopy.setInstance(instance != null ? copyVar(instance) : null);
insnCopy.setValue(copyVar(value)); insnCopy.setValue(copyVar(value));
insnCopy.setFieldType(fieldType);
copy = insnCopy; copy = insnCopy;
copy.setLocation(location); copy.setLocation(location);
} }

View File

@ -1611,6 +1611,7 @@ public class ProgramParser implements VariableDebugInformation {
insn.setInstance(getVariable(instance)); insn.setInstance(getVariable(instance));
insn.setField(new FieldReference(ownerCls, name)); insn.setField(new FieldReference(ownerCls, name));
insn.setValue(getVariable(value)); insn.setValue(getVariable(value));
insn.setFieldType(ValueType.parse(desc));
addInstruction(insn); addInstruction(insn);
break; break;
} }

View File

@ -77,7 +77,8 @@ class ProgramSourceAggregator implements InstructionReader {
@Override public void create(VariableReader receiver, String type) { } @Override public void create(VariableReader receiver, String type) { }
@Override public void getField(VariableReader receiver, VariableReader instance, FieldReference field, @Override public void getField(VariableReader receiver, VariableReader instance, FieldReference field,
ValueType fieldType) { } ValueType fieldType) { }
@Override public void putField(VariableReader instance, FieldReference field, VariableReader value) { } @Override public void putField(VariableReader instance, FieldReference field, VariableReader value,
ValueType fieldType) { }
@Override public void arrayLength(VariableReader receiver, VariableReader array) { } @Override public void arrayLength(VariableReader receiver, VariableReader array) { }
@Override public void cloneArray(VariableReader receiver, VariableReader array) { } @Override public void cloneArray(VariableReader receiver, VariableReader array) { }
@Override public void unwrapArray(VariableReader receiver, VariableReader array, ArrayElementType elementType) { } @Override public void unwrapArray(VariableReader receiver, VariableReader array, ArrayElementType elementType) { }