Remove unnecessary debugging code

This commit is contained in:
konsoletyper 2015-03-14 15:34:13 +03:00
parent 3449257db7
commit 004cb79b17
5 changed files with 172 additions and 141 deletions

View File

@ -31,7 +31,7 @@ public class IntegerStack {
public void push(int value) { public void push(int value) {
if (head == buffer.length) { if (head == buffer.length) {
buffer = Arrays.copyOf(buffer, buffer.length * 2); buffer = Arrays.copyOf(buffer, Math.max(buffer.length * 2, 1));
} }
buffer[head++] = value; buffer[head++] = value;
} }

View File

@ -19,6 +19,7 @@ import com.carrotsearch.hppc.IntOpenHashSet;
import com.carrotsearch.hppc.IntSet; import com.carrotsearch.hppc.IntSet;
import com.carrotsearch.hppc.ObjectIntMap; import com.carrotsearch.hppc.ObjectIntMap;
import com.carrotsearch.hppc.ObjectIntOpenHashMap; import com.carrotsearch.hppc.ObjectIntOpenHashMap;
import com.carrotsearch.hppc.cursors.IntCursor;
import java.util.Arrays; import java.util.Arrays;
import java.util.List; import java.util.List;
import org.teavm.common.*; import org.teavm.common.*;
@ -32,95 +33,62 @@ import org.teavm.model.instructions.*;
public class DataFlowGraphBuilder implements InstructionReader { public class DataFlowGraphBuilder implements InstructionReader {
private int lastIndex; private int lastIndex;
private GraphBuilder builder = new GraphBuilder(); private GraphBuilder builder = new GraphBuilder();
private IntSet importantNodes = new IntOpenHashSet();
private ObjectIntMap<MethodReference> methodNodes = new ObjectIntOpenHashMap<>();
private ObjectIntMap<FieldReference> fieldNodes = new ObjectIntOpenHashMap<>(); private ObjectIntMap<FieldReference> fieldNodes = new ObjectIntOpenHashMap<>();
private int[] arrayNodes;
private int returnIndex = -1; private int returnIndex = -1;
private int exceptionIndex; private int exceptionIndex;
private DisjointSet classes = new DisjointSet();
private int paramCount;
private IntSet escaping = new IntOpenHashSet();
public void important(int node) { private void join(int a, int b) {
importantNodes.add(node); if (a < paramCount || b < paramCount) {
return;
}
classes.union(a, b);
} }
public int[] buildMapping(ProgramReader program, int paramCount, boolean needsReturn) { public int[] buildMapping(ProgramReader program, boolean[] significantParams, boolean needsReturn) {
lastIndex = program.variableCount(); lastIndex = program.variableCount();
arrayNodes = new int[lastIndex]; this.paramCount = significantParams.length;
if (needsReturn) { if (needsReturn) {
returnIndex = lastIndex++; returnIndex = lastIndex++;
escaping.add(returnIndex);
} }
exceptionIndex = lastIndex++; exceptionIndex = lastIndex++;
Arrays.fill(arrayNodes, -1); for (int i = 0; i < lastIndex; ++i) {
classes.create();
}
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);
for (PhiReader phi : block.readPhis()) { for (PhiReader phi : block.readPhis()) {
for (IncomingReader incoming : phi.readIncomings()) { for (IncomingReader incoming : phi.readIncomings()) {
builder.addEdge(incoming.getValue().getIndex(), phi.getReceiver().getIndex()); int from = incoming.getValue().getIndex();
} int to = phi.getReceiver().getIndex();
} builder.addEdge(from, to);
for (TryCatchBlockReader tryCatch : block.readTryCatchBlocks()) { join(from, to);
if (tryCatch.getExceptionVariable() != null) {
important(tryCatch.getExceptionVariable().getIndex());
} }
} }
block.readAllInstructions(this); block.readAllInstructions(this);
} }
Graph graph = builder.build(); Graph graph = builder.build();
for (int i = 0; i < paramCount; ++i) {
DisjointSet classes = new DisjointSet(); if (significantParams[i]) {
for (int i = 0; i < lastIndex; ++i) { escaping.add(i);
classes.create();
}
IntegerArray startNodes = new IntegerArray(graph.size());
for (int i = paramCount; i < graph.size(); ++i) {
if (graph.incomingEdgesCount(i) == 0) {
startNodes.add(i);
}
for (int pred : graph.incomingEdges(i)) {
boolean predImportant = importantNodes.contains(classes.find(pred));
boolean nodeImportant = importantNodes.contains(classes.find(i));
if (predImportant && nodeImportant) {
continue;
}
int newCls = classes.union(pred, i);
if (nodeImportant || predImportant) {
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());
for (int[] scc : sccs) {
int last = -1;
for (int node : scc) {
if (!importantNodes.contains(classes.find(node))) {
continue;
}
last = last < 0 ? node : classes.union(node, last);
} }
} }
propagateEscaping(graph);
int[] classMap = new int[classes.size()]; int[] classMap = new int[classes.size()];
Arrays.fill(classMap, -1); Arrays.fill(classMap, -1);
int[] result = new int[program.variableCount()]; int[] result = new int[program.variableCount()];
int classCount = 0; int classCount = 0;
for (int i = 0; i < program.variableCount(); ++i) { for (int i = 0; i < program.variableCount(); ++i) {
int cls = classes.find(i); if (!escaping.contains(i) && i >= significantParams.length) {
if (!importantNodes.contains(cls)) {
result[i] = -1; result[i] = -1;
continue; continue;
} }
int cls = classes.find(i);
int packedCls = classMap[cls]; int packedCls = classMap[cls];
if (packedCls < 0) { if (packedCls < 0) {
packedCls = classCount++; packedCls = classCount++;
@ -131,6 +99,32 @@ public class DataFlowGraphBuilder implements InstructionReader {
return result; return result;
} }
private void propagateEscaping(Graph graph) {
IntegerStack stack = new IntegerStack(graph.size());
for (IntCursor node : escaping) {
stack.push(node.value);
}
escaping.clear();
while (!stack.isEmpty()) {
int node = stack.pop();
if (!escaping.add(node)) {
continue;
}
if (node < graph.size()) {
for (int pred : graph.incomingEdges(node)) {
if (!escaping.contains(pred)) {
stack.push(pred);
}
}
for (int succ : graph.outgoingEdges(node)) {
if (!escaping.contains(succ)) {
stack.push(succ);
}
}
}
}
}
@Override @Override
public void location(InstructionLocation location) { public void location(InstructionLocation location) {
} }
@ -176,15 +170,19 @@ public class DataFlowGraphBuilder implements InstructionReader {
public void negate(VariableReader receiver, VariableReader operand, NumericOperandType type) { public void negate(VariableReader receiver, VariableReader operand, NumericOperandType type) {
} }
private void connect(int a, int b) {
builder.addEdge(a, b);
join(a, b);
}
@Override @Override
public void assign(VariableReader receiver, VariableReader assignee) { public void assign(VariableReader receiver, VariableReader assignee) {
builder.addEdge(assignee.getIndex(), receiver.getIndex()); connect(assignee.getIndex(), receiver.getIndex());
} }
@Override @Override
public void cast(VariableReader receiver, VariableReader value, ValueType targetType) { public void cast(VariableReader receiver, VariableReader value, ValueType targetType) {
builder.addEdge(value.getIndex(), receiver.getIndex()); builder.addEdge(value.getIndex(), receiver.getIndex());
important(receiver.getIndex());
} }
@Override @Override
@ -219,15 +217,14 @@ public class DataFlowGraphBuilder implements InstructionReader {
@Override @Override
public void exit(VariableReader valueToReturn) { public void exit(VariableReader valueToReturn) {
if (valueToReturn != null && returnIndex >= 0) { if (valueToReturn != null && returnIndex >= 0) {
important(returnIndex); connect(valueToReturn.getIndex(), returnIndex);
builder.addEdge(valueToReturn.getIndex(), returnIndex);
} }
} }
@Override @Override
public void raise(VariableReader exception) { public void raise(VariableReader exception) {
builder.addEdge(exception.getIndex(), exceptionIndex); builder.addEdge(exception.getIndex(), exceptionIndex);
important(exceptionIndex); escaping.add(exceptionIndex);
} }
@Override @Override
@ -245,10 +242,10 @@ public class DataFlowGraphBuilder implements InstructionReader {
private int getFieldNode(FieldReference field) { private int getFieldNode(FieldReference field) {
int fieldNode = fieldNodes.getOrDefault(field, -1); int fieldNode = fieldNodes.getOrDefault(field, -1);
if (fieldNode < 0) { if (fieldNode < 0) {
fieldNode = lastIndex++; fieldNode = classes.create();
fieldNodes.put(field, fieldNode); fieldNodes.put(field, fieldNode);
} }
important(fieldNode); escaping.add(fieldNode);
return fieldNode; return fieldNode;
} }
@ -257,8 +254,7 @@ public class DataFlowGraphBuilder implements InstructionReader {
if (fieldType instanceof ValueType.Primitive) { if (fieldType instanceof ValueType.Primitive) {
return; return;
} }
int fieldNode = getFieldNode(field); connect(getFieldNode(field), receiver.getIndex());
builder.addEdge(fieldNode, receiver.getIndex());
} }
@Override @Override
@ -266,8 +262,7 @@ public class DataFlowGraphBuilder implements InstructionReader {
if (fieldType instanceof ValueType.Primitive) { if (fieldType instanceof ValueType.Primitive) {
return; return;
} }
int fieldNode = getFieldNode(field); connect(value.getIndex(), getFieldNode(field));
builder.addEdge(value.getIndex(), fieldNode);
} }
@Override @Override
@ -276,65 +271,40 @@ public class DataFlowGraphBuilder implements InstructionReader {
@Override @Override
public void cloneArray(VariableReader receiver, VariableReader array) { public void cloneArray(VariableReader receiver, VariableReader array) {
important(receiver.getIndex());
builder.addEdge(array.getIndex(), receiver.getIndex()); builder.addEdge(array.getIndex(), receiver.getIndex());
} }
@Override @Override
public void unwrapArray(VariableReader receiver, VariableReader array, ArrayElementType elementType) { public void unwrapArray(VariableReader receiver, VariableReader array, ArrayElementType elementType) {
if (elementType == ArrayElementType.OBJECT) { if (elementType == ArrayElementType.OBJECT) {
builder.addEdge(array.getIndex(), receiver.getIndex()); connect(array.getIndex(), receiver.getIndex());
} }
} }
private int getArrayElementNode(int array) {
int node = arrayNodes[array];
if (node < 0) {
node = lastIndex++;
arrayNodes[array] = node;
}
important(node);
return node;
}
@Override @Override
public void getElement(VariableReader receiver, VariableReader array, VariableReader index) { public void getElement(VariableReader receiver, VariableReader array, VariableReader index) {
important(array.getIndex()); builder.addEdge(array.getIndex(), receiver.getIndex());
builder.addEdge(getArrayElementNode(array.getIndex()), receiver.getIndex());
} }
@Override @Override
public void putElement(VariableReader array, VariableReader index, VariableReader value) { public void putElement(VariableReader array, VariableReader index, VariableReader value) {
important(array.getIndex()); builder.addEdge(value.getIndex(), array.getIndex());
builder.addEdge(value.getIndex(), getArrayElementNode(array.getIndex()));
}
private int getMethodNode(MethodReference method) {
int methodNode = methodNodes.getOrDefault(method, -1);
if (methodNode < 0) {
methodNode = lastIndex++;
methodNodes.put(method, methodNode);
}
important(methodNode);
return methodNode;
} }
@Override @Override
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 (!(method.getReturnType() instanceof ValueType.Primitive)) {
builder.addEdge(getMethodNode(method), receiver.getIndex());
}
}
ValueType[] paramTypes = method.getParameterTypes(); ValueType[] paramTypes = method.getParameterTypes();
for (int i = 0; i < paramTypes.length; ++i) { for (int i = 0; i < paramTypes.length; ++i) {
if (!(paramTypes[i] instanceof ValueType.Primitive)) { if (!(paramTypes[i] instanceof ValueType.Primitive)) {
important(arguments.get(i).getIndex()); escaping.add(arguments.get(i).getIndex());
} }
} }
if (instance != null) { if (instance != null) {
important(instance.getIndex()); escaping.add(instance.getIndex());
}
if (receiver != null && !(method.getReturnType() instanceof ValueType.Primitive)) {
escaping.add(receiver.getIndex());
} }
} }
@ -348,16 +318,16 @@ public class DataFlowGraphBuilder implements InstructionReader {
@Override @Override
public void nullCheck(VariableReader receiver, VariableReader value) { public void nullCheck(VariableReader receiver, VariableReader value) {
builder.addEdge(value.getIndex(), receiver.getIndex()); connect(value.getIndex(), receiver.getIndex());
} }
@Override @Override
public void monitorEnter(VariableReader objectRef) { public void monitorEnter(VariableReader objectRef) {
important(objectRef.getIndex()); escaping.add(objectRef.getIndex());
} }
@Override @Override
public void monitorExit(VariableReader objectRef) { public void monitorExit(VariableReader objectRef) {
important(objectRef.getIndex()); escaping.add(exceptionIndex);
} }
} }

View File

@ -504,7 +504,6 @@ 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

@ -51,10 +51,15 @@ class DependencyGraphBuilder {
resultNode = dep.getResult(); resultNode = dep.getResult();
DataFlowGraphBuilder dfgBuilder = new DataFlowGraphBuilder(); DataFlowGraphBuilder dfgBuilder = new DataFlowGraphBuilder();
for (int i = 0; i < dep.getParameterCount(); ++i) { boolean[] significantParams = new boolean[dep.getParameterCount()];
dfgBuilder.important(i); significantParams[0] = true;
for (int i = 1; i < dep.getParameterCount(); ++i) {
ValueType arg = method.parameterType(i - 1);
if (!(arg instanceof ValueType.Primitive)) {
significantParams[i] = true;
}
} }
int[] nodeMapping = dfgBuilder.buildMapping(program, dep.getParameterCount(), int[] nodeMapping = dfgBuilder.buildMapping(program, significantParams,
!(method.getResultType() instanceof ValueType.Primitive) && method.getResultType() != ValueType.VOID); !(method.getResultType() instanceof ValueType.Primitive) && method.getResultType() != ValueType.VOID);
if (DependencyChecker.shouldLog) { if (DependencyChecker.shouldLog) {
@ -93,8 +98,8 @@ class DependencyGraphBuilder {
for (IncomingReader incoming : phi.readIncomings()) { for (IncomingReader incoming : phi.readIncomings()) {
DependencyNode incomingNode = nodes[incoming.getValue().getIndex()]; DependencyNode incomingNode = nodes[incoming.getValue().getIndex()];
DependencyNode receiverNode = nodes[phi.getReceiver().getIndex()]; DependencyNode receiverNode = nodes[phi.getReceiver().getIndex()];
if (incomingNode != null || receiverNode != null) { if (incomingNode != null && receiverNode != null) {
nodes[incoming.getValue().getIndex()].connect(nodes[phi.getReceiver().getIndex()]); incomingNode.connect(receiverNode);
} }
} }
} }
@ -139,7 +144,9 @@ class DependencyGraphBuilder {
for (int i = 0; i < exceptions.length; ++i) { for (int i = 0; i < exceptions.length; ++i) {
if (exceptions[i] == null || isAssignableFrom(checker.getClassSource(), exceptions[i], if (exceptions[i] == null || isAssignableFrom(checker.getClassSource(), exceptions[i],
type.getName())) { type.getName())) {
vars[i].propagate(type); if (vars[i] != null) {
vars[i].propagate(type);
}
return; return;
} }
} }
@ -193,7 +200,7 @@ 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) { if (parameters[i] != null && targetParams[i] != null) {
parameters[i].connect(targetParams[i]); parameters[i].connect(targetParams[i]);
} }
} }
@ -307,18 +314,23 @@ class DependencyGraphBuilder {
String targetClsName = ((ValueType.Object)targetType).getClassName(); String targetClsName = ((ValueType.Object)targetType).getClassName();
final ClassReader targetClass = dependencyChecker.getClassSource().get(targetClsName); final ClassReader targetClass = dependencyChecker.getClassSource().get(targetClsName);
if (targetClass != null) { if (targetClass != null) {
valueNode.connect(receiverNode, new DependencyTypeFilter() { if (valueNode != null && receiverNode != null) {
@Override public boolean match(DependencyType type) { valueNode.connect(receiverNode, new DependencyTypeFilter() {
if (targetClass.getName().equals("java.lang.Object")) { @Override public boolean match(DependencyType type) {
return true; if (targetClass.getName().equals("java.lang.Object")) {
return true;
}
return isAssignableFrom(dependencyChecker.getClassSource(), targetClass,
type.getName());
} }
return isAssignableFrom(dependencyChecker.getClassSource(), targetClass, type.getName()); });
} }
});
return; return;
} }
} }
valueNode.connect(receiverNode); if (valueNode != null && receiverNode != null) {
valueNode.connect(receiverNode);
}
} }
@Override @Override
@ -481,7 +493,7 @@ class DependencyGraphBuilder {
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) { if (arrayNode != null && receiverNode != null && receiverNode != arrayNode.getArrayItem()) {
arrayNode.getArrayItem().connect(receiverNode); arrayNode.getArrayItem().connect(receiverNode);
} }
} }
@ -490,7 +502,7 @@ class DependencyGraphBuilder {
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) { if (valueNode != null && arrayNode != null && valueNode != arrayNode.getArrayItem()) {
valueNode.connect(arrayNode.getArrayItem()); valueNode.connect(arrayNode.getArrayItem());
} }
} }

View File

@ -24,6 +24,7 @@ import java.util.*;
public class DependencyNode implements ValueDependencyInfo { public class DependencyNode implements ValueDependencyInfo {
private DependencyChecker dependencyChecker; private DependencyChecker dependencyChecker;
private List<DependencyConsumer> followers; private List<DependencyConsumer> followers;
private int[] smallTypes;
private BitSet types; private BitSet types;
private List<DependencyNodeToNodeTransition> transitions; private List<DependencyNodeToNodeTransition> transitions;
private volatile String tag; private volatile String tag;
@ -41,6 +42,38 @@ public class DependencyNode implements ValueDependencyInfo {
this.degree = degree; this.degree = degree;
} }
private boolean addType(DependencyType type) {
if (types == null) {
if (smallTypes == null) {
smallTypes = new int[] { type.index };
return true;
}
}
if (smallTypes != null) {
for (int i = 0; i < smallTypes.length; ++i) {
if (smallTypes[i] == type.index) {
return false;
}
}
if (smallTypes.length == 5) {
types = new BitSet();
for (int existingType : smallTypes) {
types.set(existingType);
}
smallTypes = null;
} else {
smallTypes = Arrays.copyOf(smallTypes, smallTypes.length + 1);
smallTypes[smallTypes.length - 1] = type.index;
return true;
}
}
if (!types.get(type.index)) {
types.set(type.index);
return true;
}
return false;
}
public void propagate(DependencyType type) { public void propagate(DependencyType type) {
if (type.getDependencyChecker() != dependencyChecker) { if (type.getDependencyChecker() != dependencyChecker) {
throw new IllegalArgumentException("The given type does not belong to the same dependency checker"); throw new IllegalArgumentException("The given type does not belong to the same dependency checker");
@ -48,11 +81,7 @@ public class DependencyNode implements ValueDependencyInfo {
if (degree > 2) { if (degree > 2) {
return; return;
} }
if (types == null) { if (addType(type)) {
types = new BitSet();
}
if (!types.get(type.index)) {
types.set(type.index);
if (DependencyChecker.shouldLog) { if (DependencyChecker.shouldLog) {
System.out.println(tag + " -> " + type.getName()); System.out.println(tag + " -> " + type.getName());
} }
@ -64,30 +93,30 @@ public class DependencyNode implements ValueDependencyInfo {
} }
} }
public void propagate(DependencyType[] agentTypes) { public void propagate(DependencyType[] newTypes) {
DependencyType[] types = new DependencyType[agentTypes.length]; DependencyType[] types = new DependencyType[newTypes.length];
int j = 0; int j = 0;
for (int i = 0; i < agentTypes.length; ++i) { for (int i = 0; i < newTypes.length; ++i) {
DependencyType type = agentTypes[i]; DependencyType type = newTypes[i];
if (type.getDependencyChecker() != dependencyChecker) { if (type.getDependencyChecker() != dependencyChecker) {
throw new IllegalArgumentException("The given type does not belong to the same dependency checker"); throw new IllegalArgumentException("The given type does not belong to the same dependency checker");
} }
if (this.types == null || !this.types.get(type.index)) { if (addType(type)) {
types[j++] = type; types[j++] = type;
} }
} }
if (this.types == null) { if (j == 0) {
this.types = new BitSet(); return;
} }
for (int i = 0; i < j; ++i) { if (DependencyChecker.shouldLog) {
this.types.set(types[i].index); for (int i = 0; i < j; ++i) {
if (DependencyChecker.shouldLog) {
System.out.println(tag + " -> " + types[i].getName()); System.out.println(tag + " -> " + types[i].getName());
} }
} }
if (followers != null) { if (followers != null) {
types = Arrays.copyOf(types, j);
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, types);
} }
} }
} }
@ -106,6 +135,12 @@ public class DependencyNode implements ValueDependencyInfo {
types.add(dependencyChecker.types.get(index)); types.add(dependencyChecker.types.get(index));
} }
dependencyChecker.schedulePropagation(consumer, types.toArray(new DependencyType[types.size()])); dependencyChecker.schedulePropagation(consumer, types.toArray(new DependencyType[types.size()]));
} else if (this.smallTypes != null) {
DependencyType[] types = new DependencyType[smallTypes.length];
for (int i = 0; i < types.length; ++i) {
types[i] = dependencyChecker.types.get(smallTypes[i]);
}
dependencyChecker.schedulePropagation(consumer, types);
} }
} }
@ -158,10 +193,18 @@ public class DependencyNode implements ValueDependencyInfo {
@Override @Override
public boolean hasArrayType() { public boolean hasArrayType() {
return arrayItemNode != null && arrayItemNode.types != null && !arrayItemNode.types.isEmpty(); return arrayItemNode != null && (arrayItemNode.types != null || arrayItemNode.smallTypes != null);
} }
public boolean hasType(DependencyType type) { public boolean hasType(DependencyType type) {
if (smallTypes != null) {
for (int i = 0; i < smallTypes.length; ++i) {
if (smallTypes[i] == type.index) {
return true;
}
}
return false;
}
return types != null && type.getDependencyChecker() == dependencyChecker && types.get(type.index); return types != null && type.getDependencyChecker() == dependencyChecker && types.get(type.index);
} }
@ -172,6 +215,13 @@ public class DependencyNode implements ValueDependencyInfo {
@Override @Override
public String[] getTypes() { public String[] getTypes() {
if (smallTypes != null) {
String[] result = new String[smallTypes.length];
for (int i = 0; i < result.length; ++i) {
result[i] = dependencyChecker.types.get(smallTypes[i]).getName();
}
return result;
}
if (types == null) { if (types == null) {
return new String[0]; return new String[0];
} }