--- old/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/RecompilableScriptFunctionData.java 2017-01-10 15:43:23.000000000 +0100 +++ new/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/RecompilableScriptFunctionData.java 2017-01-10 15:43:23.000000000 +0100 @@ -28,6 +28,8 @@ import static jdk.nashorn.internal.lookup.Lookup.MH; import java.io.IOException; +import java.io.ObjectOutputStream; +import java.io.Serializable; import java.lang.invoke.MethodHandle; import java.lang.invoke.MethodHandles; import java.lang.invoke.MethodType; @@ -100,7 +102,7 @@ * reparsed from source, or a soft reference to a {@code FunctionNode} for other functions (it is safe * to be cleared as they can be reparsed). */ - private volatile Object cachedAst; + private volatile transient Object cachedAst; /** Token of this function within the source. */ private final long token; @@ -289,6 +291,9 @@ if (this.source == null && this.installer == null) { this.source = src; this.installer = inst; + for (final RecompilableScriptFunctionData nested : nestedFunctions.values()) { + nested.initTransients(src, inst); + } } else if (this.source != src || !this.installer.isCompatibleWith(inst)) { // Existing values must be same as those passed as parameters throw new IllegalArgumentException(); @@ -424,7 +429,7 @@ } else if (lCachedAst instanceof SerializedAst) { final SerializedAst serializedAst = (SerializedAst)lCachedAst; // Even so, are we also softly caching the AST? - final FunctionNode cachedFn = serializedAst.cachedAst.get(); + final FunctionNode cachedFn = serializedAst.cachedAst == null ? null : serializedAst.cachedAst.get(); if (cachedFn != null) { // Yes we are - this is fast return cloneSymbols(cachedFn); @@ -492,9 +497,11 @@ * we're using this tuple instead to also keep a deserialized AST around in memory to cut down on * deserialization costs. */ - private static class SerializedAst { + private static class SerializedAst implements Serializable { private final byte[] serializedAst; - private volatile Reference cachedAst; + private volatile transient Reference cachedAst; + + private static final long serialVersionUID = 1L; SerializedAst(final FunctionNode fn, final Reference cachedAst) { this.serializedAst = AstSerializer.serialize(fn); @@ -1038,8 +1045,20 @@ return true; } + private void writeObject(final ObjectOutputStream out) throws IOException { + final Object localCachedAst = cachedAst; + out.defaultWriteObject(); + // We need to persist SerializedAst for split functions as they can't reparse the source code. + if (localCachedAst instanceof SerializedAst) { + out.writeObject(localCachedAst); + } else { + out.writeObject(null); + } + } + private void readObject(final java.io.ObjectInputStream in) throws IOException, ClassNotFoundException { in.defaultReadObject(); + cachedAst = in.readObject(); createLogger(); }