Reduce memory consumption in dependency analyzer

This commit is contained in:
Alexey Andreev 2024-03-18 16:21:12 +01:00
parent 287333b54e
commit 6e416c11d7
2 changed files with 68 additions and 11 deletions

View File

@ -15,13 +15,16 @@
*/ */
package org.teavm.dependency; package org.teavm.dependency;
import com.carrotsearch.hppc.IntIntHashMap;
import java.util.BitSet; import java.util.BitSet;
import org.teavm.common.OptionalPredicate; import org.teavm.common.OptionalPredicate;
class SuperClassFilter implements DependencyTypeFilter { class SuperClassFilter implements DependencyTypeFilter {
private static final int SMALL_CACHE_THRESHOLD = 16;
private OptionalPredicate<String> predicate; private OptionalPredicate<String> predicate;
private BitSet knownTypes = new BitSet(); private IntIntHashMap smallCache;
private BitSet cache = new BitSet(); private BitSet knownTypes;
private BitSet cache;
SuperClassFilter(DependencyAnalyzer dependencyAnalyzer, DependencyType superType) { SuperClassFilter(DependencyAnalyzer dependencyAnalyzer, DependencyType superType) {
predicate = dependencyAnalyzer.getClassHierarchy().getSuperclassPredicate(superType.getName()); predicate = dependencyAnalyzer.getClassHierarchy().getSuperclassPredicate(superType.getName());
@ -29,12 +32,38 @@ class SuperClassFilter implements DependencyTypeFilter {
@Override @Override
public boolean match(DependencyType type) { public boolean match(DependencyType type) {
if (knownTypes.get(type.index)) { if (knownTypes != null) {
return cache.get(type.index); if (knownTypes.get(type.index)) {
return cache.get(type.index);
}
boolean result = predicate.test(type.getName(), false);
knownTypes.set(type.index);
cache.set(type.index, result);
return result;
} }
boolean result = predicate.test(type.getName(), false);
knownTypes.set(type.index); if (smallCache == null) {
cache.set(type.index, result); smallCache = new IntIntHashMap();
return result; }
var result = smallCache.getOrDefault(type.index, -1);
if (result != -1) {
return result != 0;
}
var value = predicate.test(type.getName(), false);
smallCache.put(type.index, value ? 1 : 0);
if (smallCache.size() > SMALL_CACHE_THRESHOLD) {
knownTypes = new BitSet();
cache = new BitSet();
for (var entry : smallCache) {
knownTypes.set(entry.key);
if (entry.value != 0) {
cache.set(entry.key);
}
}
smallCache = null;
}
return value;
} }
} }

View File

@ -15,17 +15,21 @@
*/ */
package org.teavm.dependency; package org.teavm.dependency;
import com.carrotsearch.hppc.IntHashSet;
import com.carrotsearch.hppc.IntSet;
import java.util.BitSet; import java.util.BitSet;
import org.teavm.model.CallLocation; import org.teavm.model.CallLocation;
import org.teavm.model.MethodDescriptor; import org.teavm.model.MethodDescriptor;
class VirtualCallConsumer implements DependencyConsumer { class VirtualCallConsumer implements DependencyConsumer {
private static int SMALL_TYPES_THRESHOLD = 16;
private final MethodDescriptor methodDesc; private final MethodDescriptor methodDesc;
private final DependencyAnalyzer analyzer; private final DependencyAnalyzer analyzer;
private final DependencyNode[] parameters; private final DependencyNode[] parameters;
private final DependencyNode result; private final DependencyNode result;
private final CallLocation location; private final CallLocation location;
private final BitSet knownTypes = new BitSet(); private IntSet smallKnownTypes;
private BitSet knownTypes;
private DependencyGraphBuilder.ExceptionConsumer exceptionConsumer; private DependencyGraphBuilder.ExceptionConsumer exceptionConsumer;
private DependencyTypeFilter filter; private DependencyTypeFilter filter;
private boolean isPolymorphic; private boolean isPolymorphic;
@ -43,16 +47,40 @@ class VirtualCallConsumer implements DependencyConsumer {
this.exceptionConsumer = exceptionConsumer; this.exceptionConsumer = exceptionConsumer;
} }
private boolean addKnownType(int index) {
if (knownTypes != null) {
if (knownTypes.get(index)) {
return false;
} else {
knownTypes.set(index);
return true;
}
}
if (smallKnownTypes == null) {
smallKnownTypes = new IntHashSet();
}
if (smallKnownTypes.add(index)) {
if (smallKnownTypes.size() > SMALL_TYPES_THRESHOLD) {
knownTypes = new BitSet();
for (var cursor : smallKnownTypes) {
knownTypes.set(cursor.value);
}
smallKnownTypes = null;
}
return true;
}
return false;
}
@Override @Override
public void consume(DependencyType type) { public void consume(DependencyType type) {
if (!filter.match(type)) { if (!filter.match(type)) {
return; return;
} }
if (knownTypes.get(type.index)) { if (!addKnownType(type.index)) {
return; return;
} }
knownTypes.set(type.index);
String className = type.getName(); String className = type.getName();