Reduce memory consumption

This commit is contained in:
Alexey Andreev 2024-03-18 17:02:42 +01:00
parent 6e416c11d7
commit 622006de0e
4 changed files with 90 additions and 38 deletions

View File

@ -42,7 +42,7 @@ public class DependencyNode implements ValueDependencyInfo {
private DependencyNode arrayItemNode; private DependencyNode arrayItemNode;
DependencyNode classValueNode; DependencyNode classValueNode;
DependencyNode classNodeParent; DependencyNode classNodeParent;
boolean classNodeComplete; private boolean classNodeComplete;
int degree; int degree;
boolean locked; boolean locked;
MethodReference method; MethodReference method;
@ -65,13 +65,13 @@ public class DependencyNode implements ValueDependencyInfo {
propagateCount++; propagateCount++;
moveToSeparateDomain(); moveToSeparateDomain();
typeSet.addType(type); typeSet.addType(type);
scheduleSingleType(type, null); scheduleSingleType(type);
} }
} }
private void scheduleSingleType(DependencyType type, Runnable action) { private void scheduleSingleType(DependencyType type) {
if (DependencyAnalyzer.shouldLog) { if (DependencyAnalyzer.shouldLog) {
for (DependencyNode node : typeSet.domain) { for (DependencyNode node : typeSet.domain()) {
if (node.filter(type)) { if (node.filter(type)) {
System.out.println(node.tag + " -> " + type.getName()); System.out.println(node.tag + " -> " + type.getName());
} }
@ -81,10 +81,6 @@ public class DependencyNode implements ValueDependencyInfo {
Transition[] transitions = typeSet.getTransitions().toArray(Transition.class); Transition[] transitions = typeSet.getTransitions().toArray(Transition.class);
List<ConsumerWithNode> consumerEntries = typeSet.getConsumers(); List<ConsumerWithNode> consumerEntries = typeSet.getConsumers();
if (action != null) {
action.run();
}
for (Transition transition : transitions) { for (Transition transition : transitions) {
if (transition.source.filter(type) && transition.filterType(type)) { if (transition.source.filter(type) && transition.filterType(type)) {
dependencyAnalyzer.schedulePropagation(transition, type); dependencyAnalyzer.schedulePropagation(transition, type);
@ -146,7 +142,7 @@ public class DependencyNode implements ValueDependencyInfo {
void scheduleMultipleTypes(DependencyType[] newTypes, Runnable action) { void scheduleMultipleTypes(DependencyType[] newTypes, Runnable action) {
if (DependencyAnalyzer.shouldLog) { if (DependencyAnalyzer.shouldLog) {
for (DependencyNode node : typeSet.domain) { for (var node : typeSet.domain()) {
for (DependencyType type : newTypes) { for (DependencyType type : newTypes) {
if (node.filter(type)) { if (node.filter(type)) {
System.out.println(node.tag + " -> " + type.getName()); System.out.println(node.tag + " -> " + type.getName());
@ -217,16 +213,6 @@ public class DependencyNode implements ValueDependencyInfo {
} }
} }
static class DeferredConsumerTypes {
final DependencyConsumer consumer;
final DependencyType[] types;
DeferredConsumerTypes(DependencyConsumer consumer, DependencyType[] types) {
this.consumer = consumer;
this.types = types;
}
}
boolean filter(DependencyType type) { boolean filter(DependencyType type) {
if (typeFilter == null) { if (typeFilter == null) {
return true; return true;
@ -282,7 +268,7 @@ public class DependencyNode implements ValueDependencyInfo {
} }
} }
boolean connectWithoutChildNodes(DependencyNode node, DependencyTypeFilter filter) { private boolean connectWithoutChildNodes(DependencyNode node, DependencyTypeFilter filter) {
if (this == node) { if (this == node) {
return false; return false;
} }
@ -467,7 +453,7 @@ 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, DependencyNode sourceNode, private DependencyType[] getTypesInternal(DependencyTypeFilter filter, DependencyNode sourceNode,
DependencyNode targetNode) { DependencyNode targetNode) {
if (typeSet == null) { if (typeSet == null) {
return TypeSet.EMPTY_TYPES; return TypeSet.EMPTY_TYPES;
@ -487,7 +473,7 @@ public class DependencyNode implements ValueDependencyInfo {
if (typeSet == null) { if (typeSet == null) {
Collection<DependencyNode> domain = findDomain(); Collection<DependencyNode> domain = findDomain();
typeSet = new TypeSet(dependencyAnalyzer, this); typeSet = new TypeSet(dependencyAnalyzer, this);
typeSet.domain.addAll(domain); typeSet.addDomain(domain);
for (DependencyNode node : domain) { for (DependencyNode node : domain) {
node.typeSet = typeSet; node.typeSet = typeSet;
} }
@ -503,11 +489,11 @@ public class DependencyNode implements ValueDependencyInfo {
return; return;
} }
typeSet.domain.removeAll(domain); typeSet.removeDomain(domain);
typeSet.invalidate(); typeSet.invalidate();
typeSet = typeSet.copy(this); typeSet = typeSet.copy(this);
typeSet.domain.addAll(domain); typeSet.addDomain(domain);
for (DependencyNode node : domain) { for (DependencyNode node : domain) {
node.typeSet = typeSet; node.typeSet = typeSet;
@ -515,7 +501,7 @@ public class DependencyNode implements ValueDependencyInfo {
} }
} }
Collection<DependencyNode> findDomain() { private Collection<DependencyNode> findDomain() {
if (!dependencyAnalyzer.domainOptimizationEnabled()) { if (!dependencyAnalyzer.domainOptimizationEnabled()) {
return Collections.singleton(this); return Collections.singleton(this);
} }

View File

@ -17,7 +17,6 @@ package org.teavm.dependency;
import com.carrotsearch.hppc.IntHashSet; import com.carrotsearch.hppc.IntHashSet;
import java.util.Arrays; import java.util.Arrays;
import java.util.Collection;
import org.teavm.model.ClassHierarchy; import org.teavm.model.ClassHierarchy;
import org.teavm.model.ValueType; import org.teavm.model.ValueType;
@ -26,7 +25,7 @@ class Transition {
DependencyNode destination; DependencyNode destination;
DependencyTypeFilter filter; DependencyTypeFilter filter;
IntHashSet pendingTypes; IntHashSet pendingTypes;
byte destSubsetOfSrc; private byte destSubsetOfSrc;
Transition(DependencyNode source, DependencyNode destination, DependencyTypeFilter filter) { Transition(DependencyNode source, DependencyNode destination, DependencyTypeFilter filter) {
this.source = source; this.source = source;
@ -64,19 +63,19 @@ class Transition {
} }
} }
void mergeDomains(DependencyType[] types) { private void mergeDomains(DependencyType[] types) {
destination.moveToSeparateDomain(); destination.moveToSeparateDomain();
destination.scheduleMultipleTypes(types, () -> { destination.scheduleMultipleTypes(types, () -> {
Collection<DependencyNode> domainToMerge = destination.typeSet.domain; var domainToMerge = destination.typeSet.domain();
for (DependencyNode node : domainToMerge) { for (DependencyNode node : domainToMerge) {
node.typeSet = source.typeSet; node.typeSet = source.typeSet;
source.typeSet.domain.add(node); source.typeSet.addDomain(node);
} }
source.typeSet.invalidate(); source.typeSet.invalidate();
}); });
} }
boolean shouldMergeDomains() { private boolean shouldMergeDomains() {
if (!source.dependencyAnalyzer.domainOptimizationEnabled() || filter != null || !isDestSubsetOfSrc()) { if (!source.dependencyAnalyzer.domainOptimizationEnabled() || filter != null || !isDestSubsetOfSrc()) {
return false; return false;
} }

View File

@ -20,7 +20,8 @@ import com.carrotsearch.hppc.cursors.ObjectCursor;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.BitSet; import java.util.BitSet;
import java.util.LinkedHashSet; import java.util.Collection;
import java.util.HashSet;
import java.util.List; import java.util.List;
import java.util.Set; import java.util.Set;
import java.util.function.Predicate; import java.util.function.Predicate;
@ -34,14 +35,14 @@ class TypeSet {
private BitSet types; private BitSet types;
private int typesCount; private int typesCount;
Set<DependencyNode> domain = new LinkedHashSet<>(); private Object domain;
ObjectArrayList<Transition> transitions; ObjectArrayList<Transition> transitions;
ArrayList<ConsumerWithNode> consumers; ArrayList<ConsumerWithNode> consumers;
TypeSet(DependencyAnalyzer dependencyAnalyzer, DependencyNode origin) { TypeSet(DependencyAnalyzer dependencyAnalyzer, DependencyNode origin) {
this.dependencyAnalyzer = dependencyAnalyzer; this.dependencyAnalyzer = dependencyAnalyzer;
this.origin = origin; this.origin = origin;
domain.add(origin); domain = origin;
} }
void addType(DependencyType type) { void addType(DependencyType type) {
@ -210,10 +211,76 @@ class TypeSet {
consumers = null; consumers = null;
} }
Set<? extends DependencyNode> domain() {
if (domain == null) {
return Set.of();
} else if (domain instanceof DependencyNode) {
return Set.of((DependencyNode) domain);
} else {
//noinspection unchecked
return (Set<? extends DependencyNode>) domain;
}
}
void addDomain(DependencyNode node) {
if (domain == null) {
domain = node;
} else if (domain instanceof DependencyNode) {
if (domain == node) {
return;
}
domain = new HashSet<>(Set.of((DependencyNode) domain));
}
@SuppressWarnings("unchecked")
var set = (Set<DependencyNode>) domain;
set.add(node);
}
void addDomain(Collection<? extends DependencyNode> nodes) {
if (nodes.isEmpty()) {
return;
}
if (domain == null) {
if (nodes.size() == 1) {
domain = nodes.iterator().next();
}
return;
} else if (domain instanceof DependencyNode) {
if (nodes.contains(domain) && nodes.size() == 1) {
return;
}
domain = new HashSet<>(Set.of((DependencyNode) domain));
}
@SuppressWarnings("unchecked")
var set = (Set<DependencyNode>) domain;
set.addAll(nodes);
}
void removeDomain(Collection<? extends DependencyNode> nodes) {
if (domain == null || nodes.isEmpty()) {
return;
}
if (domain instanceof DependencyNode) {
if (nodes.contains(domain)) {
domain = null;
}
return;
}
@SuppressWarnings("unchecked")
var set = (Set<DependencyNode>) domain;
set.removeAll(nodes);
if (set.isEmpty()) {
domain = null;
} else if (set.size() == 1) {
domain = set.iterator().next();
}
}
ObjectArrayList<Transition> getTransitions() { ObjectArrayList<Transition> getTransitions() {
if (transitions == null) { if (transitions == null) {
transitions = new ObjectArrayList<>(domain.size() * 2); transitions = new ObjectArrayList<>();
for (DependencyNode node : domain) { for (DependencyNode node : domain()) {
if (node.transitions != null) { if (node.transitions != null) {
for (ObjectCursor<Transition> cursor : node.transitionList) { for (ObjectCursor<Transition> cursor : node.transitionList) {
Transition transition = cursor.value; Transition transition = cursor.value;
@ -230,7 +297,7 @@ class TypeSet {
List<ConsumerWithNode> getConsumers() { List<ConsumerWithNode> getConsumers() {
if (consumers == null) { if (consumers == null) {
consumers = new ArrayList<>(); consumers = new ArrayList<>();
for (DependencyNode node : domain) { for (var node : domain()) {
if (node.followers != null) { if (node.followers != null) {
consumers.add(new ConsumerWithNode(node.followers.toArray(new DependencyConsumer[0]), node)); consumers.add(new ConsumerWithNode(node.followers.toArray(new DependencyConsumer[0]), node));
} }

View File

@ -22,7 +22,7 @@ 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 static final 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;