8162396: j.u.c java.lang.LinkageError
authordl
Tue, 26 Jul 2016 09:49:25 -0700
changeset 39777 a9b80432c521
parent 39776 34d5b0a2af92
child 39778 5cda06c52cdd
8162396: j.u.c java.lang.LinkageError Reviewed-by: martin, psandoz, plevart
jdk/src/java.base/share/classes/java/util/concurrent/atomic/AtomicInteger.java
jdk/src/java.base/share/classes/java/util/concurrent/atomic/AtomicLong.java
--- a/jdk/src/java.base/share/classes/java/util/concurrent/atomic/AtomicInteger.java	Tue Jul 26 14:30:52 2016 +0100
+++ b/jdk/src/java.base/share/classes/java/util/concurrent/atomic/AtomicInteger.java	Tue Jul 26 09:49:25 2016 -0700
@@ -35,7 +35,6 @@
 
 package java.util.concurrent.atomic;
 
-import java.lang.invoke.MethodHandles;
 import java.lang.invoke.VarHandle;
 import java.util.function.IntBinaryOperator;
 import java.util.function.IntUnaryOperator;
@@ -54,11 +53,18 @@
  */
 public class AtomicInteger extends Number implements java.io.Serializable {
     private static final long serialVersionUID = 6214790243416807050L;
-    private static final VarHandle VALUE;
+
+    /*
+     * This class intended to be implemented using VarHandles, but there
+     * are unresolved cyclic startup dependencies.
+     */
+    private static final jdk.internal.misc.Unsafe U = jdk.internal.misc.Unsafe.getUnsafe();
+    private static final long VALUE;
+
     static {
         try {
-            MethodHandles.Lookup l = MethodHandles.lookup();
-            VALUE = l.findVarHandle(AtomicInteger.class, "value", int.class);
+            VALUE = U.objectFieldOffset
+                (AtomicInteger.class.getDeclaredField("value"));
         } catch (ReflectiveOperationException e) {
             throw new Error(e);
         }
@@ -109,7 +115,7 @@
      * @since 1.6
      */
     public final void lazySet(int newValue) {
-        VALUE.setRelease(this, newValue);
+        U.putIntRelease(this, VALUE, newValue);
     }
 
     /**
@@ -120,7 +126,7 @@
      * @return the previous value
      */
     public final int getAndSet(int newValue) {
-        return (int)VALUE.getAndSet(this, newValue);
+        return U.getAndSetInt(this, VALUE, newValue);
     }
 
     /**
@@ -134,7 +140,7 @@
      * the actual value was not equal to the expected value.
      */
     public final boolean compareAndSet(int expectedValue, int newValue) {
-        return VALUE.compareAndSet(this, expectedValue, newValue);
+        return U.compareAndSwapInt(this, VALUE, expectedValue, newValue);
     }
 
     /**
@@ -147,7 +153,7 @@
      * @return {@code true} if successful
      */
     public final boolean weakCompareAndSet(int expectedValue, int newValue) {
-        return VALUE.weakCompareAndSet(this, expectedValue, newValue);
+        return U.weakCompareAndSwapInt(this, VALUE, expectedValue, newValue);
     }
 
     /**
@@ -159,7 +165,7 @@
      * @return the previous value
      */
     public final int getAndIncrement() {
-        return (int)VALUE.getAndAdd(this, 1);
+        return U.getAndAddInt(this, VALUE, 1);
     }
 
     /**
@@ -171,7 +177,7 @@
      * @return the previous value
      */
     public final int getAndDecrement() {
-        return (int)VALUE.getAndAdd(this, -1);
+        return U.getAndAddInt(this, VALUE, -1);
     }
 
     /**
@@ -182,7 +188,7 @@
      * @return the previous value
      */
     public final int getAndAdd(int delta) {
-        return (int)VALUE.getAndAdd(this, delta);
+        return U.getAndAddInt(this, VALUE, delta);
     }
 
     /**
@@ -194,7 +200,7 @@
      * @return the updated value
      */
     public final int incrementAndGet() {
-        return (int)VALUE.addAndGet(this, 1);
+        return U.getAndAddInt(this, VALUE, 1) + 1;
     }
 
     /**
@@ -206,7 +212,7 @@
      * @return the updated value
      */
     public final int decrementAndGet() {
-        return (int)VALUE.addAndGet(this, -1);
+        return U.getAndAddInt(this, VALUE, -1) - 1;
     }
 
     /**
@@ -217,7 +223,7 @@
      * @return the updated value
      */
     public final int addAndGet(int delta) {
-        return (int)VALUE.addAndGet(this, delta);
+        return U.getAndAddInt(this, VALUE, delta) + delta;
     }
 
     /**
@@ -373,7 +379,7 @@
      * @since 9
      */
     public final int getPlain() {
-        return (int)VALUE.get(this);
+        return U.getInt(this, VALUE);
     }
 
     /**
@@ -385,7 +391,7 @@
      * @since 9
      */
     public final void setPlain(int newValue) {
-        VALUE.set(this, newValue);
+        U.putInt(this, VALUE, newValue);
     }
 
     /**
@@ -396,7 +402,7 @@
      * @since 9
      */
     public final int getOpaque() {
-        return (int)VALUE.getOpaque(this);
+        return U.getIntOpaque(this, VALUE);
     }
 
     /**
@@ -407,7 +413,7 @@
      * @since 9
      */
     public final void setOpaque(int newValue) {
-        VALUE.setOpaque(this, newValue);
+        U.putIntOpaque(this, VALUE, newValue);
     }
 
     /**
@@ -418,7 +424,7 @@
      * @since 9
      */
     public final int getAcquire() {
-        return (int)VALUE.getAcquire(this);
+        return U.getIntAcquire(this, VALUE);
     }
 
     /**
@@ -429,7 +435,7 @@
      * @since 9
      */
     public final void setRelease(int newValue) {
-        VALUE.setRelease(this, newValue);
+        U.putIntRelease(this, VALUE, newValue);
     }
 
     /**
@@ -445,7 +451,7 @@
      * @since 9
      */
     public final int compareAndExchange(int expectedValue, int newValue) {
-        return (int)VALUE.compareAndExchange(this, expectedValue, newValue);
+        return U.compareAndExchangeIntVolatile(this, VALUE, expectedValue, newValue);
     }
 
     /**
@@ -461,7 +467,7 @@
      * @since 9
      */
     public final int compareAndExchangeAcquire(int expectedValue, int newValue) {
-        return (int)VALUE.compareAndExchangeAcquire(this, expectedValue, newValue);
+        return U.compareAndExchangeIntAcquire(this, VALUE, expectedValue, newValue);
     }
 
     /**
@@ -477,7 +483,7 @@
      * @since 9
      */
     public final int compareAndExchangeRelease(int expectedValue, int newValue) {
-        return (int)VALUE.compareAndExchangeRelease(this, expectedValue, newValue);
+        return U.compareAndExchangeIntRelease(this, VALUE, expectedValue, newValue);
     }
 
     /**
@@ -492,7 +498,7 @@
      * @since 9
      */
     public final boolean weakCompareAndSetVolatile(int expectedValue, int newValue) {
-        return VALUE.weakCompareAndSetVolatile(this, expectedValue, newValue);
+        return U.weakCompareAndSwapIntVolatile(this, VALUE, expectedValue, newValue);
     }
 
     /**
@@ -507,7 +513,7 @@
      * @since 9
      */
     public final boolean weakCompareAndSetAcquire(int expectedValue, int newValue) {
-        return VALUE.weakCompareAndSetAcquire(this, expectedValue, newValue);
+        return U.weakCompareAndSwapIntAcquire(this, VALUE, expectedValue, newValue);
     }
 
     /**
@@ -522,7 +528,7 @@
      * @since 9
      */
     public final boolean weakCompareAndSetRelease(int expectedValue, int newValue) {
-        return VALUE.weakCompareAndSetRelease(this, expectedValue, newValue);
+        return U.weakCompareAndSwapIntRelease(this, VALUE, expectedValue, newValue);
     }
 
 }
--- a/jdk/src/java.base/share/classes/java/util/concurrent/atomic/AtomicLong.java	Tue Jul 26 14:30:52 2016 +0100
+++ b/jdk/src/java.base/share/classes/java/util/concurrent/atomic/AtomicLong.java	Tue Jul 26 09:49:25 2016 -0700
@@ -35,7 +35,6 @@
 
 package java.util.concurrent.atomic;
 
-import java.lang.invoke.MethodHandles;
 import java.lang.invoke.VarHandle;
 import java.util.function.LongBinaryOperator;
 import java.util.function.LongUnaryOperator;
@@ -54,7 +53,6 @@
  */
 public class AtomicLong extends Number implements java.io.Serializable {
     private static final long serialVersionUID = 1927816293512124184L;
-    private static final VarHandle VALUE;
 
     /**
      * Records whether the underlying JVM supports lockless
@@ -70,10 +68,17 @@
      */
     private static native boolean VMSupportsCS8();
 
+    /*
+     * This class intended to be implemented using VarHandles, but there
+     * are unresolved cyclic startup dependencies.
+     */
+    private static final jdk.internal.misc.Unsafe U = jdk.internal.misc.Unsafe.getUnsafe();
+    private static final long VALUE;
+
     static {
         try {
-            MethodHandles.Lookup l = MethodHandles.lookup();
-            VALUE = l.findVarHandle(AtomicLong.class, "value", long.class);
+            VALUE = U.objectFieldOffset
+                (AtomicLong.class.getDeclaredField("value"));
         } catch (ReflectiveOperationException e) {
             throw new Error(e);
         }
@@ -113,7 +118,9 @@
      * @param newValue the new value
      */
     public final void set(long newValue) {
-        VALUE.setVolatile(this, newValue);
+        // Use putLongVolatile instead of ordinary volatile store when
+        // using compareAndSwapLong, for sake of some 32bit systems.
+        U.putLongVolatile(this, VALUE, newValue);
     }
 
     /**
@@ -124,7 +131,7 @@
      * @since 1.6
      */
     public final void lazySet(long newValue) {
-        VALUE.setRelease(this, newValue);
+        U.putLongRelease(this, VALUE, newValue);
     }
 
     /**
@@ -135,7 +142,7 @@
      * @return the previous value
      */
     public final long getAndSet(long newValue) {
-        return (long)VALUE.getAndSet(this, newValue);
+        return U.getAndSetLong(this, VALUE, newValue);
     }
 
     /**
@@ -149,7 +156,7 @@
      * the actual value was not equal to the expected value.
      */
     public final boolean compareAndSet(long expectedValue, long newValue) {
-        return VALUE.compareAndSet(this, expectedValue, newValue);
+        return U.compareAndSwapLong(this, VALUE, expectedValue, newValue);
     }
 
     /**
@@ -162,7 +169,7 @@
      * @return {@code true} if successful
      */
     public final boolean weakCompareAndSet(long expectedValue, long newValue) {
-        return VALUE.weakCompareAndSet(this, expectedValue, newValue);
+        return U.weakCompareAndSwapLong(this, VALUE, expectedValue, newValue);
     }
 
     /**
@@ -174,7 +181,7 @@
      * @return the previous value
      */
     public final long getAndIncrement() {
-        return (long)VALUE.getAndAdd(this, 1L);
+        return U.getAndAddLong(this, VALUE, 1L);
     }
 
     /**
@@ -186,7 +193,7 @@
      * @return the previous value
      */
     public final long getAndDecrement() {
-        return (long)VALUE.getAndAdd(this, -1L);
+        return U.getAndAddLong(this, VALUE, -1L);
     }
 
     /**
@@ -197,7 +204,7 @@
      * @return the previous value
      */
     public final long getAndAdd(long delta) {
-        return (long)VALUE.getAndAdd(this, delta);
+        return U.getAndAddLong(this, VALUE, delta);
     }
 
     /**
@@ -209,7 +216,7 @@
      * @return the updated value
      */
     public final long incrementAndGet() {
-        return (long)VALUE.addAndGet(this, 1L);
+        return U.getAndAddLong(this, VALUE, 1L) + 1L;
     }
 
     /**
@@ -221,7 +228,7 @@
      * @return the updated value
      */
     public final long decrementAndGet() {
-        return (long)VALUE.addAndGet(this, -1L);
+        return U.getAndAddLong(this, VALUE, -1L) - 1L;
     }
 
     /**
@@ -232,7 +239,7 @@
      * @return the updated value
      */
     public final long addAndGet(long delta) {
-        return (long)VALUE.addAndGet(this, delta);
+        return U.getAndAddLong(this, VALUE, delta) + delta;
     }
 
     /**
@@ -386,7 +393,7 @@
      * @since 9
      */
     public final long getPlain() {
-        return (long)VALUE.get(this);
+        return U.getLong(this, VALUE);
     }
 
     /**
@@ -398,7 +405,7 @@
      * @since 9
      */
     public final void setPlain(long newValue) {
-        VALUE.set(this, newValue);
+        U.putLong(this, VALUE, newValue);
     }
 
     /**
@@ -409,7 +416,7 @@
      * @since 9
      */
     public final long getOpaque() {
-        return (long)VALUE.getOpaque(this);
+        return U.getLongOpaque(this, VALUE);
     }
 
     /**
@@ -420,7 +427,7 @@
      * @since 9
      */
     public final void setOpaque(long newValue) {
-        VALUE.setOpaque(this, newValue);
+        U.putLongOpaque(this, VALUE, newValue);
     }
 
     /**
@@ -431,7 +438,7 @@
      * @since 9
      */
     public final long getAcquire() {
-        return (long)VALUE.getAcquire(this);
+        return U.getLongAcquire(this, VALUE);
     }
 
     /**
@@ -442,7 +449,7 @@
      * @since 9
      */
     public final void setRelease(long newValue) {
-        VALUE.setRelease(this, newValue);
+        U.putLongRelease(this, VALUE, newValue);
     }
 
     /**
@@ -458,7 +465,7 @@
      * @since 9
      */
     public final long compareAndExchange(long expectedValue, long newValue) {
-        return (long)VALUE.compareAndExchange(this, expectedValue, newValue);
+        return U.compareAndExchangeLongVolatile(this, VALUE, expectedValue, newValue);
     }
 
     /**
@@ -474,7 +481,7 @@
      * @since 9
      */
     public final long compareAndExchangeAcquire(long expectedValue, long newValue) {
-        return (long)VALUE.compareAndExchangeAcquire(this, expectedValue, newValue);
+        return U.compareAndExchangeLongAcquire(this, VALUE, expectedValue, newValue);
     }
 
     /**
@@ -490,7 +497,7 @@
      * @since 9
      */
     public final long compareAndExchangeRelease(long expectedValue, long newValue) {
-        return (long)VALUE.compareAndExchangeRelease(this, expectedValue, newValue);
+        return U.compareAndExchangeLongRelease(this, VALUE, expectedValue, newValue);
     }
 
     /**
@@ -505,7 +512,7 @@
      * @since 9
      */
     public final boolean weakCompareAndSetVolatile(long expectedValue, long newValue) {
-        return VALUE.weakCompareAndSetVolatile(this, expectedValue, newValue);
+        return U.weakCompareAndSwapLongVolatile(this, VALUE, expectedValue, newValue);
     }
 
     /**
@@ -520,7 +527,7 @@
      * @since 9
      */
     public final boolean weakCompareAndSetAcquire(long expectedValue, long newValue) {
-        return VALUE.weakCompareAndSetAcquire(this, expectedValue, newValue);
+        return U.weakCompareAndSwapLongAcquire(this, VALUE, expectedValue, newValue);
     }
 
     /**
@@ -535,7 +542,7 @@
      * @since 9
      */
     public final boolean weakCompareAndSetRelease(long expectedValue, long newValue) {
-        return VALUE.weakCompareAndSetRelease(this, expectedValue, newValue);
+        return U.weakCompareAndSwapLongRelease(this, VALUE, expectedValue, newValue);
     }
 
 }