< prev index next >
src/java.base/share/classes/java/io/ObjectInputStream.java
Print this page
*** 417,426 ****
--- 417,439 ----
return readObjectOverride();
}
// if nested read, passHandle contains handle of enclosing object
int outerHandle = passHandle;
+ // save currentReader
+ Object outerReader = currentReader;
+
+ Thread thread = Thread.currentThread();
+ if (outerReader == null ||
+ outerReader == thread ||
+ (outerReader instanceof ReaderContext &&
+ ((ReaderContext) outerReader).thread == thread)) {
+ // If no other thead caches ReaderContext or this is recursive entry,
+ // place mark so that latestUserDefinedLoader() can cache loader in
+ // this context
+ currentReader = thread;
+ }
try {
Object obj = readObject0(false);
handles.markDependency(outerHandle, passHandle);
ClassNotFoundException ex = handles.lookupException(passHandle);
if (ex != null) {
*** 434,443 ****
--- 447,463 ----
} finally {
passHandle = outerHandle;
if (closed && depth == 0) {
clear();
}
+ if (outerReader == null ||
+ outerReader == thread ||
+ (outerReader instanceof ReaderContext &&
+ ((ReaderContext) outerReader).thread == thread)) {
+ // restore/clear currentReader when in correct thread/non-nested call
+ currentReader = outerReader;
+ }
}
}
/**
* This method is called by trusted subclasses of ObjectOutputStream that
*** 512,521 ****
--- 532,554 ----
* @since 1.4
*/
public Object readUnshared() throws IOException, ClassNotFoundException {
// if nested read, passHandle contains handle of enclosing object
int outerHandle = passHandle;
+ // save currentReader
+ Object outerReader = currentReader;
+
+ Thread thread = Thread.currentThread();
+ if (outerReader == null ||
+ outerReader == thread ||
+ (outerReader instanceof ReaderContext &&
+ ((ReaderContext) outerReader).thread == thread)) {
+ // If no other thead caches ReaderContext or this is recursive entry,
+ // place mark so that latestUserDefinedLoader() can cache loader in
+ // this context
+ currentReader = thread;
+ }
try {
Object obj = readObject0(true);
handles.markDependency(outerHandle, passHandle);
ClassNotFoundException ex = handles.lookupException(passHandle);
if (ex != null) {
*** 529,538 ****
--- 562,578 ----
} finally {
passHandle = outerHandle;
if (closed && depth == 0) {
clear();
}
+ if (outerReader == null ||
+ outerReader == thread ||
+ (outerReader instanceof ReaderContext &&
+ ((ReaderContext) outerReader).thread == thread)) {
+ // restore/clear currentReader when in correct thread/non-nested call
+ currentReader = outerReader;
+ }
}
}
/**
* Read the non-static and non-transient fields of the current class from
*** 2387,2404 ****
// REMIND: remove once hotspot inlines Double.longBitsToDouble
private static native void bytesToDoubles(byte[] src, int srcpos,
double[] dst, int dstpos,
int ndoubles);
/**
* Returns the first non-null and non-platform class loader (not counting
* class loaders of generated reflection implementation classes) up the
* execution stack, or the platform class loader if only code from the
* bootstrap and platform class loader is on the stack.
*/
! private static ClassLoader latestUserDefinedLoader() {
! return jdk.internal.misc.VM.latestUserDefinedLoader();
}
/**
* Default GetField implementation.
*/
--- 2427,2490 ----
// REMIND: remove once hotspot inlines Double.longBitsToDouble
private static native void bytesToDoubles(byte[] src, int srcpos,
double[] dst, int dstpos,
int ndoubles);
+ // Holds a pair of latestUserDefinedLoader() result and the thread that called
+ // the method, so that latestUserDefinedLoader() can identify if it can reuse
+ // the cached result.
+ private static class ReaderContext {
+ final ClassLoader loader;
+ final Thread thread = Thread.currentThread();
+
+ ReaderContext(ClassLoader loader) {
+ this.loader = loader;
+ }
+ }
+
+ // Records the thread that can cache latestUserDefinedLoader. This field containes
+ // either null (when not called via public readObject() / readUnshared()), or
+ // a Thread instance (marking the thread that entered public readObject() /
+ // readUnshared() and is responsible for cleanup too), or
+ // a ReaderContext instance with cached loader.
+ // On recursive entry to public readObject() / readUnshared(), the current value
+ // of this field is saved in a local variable and reset to the Thread instance,
+ // so that the nexted latestUserDefinedLoader() can evaluate loader in the context.
+ // This field is left non-volatile because this field does not intend to limit
+ // only one thread to use ReaderContext but to make sure a thread uses correct
+ // ReaderContext and cleans it up on return from readObject() / readUnshared().
+ private Object currentReader;
+
/**
* Returns the first non-null and non-platform class loader (not counting
* class loaders of generated reflection implementation classes) up the
* execution stack, or the platform class loader if only code from the
* bootstrap and platform class loader is on the stack.
*/
! private ClassLoader latestUserDefinedLoader() {
! Object readerCtx = currentReader;
! ClassLoader loader;
! Thread thread = Thread.currentThread();
! if (readerCtx == thread) {
! // entered via public readObject() / readUnshared()
! // so we must evaluate loader lazily and cache it
! loader = jdk.internal.misc.VM.latestUserDefinedLoader();
! currentReader = new ReaderContext(loader);
! } else if (readerCtx instanceof ReaderContext &&
! ((ReaderContext) readerCtx).thread == thread) {
! // use cached value if correct thread
! loader = ((ReaderContext) readerCtx).loader;
! } else {
! // not called via public readObject() / readUnshared():
! // (readerCtx == null) or
! // invalid multi threaded use:
! // (readerCtx != Thread.currentThread() &&
! // readerCtx.thread != Thread.currentThread())
! // - don't cache
! loader = jdk.internal.misc.VM.latestUserDefinedLoader();
! }
! return loader;
}
/**
* Default GetField implementation.
*/
< prev index next >