< prev index next >

src/java.base/share/classes/java/io/ObjectInputStream.java

Print this page

        

*** 417,426 **** --- 417,437 ---- return readObjectOverride(); } // if nested read, passHandle contains handle of enclosing object int outerHandle = passHandle; + // save current cachedLoader + Object outerCL = cachedLoader; + + Thread thread = Thread.currentThread(); + if (outerCL == null || + outerCL == thread || + (outerCL instanceof CachedLoader && + ((CachedLoader) outerCL).thread == thread)) { + // place mark so that latestUserDefinedLoader() can cache loader + cachedLoader = thread; + } try { Object obj = readObject0(false); handles.markDependency(outerHandle, passHandle); ClassNotFoundException ex = handles.lookupException(passHandle); if (ex != null) {
*** 434,443 **** --- 445,461 ---- } finally { passHandle = outerHandle; if (closed && depth == 0) { clear(); } + if (outerCL == null || + outerCL == thread || + (outerCL instanceof CachedLoader && + ((CachedLoader) outerCL).thread == thread)) { + // restore/clear cachedLoader when in correct thread/non-nested call + cachedLoader = outerCL; + } } } /** * This method is called by trusted subclasses of ObjectOutputStream that
*** 512,521 **** --- 530,550 ---- * @since 1.4 */ public Object readUnshared() throws IOException, ClassNotFoundException { // if nested read, passHandle contains handle of enclosing object int outerHandle = passHandle; + // save current cachedLoader + Object outerCL = cachedLoader; + + Thread thread = Thread.currentThread(); + if (outerCL == null || + outerCL == thread || + (outerCL instanceof CachedLoader && + ((CachedLoader) outerCL).thread == thread)) { + // place mark so that latestUserDefinedLoader() can cache loader + cachedLoader = thread; + } try { Object obj = readObject0(true); handles.markDependency(outerHandle, passHandle); ClassNotFoundException ex = handles.lookupException(passHandle); if (ex != null) {
*** 529,538 **** --- 558,574 ---- } finally { passHandle = outerHandle; if (closed && depth == 0) { clear(); } + if (outerCL == null || + outerCL == thread || + (outerCL instanceof CachedLoader && + ((CachedLoader) outerCL).thread == thread)) { + // restore/clear cachedLoader when in correct thread/non-nested call + cachedLoader = outerCL; + } } } /** * 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. */ --- 2423,2479 ---- // REMIND: remove once hotspot inlines Double.longBitsToDouble private static native void bytesToDoubles(byte[] src, int srcpos, double[] dst, int dstpos, int ndoubles); + // cached latestUserDefinedLoader() result + private static class CachedLoader { + final ClassLoader loader; + final Thread thread = Thread.currentThread(); + + CachedLoader(ClassLoader loader) { + this.loader = loader; + } + } + + // 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 CachedLoader instance with cached loader + // This field is left non-volatile although there is a benign race here. + // The thread that see a non-null value can always check if the cache is for + // the thread, and such thread always cleans up the cache on return. + private Object cachedLoader; + /** * 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 cl = cachedLoader; ! ClassLoader loader; ! Thread thread = Thread.currentThread(); ! if (cl == thread) { ! // entered via public readObject() / readUnshared() ! // so we must evaluate loader lazily and cache it ! loader = jdk.internal.misc.VM.latestUserDefinedLoader(); ! cachedLoader = new CachedLoader(loader); ! } else if (cl instanceof CachedLoader && ! ((CachedLoader) cl).thread == thread) { ! // use cached value if correct thread ! loader = ((CachedLoader) cl).loader; ! } else { ! // not called via public readObject() / readUnshared(): ! // (cl == null) or ! // invalid multi threaded use: ! // (cl != Thread.currentThread() && cl.thread != Thread.currentThread()) ! // - don't cache ! loader = jdk.internal.misc.VM.latestUserDefinedLoader(); ! } ! return loader; } /** * Default GetField implementation. */
< prev index next >