7082299: AtomicReferenceArray should ensure that array is Object[]
authordl
Wed, 12 Oct 2011 16:33:48 +0100
changeset 11892 1b260c532b70
parent 10916 5a763073fa37
child 11893 6a3b541908ae
7082299: AtomicReferenceArray should ensure that array is Object[] Reviewed-by: chegar, dholmes, alanb
jdk/src/share/classes/java/util/concurrent/atomic/AtomicReferenceArray.java
--- a/jdk/src/share/classes/java/util/concurrent/atomic/AtomicReferenceArray.java	Fri Sep 30 18:47:53 2011 -0700
+++ b/jdk/src/share/classes/java/util/concurrent/atomic/AtomicReferenceArray.java	Wed Oct 12 16:33:48 2011 +0100
@@ -34,8 +34,10 @@
  */
 
 package java.util.concurrent.atomic;
+
+import java.lang.reflect.Array;
+import java.util.Arrays;
 import sun.misc.Unsafe;
-import java.util.*;
 
 /**
  * An array of object references in which elements may be updated
@@ -49,13 +51,23 @@
 public class AtomicReferenceArray<E> implements java.io.Serializable {
     private static final long serialVersionUID = -6209656149925076980L;
 
-    private static final Unsafe unsafe = Unsafe.getUnsafe();
-    private static final int base = unsafe.arrayBaseOffset(Object[].class);
+    private static final Unsafe unsafe;
+    private static final int base;
     private static final int shift;
-    private final Object[] array;
+    private static final long arrayFieldOffset;
+    private final Object[] array; // must have exact type Object[]
 
     static {
-        int scale = unsafe.arrayIndexScale(Object[].class);
+        int scale;
+        try {
+            unsafe = Unsafe.getUnsafe();
+            arrayFieldOffset = unsafe.objectFieldOffset
+                (AtomicReferenceArray.class.getDeclaredField("array"));
+            base = unsafe.arrayBaseOffset(Object[].class);
+            scale = unsafe.arrayIndexScale(Object[].class);
+        } catch (Exception e) {
+            throw new Error(e);
+        }
         if ((scale & (scale - 1)) != 0)
             throw new Error("data type scale not a power of two");
         shift = 31 - Integer.numberOfLeadingZeros(scale);
@@ -91,7 +103,7 @@
      */
     public AtomicReferenceArray(E[] array) {
         // Visibility guaranteed by final field guarantees
-        this.array = array.clone();
+        this.array = Arrays.copyOf(array, array.length, Object[].class);
     }
 
     /**
@@ -150,7 +162,7 @@
     public final E getAndSet(int i, E newValue) {
         long offset = checkedByteOffset(i);
         while (true) {
-            E current = (E) getRaw(offset);
+            E current = getRaw(offset);
             if (compareAndSetRaw(offset, current, newValue))
                 return current;
         }
@@ -196,7 +208,7 @@
      * @return the String representation of the current values of array
      */
     public String toString() {
-           int iMax = array.length - 1;
+        int iMax = array.length - 1;
         if (iMax == -1)
             return "[]";
 
@@ -210,4 +222,19 @@
         }
     }
 
+    /**
+     * Reconstitutes the instance from a stream (that is, deserializes it).
+     * @param s the stream
+     */
+    private void readObject(java.io.ObjectInputStream s)
+        throws java.io.IOException, ClassNotFoundException {
+        // Note: This must be changed if any additional fields are defined
+        Object a = s.readFields().get("array", null);
+        if (a == null || !a.getClass().isArray())
+            throw new java.io.InvalidObjectException("Not array type");
+        if (a.getClass() != Object[].class)
+            a = Arrays.copyOf((Object[])a, Array.getLength(a), Object[].class);
+        unsafe.putObjectVolatile(this, arrayFieldOffset, a);
+    }
+
 }