8074022: Serialization should issue a freeze action after reconstituting a graph that contains objects with final fields
Reviewed-by: dholmes, plevart, psandoz
--- 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);
}
}