< 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 >