changeset 14914:fe8ad62762dd

8251397: NPE on ClassValue.ClassValueMap.cacheArray Summary: Add release fence to ClassValueMap constructor. Reviewed-by: shade, psandoz Contributed-by: Galder Zamarreno <galder@redhat.com>
author sgehwolf
date Thu, 17 Sep 2020 13:42:15 +0000
parents 7432d3558458
children 15c578880963
files src/share/classes/java/lang/ClassValue.java
diffstat 1 files changed, 16 insertions(+), 4 deletions(-) [+]
line wrap: on
line diff
--- a/src/share/classes/java/lang/ClassValue.java	Thu Jan 07 17:54:43 2021 +0000
+++ b/src/share/classes/java/lang/ClassValue.java	Thu Sep 17 13:42:15 2020 +0000
@@ -30,6 +30,8 @@
 import java.lang.ref.WeakReference;
 import java.util.concurrent.atomic.AtomicInteger;
 
+import sun.misc.Unsafe;
+
 import static java.lang.ClassValue.ClassValueMap.probeHomeLocation;
 import static java.lang.ClassValue.ClassValueMap.probeBackupLocations;
 
@@ -370,15 +372,25 @@
     }
 
     private static final Object CRITICAL_SECTION = new Object();
+    private static final Unsafe UNSAFE = Unsafe.getUnsafe();
     private static ClassValueMap initializeMap(Class<?> type) {
         ClassValueMap map;
         synchronized (CRITICAL_SECTION) {  // private object to avoid deadlocks
             // happens about once per type
-            if ((map = type.classValueMap) == null)
-                type.classValueMap = map = new ClassValueMap(type);
+            if ((map = type.classValueMap) == null) {
+                map = new ClassValueMap(type);
+                // Place a Store fence after construction and before publishing to emulate
+                // ClassValueMap containing final fields. This ensures it can be
+                // published safely in the non-volatile field Class.classValueMap,
+                // since stores to the fields of ClassValueMap will not be reordered
+                // to occur after the store to the field type.classValueMap
+                UNSAFE.storeFence();
+
+                type.classValueMap = map;
+            }
         }
-            return map;
-        }
+        return map;
+    }
 
     static <T> Entry<T> makeEntry(Version<T> explicitVersion, T value) {
         // Note that explicitVersion might be different from this.version.