diff --git a/core/src/main/java/org/teavm/dependency/DependencyGraphBuilder.java b/core/src/main/java/org/teavm/dependency/DependencyGraphBuilder.java index cb6f3bef7..b8d49cfe9 100644 --- a/core/src/main/java/org/teavm/dependency/DependencyGraphBuilder.java +++ b/core/src/main/java/org/teavm/dependency/DependencyGraphBuilder.java @@ -460,7 +460,9 @@ class DependencyGraphBuilder { return; } } - valueNode.connect(receiverNode, dependencyAnalyzer.getSuperClassFilter(targetType.toString())); + if (valueNode != null && receiverNode != null) { + valueNode.connect(receiverNode, dependencyAnalyzer.getSuperClassFilter(targetType.toString())); + } return; } if (valueNode != null && receiverNode != null) { diff --git a/core/src/main/java/org/teavm/dependency/DependencyNode.java b/core/src/main/java/org/teavm/dependency/DependencyNode.java index e469b387d..a6ff6da6d 100644 --- a/core/src/main/java/org/teavm/dependency/DependencyNode.java +++ b/core/src/main/java/org/teavm/dependency/DependencyNode.java @@ -33,7 +33,7 @@ import org.teavm.model.ValueType; public class DependencyNode implements ValueDependencyInfo { private static final int SMALL_TYPES_THRESHOLD = 3; private static final int DEGREE_THRESHOLD = 2; - private DependencyAnalyzer dependencyAnalyzer; + DependencyAnalyzer dependencyAnalyzer; List<DependencyConsumer> followers; TypeSet typeSet; ObjectObjectHashMap<DependencyNode, DependencyNodeToNodeTransition> transitions; @@ -46,11 +46,10 @@ public class DependencyNode implements ValueDependencyInfo { private int degree; boolean locked; MethodReference method; - private ValueType typeFilter; + ValueType typeFilter; private DependencyTypeFilter cachedTypeFilter; boolean visitedFlag; - int splitCount; DependencyNode(DependencyAnalyzer dependencyAnalyzer, ValueType typeFilter) { this(dependencyAnalyzer, typeFilter, 0); @@ -287,7 +286,7 @@ public class DependencyNode implements ValueDependencyInfo { typeSet.transitions.add(transition); } - node.propagate(getTypesInternal()); + node.propagate(filter != null ? getTypesInternal(filter) : getTypesInternal()); } connectArrayItemNodes(node); @@ -446,6 +445,21 @@ public class DependencyNode implements ValueDependencyInfo { 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() { return tag; } @@ -483,7 +497,6 @@ public class DependencyNode implements ValueDependencyInfo { for (DependencyNode node : domain) { node.typeSet = typeSet; - node.splitCount++; } } @@ -502,7 +515,7 @@ public class DependencyNode implements ValueDependencyInfo { for (ObjectCursor<DependencyNodeToNodeTransition> cursor : node.transitionList) { DependencyNodeToNodeTransition transition = cursor.value; if (transition.filter == null && transition.destination.typeSet == typeSet - && !visited.contains(transition.destination)) { + && !visited.contains(transition.destination) && transition.isDestSubsetOfSrc()) { stack.push(transition.destination); } } diff --git a/core/src/main/java/org/teavm/dependency/DependencyNodeToNodeTransition.java b/core/src/main/java/org/teavm/dependency/DependencyNodeToNodeTransition.java index 4a654e268..b2a247516 100644 --- a/core/src/main/java/org/teavm/dependency/DependencyNodeToNodeTransition.java +++ b/core/src/main/java/org/teavm/dependency/DependencyNodeToNodeTransition.java @@ -19,6 +19,8 @@ import com.carrotsearch.hppc.IntSet; import java.util.Arrays; import java.util.BitSet; import java.util.Collection; +import org.teavm.model.ClassReaderSource; +import org.teavm.model.ValueType; class DependencyNodeToNodeTransition { DependencyNode source; @@ -26,6 +28,7 @@ class DependencyNodeToNodeTransition { DependencyTypeFilter filter; private BitSet knownFilteredOffTypes; IntSet pendingTypes; + byte destSubsetOfSrc; DependencyNodeToNodeTransition(DependencyNode source, DependencyNode destination, DependencyTypeFilter filter) { this.source = source; @@ -69,7 +72,6 @@ class DependencyNodeToNodeTransition { Collection<DependencyNode> domainToMerge = destination.typeSet.domain; for (DependencyNode node : domainToMerge) { node.typeSet = source.typeSet; - node.splitCount++; source.typeSet.domain.add(node); } source.typeSet.invalidate(); @@ -77,7 +79,7 @@ class DependencyNodeToNodeTransition { } boolean shouldMergeDomains() { - if (filter != null || destination.splitCount > 2) { + if (filter != null) { return false; } if (destination.typeSet == null) { @@ -171,4 +173,25 @@ class DependencyNodeToNodeTransition { boolean pointsToDomainOrigin() { 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); + } }