mirror of
https://github.com/Eaglercraft-TeaVM-Fork/eagler-teavm.git
synced 2024-12-22 08:14:09 -08:00
Initial optimization of dependency checker
This commit is contained in:
parent
1380e7dbf4
commit
2745f1c7f5
|
@ -36,14 +36,20 @@ public class DataFlowGraphBuilder implements InstructionReader {
|
|||
private ObjectIntMap<MethodReference> methodNodes = new ObjectIntOpenHashMap<>();
|
||||
private ObjectIntMap<FieldReference> fieldNodes = new ObjectIntOpenHashMap<>();
|
||||
private int[] arrayNodes;
|
||||
private int returnIndex = -1;
|
||||
private int exceptionIndex;
|
||||
|
||||
public void important(int node) {
|
||||
importantNodes.add(node);
|
||||
}
|
||||
|
||||
public int[] buildMapping(ProgramReader program, int paramCount) {
|
||||
public int[] buildMapping(ProgramReader program, int paramCount, boolean needsReturn) {
|
||||
lastIndex = program.variableCount();
|
||||
arrayNodes = new int[lastIndex];
|
||||
if (needsReturn) {
|
||||
returnIndex = lastIndex++;
|
||||
}
|
||||
exceptionIndex = lastIndex++;
|
||||
Arrays.fill(arrayNodes, -1);
|
||||
for (int i = 0; i < program.basicBlockCount(); ++i) {
|
||||
BasicBlockReader block = program.basicBlockAt(i);
|
||||
|
@ -52,6 +58,11 @@ public class DataFlowGraphBuilder implements InstructionReader {
|
|||
builder.addEdge(incoming.getValue().getIndex(), phi.getReceiver().getIndex());
|
||||
}
|
||||
}
|
||||
for (TryCatchBlockReader tryCatch : block.readTryCatchBlocks()) {
|
||||
if (tryCatch.getExceptionVariable() != null) {
|
||||
important(tryCatch.getExceptionVariable().getIndex());
|
||||
}
|
||||
}
|
||||
block.readAllInstructions(this);
|
||||
}
|
||||
Graph graph = builder.build();
|
||||
|
@ -76,6 +87,17 @@ public class DataFlowGraphBuilder implements InstructionReader {
|
|||
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());
|
||||
|
@ -88,7 +110,25 @@ public class DataFlowGraphBuilder implements InstructionReader {
|
|||
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
|
||||
|
@ -178,14 +218,16 @@ public class DataFlowGraphBuilder implements InstructionReader {
|
|||
|
||||
@Override
|
||||
public void exit(VariableReader valueToReturn) {
|
||||
if (valueToReturn != null) {
|
||||
important(valueToReturn.getIndex());
|
||||
if (valueToReturn != null && returnIndex >= 0) {
|
||||
important(returnIndex);
|
||||
builder.addEdge(valueToReturn.getIndex(), returnIndex);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void raise(VariableReader exception) {
|
||||
important(exception.getIndex());
|
||||
builder.addEdge(exception.getIndex(), exceptionIndex);
|
||||
important(exceptionIndex);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -212,13 +254,18 @@ public class DataFlowGraphBuilder implements InstructionReader {
|
|||
|
||||
@Override
|
||||
public void getField(VariableReader receiver, VariableReader instance, FieldReference field, ValueType fieldType) {
|
||||
if (fieldType instanceof ValueType.Primitive) {
|
||||
return;
|
||||
}
|
||||
int fieldNode = getFieldNode(field);
|
||||
builder.addEdge(fieldNode, receiver.getIndex());
|
||||
}
|
||||
|
||||
|
||||
@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);
|
||||
builder.addEdge(value.getIndex(), fieldNode);
|
||||
}
|
||||
|
@ -274,7 +321,18 @@ public class DataFlowGraphBuilder implements InstructionReader {
|
|||
public void invoke(VariableReader receiver, VariableReader instance, MethodReference method,
|
||||
List<? extends VariableReader> arguments, InvocationType type) {
|
||||
if (receiver != null) {
|
||||
builder.addEdge(getMethodNode(method), receiver.getIndex());
|
||||
if (!(method.getReturnType() instanceof ValueType.Primitive)) {
|
||||
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());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -293,9 +351,11 @@ public class DataFlowGraphBuilder implements InstructionReader {
|
|||
|
||||
@Override
|
||||
public void monitorEnter(VariableReader objectRef) {
|
||||
important(objectRef.getIndex());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void monitorExit(VariableReader objectRef) {
|
||||
important(objectRef.getIndex());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -62,6 +62,8 @@ public class DependencyChecker implements DependencyInfo {
|
|||
private Diagnostics diagnostics;
|
||||
DefaultCallGraph callGraph = new DefaultCallGraph();
|
||||
private DependencyAgent agent;
|
||||
List<DependencyNode> nodes = new ArrayList<>();
|
||||
List<BitSet> typeBitSets = new ArrayList<>();
|
||||
|
||||
public DependencyChecker(ClassReaderSource classSource, ClassLoader classLoader, ServiceRepository services,
|
||||
Diagnostics diagnostics) {
|
||||
|
@ -128,13 +130,16 @@ public class DependencyChecker implements DependencyInfo {
|
|||
if (type == null) {
|
||||
type = new DependencyType(this, name, types.size());
|
||||
types.add(type);
|
||||
typeBitSets.add(new BitSet(nodes.size()));
|
||||
typeMap.put(name, type);
|
||||
}
|
||||
return type;
|
||||
}
|
||||
|
||||
public DependencyNode createNode() {
|
||||
return new DependencyNode(this);
|
||||
DependencyNode node = new DependencyNode(this, nodes.size());
|
||||
nodes.add(node);
|
||||
return node;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -336,11 +341,9 @@ public class DependencyChecker implements DependencyInfo {
|
|||
private MethodDependency createMethodDep(MethodReference methodRef, MethodReader method) {
|
||||
ValueType[] arguments = methodRef.getParameterTypes();
|
||||
int paramCount = arguments.length + 1;
|
||||
int varCount = Math.max(paramCount, method != null && method.getProgram() != null ?
|
||||
method.getProgram().variableCount() : 0);
|
||||
DependencyNode[] parameterNodes = new DependencyNode[varCount];
|
||||
for (int i = 0; i < varCount; ++i) {
|
||||
parameterNodes[i] = new DependencyNode(this);
|
||||
DependencyNode[] parameterNodes = new DependencyNode[arguments.length + 1];
|
||||
for (int i = 0; i < parameterNodes.length; ++i) {
|
||||
parameterNodes[i] = createNode();
|
||||
if (shouldLog) {
|
||||
parameterNodes[i].setTag(methodRef + ":" + i);
|
||||
}
|
||||
|
@ -349,7 +352,7 @@ public class DependencyChecker implements DependencyInfo {
|
|||
if (methodRef.getDescriptor().getResultType() == ValueType.VOID) {
|
||||
resultNode = null;
|
||||
} else {
|
||||
resultNode = new DependencyNode(this);
|
||||
resultNode = createNode();
|
||||
if (shouldLog) {
|
||||
resultNode.setTag(methodRef + ":RESULT");
|
||||
}
|
||||
|
@ -431,7 +434,7 @@ public class DependencyChecker implements DependencyInfo {
|
|||
}
|
||||
|
||||
private FieldDependency createFieldNode(final FieldReference fieldRef, FieldReader field) {
|
||||
DependencyNode node = new DependencyNode(this);
|
||||
DependencyNode node = createNode();
|
||||
if (shouldLog) {
|
||||
node.setTag(fieldRef.getClassName() + "#" + fieldRef.getFieldName());
|
||||
}
|
||||
|
@ -501,6 +504,7 @@ public class DependencyChecker implements DependencyInfo {
|
|||
index = 0;
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
public <T> T getService(Class<T> type) {
|
||||
|
|
|
@ -15,6 +15,7 @@
|
|||
*/
|
||||
package org.teavm.dependency;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
@ -48,20 +49,29 @@ class DependencyGraphBuilder {
|
|||
}
|
||||
program = method.getProgram();
|
||||
if (DependencyChecker.shouldLog) {
|
||||
System.out.println("Method achieved: " + method.getReference());
|
||||
System.out.println("Method reached: " + method.getReference());
|
||||
System.out.println(new ListingBuilder().buildListing(program, " "));
|
||||
}
|
||||
resultNode = dep.getResult();
|
||||
|
||||
DependencyNode[] origNodes = dep.getVariables();
|
||||
DataFlowGraphBuilder dfgBuilder = new DataFlowGraphBuilder();
|
||||
for (int i = 0; i < dep.getParameterCount(); ++i) {
|
||||
dfgBuilder.important(i);
|
||||
}
|
||||
int[] nodeMapping = dfgBuilder.buildMapping(program, dep.getParameterCount());
|
||||
nodes = new DependencyNode[origNodes.length];
|
||||
int[] nodeMapping = dfgBuilder.buildMapping(program, dep.getParameterCount(),
|
||||
!(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) {
|
||||
nodes[i] = origNodes[nodeMapping[i]];
|
||||
int mappedNode = nodeMapping[i];
|
||||
nodes[i] = mappedNode >= 0 ? nodeClasses[mappedNode] : null;
|
||||
}
|
||||
dep.setVariables(nodes);
|
||||
|
||||
|
@ -71,7 +81,11 @@ class DependencyGraphBuilder {
|
|||
block.readAllInstructions(reader);
|
||||
for (PhiReader phi : block.readPhis()) {
|
||||
for (IncomingReader incoming : phi.readIncomings()) {
|
||||
nodes[incoming.getValue().getIndex()].connect(nodes[phi.getReceiver().getIndex()]);
|
||||
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()]);
|
||||
}
|
||||
}
|
||||
}
|
||||
for (TryCatchBlockReader tryCatch : block.readTryCatchBlocks()) {
|
||||
|
@ -169,7 +183,9 @@ class DependencyGraphBuilder {
|
|||
methodDep.use();
|
||||
DependencyNode[] targetParams = methodDep.getVariables();
|
||||
for (int i = 0; i < parameters.length; ++i) {
|
||||
parameters[i].connect(targetParams[i]);
|
||||
if (parameters[i] != null) {
|
||||
parameters[i].connect(targetParams[i]);
|
||||
}
|
||||
}
|
||||
if (result != null && methodDep.getResult() != null) {
|
||||
methodDep.getResult().connect(result);
|
||||
|
@ -211,7 +227,10 @@ class DependencyGraphBuilder {
|
|||
|
||||
@Override
|
||||
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) {
|
||||
cst = ((ValueType.Array)cst).getItemType();
|
||||
}
|
||||
|
@ -243,7 +262,10 @@ class DependencyGraphBuilder {
|
|||
|
||||
@Override
|
||||
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,
|
||||
"<init>", char[].class, void.class), new CallLocation(caller.getMethod(), currentLocation));
|
||||
method.use();
|
||||
|
@ -262,7 +284,9 @@ class DependencyGraphBuilder {
|
|||
public void assign(VariableReader receiver, VariableReader assignee) {
|
||||
DependencyNode valueNode = nodes[assignee.getIndex()];
|
||||
DependencyNode receiverNode = nodes[receiver.getIndex()];
|
||||
valueNode.connect(receiverNode);
|
||||
if (valueNode != null && receiverNode != null) {
|
||||
valueNode.connect(receiverNode);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -319,7 +343,10 @@ class DependencyGraphBuilder {
|
|||
@Override
|
||||
public void exit(VariableReader valueToReturn) {
|
||||
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
|
||||
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);
|
||||
if (className != null) {
|
||||
dependencyChecker.linkClass(className, new CallLocation(caller.getMethod(), currentLocation));
|
||||
|
@ -361,6 +391,9 @@ class DependencyGraphBuilder {
|
|||
sb.append(itemTypeStr);
|
||||
DependencyNode node = nodes[receiver.getIndex()];
|
||||
for (int i = 0; i < dimensions.size(); ++i) {
|
||||
if (node == null) {
|
||||
break;
|
||||
}
|
||||
node.propagate(dependencyChecker.getType(sb.substring(i, sb.length())));
|
||||
node = node.getArrayItem();
|
||||
}
|
||||
|
@ -373,25 +406,37 @@ class DependencyGraphBuilder {
|
|||
@Override
|
||||
public void create(VariableReader receiver, String type) {
|
||||
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
|
||||
public void getField(VariableReader receiver, VariableReader instance, FieldReference field,
|
||||
ValueType fieldType) {
|
||||
FieldDependency fieldDep = dependencyChecker.linkField(field,
|
||||
new CallLocation(caller.getMethod(), currentLocation));
|
||||
DependencyNode receiverNode = nodes[receiver.getIndex()];
|
||||
fieldDep.getValue().connect(receiverNode);
|
||||
if (!(fieldType instanceof ValueType.Primitive)) {
|
||||
FieldDependency fieldDep = dependencyChecker.linkField(field,
|
||||
new CallLocation(caller.getMethod(), currentLocation));
|
||||
DependencyNode receiverNode = nodes[receiver.getIndex()];
|
||||
if (receiverNode != null) {
|
||||
fieldDep.getValue().connect(receiverNode);
|
||||
}
|
||||
}
|
||||
initClass(field.getClassName());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void putField(VariableReader instance, FieldReference field, VariableReader value) {
|
||||
FieldDependency fieldDep = dependencyChecker.linkField(field,
|
||||
new CallLocation(caller.getMethod(), currentLocation));
|
||||
DependencyNode valueNode = nodes[value.getIndex()];
|
||||
valueNode.connect(fieldDep.getValue());
|
||||
public void putField(VariableReader instance, FieldReference field, VariableReader value,
|
||||
ValueType fieldType) {
|
||||
if (!(fieldType instanceof ValueType.Primitive)) {
|
||||
FieldDependency fieldDep = dependencyChecker.linkField(field,
|
||||
new CallLocation(caller.getMethod(), currentLocation));
|
||||
DependencyNode valueNode = nodes[value.getIndex()];
|
||||
if (valueNode != null) {
|
||||
valueNode.connect(fieldDep.getValue());
|
||||
}
|
||||
}
|
||||
initClass(field.getClassName());
|
||||
}
|
||||
|
||||
|
@ -403,33 +448,41 @@ class DependencyGraphBuilder {
|
|||
public void cloneArray(VariableReader receiver, VariableReader array) {
|
||||
DependencyNode arrayNode = nodes[array.getIndex()];
|
||||
final DependencyNode receiverNode = nodes[receiver.getIndex()];
|
||||
arrayNode.addConsumer(new DependencyConsumer() {
|
||||
@Override public void consume(DependencyType type) {
|
||||
receiverNode.propagate(type);
|
||||
}
|
||||
});
|
||||
arrayNode.getArrayItem().connect(receiverNode.getArrayItem());
|
||||
if (arrayNode != null && receiverNode != null) {
|
||||
arrayNode.addConsumer(new DependencyConsumer() {
|
||||
@Override public void consume(DependencyType type) {
|
||||
receiverNode.propagate(type);
|
||||
}
|
||||
});
|
||||
arrayNode.getArrayItem().connect(receiverNode.getArrayItem());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void unwrapArray(VariableReader receiver, VariableReader array, ArrayElementType elementType) {
|
||||
DependencyNode arrayNode = nodes[array.getIndex()];
|
||||
DependencyNode receiverNode = nodes[receiver.getIndex()];
|
||||
arrayNode.connect(receiverNode);
|
||||
if (arrayNode != null && receiverNode != null) {
|
||||
arrayNode.connect(receiverNode);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void getElement(VariableReader receiver, VariableReader array, VariableReader index) {
|
||||
DependencyNode arrayNode = nodes[array.getIndex()];
|
||||
DependencyNode receiverNode = nodes[receiver.getIndex()];
|
||||
arrayNode.getArrayItem().connect(receiverNode);
|
||||
if (arrayNode != null && receiverNode != null) {
|
||||
arrayNode.getArrayItem().connect(receiverNode);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void putElement(VariableReader array, VariableReader index, VariableReader value) {
|
||||
DependencyNode valueNode = nodes[value.getIndex()];
|
||||
DependencyNode arrayNode = nodes[array.getIndex()];
|
||||
valueNode.connect(arrayNode.getArrayItem());
|
||||
if (valueNode != null && arrayNode != null) {
|
||||
valueNode.connect(arrayNode.getArrayItem());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -460,13 +513,20 @@ class DependencyGraphBuilder {
|
|||
methodDep.use();
|
||||
DependencyNode[] targetParams = methodDep.getVariables();
|
||||
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) {
|
||||
nodes[instance.getIndex()].connect(targetParams[0]);
|
||||
}
|
||||
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);
|
||||
initClass(method.getClassName());
|
||||
|
|
|
@ -23,19 +23,21 @@ import java.util.*;
|
|||
*/
|
||||
public class DependencyNode implements ValueDependencyInfo {
|
||||
private DependencyChecker dependencyChecker;
|
||||
private Set<DependencyConsumer> followers = new HashSet<>();
|
||||
private List<DependencyConsumer> followers;
|
||||
private BitSet types;
|
||||
private Map<DependencyNode, DependencyNodeToNodeTransition> transitions = new HashMap<>();
|
||||
private List<DependencyNodeToNodeTransition> transitions;
|
||||
private volatile String tag;
|
||||
private DependencyNode arrayItemNode;
|
||||
private int degree;
|
||||
int index;
|
||||
|
||||
DependencyNode(DependencyChecker dependencyChecker) {
|
||||
this(dependencyChecker, 0);
|
||||
DependencyNode(DependencyChecker dependencyChecker, int index) {
|
||||
this(dependencyChecker, index, 0);
|
||||
}
|
||||
|
||||
DependencyNode(DependencyChecker dependencyChecker, int degree) {
|
||||
DependencyNode(DependencyChecker dependencyChecker, int index, int degree) {
|
||||
this.dependencyChecker = dependencyChecker;
|
||||
this.index = index;
|
||||
this.degree = degree;
|
||||
}
|
||||
|
||||
|
@ -54,8 +56,10 @@ public class DependencyNode implements ValueDependencyInfo {
|
|||
if (DependencyChecker.shouldLog) {
|
||||
System.out.println(tag + " -> " + type.getName());
|
||||
}
|
||||
for (DependencyConsumer consumer : followers.toArray(new DependencyConsumer[followers.size()])) {
|
||||
dependencyChecker.schedulePropagation(consumer, type);
|
||||
if (followers != null) {
|
||||
for (DependencyConsumer consumer : followers.toArray(new DependencyConsumer[followers.size()])) {
|
||||
dependencyChecker.schedulePropagation(consumer, type);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -81,13 +85,22 @@ public class DependencyNode implements ValueDependencyInfo {
|
|||
System.out.println(tag + " -> " + types[i].getName());
|
||||
}
|
||||
}
|
||||
for (DependencyConsumer consumer : followers.toArray(new DependencyConsumer[followers.size()])) {
|
||||
dependencyChecker.schedulePropagation(consumer, Arrays.copyOf(types, j));
|
||||
if (followers != null) {
|
||||
for (DependencyConsumer consumer : followers.toArray(new DependencyConsumer[followers.size()])) {
|
||||
dependencyChecker.schedulePropagation(consumer, Arrays.copyOf(types, j));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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<>();
|
||||
for (int index = this.types.nextSetBit(0); index >= 0; index = this.types.nextSetBit(index + 1)) {
|
||||
types.add(dependencyChecker.types.get(index));
|
||||
|
@ -100,14 +113,26 @@ public class DependencyNode implements ValueDependencyInfo {
|
|||
if (this == node) {
|
||||
return;
|
||||
}
|
||||
DependencyNodeToNodeTransition transition = new DependencyNodeToNodeTransition(this, node, filter);
|
||||
if (!transitions.containsKey(node)) {
|
||||
transitions.put(node, transition);
|
||||
if (DependencyChecker.shouldLog) {
|
||||
System.out.println("Connecting " + tag + " to " + node.tag);
|
||||
}
|
||||
addConsumer(transition);
|
||||
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);
|
||||
if (transitions == null) {
|
||||
transitions = new ArrayList<>();
|
||||
}
|
||||
|
||||
transitions.add(transition);
|
||||
if (DependencyChecker.shouldLog) {
|
||||
System.out.println("Connecting " + tag + " to " + node.tag);
|
||||
}
|
||||
addConsumer(transition);
|
||||
}
|
||||
|
||||
public void connect(DependencyNode node) {
|
||||
|
@ -117,7 +142,8 @@ public class DependencyNode implements ValueDependencyInfo {
|
|||
@Override
|
||||
public DependencyNode getArrayItem() {
|
||||
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) {
|
||||
arrayItemNode.tag = tag + "[";
|
||||
}
|
||||
|
|
|
@ -20,8 +20,8 @@ package org.teavm.dependency;
|
|||
* @author Alexey Andreev
|
||||
*/
|
||||
class DependencyNodeToNodeTransition implements DependencyConsumer {
|
||||
private DependencyNode source;
|
||||
private DependencyNode destination;
|
||||
DependencyNode source;
|
||||
DependencyNode destination;
|
||||
private DependencyTypeFilter filter;
|
||||
|
||||
public DependencyNodeToNodeTransition(DependencyNode source, DependencyNode destination,
|
||||
|
|
|
@ -153,7 +153,7 @@ class InstructionReadVisitor implements InstructionVisitor {
|
|||
|
||||
@Override
|
||||
public void visit(PutFieldInstruction insn) {
|
||||
reader.putField(insn.getInstance(), insn.getField(), insn.getValue());
|
||||
reader.putField(insn.getInstance(), insn.getField(), insn.getValue(), insn.getFieldType());
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -99,6 +99,10 @@ public class MethodReference {
|
|||
return Arrays.copyOf(signature, signature.length);
|
||||
}
|
||||
|
||||
public ValueType getReturnType() {
|
||||
return signature[signature.length - 1];
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
|
|
@ -79,7 +79,7 @@ public interface InstructionReader {
|
|||
|
||||
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);
|
||||
|
||||
|
@ -100,8 +100,8 @@ public interface InstructionReader {
|
|||
void initClass(String className);
|
||||
|
||||
void nullCheck(VariableReader receiver, VariableReader value);
|
||||
|
||||
|
||||
void monitorEnter(VariableReader objectRef);
|
||||
|
||||
|
||||
void monitorExit(VariableReader objectRef);
|
||||
}
|
||||
|
|
|
@ -17,6 +17,7 @@ package org.teavm.model.instructions;
|
|||
|
||||
import org.teavm.model.FieldReference;
|
||||
import org.teavm.model.Instruction;
|
||||
import org.teavm.model.ValueType;
|
||||
import org.teavm.model.Variable;
|
||||
|
||||
/**
|
||||
|
@ -27,6 +28,7 @@ public class PutFieldInstruction extends Instruction {
|
|||
private Variable instance;
|
||||
private FieldReference field;
|
||||
private Variable value;
|
||||
private ValueType fieldType;
|
||||
|
||||
public Variable getInstance() {
|
||||
return instance;
|
||||
|
@ -52,6 +54,14 @@ public class PutFieldInstruction extends Instruction {
|
|||
this.value = value;
|
||||
}
|
||||
|
||||
public ValueType getFieldType() {
|
||||
return fieldType;
|
||||
}
|
||||
|
||||
public void setFieldType(ValueType fieldType) {
|
||||
this.fieldType = fieldType;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void acceptVisitor(InstructionVisitor visitor) {
|
||||
visitor.visit(this);
|
||||
|
|
|
@ -330,7 +330,8 @@ public class AsyncMethodFinder {
|
|||
}
|
||||
|
||||
@Override
|
||||
public void putField(VariableReader instance, FieldReference field, VariableReader value) {
|
||||
public void putField(VariableReader instance, FieldReference field, VariableReader value,
|
||||
ValueType fieldType) {
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -280,7 +280,7 @@ public class InstructionStringifier implements InstructionReader {
|
|||
}
|
||||
|
||||
@Override
|
||||
public void putField(VariableReader instance, FieldReference field, VariableReader value) {
|
||||
public void putField(VariableReader instance, FieldReference field, VariableReader value, ValueType fieldType) {
|
||||
if (instance != null) {
|
||||
sb.append("@").append(instance.getIndex());
|
||||
} else {
|
||||
|
|
|
@ -398,11 +398,13 @@ public final class ProgramUtils {
|
|||
}
|
||||
|
||||
@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();
|
||||
insnCopy.setField(field);
|
||||
insnCopy.setInstance(instance != null ? copyVar(instance) : null);
|
||||
insnCopy.setValue(copyVar(value));
|
||||
insnCopy.setFieldType(fieldType);
|
||||
copy = insnCopy;
|
||||
copy.setLocation(location);
|
||||
}
|
||||
|
|
|
@ -1568,7 +1568,7 @@ public class ProgramParser implements VariableDebugInformation {
|
|||
addInstruction(insn);
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1611,6 +1611,7 @@ public class ProgramParser implements VariableDebugInformation {
|
|||
insn.setInstance(getVariable(instance));
|
||||
insn.setField(new FieldReference(ownerCls, name));
|
||||
insn.setValue(getVariable(value));
|
||||
insn.setFieldType(ValueType.parse(desc));
|
||||
addInstruction(insn);
|
||||
break;
|
||||
}
|
||||
|
|
|
@ -77,7 +77,8 @@ class ProgramSourceAggregator implements InstructionReader {
|
|||
@Override public void create(VariableReader receiver, String type) { }
|
||||
@Override public void getField(VariableReader receiver, VariableReader instance, FieldReference field,
|
||||
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 cloneArray(VariableReader receiver, VariableReader array) { }
|
||||
@Override public void unwrapArray(VariableReader receiver, VariableReader array, ArrayElementType elementType) { }
|
||||
|
@ -91,11 +92,11 @@ class ProgramSourceAggregator implements InstructionReader {
|
|||
|
||||
@Override
|
||||
public void monitorEnter(VariableReader objectRef) {
|
||||
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void monitorExit(VariableReader objectRef) {
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue
Block a user