Skip to content

Commit 6b579e5

Browse files
committed
Optimize reachability handlers memory footprint.
1 parent 6bb5b29 commit 6b579e5

File tree

4 files changed

+361
-13
lines changed

4 files changed

+361
-13
lines changed

substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/meta/AnalysisElement.java

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -28,9 +28,11 @@
2828
import java.util.Set;
2929
import java.util.concurrent.ConcurrentHashMap;
3030
import java.util.concurrent.atomic.AtomicBoolean;
31+
import java.util.concurrent.atomic.AtomicReferenceFieldUpdater;
3132
import java.util.function.BiConsumer;
3233
import java.util.function.Consumer;
3334

35+
import com.oracle.graal.pointsto.util.ConcurrentLightHashSet;
3436
import org.graalvm.nativeimage.hosted.Feature.DuringAnalysisAccess;
3537

3638
import com.oracle.graal.pointsto.PointsToAnalysis;
@@ -41,20 +43,24 @@ public abstract class AnalysisElement {
4143
* Contains reachability handlers that are notified when the element is marked as reachable.
4244
* Each handler is notified only once, and then it is removed from the set.
4345
*/
44-
private final Set<ElementReachableNotification> elementReachableNotifications = ConcurrentHashMap.newKeySet();
46+
47+
private static final AtomicReferenceFieldUpdater<AnalysisElement, Object> reachableNotificationsUpdater = AtomicReferenceFieldUpdater
48+
.newUpdater(AnalysisElement.class, Object.class, "elementReachableNotifications");
49+
50+
@SuppressWarnings("unused") private volatile Object elementReachableNotifications;
4551

4652
public void registerReachabilityNotification(ElementReachableNotification notification) {
47-
elementReachableNotifications.add(notification);
53+
ConcurrentLightHashSet.addElement(this, reachableNotificationsUpdater, notification);
4854
}
4955

5056
public void notifyReachabilityCallback(AnalysisUniverse universe, ElementReachableNotification notification) {
5157
notification.notifyCallback(universe, this);
52-
elementReachableNotifications.remove(notification);
58+
ConcurrentLightHashSet.removeElement(this, reachableNotificationsUpdater, notification);
5359
}
5460

5561
protected void notifyReachabilityCallbacks(AnalysisUniverse universe) {
56-
elementReachableNotifications.forEach(c -> c.notifyCallback(universe, this));
57-
elementReachableNotifications.removeIf(ElementReachableNotification::isNotified);
62+
ConcurrentLightHashSet.forEach(this, reachableNotificationsUpdater, (ElementReachableNotification c) -> c.notifyCallback(universe, this));
63+
ConcurrentLightHashSet.removeElementIf(this, reachableNotificationsUpdater, ElementReachableNotification::isNotified);
5864
}
5965

6066
public abstract boolean isReachable();

substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/meta/AnalysisType.java

Lines changed: 18 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@
4040
import java.util.concurrent.atomic.AtomicReferenceFieldUpdater;
4141
import java.util.function.Consumer;
4242

43+
import com.oracle.graal.pointsto.util.ConcurrentLightHashMap;
4344
import org.graalvm.compiler.debug.GraalError;
4445
import org.graalvm.compiler.graph.Node;
4546
import org.graalvm.util.GuardedAnnotationAccess;
@@ -87,6 +88,12 @@ public abstract class AnalysisType extends AnalysisElement implements WrappedJav
8788
private static final AtomicReferenceFieldUpdater<AnalysisType, Object> INTERCEPTORS_UPDATER = //
8889
AtomicReferenceFieldUpdater.newUpdater(AnalysisType.class, Object.class, "interceptors");
8990

91+
private static final AtomicReferenceFieldUpdater<AnalysisType, Object> subtypeReachableNotificationsUpdater = AtomicReferenceFieldUpdater
92+
.newUpdater(AnalysisType.class, Object.class, "subtypeReachableNotifications");
93+
94+
private static final AtomicReferenceFieldUpdater<AnalysisType, Object> overrideReachableNotificationsUpdater = AtomicReferenceFieldUpdater
95+
.newUpdater(AnalysisType.class, Object.class, "overrideReachableNotifications");
96+
9097
protected final AnalysisUniverse universe;
9198
private final ResolvedJavaType wrapped;
9299

@@ -168,14 +175,14 @@ public enum UsageKind {
168175
* Contains reachability handlers that are notified when any of the subtypes are marked as
169176
* reachable. Each handler is notified only once per subtype.
170177
*/
171-
private final Set<SubtypeReachableNotification> subtypeReachableNotifications = ConcurrentHashMap.newKeySet();
178+
@SuppressWarnings("unused") private volatile Object subtypeReachableNotifications;
172179

173180
/**
174181
* Contains reachability handlers that are notified when any of the method override becomes
175182
* reachable *and* the declaring class of the override (or any subtype) is instantiated. Each
176183
* handler is notified only once per method override.
177184
*/
178-
private final Map<AnalysisMethod, Set<MethodOverrideReachableNotification>> overrideReachableNotifications = new ConcurrentHashMap<>();
185+
@SuppressWarnings("unused") private volatile Object overrideReachableNotifications;
179186

180187
AnalysisType(AnalysisUniverse universe, ResolvedJavaType javaType, JavaKind storageKind, AnalysisType objectType, AnalysisType cloneableType) {
181188
this.universe = universe;
@@ -476,7 +483,8 @@ private void processMethodOverrides() {
476483
forAllSuperTypes(superType -> {
477484
AtomicUtils.atomicMark(superType.isAnySubtypeInstantiated);
478485
seenSubtypes.add(superType);
479-
for (var entry : superType.overrideReachableNotifications.entrySet()) {
486+
Map<AnalysisMethod, Set<MethodOverrideReachableNotification>> overrides = ConcurrentLightHashMap.getEntries(superType, overrideReachableNotificationsUpdater);
487+
for (var entry : overrides.entrySet()) {
480488
AnalysisMethod baseMethod = entry.getKey();
481489
Set<MethodOverrideReachableNotification> overrideNotifications = entry.getValue();
482490
for (AnalysisType subType : seenSubtypes) {
@@ -517,7 +525,8 @@ public boolean registerAsReachable() {
517525
@Override
518526
protected void onReachable() {
519527
notifyReachabilityCallbacks(universe);
520-
forAllSuperTypes(type -> type.subtypeReachableNotifications.forEach(n -> n.notifyCallback(universe, this)));
528+
forAllSuperTypes(type -> ConcurrentLightHashSet.forEach(type, subtypeReachableNotificationsUpdater,
529+
(SubtypeReachableNotification n) -> n.notifyCallback(universe, this)));
521530
universe.notifyReachableType();
522531
universe.hostVM.checkForbidden(this, UsageKind.Reachable);
523532
if (isArray()) {
@@ -533,16 +542,18 @@ protected void onReachable() {
533542
}
534543

535544
public void registerSubtypeReachabilityNotification(SubtypeReachableNotification notification) {
536-
subtypeReachableNotifications.add(notification);
545+
ConcurrentLightHashSet.addElement(this, subtypeReachableNotificationsUpdater, notification);
537546
}
538547

539548
public void registerOverrideReachabilityNotification(AnalysisMethod declaredMethod, MethodOverrideReachableNotification notification) {
540549
assert declaredMethod.getDeclaringClass() == this;
541-
overrideReachableNotifications.computeIfAbsent(declaredMethod, m -> ConcurrentHashMap.newKeySet()).add(notification);
550+
Set<MethodOverrideReachableNotification> overrideNotifications = ConcurrentLightHashMap.computeIfAbsent(this,
551+
overrideReachableNotificationsUpdater, declaredMethod, m -> ConcurrentHashMap.newKeySet());
552+
overrideNotifications.add(notification);
542553
}
543554

544555
public Set<MethodOverrideReachableNotification> getOverrideReachabilityNotifications(AnalysisMethod method) {
545-
return overrideReachableNotifications.getOrDefault(method, Collections.emptySet());
556+
return ConcurrentLightHashMap.getOrDefault(this, overrideReachableNotificationsUpdater, method, Collections.emptySet());
546557
}
547558

548559
/**

0 commit comments

Comments
 (0)