From e6a60ed01934d8eca41b8ea6f1afa9d089396e85 Mon Sep 17 00:00:00 2001 From: Tom Rodriguez Date: Mon, 4 Dec 2023 21:14:41 -0800 Subject: [PATCH 1/2] 8321288: [JVMCI] HotSpotJVMCIRuntime doesn't clean up WeakReferences in resolvedJavaTypes --- .../vm/ci/hotspot/HotSpotJVMCIRuntime.java | 37 +++++++++++++++++-- 1 file changed, 34 insertions(+), 3 deletions(-) diff --git a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotJVMCIRuntime.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotJVMCIRuntime.java index b0ee27f36a702..8ba94609f5d58 100644 --- a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotJVMCIRuntime.java +++ b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotJVMCIRuntime.java @@ -35,6 +35,7 @@ import java.lang.invoke.CallSite; import java.lang.invoke.ConstantCallSite; import java.lang.invoke.MethodHandle; +import java.lang.ref.ReferenceQueue; import java.lang.ref.WeakReference; import java.lang.reflect.Executable; import java.lang.reflect.Field; @@ -499,7 +500,20 @@ T get() { } } - @NativeImageReinitialize private HashMap> resolvedJavaTypes; + + static class KlassWeakReference extends WeakReference { + + private final Long klassPointer; + + public KlassWeakReference(Long klassPointer, ResolvedJavaType referent, ReferenceQueueq) { + super(referent, q); + this.klassPointer = klassPointer; + } + } + + @NativeImageReinitialize private HashMap resolvedJavaTypes; + + @NativeImageReinitialize private ReferenceQueue resolvedJavaTypesQueue; /** * Stores the value set by {@link #excludeFromJVMCICompilation(Module...)} so that it can be @@ -662,9 +676,10 @@ HotSpotResolvedJavaType fromClass(Class javaClass) { return fromClass0(javaClass); } - synchronized HotSpotResolvedObjectTypeImpl fromMetaspace(long klassPointer) { + synchronized HotSpotResolvedObjectTypeImpl fromMetaspace(Long klassPointer) { if (resolvedJavaTypes == null) { resolvedJavaTypes = new HashMap<>(); + resolvedJavaTypesQueue = new ReferenceQueue<>(); } assert klassPointer != 0; WeakReference klassReference = resolvedJavaTypes.get(klassPointer); @@ -675,11 +690,27 @@ synchronized HotSpotResolvedObjectTypeImpl fromMetaspace(long klassPointer) { if (javaType == null) { String name = compilerToVm.getSignatureName(klassPointer); javaType = new HotSpotResolvedObjectTypeImpl(klassPointer, name); - resolvedJavaTypes.put(klassPointer, new WeakReference<>(javaType)); + resolvedJavaTypes.put(klassPointer, new KlassWeakReference(klassPointer, javaType, resolvedJavaTypesQueue)); } + expungeStaleEntries(); return javaType; } + + /** + * Clean up WeakReferences whose referents have been cleared. + */ + private void expungeStaleEntries() { + KlassWeakReference current = (KlassWeakReference) resolvedJavaTypesQueue.poll(); + while (current != null) { + // Make sure the entry is still mapped to the weak reference + if (resolvedJavaTypes.get(current.klassPointer) == current) { + resolvedJavaTypes.remove(current.klassPointer); + } + current = (KlassWeakReference) resolvedJavaTypesQueue.poll(); + } + } + private JVMCIBackend registerBackend(JVMCIBackend backend) { Class arch = backend.getCodeCache().getTarget().arch.getClass(); JVMCIBackend oldValue = backends.put(arch, backend); From b0d6a142a44f7ee6b4cb5ea8c0616b2d073315d2 Mon Sep 17 00:00:00 2001 From: Tom Rodriguez Date: Sun, 10 Dec 2023 20:35:07 -0800 Subject: [PATCH 2/2] Comment and types improvements --- .../vm/ci/hotspot/HotSpotJVMCIRuntime.java | 28 +++++++++++++------ 1 file changed, 20 insertions(+), 8 deletions(-) diff --git a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotJVMCIRuntime.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotJVMCIRuntime.java index 8ba94609f5d58..aa4d48b720e97 100644 --- a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotJVMCIRuntime.java +++ b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotJVMCIRuntime.java @@ -501,19 +501,31 @@ T get() { } - static class KlassWeakReference extends WeakReference { + /** + * A weak reference that also tracks the key used to insert the value into {@link #resolvedJavaTypes} so that + * it can be removed when the referent is cleared. + */ + static class KlassWeakReference extends WeakReference { private final Long klassPointer; - public KlassWeakReference(Long klassPointer, ResolvedJavaType referent, ReferenceQueueq) { + public KlassWeakReference(Long klassPointer, HotSpotResolvedObjectTypeImpl referent, ReferenceQueue q) { super(referent, q); this.klassPointer = klassPointer; } } + /** + * A mapping from the {@code Klass*} to the corresponding {@link HotSpotResolvedObjectTypeImpl}. The value is + * held weakly through a {@link KlassWeakReference} so that unused types can be unloaded when the compiler no longer needs them. + */ @NativeImageReinitialize private HashMap resolvedJavaTypes; - @NativeImageReinitialize private ReferenceQueue resolvedJavaTypesQueue; + /** + * A {@link ReferenceQueue} to track when {@link KlassWeakReference}s have been freed so that the corresponding + * entry in {@link #resolvedJavaTypes} can be cleared. + */ + @NativeImageReinitialize private ReferenceQueue resolvedJavaTypesQueue; /** * Stores the value set by {@link #excludeFromJVMCICompilation(Module...)} so that it can be @@ -682,25 +694,25 @@ synchronized HotSpotResolvedObjectTypeImpl fromMetaspace(Long klassPointer) { resolvedJavaTypesQueue = new ReferenceQueue<>(); } assert klassPointer != 0; - WeakReference klassReference = resolvedJavaTypes.get(klassPointer); + KlassWeakReference klassReference = resolvedJavaTypes.get(klassPointer); HotSpotResolvedObjectTypeImpl javaType = null; if (klassReference != null) { - javaType = (HotSpotResolvedObjectTypeImpl) klassReference.get(); + javaType = klassReference.get(); } if (javaType == null) { String name = compilerToVm.getSignatureName(klassPointer); javaType = new HotSpotResolvedObjectTypeImpl(klassPointer, name); resolvedJavaTypes.put(klassPointer, new KlassWeakReference(klassPointer, javaType, resolvedJavaTypesQueue)); } - expungeStaleEntries(); + expungeStaleKlassEntries(); return javaType; } /** - * Clean up WeakReferences whose referents have been cleared. + * Clean up WeakReferences whose referents have been cleared. This should be called from a synchronized context. */ - private void expungeStaleEntries() { + private void expungeStaleKlassEntries() { KlassWeakReference current = (KlassWeakReference) resolvedJavaTypesQueue.poll(); while (current != null) { // Make sure the entry is still mapped to the weak reference