changeset 16534:f1b7d60adc19

8173083: VarHandle usages in LockSupport and ThreadLocalRandom result in circularity issues Reviewed-by: martin
author psandoz
date Fri, 20 Jan 2017 08:01:43 -0800
parents 8102fc376591
children 467b3b7aeb1b
files src/java.base/share/classes/java/util/concurrent/ThreadLocalRandom.java src/java.base/share/classes/java/util/concurrent/locks/LockSupport.java
diffstat 2 files changed, 50 insertions(+), 73 deletions(-) [+]
line wrap: on
line diff
--- a/src/java.base/share/classes/java/util/concurrent/ThreadLocalRandom.java	Fri Jan 20 19:12:46 2017 +0530
+++ b/src/java.base/share/classes/java/util/concurrent/ThreadLocalRandom.java	Fri Jan 20 08:01:43 2017 -0800
@@ -36,8 +36,6 @@
 package java.util.concurrent;
 
 import java.io.ObjectStreamField;
-import java.lang.invoke.MethodHandles;
-import java.lang.invoke.VarHandle;
 import java.security.AccessControlContext;
 import java.util.Random;
 import java.util.Spliterator;
@@ -50,6 +48,7 @@
 import java.util.stream.IntStream;
 import java.util.stream.LongStream;
 import java.util.stream.StreamSupport;
+import jdk.internal.misc.Unsafe;
 
 /**
  * A random number generator isolated to the current thread.  Like the
@@ -109,7 +108,7 @@
      * though, we use only a single 64bit gamma.
      *
      * Because this class is in a different package than class Thread,
-     * field access methods use VarHandles to bypass access control rules.
+     * field access methods use Unsafe to bypass access control rules.
      * To conform to the requirements of the Random superclass
      * constructor, the common static ThreadLocalRandom maintains an
      * "initialized" field for the sake of rejecting user calls to
@@ -164,8 +163,8 @@
         int probe = (p == 0) ? 1 : p; // skip 0
         long seed = mix64(seeder.getAndAdd(SEEDER_INCREMENT));
         Thread t = Thread.currentThread();
-        SEED.set(t, seed);
-        PROBE.set(t, probe);
+        U.putLong(t, SEED, seed);
+        U.putInt(t, PROBE, probe);
     }
 
     /**
@@ -174,7 +173,7 @@
      * @return the current thread's {@code ThreadLocalRandom}
      */
     public static ThreadLocalRandom current() {
-        if ((int) PROBE.get(Thread.currentThread()) == 0)
+        if (U.getInt(Thread.currentThread(), PROBE) == 0)
             localInit();
         return instance;
     }
@@ -193,8 +192,8 @@
 
     final long nextSeed() {
         Thread t; long r; // read and update per-thread seed
-        SEED.set(t = Thread.currentThread(),
-                 (r = (long) SEED.get(t)) + GAMMA);
+        U.putLong(t = Thread.currentThread(), SEED,
+                  r = U.getLong(t, SEED) + GAMMA);
         return r;
     }
 
@@ -939,7 +938,7 @@
      * can be used to force initialization on zero return.
      */
     static final int getProbe() {
-        return (int) PROBE.get(Thread.currentThread());
+        return U.getInt(Thread.currentThread(), PROBE);
     }
 
     /**
@@ -950,7 +949,7 @@
         probe ^= probe << 13;   // xorshift
         probe ^= probe >>> 17;
         probe ^= probe << 5;
-        PROBE.set(Thread.currentThread(), probe);
+        U.putInt(Thread.currentThread(), PROBE, probe);
         return probe;
     }
 
@@ -960,14 +959,14 @@
     static final int nextSecondarySeed() {
         int r;
         Thread t = Thread.currentThread();
-        if ((r = (int) SECONDARY.get(t)) != 0) {
+        if ((r = U.getInt(t, SECONDARY)) != 0) {
             r ^= r << 13;   // xorshift
             r ^= r >>> 17;
             r ^= r << 5;
         }
         else if ((r = mix32(seeder.getAndAdd(SEEDER_INCREMENT))) == 0)
             r = 1; // avoid zero
-        SECONDARY.set(t, r);
+        U.putInt(t, SECONDARY, r);
         return r;
     }
 
@@ -977,13 +976,13 @@
      * Erases ThreadLocals by nulling out Thread maps.
      */
     static final void eraseThreadLocals(Thread thread) {
-        THREADLOCALS.set(thread, null);
-        INHERITABLETHREADLOCALS.set(thread, null);
+        U.putObject(thread, THREADLOCALS, null);
+        U.putObject(thread, INHERITABLETHREADLOCALS, null);
     }
 
     static final void setInheritedAccessControlContext(Thread thread,
                                                        AccessControlContext acc) {
-        INHERITEDACCESSCONTROLCONTEXT.setRelease(thread, acc);
+        U.putObjectRelease(thread, INHERITEDACCESSCONTROLCONTEXT, acc);
     }
 
     // Serialization support
@@ -1010,7 +1009,7 @@
         throws java.io.IOException {
 
         java.io.ObjectOutputStream.PutField fields = s.putFields();
-        fields.put("rnd", (long) SEED.get(Thread.currentThread()));
+        fields.put("rnd", U.getLong(Thread.currentThread(), SEED));
         fields.put("initialized", true);
         s.writeFields();
     }
@@ -1049,38 +1048,28 @@
     static final String BAD_RANGE = "bound must be greater than origin";
     static final String BAD_SIZE  = "size must be non-negative";
 
-    // VarHandle mechanics
-    private static final VarHandle SEED;
-    private static final VarHandle PROBE;
-    private static final VarHandle SECONDARY;
-    private static final VarHandle THREADLOCALS;
-    private static final VarHandle INHERITABLETHREADLOCALS;
-    private static final VarHandle INHERITEDACCESSCONTROLCONTEXT;
+    // Unsafe mechanics
+    private static final Unsafe U = Unsafe.getUnsafe();
+    private static final long SEED;
+    private static final long PROBE;
+    private static final long SECONDARY;
+    private static final long THREADLOCALS;
+    private static final long INHERITABLETHREADLOCALS;
+    private static final long INHERITEDACCESSCONTROLCONTEXT;
     static {
         try {
-            MethodHandles.Lookup l = java.security.AccessController.doPrivileged(
-                    new java.security.PrivilegedAction<>() {
-                        public MethodHandles.Lookup run() {
-                            try {
-                                return MethodHandles.privateLookupIn(Thread.class,
-                                        MethodHandles.lookup());
-                            } catch (ReflectiveOperationException e) {
-                                throw new Error(e);
-                            }
-                        }});
-            SEED = l.findVarHandle(Thread.class,
-                    "threadLocalRandomSeed", long.class);
-            PROBE = l.findVarHandle(Thread.class,
-                    "threadLocalRandomProbe", int.class);
-            SECONDARY = l.findVarHandle(Thread.class,
-                    "threadLocalRandomSecondarySeed", int.class);
-            Class<?> tlm = Class.forName("java.lang.ThreadLocal$ThreadLocalMap");
-            THREADLOCALS = l.findVarHandle(Thread.class,
-                    "threadLocals", tlm);
-            INHERITABLETHREADLOCALS = l.findVarHandle(Thread.class,
-                    "inheritableThreadLocals", tlm);
-            INHERITEDACCESSCONTROLCONTEXT = l.findVarHandle(Thread.class,
-                    "inheritedAccessControlContext", AccessControlContext.class);
+            SEED = U.objectFieldOffset
+                    (Thread.class.getDeclaredField("threadLocalRandomSeed"));
+            PROBE = U.objectFieldOffset
+                    (Thread.class.getDeclaredField("threadLocalRandomProbe"));
+            SECONDARY = U.objectFieldOffset
+                    (Thread.class.getDeclaredField("threadLocalRandomSecondarySeed"));
+            THREADLOCALS = U.objectFieldOffset
+                    (Thread.class.getDeclaredField("threadLocals"));
+            INHERITABLETHREADLOCALS = U.objectFieldOffset
+                    (Thread.class.getDeclaredField("inheritableThreadLocals"));
+            INHERITEDACCESSCONTROLCONTEXT = U.objectFieldOffset
+                    (Thread.class.getDeclaredField("inheritedAccessControlContext"));
         } catch (ReflectiveOperationException e) {
             throw new Error(e);
         }
--- a/src/java.base/share/classes/java/util/concurrent/locks/LockSupport.java	Fri Jan 20 19:12:46 2017 +0530
+++ b/src/java.base/share/classes/java/util/concurrent/locks/LockSupport.java	Fri Jan 20 08:01:43 2017 -0800
@@ -37,9 +37,6 @@
 
 import jdk.internal.misc.Unsafe;
 
-import java.lang.invoke.MethodHandles;
-import java.lang.invoke.VarHandle;
-
 /**
  * Basic thread blocking primitives for creating locks and other
  * synchronization classes.
@@ -142,7 +139,7 @@
 
     private static void setBlocker(Thread t, Object arg) {
         // Even though volatile, hotspot doesn't need a write barrier here.
-        THREAD_PARKBLOCKER.set(t, arg);
+        U.putObject(t, PARKBLOCKER, arg);
     }
 
     /**
@@ -292,7 +289,7 @@
     public static Object getBlocker(Thread t) {
         if (t == null)
             throw new NullPointerException();
-        return THREAD_PARKBLOCKER.getVolatile(t);
+        return U.getObjectVolatile(t, PARKBLOCKER);
     }
 
     /**
@@ -399,14 +396,14 @@
     static final int nextSecondarySeed() {
         int r;
         Thread t = Thread.currentThread();
-        if ((r = (int) THREAD_SECONDARY.get(t)) != 0) {
+        if ((r = U.getInt(t, SECONDARY)) != 0) {
             r ^= r << 13;   // xorshift
             r ^= r >>> 17;
             r ^= r << 5;
         }
         else if ((r = java.util.concurrent.ThreadLocalRandom.current().nextInt()) == 0)
             r = 1; // avoid zero
-        THREAD_SECONDARY.set(t, r);
+        U.putInt(t, SECONDARY, r);
         return r;
     }
 
@@ -417,32 +414,23 @@
      * ways that do not preserve unique mappings.
      */
     static final long getThreadId(Thread thread) {
-        return (long) THREAD_TID.getVolatile(thread);
+        return U.getLongVolatile(thread, TID);
     }
 
     // Hotspot implementation via intrinsics API
     private static final Unsafe U = Unsafe.getUnsafe();
-    // VarHandle mechanics
-    private static final VarHandle THREAD_PARKBLOCKER;
-    private static final VarHandle THREAD_SECONDARY;
-    private static final VarHandle THREAD_TID;
+    private static final long PARKBLOCKER;
+    private static final long SECONDARY;
+    private static final long TID;
     static {
         try {
-            MethodHandles.Lookup l = java.security.AccessController.doPrivileged(
-                    new java.security.PrivilegedAction<>() {
-                        public MethodHandles.Lookup run() {
-                            try {
-                                return MethodHandles.privateLookupIn(Thread.class, MethodHandles.lookup());
-                            } catch (ReflectiveOperationException e) {
-                                throw new Error(e);
-                            }
-                        }});
-            THREAD_PARKBLOCKER = l.findVarHandle(Thread.class,
-                    "parkBlocker", Object.class);
-            THREAD_SECONDARY = l.findVarHandle(Thread.class,
-                    "threadLocalRandomSecondarySeed", int.class);
-            THREAD_TID = l.findVarHandle(Thread.class,
-                    "tid", long.class);
+            PARKBLOCKER = U.objectFieldOffset
+                    (Thread.class.getDeclaredField("parkBlocker"));
+            SECONDARY = U.objectFieldOffset
+                    (Thread.class.getDeclaredField("threadLocalRandomSecondarySeed"));
+            TID = U.objectFieldOffset
+                    (Thread.class.getDeclaredField("tid"));
+
         } catch (ReflectiveOperationException e) {
             throw new Error(e);
         }