Fix NPE in dependency analyzer. Fix excessive types propagating in dependency analyzer

This commit is contained in:
Alexey Andreev 2018-08-27 16:17:23 +03:00
parent 558c3f2f1e
commit d6363c5fbf
3 changed files with 47 additions and 9 deletions

View File

@ -460,7 +460,9 @@ class DependencyGraphBuilder {
return; return;
} }
} }
if (valueNode != null && receiverNode != null) {
valueNode.connect(receiverNode, dependencyAnalyzer.getSuperClassFilter(targetType.toString())); valueNode.connect(receiverNode, dependencyAnalyzer.getSuperClassFilter(targetType.toString()));
}
return; return;
} }
if (valueNode != null && receiverNode != null) { if (valueNode != null && receiverNode != null) {

View File

@ -33,7 +33,7 @@ import org.teavm.model.ValueType;
public class DependencyNode implements ValueDependencyInfo { public class DependencyNode implements ValueDependencyInfo {
private static final int SMALL_TYPES_THRESHOLD = 3; private static final int SMALL_TYPES_THRESHOLD = 3;
private static final int DEGREE_THRESHOLD = 2; private static final int DEGREE_THRESHOLD = 2;
private DependencyAnalyzer dependencyAnalyzer; DependencyAnalyzer dependencyAnalyzer;
List<DependencyConsumer> followers; List<DependencyConsumer> followers;
TypeSet typeSet; TypeSet typeSet;
ObjectObjectHashMap<DependencyNode, DependencyNodeToNodeTransition> transitions; ObjectObjectHashMap<DependencyNode, DependencyNodeToNodeTransition> transitions;
@ -46,11 +46,10 @@ public class DependencyNode implements ValueDependencyInfo {
private int degree; private int degree;
boolean locked; boolean locked;
MethodReference method; MethodReference method;
private ValueType typeFilter; ValueType typeFilter;
private DependencyTypeFilter cachedTypeFilter; private DependencyTypeFilter cachedTypeFilter;
boolean visitedFlag; boolean visitedFlag;
int splitCount;
DependencyNode(DependencyAnalyzer dependencyAnalyzer, ValueType typeFilter) { DependencyNode(DependencyAnalyzer dependencyAnalyzer, ValueType typeFilter) {
this(dependencyAnalyzer, typeFilter, 0); this(dependencyAnalyzer, typeFilter, 0);
@ -287,7 +286,7 @@ public class DependencyNode implements ValueDependencyInfo {
typeSet.transitions.add(transition); typeSet.transitions.add(transition);
} }
node.propagate(getTypesInternal()); node.propagate(filter != null ? getTypesInternal(filter) : getTypesInternal());
} }
connectArrayItemNodes(node); connectArrayItemNodes(node);
@ -446,6 +445,21 @@ public class DependencyNode implements ValueDependencyInfo {
return i == result.length ? result : Arrays.copyOf(result, i); return i == result.length ? result : Arrays.copyOf(result, i);
} }
DependencyType[] getTypesInternal(DependencyTypeFilter filter) {
if (typeSet == null) {
return new DependencyType[0];
}
DependencyType[] types = typeSet.getTypes();
DependencyType[] result = new DependencyType[types.length];
int i = 0;
for (DependencyType type : types) {
if (filter(type) && filter.match(type)) {
result[i++] = type;
}
}
return i == result.length ? result : Arrays.copyOf(result, i);
}
public String getTag() { public String getTag() {
return tag; return tag;
} }
@ -483,7 +497,6 @@ public class DependencyNode implements ValueDependencyInfo {
for (DependencyNode node : domain) { for (DependencyNode node : domain) {
node.typeSet = typeSet; node.typeSet = typeSet;
node.splitCount++;
} }
} }
@ -502,7 +515,7 @@ public class DependencyNode implements ValueDependencyInfo {
for (ObjectCursor<DependencyNodeToNodeTransition> cursor : node.transitionList) { for (ObjectCursor<DependencyNodeToNodeTransition> cursor : node.transitionList) {
DependencyNodeToNodeTransition transition = cursor.value; DependencyNodeToNodeTransition transition = cursor.value;
if (transition.filter == null && transition.destination.typeSet == typeSet if (transition.filter == null && transition.destination.typeSet == typeSet
&& !visited.contains(transition.destination)) { && !visited.contains(transition.destination) && transition.isDestSubsetOfSrc()) {
stack.push(transition.destination); stack.push(transition.destination);
} }
} }

View File

@ -19,6 +19,8 @@ import com.carrotsearch.hppc.IntSet;
import java.util.Arrays; import java.util.Arrays;
import java.util.BitSet; import java.util.BitSet;
import java.util.Collection; import java.util.Collection;
import org.teavm.model.ClassReaderSource;
import org.teavm.model.ValueType;
class DependencyNodeToNodeTransition { class DependencyNodeToNodeTransition {
DependencyNode source; DependencyNode source;
@ -26,6 +28,7 @@ class DependencyNodeToNodeTransition {
DependencyTypeFilter filter; DependencyTypeFilter filter;
private BitSet knownFilteredOffTypes; private BitSet knownFilteredOffTypes;
IntSet pendingTypes; IntSet pendingTypes;
byte destSubsetOfSrc;
DependencyNodeToNodeTransition(DependencyNode source, DependencyNode destination, DependencyTypeFilter filter) { DependencyNodeToNodeTransition(DependencyNode source, DependencyNode destination, DependencyTypeFilter filter) {
this.source = source; this.source = source;
@ -69,7 +72,6 @@ class DependencyNodeToNodeTransition {
Collection<DependencyNode> domainToMerge = destination.typeSet.domain; Collection<DependencyNode> domainToMerge = destination.typeSet.domain;
for (DependencyNode node : domainToMerge) { for (DependencyNode node : domainToMerge) {
node.typeSet = source.typeSet; node.typeSet = source.typeSet;
node.splitCount++;
source.typeSet.domain.add(node); source.typeSet.domain.add(node);
} }
source.typeSet.invalidate(); source.typeSet.invalidate();
@ -77,7 +79,7 @@ class DependencyNodeToNodeTransition {
} }
boolean shouldMergeDomains() { boolean shouldMergeDomains() {
if (filter != null || destination.splitCount > 2) { if (filter != null) {
return false; return false;
} }
if (destination.typeSet == null) { if (destination.typeSet == null) {
@ -171,4 +173,25 @@ class DependencyNodeToNodeTransition {
boolean pointsToDomainOrigin() { boolean pointsToDomainOrigin() {
return destination.typeSet == null || destination.typeSet.origin == destination; return destination.typeSet == null || destination.typeSet.origin == destination;
} }
boolean isDestSubsetOfSrc() {
if (destSubsetOfSrc == 0) {
destSubsetOfSrc = calculateDestSubsetOfSrc() ? (byte) 2 : 1;
}
return destSubsetOfSrc == 2;
}
private boolean calculateDestSubsetOfSrc() {
if (source.typeFilter == null) {
return true;
}
if (destination.typeFilter == null) {
return false;
}
ValueType sourceType = source.typeFilter;
ValueType destType = destination.typeFilter;
ClassReaderSource classSource = source.dependencyAnalyzer.getClassSource();
return classSource.isSuperType(sourceType, destType).orElse(false);
}
} }