From 622006de0e9b37039afab985bf2888054470b15e Mon Sep 17 00:00:00 2001 From: Alexey Andreev Date: Mon, 18 Mar 2024 17:02:42 +0100 Subject: [PATCH] Reduce memory consumption --- .../org/teavm/dependency/DependencyNode.java | 36 +++------ .../java/org/teavm/dependency/Transition.java | 11 ++- .../java/org/teavm/dependency/TypeSet.java | 79 +++++++++++++++++-- .../teavm/dependency/VirtualCallConsumer.java | 2 +- 4 files changed, 90 insertions(+), 38 deletions(-) diff --git a/core/src/main/java/org/teavm/dependency/DependencyNode.java b/core/src/main/java/org/teavm/dependency/DependencyNode.java index c3874b2e0..74125e277 100644 --- a/core/src/main/java/org/teavm/dependency/DependencyNode.java +++ b/core/src/main/java/org/teavm/dependency/DependencyNode.java @@ -42,7 +42,7 @@ public class DependencyNode implements ValueDependencyInfo { private DependencyNode arrayItemNode; DependencyNode classValueNode; DependencyNode classNodeParent; - boolean classNodeComplete; + private boolean classNodeComplete; int degree; boolean locked; MethodReference method; @@ -65,13 +65,13 @@ public class DependencyNode implements ValueDependencyInfo { propagateCount++; moveToSeparateDomain(); typeSet.addType(type); - scheduleSingleType(type, null); + scheduleSingleType(type); } } - private void scheduleSingleType(DependencyType type, Runnable action) { + private void scheduleSingleType(DependencyType type) { if (DependencyAnalyzer.shouldLog) { - for (DependencyNode node : typeSet.domain) { + for (DependencyNode node : typeSet.domain()) { if (node.filter(type)) { System.out.println(node.tag + " -> " + type.getName()); } @@ -81,10 +81,6 @@ public class DependencyNode implements ValueDependencyInfo { Transition[] transitions = typeSet.getTransitions().toArray(Transition.class); List consumerEntries = typeSet.getConsumers(); - if (action != null) { - action.run(); - } - for (Transition transition : transitions) { if (transition.source.filter(type) && transition.filterType(type)) { dependencyAnalyzer.schedulePropagation(transition, type); @@ -146,7 +142,7 @@ public class DependencyNode implements ValueDependencyInfo { void scheduleMultipleTypes(DependencyType[] newTypes, Runnable action) { if (DependencyAnalyzer.shouldLog) { - for (DependencyNode node : typeSet.domain) { + for (var node : typeSet.domain()) { for (DependencyType type : newTypes) { if (node.filter(type)) { 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) { if (typeFilter == null) { 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) { return false; } @@ -467,7 +453,7 @@ public class DependencyNode implements ValueDependencyInfo { return i == result.length ? result : Arrays.copyOf(result, i); } - DependencyType[] getTypesInternal(DependencyTypeFilter filter, DependencyNode sourceNode, + private DependencyType[] getTypesInternal(DependencyTypeFilter filter, DependencyNode sourceNode, DependencyNode targetNode) { if (typeSet == null) { return TypeSet.EMPTY_TYPES; @@ -487,7 +473,7 @@ public class DependencyNode implements ValueDependencyInfo { if (typeSet == null) { Collection domain = findDomain(); typeSet = new TypeSet(dependencyAnalyzer, this); - typeSet.domain.addAll(domain); + typeSet.addDomain(domain); for (DependencyNode node : domain) { node.typeSet = typeSet; } @@ -503,11 +489,11 @@ public class DependencyNode implements ValueDependencyInfo { return; } - typeSet.domain.removeAll(domain); + typeSet.removeDomain(domain); typeSet.invalidate(); typeSet = typeSet.copy(this); - typeSet.domain.addAll(domain); + typeSet.addDomain(domain); for (DependencyNode node : domain) { node.typeSet = typeSet; @@ -515,7 +501,7 @@ public class DependencyNode implements ValueDependencyInfo { } } - Collection findDomain() { + private Collection findDomain() { if (!dependencyAnalyzer.domainOptimizationEnabled()) { return Collections.singleton(this); } diff --git a/core/src/main/java/org/teavm/dependency/Transition.java b/core/src/main/java/org/teavm/dependency/Transition.java index 262a97986..67fcb6ee3 100644 --- a/core/src/main/java/org/teavm/dependency/Transition.java +++ b/core/src/main/java/org/teavm/dependency/Transition.java @@ -17,7 +17,6 @@ package org.teavm.dependency; import com.carrotsearch.hppc.IntHashSet; import java.util.Arrays; -import java.util.Collection; import org.teavm.model.ClassHierarchy; import org.teavm.model.ValueType; @@ -26,7 +25,7 @@ class Transition { DependencyNode destination; DependencyTypeFilter filter; IntHashSet pendingTypes; - byte destSubsetOfSrc; + private byte destSubsetOfSrc; Transition(DependencyNode source, DependencyNode destination, DependencyTypeFilter filter) { this.source = source; @@ -64,19 +63,19 @@ class Transition { } } - void mergeDomains(DependencyType[] types) { + private void mergeDomains(DependencyType[] types) { destination.moveToSeparateDomain(); destination.scheduleMultipleTypes(types, () -> { - Collection domainToMerge = destination.typeSet.domain; + var domainToMerge = destination.typeSet.domain(); for (DependencyNode node : domainToMerge) { node.typeSet = source.typeSet; - source.typeSet.domain.add(node); + source.typeSet.addDomain(node); } source.typeSet.invalidate(); }); } - boolean shouldMergeDomains() { + private boolean shouldMergeDomains() { if (!source.dependencyAnalyzer.domainOptimizationEnabled() || filter != null || !isDestSubsetOfSrc()) { return false; } diff --git a/core/src/main/java/org/teavm/dependency/TypeSet.java b/core/src/main/java/org/teavm/dependency/TypeSet.java index 34e9c1bef..fdceba944 100644 --- a/core/src/main/java/org/teavm/dependency/TypeSet.java +++ b/core/src/main/java/org/teavm/dependency/TypeSet.java @@ -20,7 +20,8 @@ import com.carrotsearch.hppc.cursors.ObjectCursor; import java.util.ArrayList; import java.util.Arrays; import java.util.BitSet; -import java.util.LinkedHashSet; +import java.util.Collection; +import java.util.HashSet; import java.util.List; import java.util.Set; import java.util.function.Predicate; @@ -34,14 +35,14 @@ class TypeSet { private BitSet types; private int typesCount; - Set domain = new LinkedHashSet<>(); + private Object domain; ObjectArrayList transitions; ArrayList consumers; TypeSet(DependencyAnalyzer dependencyAnalyzer, DependencyNode origin) { this.dependencyAnalyzer = dependencyAnalyzer; this.origin = origin; - domain.add(origin); + domain = origin; } void addType(DependencyType type) { @@ -210,10 +211,76 @@ class TypeSet { consumers = null; } + Set domain() { + if (domain == null) { + return Set.of(); + } else if (domain instanceof DependencyNode) { + return Set.of((DependencyNode) domain); + } else { + //noinspection unchecked + return (Set) 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) domain; + set.add(node); + } + + void addDomain(Collection 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) domain; + set.addAll(nodes); + } + + void removeDomain(Collection nodes) { + if (domain == null || nodes.isEmpty()) { + return; + } + if (domain instanceof DependencyNode) { + if (nodes.contains(domain)) { + domain = null; + } + return; + } + + @SuppressWarnings("unchecked") + var set = (Set) domain; + set.removeAll(nodes); + if (set.isEmpty()) { + domain = null; + } else if (set.size() == 1) { + domain = set.iterator().next(); + } + } + ObjectArrayList getTransitions() { if (transitions == null) { - transitions = new ObjectArrayList<>(domain.size() * 2); - for (DependencyNode node : domain) { + transitions = new ObjectArrayList<>(); + for (DependencyNode node : domain()) { if (node.transitions != null) { for (ObjectCursor cursor : node.transitionList) { Transition transition = cursor.value; @@ -230,7 +297,7 @@ class TypeSet { List getConsumers() { if (consumers == null) { consumers = new ArrayList<>(); - for (DependencyNode node : domain) { + for (var node : domain()) { if (node.followers != null) { consumers.add(new ConsumerWithNode(node.followers.toArray(new DependencyConsumer[0]), node)); } diff --git a/core/src/main/java/org/teavm/dependency/VirtualCallConsumer.java b/core/src/main/java/org/teavm/dependency/VirtualCallConsumer.java index 7b7f454c8..633c6a437 100644 --- a/core/src/main/java/org/teavm/dependency/VirtualCallConsumer.java +++ b/core/src/main/java/org/teavm/dependency/VirtualCallConsumer.java @@ -22,7 +22,7 @@ import org.teavm.model.CallLocation; import org.teavm.model.MethodDescriptor; 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 DependencyAnalyzer analyzer; private final DependencyNode[] parameters;