8074022: Serialization should issue a freeze action after reconstituting a graph that contains objects with final fields
authorchegar
Fri, 27 Feb 2015 11:45:07 +0000
changeset 29220 b07abc731618
parent 29219 33fb011789eb
child 29221 e946919cf487
8074022: Serialization should issue a freeze action after reconstituting a graph that contains objects with final fields Reviewed-by: dholmes, plevart, psandoz
jdk/src/java.base/share/classes/java/io/ObjectInputStream.java
jdk/src/java.base/share/classes/java/math/BigDecimal.java
jdk/src/java.base/share/classes/java/math/BigInteger.java
--- a/jdk/src/java.base/share/classes/java/io/ObjectInputStream.java	Fri Feb 27 11:56:42 2015 +0100
+++ b/jdk/src/java.base/share/classes/java/io/ObjectInputStream.java	Fri Feb 27 11:45:07 2015 +0000
@@ -40,6 +40,7 @@
 import java.util.concurrent.ConcurrentHashMap;
 import java.util.concurrent.ConcurrentMap;
 import static java.io.ObjectStreamClass.processQueue;
+import sun.misc.Unsafe;
 import sun.reflect.misc.ReflectUtil;
 
 /**
@@ -375,6 +376,7 @@
             }
             if (depth == 0) {
                 vlist.doCallbacks();
+                freeze();
             }
             return obj;
         } finally {
@@ -465,6 +467,7 @@
             }
             if (depth == 0) {
                 vlist.doCallbacks();
+                freeze();
             }
             return obj;
         } finally {
@@ -2357,6 +2360,26 @@
         }
     }
 
+    private static final Unsafe UNSAFE = Unsafe.getUnsafe();
+
+    /**
+     * Performs a "freeze" action, required to adhere to final field semantics.
+     *
+     * <p> This method can be called unconditionally before returning the graph,
+     * from the topmost readObject call, since it is expected that the
+     * additional cost of the freeze action is negligible compared to
+     * reconstituting even the most simple graph.
+     *
+     * <p> Nested calls to readObject do not issue freeze actions because the
+     * sub-graph returned from a nested call is not guaranteed to be fully
+     * initialized yet (possible cycles).
+     */
+    private void freeze() {
+        // Issue a StoreStore|StoreLoad fence, which is at least sufficient
+        // to provide final-freeze semantics.
+        UNSAFE.storeFence();
+    }
+
     /**
      * Input stream with two modes: in default mode, inputs data written in the
      * same format as DataOutputStream; in "block data" mode, inputs data
--- a/jdk/src/java.base/share/classes/java/math/BigDecimal.java	Fri Feb 27 11:56:42 2015 +0100
+++ b/jdk/src/java.base/share/classes/java/math/BigDecimal.java	Fri Feb 27 11:45:07 2015 +0000
@@ -3740,8 +3740,8 @@
                 throw new ExceptionInInitializerError(ex);
             }
         }
-        static void setIntCompactVolatile(BigDecimal bd, long val) {
-            unsafe.putLongVolatile(bd, intCompactOffset, val);
+        static void setIntCompact(BigDecimal bd, long val) {
+            unsafe.putLong(bd, intCompactOffset, val);
         }
 
         static void setIntValVolatile(BigDecimal bd, BigInteger val) {
@@ -3765,7 +3765,7 @@
             throw new java.io.StreamCorruptedException(message);
         // [all values of scale are now allowed]
         }
-        UnsafeHolder.setIntCompactVolatile(this, compactValFor(intVal));
+        UnsafeHolder.setIntCompact(this, compactValFor(intVal));
     }
 
    /**
--- a/jdk/src/java.base/share/classes/java/math/BigInteger.java	Fri Feb 27 11:56:42 2015 +0100
+++ b/jdk/src/java.base/share/classes/java/math/BigInteger.java	Fri Feb 27 11:45:07 2015 +0000
@@ -4368,11 +4368,11 @@
         }
 
         static void putSign(BigInteger bi, int sign) {
-            unsafe.putIntVolatile(bi, signumOffset, sign);
+            unsafe.putInt(bi, signumOffset, sign);
         }
 
         static void putMag(BigInteger bi, int[] magnitude) {
-            unsafe.putObjectVolatile(bi, magOffset, magnitude);
+            unsafe.putObject(bi, magOffset, magnitude);
         }
     }