8059844: Implement optimistic splitter

Mon, 20 Oct 2014 12:06:36 +0200

author
attila
date
Mon, 20 Oct 2014 12:06:36 +0200
changeset 1064
03c06c337d9d
parent 1063
8c51767d534d
child 1065
3219e9e47daf

8059844: Implement optimistic splitter
Reviewed-by: hannesw, lagergren

src/jdk/nashorn/internal/codegen/ApplySpecialization.java file | annotate | diff | comparison | revisions
src/jdk/nashorn/internal/codegen/AssignSymbols.java file | annotate | diff | comparison | revisions
src/jdk/nashorn/internal/codegen/AstSerializer.java file | annotate | diff | comparison | revisions
src/jdk/nashorn/internal/codegen/ClassEmitter.java file | annotate | diff | comparison | revisions
src/jdk/nashorn/internal/codegen/CodeGenerator.java file | annotate | diff | comparison | revisions
src/jdk/nashorn/internal/codegen/CompilationPhase.java file | annotate | diff | comparison | revisions
src/jdk/nashorn/internal/codegen/CompileUnit.java file | annotate | diff | comparison | revisions
src/jdk/nashorn/internal/codegen/Compiler.java file | annotate | diff | comparison | revisions
src/jdk/nashorn/internal/codegen/FindScopeDepths.java file | annotate | diff | comparison | revisions
src/jdk/nashorn/internal/codegen/LocalVariableTypesCalculator.java file | annotate | diff | comparison | revisions
src/jdk/nashorn/internal/codegen/Lower.java file | annotate | diff | comparison | revisions
src/jdk/nashorn/internal/codegen/MethodEmitter.java file | annotate | diff | comparison | revisions
src/jdk/nashorn/internal/codegen/OptimisticTypesCalculator.java file | annotate | diff | comparison | revisions
src/jdk/nashorn/internal/codegen/ProgramPoints.java file | annotate | diff | comparison | revisions
src/jdk/nashorn/internal/codegen/ReplaceCompileUnits.java file | annotate | diff | comparison | revisions
src/jdk/nashorn/internal/codegen/SplitIntoFunctions.java file | annotate | diff | comparison | revisions
src/jdk/nashorn/internal/codegen/SplitMethodEmitter.java file | annotate | diff | comparison | revisions
src/jdk/nashorn/internal/ir/BlockLexicalContext.java file | annotate | diff | comparison | revisions
src/jdk/nashorn/internal/ir/FunctionNode.java file | annotate | diff | comparison | revisions
src/jdk/nashorn/internal/ir/GetSplitState.java file | annotate | diff | comparison | revisions
src/jdk/nashorn/internal/ir/LexicalContext.java file | annotate | diff | comparison | revisions
src/jdk/nashorn/internal/ir/LiteralNode.java file | annotate | diff | comparison | revisions
src/jdk/nashorn/internal/ir/Node.java file | annotate | diff | comparison | revisions
src/jdk/nashorn/internal/ir/SetSplitState.java file | annotate | diff | comparison | revisions
src/jdk/nashorn/internal/ir/SplitNode.java file | annotate | diff | comparison | revisions
src/jdk/nashorn/internal/ir/SplitReturn.java file | annotate | diff | comparison | revisions
src/jdk/nashorn/internal/ir/Symbol.java file | annotate | diff | comparison | revisions
src/jdk/nashorn/internal/ir/visitor/NodeVisitor.java file | annotate | diff | comparison | revisions
src/jdk/nashorn/internal/runtime/AstDeserializer.java file | annotate | diff | comparison | revisions
src/jdk/nashorn/internal/runtime/CompiledFunction.java file | annotate | diff | comparison | revisions
src/jdk/nashorn/internal/runtime/RecompilableScriptFunctionData.java file | annotate | diff | comparison | revisions
     1.1 --- a/src/jdk/nashorn/internal/codegen/ApplySpecialization.java	Fri Oct 17 14:24:26 2014 +0200
     1.2 +++ b/src/jdk/nashorn/internal/codegen/ApplySpecialization.java	Mon Oct 20 12:06:36 2014 +0200
     1.3 @@ -27,6 +27,7 @@
     1.4  
     1.5  import static jdk.nashorn.internal.codegen.CompilerConstants.ARGUMENTS_VAR;
     1.6  import static jdk.nashorn.internal.codegen.CompilerConstants.EXPLODED_ARGUMENT_PREFIX;
     1.7 +
     1.8  import java.lang.invoke.MethodType;
     1.9  import java.util.ArrayDeque;
    1.10  import java.util.ArrayList;
    1.11 @@ -38,6 +39,7 @@
    1.12  import jdk.nashorn.internal.ir.CallNode;
    1.13  import jdk.nashorn.internal.ir.Expression;
    1.14  import jdk.nashorn.internal.ir.FunctionNode;
    1.15 +import jdk.nashorn.internal.ir.FunctionNode.CompilationState;
    1.16  import jdk.nashorn.internal.ir.IdentNode;
    1.17  import jdk.nashorn.internal.ir.LexicalContext;
    1.18  import jdk.nashorn.internal.ir.Node;
    1.19 @@ -321,7 +323,7 @@
    1.20  
    1.21          explodedArguments.pop();
    1.22  
    1.23 -        return newFunctionNode;
    1.24 +        return newFunctionNode.setState(lc, CompilationState.BUILTINS_TRANSFORMED);
    1.25      }
    1.26  
    1.27      private static boolean isApply(final CallNode callNode) {
     2.1 --- a/src/jdk/nashorn/internal/codegen/AssignSymbols.java	Fri Oct 17 14:24:26 2014 +0200
     2.2 +++ b/src/jdk/nashorn/internal/codegen/AssignSymbols.java	Mon Oct 20 12:06:36 2014 +0200
     2.3 @@ -76,7 +76,6 @@
     2.4  import jdk.nashorn.internal.ir.Node;
     2.5  import jdk.nashorn.internal.ir.RuntimeNode;
     2.6  import jdk.nashorn.internal.ir.RuntimeNode.Request;
     2.7 -import jdk.nashorn.internal.ir.SplitNode;
     2.8  import jdk.nashorn.internal.ir.Statement;
     2.9  import jdk.nashorn.internal.ir.SwitchNode;
    2.10  import jdk.nashorn.internal.ir.Symbol;
    2.11 @@ -135,9 +134,6 @@
    2.12          if (!(functionNode.hasScopeBlock() || functionNode.needsParentScope())) {
    2.13              functionNode.compilerConstant(SCOPE).setNeedsSlot(false);
    2.14          }
    2.15 -        if (!functionNode.usesReturnSymbol()) {
    2.16 -            functionNode.compilerConstant(RETURN).setNeedsSlot(false);
    2.17 -        }
    2.18          // Named function expressions that end up not referencing themselves won't need a local slot for the self symbol.
    2.19          if(!functionNode.isDeclared() && !functionNode.usesSelfSymbol() && !functionNode.isAnonymous()) {
    2.20              final Symbol selfSymbol = functionNode.getBody().getExistingSymbol(functionNode.getIdent().getName());
    2.21 @@ -1014,7 +1010,7 @@
    2.22          boolean previousWasBlock = false;
    2.23          for (final Iterator<LexicalContextNode> it = lc.getAllNodes(); it.hasNext();) {
    2.24              final LexicalContextNode node = it.next();
    2.25 -            if (node instanceof FunctionNode || node instanceof SplitNode || isSplitArray(node)) {
    2.26 +            if (node instanceof FunctionNode || isSplitArray(node)) {
    2.27                  // We reached the function boundary or a splitting boundary without seeing a definition for the symbol.
    2.28                  // It needs to be in scope.
    2.29                  return true;
     3.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     3.2 +++ b/src/jdk/nashorn/internal/codegen/AstSerializer.java	Mon Oct 20 12:06:36 2014 +0200
     3.3 @@ -0,0 +1,71 @@
     3.4 +/*
     3.5 + * Copyright (c) 2010, 2014, Oracle and/or its affiliates. All rights reserved.
     3.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
     3.7 + *
     3.8 + * This code is free software; you can redistribute it and/or modify it
     3.9 + * under the terms of the GNU General Public License version 2 only, as
    3.10 + * published by the Free Software Foundation.  Oracle designates this
    3.11 + * particular file as subject to the "Classpath" exception as provided
    3.12 + * by Oracle in the LICENSE file that accompanied this code.
    3.13 + *
    3.14 + * This code is distributed in the hope that it will be useful, but WITHOUT
    3.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
    3.16 + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
    3.17 + * version 2 for more details (a copy is included in the LICENSE file that
    3.18 + * accompanied this code).
    3.19 + *
    3.20 + * You should have received a copy of the GNU General Public License version
    3.21 + * 2 along with this work; if not, write to the Free Software Foundation,
    3.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
    3.23 + *
    3.24 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
    3.25 + * or visit www.oracle.com if you need additional information or have any
    3.26 + * questions.
    3.27 + */
    3.28 +package jdk.nashorn.internal.codegen;
    3.29 +
    3.30 +import java.io.ByteArrayOutputStream;
    3.31 +import java.io.IOException;
    3.32 +import java.io.ObjectOutputStream;
    3.33 +import java.util.Collections;
    3.34 +import java.util.zip.Deflater;
    3.35 +import java.util.zip.DeflaterOutputStream;
    3.36 +import jdk.nashorn.internal.ir.Block;
    3.37 +import jdk.nashorn.internal.ir.FunctionNode;
    3.38 +import jdk.nashorn.internal.ir.LexicalContext;
    3.39 +import jdk.nashorn.internal.ir.Node;
    3.40 +import jdk.nashorn.internal.ir.Statement;
    3.41 +import jdk.nashorn.internal.ir.visitor.NodeVisitor;
    3.42 +import jdk.nashorn.internal.runtime.options.Options;
    3.43 +
    3.44 +/**
    3.45 + * This static utility class performs serialization of FunctionNode ASTs to a byte array.
    3.46 + * The format is a standard Java serialization stream, deflated.
    3.47 + */
    3.48 +final class AstSerializer {
    3.49 +    // Experimentally, we concluded that compression level 4 gives a good tradeoff between serialization speed
    3.50 +    // and size.
    3.51 +    private static final int COMPRESSION_LEVEL = Options.getIntProperty("nashorn.serialize.compression", 4);
    3.52 +    static byte[] serialize(final FunctionNode fn) {
    3.53 +        final ByteArrayOutputStream out = new ByteArrayOutputStream();
    3.54 +        try (final ObjectOutputStream oout = new ObjectOutputStream(new DeflaterOutputStream(out,
    3.55 +                new Deflater(COMPRESSION_LEVEL)))) {
    3.56 +            oout.writeObject(removeInnerFunctionBodies(fn));
    3.57 +        } catch (final IOException e) {
    3.58 +            throw new AssertionError("Unexpected exception serializing function", e);
    3.59 +        }
    3.60 +        return out.toByteArray();
    3.61 +    }
    3.62 +
    3.63 +    private static FunctionNode removeInnerFunctionBodies(final FunctionNode fn) {
    3.64 +        return (FunctionNode)fn.accept(new NodeVisitor<LexicalContext>(new LexicalContext()) {
    3.65 +            @Override
    3.66 +            public Node leaveBlock(final Block block) {
    3.67 +                if (lc.isFunctionBody() && lc.getFunction(block) != lc.getOutermostFunction()) {
    3.68 +                    return block.setStatements(lc, Collections.<Statement>emptyList());
    3.69 +                }
    3.70 +                return super.leaveBlock(block);
    3.71 +            }
    3.72 +        });
    3.73 +    }
    3.74 +}
     4.1 --- a/src/jdk/nashorn/internal/codegen/ClassEmitter.java	Fri Oct 17 14:24:26 2014 +0200
     4.2 +++ b/src/jdk/nashorn/internal/codegen/ClassEmitter.java	Mon Oct 20 12:06:36 2014 +0200
     4.3 @@ -51,6 +51,7 @@
     4.4  import static jdk.nashorn.internal.codegen.CompilerConstants.methodDescriptor;
     4.5  import static jdk.nashorn.internal.codegen.CompilerConstants.typeDescriptor;
     4.6  import static jdk.nashorn.internal.codegen.CompilerConstants.virtualCallNoLookup;
     4.7 +
     4.8  import java.io.ByteArrayOutputStream;
     4.9  import java.io.PrintWriter;
    4.10  import java.security.AccessController;
    4.11 @@ -64,7 +65,6 @@
    4.12  import jdk.internal.org.objectweb.asm.util.TraceClassVisitor;
    4.13  import jdk.nashorn.internal.codegen.types.Type;
    4.14  import jdk.nashorn.internal.ir.FunctionNode;
    4.15 -import jdk.nashorn.internal.ir.SplitNode;
    4.16  import jdk.nashorn.internal.ir.debug.NashornClassReader;
    4.17  import jdk.nashorn.internal.ir.debug.NashornTextifier;
    4.18  import jdk.nashorn.internal.runtime.Context;
    4.19 @@ -476,12 +476,6 @@
    4.20          methodsStarted.remove(method);
    4.21      }
    4.22  
    4.23 -    SplitMethodEmitter method(final SplitNode splitNode, final String methodName, final Class<?> rtype, final Class<?>... ptypes) {
    4.24 -        methodCount++;
    4.25 -        methodNames.add(methodName);
    4.26 -        return new SplitMethodEmitter(this, methodVisitor(EnumSet.of(Flag.PUBLIC, Flag.STATIC), methodName, rtype, ptypes), splitNode);
    4.27 -    }
    4.28 -
    4.29      /**
    4.30       * Add a new method to the class - defaults to public method
    4.31       *
     5.1 --- a/src/jdk/nashorn/internal/codegen/CodeGenerator.java	Fri Oct 17 14:24:26 2014 +0200
     5.2 +++ b/src/jdk/nashorn/internal/codegen/CodeGenerator.java	Mon Oct 20 12:06:36 2014 +0200
     5.3 @@ -34,9 +34,7 @@
     5.4  import static jdk.nashorn.internal.codegen.CompilerConstants.GET_STRING;
     5.5  import static jdk.nashorn.internal.codegen.CompilerConstants.QUICK_PREFIX;
     5.6  import static jdk.nashorn.internal.codegen.CompilerConstants.REGEX_PREFIX;
     5.7 -import static jdk.nashorn.internal.codegen.CompilerConstants.RETURN;
     5.8  import static jdk.nashorn.internal.codegen.CompilerConstants.SCOPE;
     5.9 -import static jdk.nashorn.internal.codegen.CompilerConstants.SPLIT_ARRAY_ARG;
    5.10  import static jdk.nashorn.internal.codegen.CompilerConstants.SPLIT_PREFIX;
    5.11  import static jdk.nashorn.internal.codegen.CompilerConstants.THIS;
    5.12  import static jdk.nashorn.internal.codegen.CompilerConstants.VARARGS;
    5.13 @@ -99,10 +97,10 @@
    5.14  import jdk.nashorn.internal.ir.ForNode;
    5.15  import jdk.nashorn.internal.ir.FunctionNode;
    5.16  import jdk.nashorn.internal.ir.FunctionNode.CompilationState;
    5.17 +import jdk.nashorn.internal.ir.GetSplitState;
    5.18  import jdk.nashorn.internal.ir.IdentNode;
    5.19  import jdk.nashorn.internal.ir.IfNode;
    5.20  import jdk.nashorn.internal.ir.IndexNode;
    5.21 -import jdk.nashorn.internal.ir.JoinPredecessor;
    5.22  import jdk.nashorn.internal.ir.JoinPredecessorExpression;
    5.23  import jdk.nashorn.internal.ir.JumpStatement;
    5.24  import jdk.nashorn.internal.ir.LabelNode;
    5.25 @@ -121,7 +119,8 @@
    5.26  import jdk.nashorn.internal.ir.ReturnNode;
    5.27  import jdk.nashorn.internal.ir.RuntimeNode;
    5.28  import jdk.nashorn.internal.ir.RuntimeNode.Request;
    5.29 -import jdk.nashorn.internal.ir.SplitNode;
    5.30 +import jdk.nashorn.internal.ir.SetSplitState;
    5.31 +import jdk.nashorn.internal.ir.SplitReturn;
    5.32  import jdk.nashorn.internal.ir.Statement;
    5.33  import jdk.nashorn.internal.ir.SwitchNode;
    5.34  import jdk.nashorn.internal.ir.Symbol;
    5.35 @@ -493,8 +492,7 @@
    5.36          //walk up the chain from starting block and when we bump into the current function boundary, add the external
    5.37          //information.
    5.38          final FunctionNode fn   = lc.getCurrentFunction();
    5.39 -        final int          fnId = fn.getId();
    5.40 -        final int externalDepth = compiler.getScriptFunctionData(fnId).getExternalSymbolDepth(symbol.getName());
    5.41 +        final int externalDepth = compiler.getScriptFunctionData(fn.getId()).getExternalSymbolDepth(symbol.getName());
    5.42  
    5.43          //count the number of scopes from this place to the start of the function
    5.44  
    5.45 @@ -1048,6 +1046,13 @@
    5.46              }
    5.47  
    5.48              @Override
    5.49 +            public boolean enterGetSplitState(final GetSplitState getSplitState) {
    5.50 +                method.loadScope();
    5.51 +                method.invoke(Scope.GET_SPLIT_STATE);
    5.52 +                return false;
    5.53 +            }
    5.54 +
    5.55 +            @Override
    5.56              public boolean enterDefault(final Node otherNode) {
    5.57                  // Must have handled all expressions that can legally be encountered.
    5.58                  throw new AssertionError(otherNode.getClass().getName());
    5.59 @@ -1219,7 +1224,7 @@
    5.60          popScopesUntil(target);
    5.61          final Label targetLabel = jump.getTargetLabel(target);
    5.62          targetLabel.markAsBreakTarget();
    5.63 -        method.splitAwareGoto(lc, targetLabel, target);
    5.64 +        method._goto(targetLabel);
    5.65  
    5.66          return false;
    5.67      }
    5.68 @@ -2029,10 +2034,10 @@
    5.69      }
    5.70  
    5.71      private void lineNumber(final int lineNumber) {
    5.72 -        if (lineNumber != lastLineNumber) {
    5.73 +        if (lineNumber != lastLineNumber && lineNumber != Node.NO_LINE_NUMBER) {
    5.74              method.lineNumber(lineNumber);
    5.75 -        }
    5.76 -        lastLineNumber = lineNumber;
    5.77 +            lastLineNumber = lineNumber;
    5.78 +        }
    5.79      }
    5.80  
    5.81      int getLastLineNumber() {
    5.82 @@ -2079,13 +2084,14 @@
    5.83                  method.begin();
    5.84  
    5.85                  defineCommonSplitMethodParameters();
    5.86 -                defineSplitMethodParameter(3, arrayType);
    5.87 -
    5.88 -                fixScopeSlot(currentFunction);
    5.89 +                defineSplitMethodParameter(CompilerConstants.SPLIT_ARRAY_ARG.slot(), arrayType);
    5.90 +
    5.91 +                // NOTE: when this is no longer needed, SplitIntoFunctions will no longer have to add IS_SPLIT
    5.92 +                // to synthetic functions, and FunctionNode.needsCallee() will no longer need to test for isSplit().
    5.93 +                final int arraySlot = fixScopeSlot(currentFunction, 3);
    5.94  
    5.95                  lc.enterSplitNode();
    5.96  
    5.97 -                final int arraySlot = SPLIT_ARRAY_ARG.slot();
    5.98                  for (int i = arrayUnit.getLo(); i < arrayUnit.getHi(); i++) {
    5.99                      method.load(arrayType, arraySlot);
   5.100                      storeElement(nodes, elementType, postsets[i]);
   5.101 @@ -2700,73 +2706,6 @@
   5.102          method.convert(newRuntimeNode.getType());
   5.103      }
   5.104  
   5.105 -    @Override
   5.106 -    public boolean enterSplitNode(final SplitNode splitNode) {
   5.107 -        if(!method.isReachable()) {
   5.108 -            return false;
   5.109 -        }
   5.110 -
   5.111 -        final CompileUnit splitCompileUnit = splitNode.getCompileUnit();
   5.112 -
   5.113 -        final FunctionNode fn   = lc.getCurrentFunction();
   5.114 -        final String className  = splitCompileUnit.getUnitClassName();
   5.115 -        final String name       = splitNode.getName();
   5.116 -
   5.117 -        final Type returnType = fn.getReturnType();
   5.118 -
   5.119 -        final Class<?>   rtype          = fn.getReturnType().getTypeClass();
   5.120 -        final boolean    needsArguments = fn.needsArguments();
   5.121 -        final Class<?>[] ptypes         = needsArguments ?
   5.122 -                new Class<?>[] {ScriptFunction.class, Object.class, ScriptObject.class, ScriptObject.class} :
   5.123 -                new Class<?>[] {ScriptFunction.class, Object.class, ScriptObject.class};
   5.124 -
   5.125 -        final MethodEmitter caller = method;
   5.126 -        unit = lc.pushCompileUnit(splitCompileUnit);
   5.127 -
   5.128 -        final Call splitCall = staticCallNoLookup(
   5.129 -            className,
   5.130 -            name,
   5.131 -            methodDescriptor(rtype, ptypes));
   5.132 -
   5.133 -        final MethodEmitter splitEmitter =
   5.134 -                splitCompileUnit.getClassEmitter().method(
   5.135 -                        splitNode,
   5.136 -                        name,
   5.137 -                        rtype,
   5.138 -                        ptypes);
   5.139 -
   5.140 -        pushMethodEmitter(splitEmitter);
   5.141 -        method.setFunctionNode(fn);
   5.142 -
   5.143 -        assert fn.needsCallee() : "split function should require callee";
   5.144 -        caller.loadCompilerConstant(CALLEE);
   5.145 -        caller.loadCompilerConstant(THIS);
   5.146 -        caller.loadCompilerConstant(SCOPE);
   5.147 -        if (needsArguments) {
   5.148 -            caller.loadCompilerConstant(ARGUMENTS);
   5.149 -        }
   5.150 -        caller.invoke(splitCall);
   5.151 -        caller.storeCompilerConstant(RETURN, returnType);
   5.152 -
   5.153 -        method.begin();
   5.154 -
   5.155 -        defineCommonSplitMethodParameters();
   5.156 -        if(needsArguments) {
   5.157 -            defineSplitMethodParameter(3, ARGUMENTS);
   5.158 -        }
   5.159 -
   5.160 -        // Copy scope to its target slot as first thing because the original slot could be used by return symbol.
   5.161 -        fixScopeSlot(fn);
   5.162 -
   5.163 -        final int returnSlot = fn.compilerConstant(RETURN).getSlot(returnType);
   5.164 -        method.defineBlockLocalVariable(returnSlot, returnSlot + returnType.getSlots());
   5.165 -        method.loadUndefined(returnType);
   5.166 -        method.storeCompilerConstant(RETURN, returnType);
   5.167 -
   5.168 -        lc.enterSplitNode();
   5.169 -        return true;
   5.170 -    }
   5.171 -
   5.172      private void defineCommonSplitMethodParameters() {
   5.173          defineSplitMethodParameter(0, CALLEE);
   5.174          defineSplitMethodParameter(1, THIS);
   5.175 @@ -2782,114 +2721,40 @@
   5.176          method.onLocalStore(type, slot);
   5.177      }
   5.178  
   5.179 -    private void fixScopeSlot(final FunctionNode functionNode) {
   5.180 +    private int fixScopeSlot(final FunctionNode functionNode, final int extraSlot) {
   5.181          // TODO hack to move the scope to the expected slot (needed because split methods reuse the same slots as the root method)
   5.182          final int actualScopeSlot = functionNode.compilerConstant(SCOPE).getSlot(SCOPE_TYPE);
   5.183          final int defaultScopeSlot = SCOPE.slot();
   5.184 +        int newExtraSlot = extraSlot;
   5.185          if (actualScopeSlot != defaultScopeSlot) {
   5.186 -            method.defineBlockLocalVariable(actualScopeSlot, actualScopeSlot + 1);
   5.187 +            if (actualScopeSlot == extraSlot) {
   5.188 +                newExtraSlot = extraSlot + 1;
   5.189 +                method.defineBlockLocalVariable(newExtraSlot, newExtraSlot + 1);
   5.190 +                method.load(Type.OBJECT, extraSlot);
   5.191 +                method.storeHidden(Type.OBJECT, newExtraSlot);
   5.192 +            } else {
   5.193 +                method.defineBlockLocalVariable(actualScopeSlot, actualScopeSlot + 1);
   5.194 +            }
   5.195              method.load(SCOPE_TYPE, defaultScopeSlot);
   5.196              method.storeCompilerConstant(SCOPE);
   5.197          }
   5.198 +        return newExtraSlot;
   5.199      }
   5.200  
   5.201      @Override
   5.202 -    public Node leaveSplitNode(final SplitNode splitNode) {
   5.203 -        assert method instanceof SplitMethodEmitter;
   5.204 -        lc.exitSplitNode();
   5.205 -        final boolean hasReturn = method.hasReturn();
   5.206 -        final SplitMethodEmitter splitMethod = ((SplitMethodEmitter)method);
   5.207 -        final List<Label> targets = splitMethod.getExternalTargets();
   5.208 -        final boolean hasControlFlow = hasReturn || !targets.isEmpty();
   5.209 -        final List<BreakableNode> targetNodes  = splitMethod.getExternalTargetNodes();
   5.210 -        final Type returnType = lc.getCurrentFunction().getReturnType();
   5.211 -
   5.212 -        try {
   5.213 -            // Wrap up this method.
   5.214 -
   5.215 -            if(method.isReachable()) {
   5.216 -                if (hasControlFlow) {
   5.217 -                    method.setSplitState(-1);
   5.218 -                }
   5.219 -                method.loadCompilerConstant(RETURN, returnType);
   5.220 -                method._return(returnType);
   5.221 -            }
   5.222 -            method.end();
   5.223 -
   5.224 -            lc.releaseSlots();
   5.225 -
   5.226 -            unit   = lc.popCompileUnit(splitNode.getCompileUnit());
   5.227 -            popMethodEmitter();
   5.228 -
   5.229 -        } catch (final Throwable t) {
   5.230 -            Context.printStackTrace(t);
   5.231 -            final VerifyError e = new VerifyError("Code generation bug in \"" + splitNode.getName() + "\": likely stack misaligned: " + t + " " + getCurrentSource().getName());
   5.232 -            e.initCause(t);
   5.233 -            throw e;
   5.234 -        }
   5.235 -
   5.236 -        //no external jump targets or return in switch node
   5.237 -        if (!hasControlFlow) {
   5.238 -            return splitNode;
   5.239 -        }
   5.240 -
   5.241 -        // Handle return from split method if there was one.
   5.242 -        final MethodEmitter caller = method;
   5.243 -        final int     targetCount = targets.size();
   5.244 -
   5.245 -        caller.loadScope();
   5.246 -        caller.invoke(Scope.GET_SPLIT_STATE);
   5.247 -
   5.248 -        final Label breakLabel = new Label("no_split_state");
   5.249 -        // Split state is -1 for no split state, 0 for return, 1..n+1 for break/continue
   5.250 -
   5.251 -        //the common case is that we don't need a switch
   5.252 -        if (targetCount == 0) {
   5.253 -            assert hasReturn;
   5.254 -            caller.ifne(breakLabel);
   5.255 -            //has to be zero
   5.256 -            caller.label(new Label("split_return"));
   5.257 -            caller.loadCompilerConstant(RETURN, returnType);
   5.258 -            caller._return(returnType);
   5.259 -            caller.label(breakLabel);
   5.260 -        } else {
   5.261 -            assert !targets.isEmpty();
   5.262 -
   5.263 -            final int     low         = hasReturn ? 0 : 1;
   5.264 -            final int     labelCount  = targetCount + 1 - low;
   5.265 -            final Label[] labels      = new Label[labelCount];
   5.266 -
   5.267 -            for (int i = 0; i < labelCount; i++) {
   5.268 -                labels[i] = new Label(i == 0 ? "split_return" : "split_" + targets.get(i - 1));
   5.269 -            }
   5.270 -            caller.tableswitch(low, targetCount, breakLabel, labels);
   5.271 -            for (int i = low; i <= targetCount; i++) {
   5.272 -                caller.label(labels[i - low]);
   5.273 -                if (i == 0) {
   5.274 -                    caller.loadCompilerConstant(RETURN, returnType);
   5.275 -                    caller._return(returnType);
   5.276 -                } else {
   5.277 -                    final BreakableNode targetNode = targetNodes.get(i - 1);
   5.278 -                    final Label label = targets.get(i - 1);
   5.279 -                    if (!lc.isExternalTarget(splitNode, targetNode)) {
   5.280 -                        final JoinPredecessor jumpOrigin = splitNode.getJumpOrigin(label);
   5.281 -                        if(jumpOrigin != null) {
   5.282 -                            method.beforeJoinPoint(jumpOrigin);
   5.283 -                        }
   5.284 -                        popScopesUntil(targetNode);
   5.285 -                    }
   5.286 -                    caller.splitAwareGoto(lc, label, targetNode);
   5.287 -                }
   5.288 -            }
   5.289 -            caller.label(breakLabel);
   5.290 -        }
   5.291 -
   5.292 -        // If split has a return and caller is itself a split method it needs to propagate the return.
   5.293 -        if (hasReturn) {
   5.294 -            caller.setHasReturn();
   5.295 -        }
   5.296 -
   5.297 -        return splitNode;
   5.298 +    public boolean enterSplitReturn(final SplitReturn splitReturn) {
   5.299 +        if (method.isReachable()) {
   5.300 +            method.loadUndefined(lc.getCurrentFunction().getReturnType())._return();
   5.301 +        }
   5.302 +        return false;
   5.303 +    }
   5.304 +
   5.305 +    @Override
   5.306 +    public boolean enterSetSplitState(final SetSplitState setSplitState) {
   5.307 +        if (method.isReachable()) {
   5.308 +            method.setSplitState(setSplitState.getState());
   5.309 +        }
   5.310 +        return false;
   5.311      }
   5.312  
   5.313      @Override
   5.314 @@ -4379,11 +4244,7 @@
   5.315      private void newFunctionObject(final FunctionNode functionNode, final boolean addInitializer) {
   5.316          assert lc.peek() == functionNode;
   5.317  
   5.318 -        final int fnId = functionNode.getId();
   5.319 -
   5.320 -        final RecompilableScriptFunctionData data = compiler.getScriptFunctionData(fnId);
   5.321 -
   5.322 -        assert data != null : functionNode.getName() + " has no data";
   5.323 +        final RecompilableScriptFunctionData data = compiler.getScriptFunctionData(functionNode.getId());
   5.324  
   5.325          if (functionNode.isProgram() && !compiler.isOnDemandCompilation()) {
   5.326              final CompileUnit fnUnit = functionNode.getCompileUnit();
     6.1 --- a/src/jdk/nashorn/internal/codegen/CompilationPhase.java	Fri Oct 17 14:24:26 2014 +0200
     6.2 +++ b/src/jdk/nashorn/internal/codegen/CompilationPhase.java	Mon Oct 20 12:06:36 2014 +0200
     6.3 @@ -38,12 +38,11 @@
     6.4  import static jdk.nashorn.internal.ir.FunctionNode.CompilationState.SPLIT;
     6.5  import static jdk.nashorn.internal.ir.FunctionNode.CompilationState.SYMBOLS_ASSIGNED;
     6.6  import static jdk.nashorn.internal.runtime.logging.DebugLogger.quote;
     6.7 +
     6.8  import java.io.PrintWriter;
     6.9 -import java.util.ArrayList;
    6.10  import java.util.EnumSet;
    6.11  import java.util.HashMap;
    6.12  import java.util.LinkedHashMap;
    6.13 -import java.util.List;
    6.14  import java.util.Map;
    6.15  import java.util.Map.Entry;
    6.16  import java.util.Set;
    6.17 @@ -53,10 +52,7 @@
    6.18  import jdk.nashorn.internal.ir.FunctionNode.CompilationState;
    6.19  import jdk.nashorn.internal.ir.LexicalContext;
    6.20  import jdk.nashorn.internal.ir.LiteralNode;
    6.21 -import jdk.nashorn.internal.ir.LiteralNode.ArrayLiteralNode;
    6.22 -import jdk.nashorn.internal.ir.LiteralNode.ArrayLiteralNode.ArrayUnit;
    6.23  import jdk.nashorn.internal.ir.Node;
    6.24 -import jdk.nashorn.internal.ir.SplitNode;
    6.25  import jdk.nashorn.internal.ir.debug.ASTWriter;
    6.26  import jdk.nashorn.internal.ir.debug.PrintVisitor;
    6.27  import jdk.nashorn.internal.ir.visitor.NodeVisitor;
    6.28 @@ -81,7 +77,7 @@
    6.29                  PARSED)) {
    6.30          @Override
    6.31          FunctionNode transform(final Compiler compiler, final CompilationPhases phases, final FunctionNode fn) {
    6.32 -            return (FunctionNode)fn.accept(new FoldConstants(compiler));
    6.33 +            return transformFunction(fn, new FoldConstants(compiler));
    6.34          }
    6.35  
    6.36          @Override
    6.37 @@ -104,7 +100,7 @@
    6.38                  CONSTANT_FOLDED)) {
    6.39          @Override
    6.40          FunctionNode transform(final Compiler compiler, final CompilationPhases phases, final FunctionNode fn) {
    6.41 -            return (FunctionNode)fn.accept(new Lower(compiler));
    6.42 +            return transformFunction(fn, new Lower(compiler));
    6.43          }
    6.44  
    6.45          @Override
    6.46 @@ -118,23 +114,6 @@
    6.47       * optimistic ops a program point so that an UnwarrantedException knows from where
    6.48       * a guess went wrong when creating the continuation to roll back this execution
    6.49       */
    6.50 -    PROGRAM_POINT_PHASE(
    6.51 -            EnumSet.of(
    6.52 -                INITIALIZED,
    6.53 -                PARSED,
    6.54 -                CONSTANT_FOLDED,
    6.55 -                LOWERED)) {
    6.56 -        @Override
    6.57 -        FunctionNode transform(final Compiler compiler, final CompilationPhases phases, final FunctionNode fn) {
    6.58 -            return (FunctionNode)fn.accept(new ProgramPoints());
    6.59 -        }
    6.60 -
    6.61 -        @Override
    6.62 -        public String toString() {
    6.63 -            return "'Program Point Calculation'";
    6.64 -        }
    6.65 -    },
    6.66 -
    6.67      TRANSFORM_BUILTINS_PHASE(
    6.68              EnumSet.of(
    6.69                      INITIALIZED,
    6.70 @@ -144,13 +123,7 @@
    6.71          //we only do this if we have a param type map, otherwise this is not a specialized recompile
    6.72          @Override
    6.73          FunctionNode transform(final Compiler compiler, final CompilationPhases phases, final FunctionNode fn) {
    6.74 -            final FunctionNode newFunctionNode = (FunctionNode)fn.accept(new ApplySpecialization(compiler));
    6.75 -            return (FunctionNode)newFunctionNode.accept(new NodeVisitor<LexicalContext>(new LexicalContext()) {
    6.76 -                @Override
    6.77 -                public Node leaveFunctionNode(final FunctionNode node) {
    6.78 -                    return node.setState(lc, BUILTINS_TRANSFORMED);
    6.79 -                }
    6.80 -            });
    6.81 +            return setStates(transformFunction(fn, new ApplySpecialization(compiler)), BUILTINS_TRANSFORMED);
    6.82          }
    6.83  
    6.84          @Override
    6.85 @@ -177,7 +150,7 @@
    6.86              FunctionNode newFunctionNode;
    6.87  
    6.88              //ensure elementTypes, postsets and presets exist for splitter and arraynodes
    6.89 -            newFunctionNode = (FunctionNode)fn.accept(new NodeVisitor<LexicalContext>(new LexicalContext()) {
    6.90 +            newFunctionNode = transformFunction(fn, new NodeVisitor<LexicalContext>(new LexicalContext()) {
    6.91                  @Override
    6.92                  public LiteralNode<?> leaveLiteralNode(final LiteralNode<?> literalNode) {
    6.93                      return literalNode.initialize(lc);
    6.94 @@ -185,7 +158,7 @@
    6.95              });
    6.96  
    6.97              newFunctionNode = new Splitter(compiler, newFunctionNode, outermostCompileUnit).split(newFunctionNode, true);
    6.98 -
    6.99 +            newFunctionNode = transformFunction(newFunctionNode, new SplitIntoFunctions(compiler));
   6.100              assert newFunctionNode.getCompileUnit() == outermostCompileUnit : "fn=" + fn.getName() + ", fn.compileUnit (" + newFunctionNode.getCompileUnit() + ") != " + outermostCompileUnit;
   6.101              assert newFunctionNode.isStrict() == compiler.isStrict() : "functionNode.isStrict() != compiler.isStrict() for " + quote(newFunctionNode.getName());
   6.102  
   6.103 @@ -198,6 +171,52 @@
   6.104          }
   6.105      },
   6.106  
   6.107 +    PROGRAM_POINT_PHASE(
   6.108 +            EnumSet.of(
   6.109 +                    INITIALIZED,
   6.110 +                    PARSED,
   6.111 +                    CONSTANT_FOLDED,
   6.112 +                    LOWERED,
   6.113 +                    BUILTINS_TRANSFORMED,
   6.114 +                    SPLIT)) {
   6.115 +        @Override
   6.116 +        FunctionNode transform(final Compiler compiler, final CompilationPhases phases, final FunctionNode fn) {
   6.117 +            return transformFunction(fn, new ProgramPoints());
   6.118 +        }
   6.119 +
   6.120 +        @Override
   6.121 +        public String toString() {
   6.122 +            return "'Program Point Calculation'";
   6.123 +        }
   6.124 +    },
   6.125 +
   6.126 +    SERIALIZE_SPLIT_PHASE(
   6.127 +            EnumSet.of(
   6.128 +                    INITIALIZED,
   6.129 +                    PARSED,
   6.130 +                    CONSTANT_FOLDED,
   6.131 +                    LOWERED,
   6.132 +                    BUILTINS_TRANSFORMED,
   6.133 +                    SPLIT)) {
   6.134 +        @Override
   6.135 +        FunctionNode transform(final Compiler compiler, final CompilationPhases phases, final FunctionNode fn) {
   6.136 +            return transformFunction(fn, new NodeVisitor<LexicalContext>(new LexicalContext()) {
   6.137 +                @Override
   6.138 +                public boolean enterFunctionNode(final FunctionNode functionNode) {
   6.139 +                    if (functionNode.isSplit()) {
   6.140 +                        compiler.serializeAst(functionNode);
   6.141 +                    }
   6.142 +                    return true;
   6.143 +                }
   6.144 +            });
   6.145 +        }
   6.146 +
   6.147 +        @Override
   6.148 +        public String toString() {
   6.149 +            return "'Serialize Split Functions'";
   6.150 +        }
   6.151 +    },
   6.152 +
   6.153      SYMBOL_ASSIGNMENT_PHASE(
   6.154              EnumSet.of(
   6.155                      INITIALIZED,
   6.156 @@ -208,7 +227,7 @@
   6.157                      SPLIT)) {
   6.158          @Override
   6.159          FunctionNode transform(final Compiler compiler, final CompilationPhases phases, final FunctionNode fn) {
   6.160 -            return (FunctionNode)fn.accept(new AssignSymbols(compiler));
   6.161 +            return transformFunction(fn, new AssignSymbols(compiler));
   6.162          }
   6.163  
   6.164          @Override
   6.165 @@ -228,7 +247,7 @@
   6.166                      SYMBOLS_ASSIGNED)) {
   6.167          @Override
   6.168          FunctionNode transform(final Compiler compiler, final CompilationPhases phases, final FunctionNode fn) {
   6.169 -            return (FunctionNode)fn.accept(new FindScopeDepths(compiler));
   6.170 +            return transformFunction(fn, new FindScopeDepths(compiler));
   6.171          }
   6.172  
   6.173          @Override
   6.174 @@ -250,7 +269,7 @@
   6.175          @Override
   6.176          FunctionNode transform(final Compiler compiler, final CompilationPhases phases, final FunctionNode fn) {
   6.177              if (compiler.useOptimisticTypes()) {
   6.178 -                return (FunctionNode)fn.accept(new OptimisticTypesCalculator(compiler));
   6.179 +                return transformFunction(fn, new OptimisticTypesCalculator(compiler));
   6.180              }
   6.181              return setStates(fn, OPTIMISTIC_TYPES_ASSIGNED);
   6.182          }
   6.183 @@ -274,8 +293,7 @@
   6.184                      OPTIMISTIC_TYPES_ASSIGNED)) {
   6.185          @Override
   6.186          FunctionNode transform(final Compiler compiler, final CompilationPhases phases, final FunctionNode fn) {
   6.187 -            final FunctionNode newFunctionNode = (FunctionNode)fn.accept(new LocalVariableTypesCalculator(compiler));
   6.188 -
   6.189 +            final FunctionNode newFunctionNode = transformFunction(fn, new LocalVariableTypesCalculator(compiler));
   6.190              final ScriptEnvironment senv = compiler.getScriptEnvironment();
   6.191              final PrintWriter       err  = senv.getErr();
   6.192  
   6.193 @@ -330,13 +348,7 @@
   6.194  
   6.195              for (final CompileUnit oldUnit : compiler.getCompileUnits()) {
   6.196                  assert map.get(oldUnit) == null;
   6.197 -                final StringBuilder sb = new StringBuilder(compiler.nextCompileUnitName());
   6.198 -                if (phases.isRestOfCompilation()) {
   6.199 -                    sb.append("$restOf");
   6.200 -                }
   6.201 -                //it's ok to not copy the initCount, methodCount and clinitCount here, as codegen is what
   6.202 -                //fills those out anyway. Thus no need for a copy constructor
   6.203 -                final CompileUnit newUnit = compiler.createCompileUnit(sb.toString(), oldUnit.getWeight());
   6.204 +                final CompileUnit newUnit = createNewCompileUnit(compiler, phases);
   6.205                  log.fine("Creating new compile unit ", oldUnit, " => ", newUnit);
   6.206                  map.put(oldUnit, newUnit);
   6.207                  assert newUnit != null;
   6.208 @@ -350,47 +362,10 @@
   6.209              //replace old compile units in function nodes, if any are assigned,
   6.210              //for example by running the splitter on this function node in a previous
   6.211              //partial code generation
   6.212 -            final FunctionNode newFunctionNode = (FunctionNode)fn.accept(new NodeVisitor<LexicalContext>(new LexicalContext()) {
   6.213 +            final FunctionNode newFunctionNode = transformFunction(fn, new ReplaceCompileUnits() {
   6.214                  @Override
   6.215 -                public Node leaveFunctionNode(final FunctionNode node) {
   6.216 -                    final CompileUnit oldUnit = node.getCompileUnit();
   6.217 -                    assert oldUnit != null : "no compile unit in function node";
   6.218 -
   6.219 -                    final CompileUnit newUnit = map.get(oldUnit);
   6.220 -                    assert newUnit != null : "old unit has no mapping to new unit " + oldUnit;
   6.221 -
   6.222 -                    log.fine("Replacing compile unit: ", oldUnit, " => ", newUnit, " in ", quote(node.getName()));
   6.223 -                    return node.setCompileUnit(lc, newUnit).setState(lc, CompilationState.COMPILE_UNITS_REUSED);
   6.224 -                }
   6.225 -
   6.226 -                @Override
   6.227 -                public Node leaveSplitNode(final SplitNode node) {
   6.228 -                    final CompileUnit oldUnit = node.getCompileUnit();
   6.229 -                    assert oldUnit != null : "no compile unit in function node";
   6.230 -
   6.231 -                    final CompileUnit newUnit = map.get(oldUnit);
   6.232 -                    assert newUnit != null : "old unit has no mapping to new unit " + oldUnit;
   6.233 -
   6.234 -                    log.fine("Replacing compile unit: ", oldUnit, " => ", newUnit, " in ", quote(node.getName()));
   6.235 -                    return node.setCompileUnit(lc, newUnit);
   6.236 -                }
   6.237 -
   6.238 -                @Override
   6.239 -                public Node leaveLiteralNode(final LiteralNode<?> node) {
   6.240 -                    if (node instanceof ArrayLiteralNode) {
   6.241 -                        final ArrayLiteralNode aln = (ArrayLiteralNode)node;
   6.242 -                        if (aln.getUnits() == null) {
   6.243 -                            return node;
   6.244 -                        }
   6.245 -                        final List<ArrayUnit> newArrayUnits = new ArrayList<>();
   6.246 -                        for (final ArrayUnit au : aln.getUnits()) {
   6.247 -                            final CompileUnit newUnit = map.get(au.getCompileUnit());
   6.248 -                            assert newUnit != null;
   6.249 -                            newArrayUnits.add(new ArrayUnit(newUnit, au.getLo(), au.getHi()));
   6.250 -                        }
   6.251 -                        return aln.setUnits(lc, newArrayUnits);
   6.252 -                    }
   6.253 -                    return node;
   6.254 +                CompileUnit getReplacement(CompileUnit original) {
   6.255 +                    return map.get(original);
   6.256                  }
   6.257  
   6.258                  @Override
   6.259 @@ -408,7 +383,59 @@
   6.260          }
   6.261      },
   6.262  
   6.263 -     /**
   6.264 +    REINITIALIZE_SERIALIZED(
   6.265 +            EnumSet.of(
   6.266 +                    INITIALIZED,
   6.267 +                    PARSED,
   6.268 +                    CONSTANT_FOLDED,
   6.269 +                    LOWERED,
   6.270 +                    BUILTINS_TRANSFORMED,
   6.271 +                    SPLIT)) {
   6.272 +        @Override
   6.273 +        FunctionNode transform(final Compiler compiler, final CompilationPhases phases, final FunctionNode fn) {
   6.274 +            final Set<CompileUnit> unitSet = CompileUnit.createCompileUnitSet();
   6.275 +            final Map<CompileUnit, CompileUnit> unitMap = new HashMap<>();
   6.276 +
   6.277 +            // Ensure that the FunctionNode's compile unit is the first in the list of new units. Install phase
   6.278 +            // will use that as the root class.
   6.279 +            createCompileUnit(fn.getCompileUnit(), unitSet, unitMap, compiler, phases);
   6.280 +
   6.281 +            final FunctionNode newFn = transformFunction(fn, new ReplaceCompileUnits() {
   6.282 +                @Override
   6.283 +                CompileUnit getReplacement(final CompileUnit oldUnit) {
   6.284 +                    final CompileUnit existing = unitMap.get(oldUnit);
   6.285 +                    if (existing != null) {
   6.286 +                        return existing;
   6.287 +                    }
   6.288 +                    return createCompileUnit(oldUnit, unitSet, unitMap, compiler, phases);
   6.289 +                }
   6.290 +
   6.291 +                @Override
   6.292 +                public Node leaveFunctionNode(final FunctionNode fn2) {
   6.293 +                    return super.leaveFunctionNode(
   6.294 +                            // restore flags for deserialized nested function nodes
   6.295 +                            compiler.getScriptFunctionData(fn2.getId()).restoreFlags(lc, fn2));
   6.296 +                };
   6.297 +            });
   6.298 +            compiler.replaceCompileUnits(unitSet);
   6.299 +            return newFn;
   6.300 +        }
   6.301 +
   6.302 +        private CompileUnit createCompileUnit(final CompileUnit oldUnit, final Set<CompileUnit> unitSet,
   6.303 +                final Map<CompileUnit, CompileUnit> unitMap, final Compiler compiler, final CompilationPhases phases) {
   6.304 +            final CompileUnit newUnit = createNewCompileUnit(compiler, phases);
   6.305 +            unitMap.put(oldUnit, newUnit);
   6.306 +            unitSet.add(newUnit);
   6.307 +            return newUnit;
   6.308 +        }
   6.309 +
   6.310 +        @Override
   6.311 +        public String toString() {
   6.312 +            return "'Deserialize'";
   6.313 +        }
   6.314 +    },
   6.315 +
   6.316 +    /**
   6.317       * Bytecode generation:
   6.318       *
   6.319       * Generate the byte code class(es) resulting from the compiled FunctionNode
   6.320 @@ -443,7 +470,7 @@
   6.321              try {
   6.322                  // Explicitly set BYTECODE_GENERATED here; it can not be set in case of skipping codegen for :program
   6.323                  // in the lazy + optimistic world. See CodeGenerator.skipFunction().
   6.324 -                newFunctionNode = ((FunctionNode)newFunctionNode.accept(codegen)).setState(null, BYTECODE_GENERATED);
   6.325 +                newFunctionNode = transformFunction(newFunctionNode, codegen).setState(null, BYTECODE_GENERATED);
   6.326                  codegen.generateScopeCalls();
   6.327              } catch (final VerifyError e) {
   6.328                  if (senv._verify_code || senv._print_code) {
   6.329 @@ -615,7 +642,7 @@
   6.330          if (!AssertsEnabled.assertsEnabled()) {
   6.331              return functionNode;
   6.332          }
   6.333 -        return (FunctionNode)functionNode.accept(new NodeVisitor<LexicalContext>(new LexicalContext()) {
   6.334 +        return transformFunction(functionNode, new NodeVisitor<LexicalContext>(new LexicalContext()) {
   6.335              @Override
   6.336              public Node leaveFunctionNode(final FunctionNode fn) {
   6.337                  return fn.setState(lc, state);
   6.338 @@ -701,4 +728,17 @@
   6.339          return end(compiler, transform(compiler, phases, begin(compiler, functionNode)));
   6.340      }
   6.341  
   6.342 +    private static FunctionNode transformFunction(final FunctionNode fn, final NodeVisitor<?> visitor) {
   6.343 +        return (FunctionNode) fn.accept(visitor);
   6.344 +    }
   6.345 +
   6.346 +    private static CompileUnit createNewCompileUnit(final Compiler compiler, final CompilationPhases phases) {
   6.347 +        final StringBuilder sb = new StringBuilder(compiler.nextCompileUnitName());
   6.348 +        if (phases.isRestOfCompilation()) {
   6.349 +            sb.append("$restOf");
   6.350 +        }
   6.351 +        //it's ok to not copy the initCount, methodCount and clinitCount here, as codegen is what
   6.352 +        //fills those out anyway. Thus no need for a copy constructor
   6.353 +        return compiler.createCompileUnit(sb.toString(), 0);
   6.354 +    }
   6.355  }
     7.1 --- a/src/jdk/nashorn/internal/codegen/CompileUnit.java	Fri Oct 17 14:24:26 2014 +0200
     7.2 +++ b/src/jdk/nashorn/internal/codegen/CompileUnit.java	Mon Oct 20 12:06:36 2014 +0200
     7.3 @@ -28,11 +28,13 @@
     7.4  import java.io.Serializable;
     7.5  import java.util.Set;
     7.6  import java.util.TreeSet;
     7.7 +import jdk.nashorn.internal.ir.CompileUnitHolder;
     7.8  
     7.9  /**
    7.10    * Used to track split class compilation. Note that instances of the class are serializable, but all fields are
    7.11    * transient, making the serialized version of the class only useful for tracking the referential topology of other
    7.12 -  * AST nodes referencing the same or different compile units.
    7.13 +  * AST nodes referencing the same or different compile units. We do want to preserve this topology though as
    7.14 +  * {@link CompileUnitHolder}s in a deserialized AST will undergo reinitialization.
    7.15    */
    7.16  public final class CompileUnit implements Comparable<CompileUnit>, Serializable {
    7.17      private static final long serialVersionUID = 1L;
    7.18 @@ -127,14 +129,6 @@
    7.19      }
    7.20  
    7.21      /**
    7.22 -     * Get the current weight of the compile unit.
    7.23 -     * @return the unit's weight
    7.24 -     */
    7.25 -    long getWeight() {
    7.26 -        return weight;
    7.27 -    }
    7.28 -
    7.29 -    /**
    7.30       * Check if this compile unit can hold {@code weight} more units of weight
    7.31       * @param w weight to check if can be added
    7.32       * @return true if weight fits in this compile unit
    7.33 @@ -160,7 +154,7 @@
    7.34      }
    7.35  
    7.36      private static String shortName(final String name) {
    7.37 -        return name.lastIndexOf('/') == -1 ? name : name.substring(name.lastIndexOf('/') + 1);
    7.38 +        return name == null ? null : name.lastIndexOf('/') == -1 ? name : name.substring(name.lastIndexOf('/') + 1);
    7.39      }
    7.40  
    7.41      @Override
     8.1 --- a/src/jdk/nashorn/internal/codegen/Compiler.java	Fri Oct 17 14:24:26 2014 +0200
     8.2 +++ b/src/jdk/nashorn/internal/codegen/Compiler.java	Mon Oct 20 12:06:36 2014 +0200
     8.3 @@ -32,15 +32,16 @@
     8.4  import static jdk.nashorn.internal.codegen.CompilerConstants.THIS;
     8.5  import static jdk.nashorn.internal.codegen.CompilerConstants.VARARGS;
     8.6  import static jdk.nashorn.internal.runtime.logging.DebugLogger.quote;
     8.7 +
     8.8  import java.io.File;
     8.9  import java.lang.invoke.MethodType;
    8.10 +import java.util.ArrayList;
    8.11  import java.util.Arrays;
    8.12  import java.util.Collections;
    8.13  import java.util.Comparator;
    8.14  import java.util.HashMap;
    8.15  import java.util.Iterator;
    8.16  import java.util.LinkedHashMap;
    8.17 -import java.util.LinkedList;
    8.18  import java.util.List;
    8.19  import java.util.Map;
    8.20  import java.util.Set;
    8.21 @@ -159,75 +160,142 @@
    8.22       */
    8.23      private static final int COMPILE_UNIT_NAME_BUFFER_SIZE = 32;
    8.24  
    8.25 +    private final Map<Integer, byte[]> serializedAsts = new HashMap<>();
    8.26 +
    8.27      /**
    8.28       * Compilation phases that a compilation goes through
    8.29       */
    8.30      public static class CompilationPhases implements Iterable<CompilationPhase> {
    8.31  
    8.32 -        /** Singleton that describes a standard eager compilation - this includes code installation */
    8.33 -        public final static CompilationPhases COMPILE_ALL = new CompilationPhases(
    8.34 -                "Compile all",
    8.35 -                new CompilationPhase[] {
    8.36 -                        CompilationPhase.CONSTANT_FOLDING_PHASE,
    8.37 -                        CompilationPhase.LOWERING_PHASE,
    8.38 -                        CompilationPhase.PROGRAM_POINT_PHASE,
    8.39 -                        CompilationPhase.TRANSFORM_BUILTINS_PHASE,
    8.40 -                        CompilationPhase.SPLITTING_PHASE,
    8.41 -                        CompilationPhase.SYMBOL_ASSIGNMENT_PHASE,
    8.42 -                        CompilationPhase.SCOPE_DEPTH_COMPUTATION_PHASE,
    8.43 -                        CompilationPhase.OPTIMISTIC_TYPE_ASSIGNMENT_PHASE,
    8.44 -                        CompilationPhase.LOCAL_VARIABLE_TYPE_CALCULATION_PHASE,
    8.45 -                        CompilationPhase.BYTECODE_GENERATION_PHASE,
    8.46 -                        CompilationPhase.INSTALL_PHASE
    8.47 -                });
    8.48 +        /**
    8.49 +         * Singleton that describes compilation up to the phase where a function can be serialized.
    8.50 +         */
    8.51 +        private final static CompilationPhases COMPILE_UPTO_SERIALIZABLE = new CompilationPhases(
    8.52 +                "Common initial phases",
    8.53 +                CompilationPhase.CONSTANT_FOLDING_PHASE,
    8.54 +                CompilationPhase.LOWERING_PHASE,
    8.55 +                CompilationPhase.TRANSFORM_BUILTINS_PHASE,
    8.56 +                CompilationPhase.SPLITTING_PHASE,
    8.57 +                CompilationPhase.PROGRAM_POINT_PHASE,
    8.58 +                CompilationPhase.SERIALIZE_SPLIT_PHASE
    8.59 +                );
    8.60  
    8.61 -        /** Compile all for a rest of method */
    8.62 -        public final static CompilationPhases COMPILE_ALL_RESTOF =
    8.63 -                COMPILE_ALL.setDescription("Compile all, rest of").addAfter(CompilationPhase.LOCAL_VARIABLE_TYPE_CALCULATION_PHASE, CompilationPhase.REUSE_COMPILE_UNITS_PHASE);
    8.64 +        private final static CompilationPhases COMPILE_SERIALIZABLE_UPTO_BYTECODE = new CompilationPhases(
    8.65 +                "After common phases, before bytecode generator",
    8.66 +                CompilationPhase.SYMBOL_ASSIGNMENT_PHASE,
    8.67 +                CompilationPhase.SCOPE_DEPTH_COMPUTATION_PHASE,
    8.68 +                CompilationPhase.OPTIMISTIC_TYPE_ASSIGNMENT_PHASE,
    8.69 +                CompilationPhase.LOCAL_VARIABLE_TYPE_CALCULATION_PHASE
    8.70 +                );
    8.71  
    8.72 -        /** Singleton that describes a standard eager compilation, but no installation, for example used by --compile-only */
    8.73 -        public final static CompilationPhases COMPILE_ALL_NO_INSTALL =
    8.74 -                COMPILE_ALL.
    8.75 -                removeLast().
    8.76 -                setDescription("Compile without install");
    8.77 -
    8.78 -        /** Singleton that describes compilation up to the CodeGenerator, but not actually generating code */
    8.79 -        public final static CompilationPhases COMPILE_UPTO_BYTECODE =
    8.80 -                COMPILE_ALL.
    8.81 -                removeLast().
    8.82 -                removeLast().
    8.83 -                setDescription("Compile upto bytecode");
    8.84 +        /**
    8.85 +         * Singleton that describes additional steps to be taken after deserializing, all the way up to (but not
    8.86 +         * including) generating and installing code.
    8.87 +         */
    8.88 +        public final static CompilationPhases RECOMPILE_SERIALIZED_UPTO_BYTECODE = new CompilationPhases(
    8.89 +                "Recompile serialized function up to bytecode",
    8.90 +                CompilationPhase.REINITIALIZE_SERIALIZED,
    8.91 +                COMPILE_SERIALIZABLE_UPTO_BYTECODE
    8.92 +                );
    8.93  
    8.94          /**
    8.95           * Singleton that describes back end of method generation, given that we have generated the normal
    8.96           * method up to CodeGenerator as in {@link CompilationPhases#COMPILE_UPTO_BYTECODE}
    8.97           */
    8.98 -        public final static CompilationPhases COMPILE_FROM_BYTECODE = new CompilationPhases(
    8.99 +        public final static CompilationPhases GENERATE_BYTECODE_AND_INSTALL = new CompilationPhases(
   8.100                  "Generate bytecode and install",
   8.101 -                new CompilationPhase[] {
   8.102 -                        CompilationPhase.BYTECODE_GENERATION_PHASE,
   8.103 -                        CompilationPhase.INSTALL_PHASE
   8.104 -                });
   8.105 +                CompilationPhase.BYTECODE_GENERATION_PHASE,
   8.106 +                CompilationPhase.INSTALL_PHASE
   8.107 +                );
   8.108 +
   8.109 +        /** Singleton that describes compilation up to the CodeGenerator, but not actually generating code */
   8.110 +        public final static CompilationPhases COMPILE_UPTO_BYTECODE = new CompilationPhases(
   8.111 +                "Compile upto bytecode",
   8.112 +                COMPILE_UPTO_SERIALIZABLE,
   8.113 +                COMPILE_SERIALIZABLE_UPTO_BYTECODE);
   8.114 +
   8.115 +        /** Singleton that describes a standard eager compilation, but no installation, for example used by --compile-only */
   8.116 +        public final static CompilationPhases COMPILE_ALL_NO_INSTALL = new CompilationPhases(
   8.117 +                "Compile without install",
   8.118 +                COMPILE_UPTO_BYTECODE,
   8.119 +                CompilationPhase.BYTECODE_GENERATION_PHASE);
   8.120 +
   8.121 +        /** Singleton that describes a standard eager compilation - this includes code installation */
   8.122 +        public final static CompilationPhases COMPILE_ALL = new CompilationPhases(
   8.123 +                "Full eager compilation",
   8.124 +                COMPILE_UPTO_BYTECODE,
   8.125 +                GENERATE_BYTECODE_AND_INSTALL);
   8.126 +
   8.127 +        /** Singleton that describes a full compilation - this includes code installation - from serialized state*/
   8.128 +        public final static CompilationPhases COMPILE_ALL_SERIALIZED = new CompilationPhases(
   8.129 +                "Eager compilation from serializaed state",
   8.130 +                RECOMPILE_SERIALIZED_UPTO_BYTECODE,
   8.131 +                GENERATE_BYTECODE_AND_INSTALL);
   8.132  
   8.133          /**
   8.134           * Singleton that describes restOf method generation, given that we have generated the normal
   8.135           * method up to CodeGenerator as in {@link CompilationPhases#COMPILE_UPTO_BYTECODE}
   8.136           */
   8.137 -        public final static CompilationPhases COMPILE_FROM_BYTECODE_RESTOF =
   8.138 -                COMPILE_FROM_BYTECODE.
   8.139 -                addFirst(CompilationPhase.REUSE_COMPILE_UNITS_PHASE).
   8.140 -                setDescription("Generate bytecode and install - RestOf method");
   8.141 +        public final static CompilationPhases GENERATE_BYTECODE_AND_INSTALL_RESTOF = new CompilationPhases(
   8.142 +                "Generate bytecode and install - RestOf method",
   8.143 +                CompilationPhase.REUSE_COMPILE_UNITS_PHASE,
   8.144 +                GENERATE_BYTECODE_AND_INSTALL);
   8.145 +
   8.146 +        /** Compile all for a rest of method */
   8.147 +        public final static CompilationPhases COMPILE_ALL_RESTOF = new CompilationPhases(
   8.148 +                "Compile all, rest of",
   8.149 +                COMPILE_UPTO_BYTECODE,
   8.150 +                GENERATE_BYTECODE_AND_INSTALL_RESTOF);
   8.151 +
   8.152 +        /** Compile from serialized for a rest of method */
   8.153 +        public final static CompilationPhases COMPILE_SERIALIZED_RESTOF = new CompilationPhases(
   8.154 +                "Compile serialized, rest of",
   8.155 +                RECOMPILE_SERIALIZED_UPTO_BYTECODE,
   8.156 +                GENERATE_BYTECODE_AND_INSTALL_RESTOF);
   8.157  
   8.158          private final List<CompilationPhase> phases;
   8.159  
   8.160          private final String desc;
   8.161  
   8.162          private CompilationPhases(final String desc, final CompilationPhase... phases) {
   8.163 +            this(desc, Arrays.asList(phases));
   8.164 +        }
   8.165 +
   8.166 +        private CompilationPhases(final String desc, final CompilationPhases base, final CompilationPhase... phases) {
   8.167 +            this(desc, concat(base.phases, Arrays.asList(phases)));
   8.168 +        }
   8.169 +
   8.170 +        private CompilationPhases(final String desc, final CompilationPhase first, final CompilationPhases rest) {
   8.171 +            this(desc, concat(Collections.singletonList(first), rest.phases));
   8.172 +        }
   8.173 +
   8.174 +        private CompilationPhases(final String desc, final CompilationPhases base) {
   8.175 +            this(desc, base.phases);
   8.176 +        }
   8.177 +
   8.178 +        private CompilationPhases(final String desc, final CompilationPhases... bases) {
   8.179 +            this(desc, concatPhases(bases));
   8.180 +        }
   8.181 +
   8.182 +        private CompilationPhases(final String desc, final List<CompilationPhase> phases) {
   8.183              this.desc = desc;
   8.184 +            this.phases = phases;
   8.185 +        }
   8.186  
   8.187 -            final List<CompilationPhase> newPhases = new LinkedList<>();
   8.188 -            newPhases.addAll(Arrays.asList(phases));
   8.189 -            this.phases = Collections.unmodifiableList(newPhases);
   8.190 +        private static List<CompilationPhase> concatPhases(final CompilationPhases[] bases) {
   8.191 +            final ArrayList<CompilationPhase> l = new ArrayList<>();
   8.192 +            for(final CompilationPhases base: bases) {
   8.193 +                l.addAll(base.phases);
   8.194 +            }
   8.195 +            l.trimToSize();
   8.196 +            return l;
   8.197 +        }
   8.198 +
   8.199 +        private static <T> List<T> concat(final List<T> l1, final List<T> l2) {
   8.200 +            final ArrayList<T> l = new ArrayList<>(l1);
   8.201 +            l.addAll(l2);
   8.202 +            l.trimToSize();
   8.203 +            return l;
   8.204          }
   8.205  
   8.206          @Override
   8.207 @@ -235,45 +303,6 @@
   8.208              return "'" + desc + "' " + phases.toString();
   8.209          }
   8.210  
   8.211 -        private CompilationPhases setDescription(final String desc) {
   8.212 -            return new CompilationPhases(desc, phases.toArray(new CompilationPhase[phases.size()]));
   8.213 -        }
   8.214 -
   8.215 -        private CompilationPhases removeLast() {
   8.216 -            final LinkedList<CompilationPhase> list = new LinkedList<>(phases);
   8.217 -            list.removeLast();
   8.218 -            return new CompilationPhases(desc, list.toArray(new CompilationPhase[list.size()]));
   8.219 -        }
   8.220 -
   8.221 -        private CompilationPhases addFirst(final CompilationPhase phase) {
   8.222 -            if (phases.contains(phase)) {
   8.223 -                return this;
   8.224 -            }
   8.225 -            final LinkedList<CompilationPhase> list = new LinkedList<>(phases);
   8.226 -            list.addFirst(phase);
   8.227 -            return new CompilationPhases(desc, list.toArray(new CompilationPhase[list.size()]));
   8.228 -        }
   8.229 -
   8.230 -        @SuppressWarnings("unused") //TODO I'll use this soon
   8.231 -        private CompilationPhases replace(final CompilationPhase phase, final CompilationPhase newPhase) {
   8.232 -            final LinkedList<CompilationPhase> list = new LinkedList<>();
   8.233 -            for (final CompilationPhase p : phases) {
   8.234 -                list.add(p == phase ? newPhase : p);
   8.235 -            }
   8.236 -            return new CompilationPhases(desc, list.toArray(new CompilationPhase[list.size()]));
   8.237 -        }
   8.238 -
   8.239 -        private CompilationPhases addAfter(final CompilationPhase phase, final CompilationPhase newPhase) {
   8.240 -            final LinkedList<CompilationPhase> list = new LinkedList<>();
   8.241 -            for (final CompilationPhase p : phases) {
   8.242 -                list.add(p);
   8.243 -                if (p == phase) {
   8.244 -                    list.add(newPhase);
   8.245 -                }
   8.246 -            }
   8.247 -            return new CompilationPhases(desc, list.toArray(new CompilationPhase[list.size()]));
   8.248 -        }
   8.249 -
   8.250          boolean contains(final CompilationPhase phase) {
   8.251              return phases.contains(phase);
   8.252          }
   8.253 @@ -284,7 +313,7 @@
   8.254          }
   8.255  
   8.256          boolean isRestOfCompilation() {
   8.257 -            return this == COMPILE_ALL_RESTOF || this == COMPILE_FROM_BYTECODE_RESTOF;
   8.258 +            return this == COMPILE_ALL_RESTOF || this == GENERATE_BYTECODE_AND_INSTALL_RESTOF || this == COMPILE_SERIALIZED_RESTOF;
   8.259          }
   8.260  
   8.261          String getDesc() {
   8.262 @@ -749,6 +778,14 @@
   8.263          compileUnits.addAll(newUnits);
   8.264      }
   8.265  
   8.266 +    void serializeAst(final FunctionNode fn) {
   8.267 +        serializedAsts.put(fn.getId(), AstSerializer.serialize(fn));
   8.268 +    }
   8.269 +
   8.270 +    byte[] removeSerializedAst(final int fnId) {
   8.271 +        return serializedAsts.remove(fnId);
   8.272 +    }
   8.273 +
   8.274      CompileUnit findUnit(final long weight) {
   8.275          for (final CompileUnit unit : compileUnits) {
   8.276              if (unit.canHold(weight)) {
   8.277 @@ -771,7 +808,10 @@
   8.278      }
   8.279  
   8.280      RecompilableScriptFunctionData getScriptFunctionData(final int functionId) {
   8.281 -        return compiledFunction == null ? null : compiledFunction.getScriptFunctionData(functionId);
   8.282 +        assert compiledFunction != null;
   8.283 +        final RecompilableScriptFunctionData fn = compiledFunction.getScriptFunctionData(functionId);
   8.284 +        assert fn != null : functionId;
   8.285 +        return fn;
   8.286      }
   8.287  
   8.288      boolean isGlobalSymbol(final FunctionNode fn, final String name) {
     9.1 --- a/src/jdk/nashorn/internal/codegen/FindScopeDepths.java	Fri Oct 17 14:24:26 2014 +0200
     9.2 +++ b/src/jdk/nashorn/internal/codegen/FindScopeDepths.java	Mon Oct 20 12:06:36 2014 +0200
     9.3 @@ -187,7 +187,6 @@
     9.4  
     9.5          if (compiler.isOnDemandCompilation()) {
     9.6              final RecompilableScriptFunctionData data = compiler.getScriptFunctionData(newFunctionNode.getId());
     9.7 -            assert data != null : newFunctionNode.getName() + " lacks data";
     9.8              if (data.inDynamicContext()) {
     9.9                  log.fine("Reviving scriptfunction ", quote(name), " as defined in previous (now lost) dynamic scope.");
    9.10                  newFunctionNode = newFunctionNode.setInDynamicContext(lc);
    9.11 @@ -202,7 +201,7 @@
    9.12  
    9.13          //create recompilable scriptfunctiondata
    9.14          final int fnId = newFunctionNode.getId();
    9.15 -        final Map<Integer, RecompilableScriptFunctionData> nestedFunctions = fnIdToNestedFunctions.get(fnId);
    9.16 +        final Map<Integer, RecompilableScriptFunctionData> nestedFunctions = fnIdToNestedFunctions.remove(fnId);
    9.17  
    9.18          assert nestedFunctions != null;
    9.19          // Generate the object class and property map in case this function is ever used as constructor
    9.20 @@ -212,8 +211,8 @@
    9.21                  new AllocatorDescriptor(newFunctionNode.getThisProperties()),
    9.22                  nestedFunctions,
    9.23                  externalSymbolDepths.get(fnId),
    9.24 -                internalSymbols.get(fnId)
    9.25 -                );
    9.26 +                internalSymbols.get(fnId),
    9.27 +                compiler.removeSerializedAst(fnId));
    9.28  
    9.29          if (lc.getOutermostFunction() != newFunctionNode) {
    9.30              final FunctionNode parentFn = lc.getParentFunction(newFunctionNode);
    10.1 --- a/src/jdk/nashorn/internal/codegen/LocalVariableTypesCalculator.java	Fri Oct 17 14:24:26 2014 +0200
    10.2 +++ b/src/jdk/nashorn/internal/codegen/LocalVariableTypesCalculator.java	Mon Oct 20 12:06:36 2014 +0200
    10.3 @@ -72,7 +72,7 @@
    10.4  import jdk.nashorn.internal.ir.ReturnNode;
    10.5  import jdk.nashorn.internal.ir.RuntimeNode;
    10.6  import jdk.nashorn.internal.ir.RuntimeNode.Request;
    10.7 -import jdk.nashorn.internal.ir.SplitNode;
    10.8 +import jdk.nashorn.internal.ir.SplitReturn;
    10.9  import jdk.nashorn.internal.ir.Statement;
   10.10  import jdk.nashorn.internal.ir.SwitchNode;
   10.11  import jdk.nashorn.internal.ir.Symbol;
   10.12 @@ -361,10 +361,6 @@
   10.13      // Synthetic return node that we must insert at the end of the function if it's end is reachable.
   10.14      private ReturnNode syntheticReturn;
   10.15  
   10.16 -    // Topmost current split node (if any)
   10.17 -    private SplitNode topSplit;
   10.18 -    private boolean split;
   10.19 -
   10.20      private boolean alreadyEnteredTopLevelFunction;
   10.21  
   10.22      // LvarType and conversion information gathered during the top-down pass; applied to nodes in the bottom-up pass.
   10.23 @@ -477,22 +473,7 @@
   10.24              return false;
   10.25          }
   10.26          final BreakableNode target = jump.getTarget(lc);
   10.27 -        return splitAwareJumpToLabel(jump, target, jump.getTargetLabel(target));
   10.28 -    }
   10.29 -
   10.30 -    private boolean splitAwareJumpToLabel(final JumpStatement jumpStatement, final BreakableNode target, final Label targetLabel) {
   10.31 -        final JoinPredecessor jumpOrigin;
   10.32 -        if(topSplit != null && lc.isExternalTarget(topSplit, target)) {
   10.33 -            // If the jump target is outside the topmost split node, then we'll create a synthetic jump origin in the
   10.34 -            // split node.
   10.35 -            jumpOrigin = new JoinPredecessorExpression();
   10.36 -            topSplit.addJump(jumpOrigin, targetLabel);
   10.37 -        } else {
   10.38 -            // Otherwise, the original jump statement is the jump origin
   10.39 -            jumpOrigin = jumpStatement;
   10.40 -        }
   10.41 -
   10.42 -        jumpToLabel(jumpOrigin, targetLabel, getBreakTargetTypes(target));
   10.43 +        jumpToLabel(jump, jump.getTargetLabel(target), getBreakTargetTypes(target));
   10.44          doesNotContinueSequentially();
   10.45          return false;
   10.46      }
   10.47 @@ -703,18 +684,9 @@
   10.48      }
   10.49  
   10.50      @Override
   10.51 -    public boolean enterSplitNode(final SplitNode splitNode) {
   10.52 -        if(!reachable) {
   10.53 -            return false;
   10.54 -        }
   10.55 -        // Need to visit inside of split nodes. While it's true that they don't have local variables, we need to visit
   10.56 -        // breaks, continues, and returns in them.
   10.57 -        if(topSplit == null) {
   10.58 -            topSplit = splitNode;
   10.59 -        }
   10.60 -        split = true;
   10.61 -        setType(getCompilerConstantSymbol(lc.getCurrentFunction(), CompilerConstants.RETURN), LvarType.UNDEFINED);
   10.62 -        return true;
   10.63 +    public boolean enterSplitReturn(final SplitReturn splitReturn) {
   10.64 +        doesNotContinueSequentially();
   10.65 +        return false;
   10.66      }
   10.67  
   10.68      @Override
   10.69 @@ -1116,15 +1088,6 @@
   10.70          if(returnType.isUnknown()) {
   10.71              returnType = Type.OBJECT;
   10.72          }
   10.73 -
   10.74 -        if(split) {
   10.75 -            // If the function is split, the ":return" symbol is used and needs a slot. Note we can't mark the return
   10.76 -            // symbol as used in enterSplitNode, as we don't know the final return type of the function earlier than
   10.77 -            // here.
   10.78 -            final Symbol retSymbol = getCompilerConstantSymbol(lc.getCurrentFunction(), CompilerConstants.RETURN);
   10.79 -            retSymbol.setHasSlotFor(returnType);
   10.80 -            retSymbol.setNeedsSlot(true);
   10.81 -        }
   10.82      }
   10.83  
   10.84      private void createSyntheticReturn(final Block body) {
    11.1 --- a/src/jdk/nashorn/internal/codegen/Lower.java	Fri Oct 17 14:24:26 2014 +0200
    11.2 +++ b/src/jdk/nashorn/internal/codegen/Lower.java	Mon Oct 20 12:06:36 2014 +0200
    11.3 @@ -352,8 +352,6 @@
    11.4      private Node spliceFinally(final TryNode tryNode, final List<ThrowNode> rethrows, final Block finallyBody) {
    11.5          assert tryNode.getFinallyBody() == null;
    11.6  
    11.7 -        final LexicalContext lowerLc = lc;
    11.8 -
    11.9          final TryNode newTryNode = (TryNode)tryNode.accept(new NodeVisitor<LexicalContext>(new LexicalContext()) {
   11.10              final List<Node> insideTry = new ArrayList<>();
   11.11  
   11.12 @@ -406,7 +404,6 @@
   11.13                      //still in the try block, store it in a result value and return it afterwards
   11.14                      resultNode = new IdentNode(Lower.this.compilerConstant(RETURN));
   11.15                      newStatements.add(new ExpressionStatement(returnNode.getLineNumber(), returnNode.getToken(), returnNode.getFinish(), new BinaryNode(Token.recast(returnNode.getToken(), TokenType.ASSIGN), resultNode, expr)));
   11.16 -                    lowerLc.setFlag(lowerLc.getCurrentFunction(), FunctionNode.USES_RETURN_SYMBOL);
   11.17                  } else {
   11.18                      resultNode = null;
   11.19                  }
    12.1 --- a/src/jdk/nashorn/internal/codegen/MethodEmitter.java	Fri Oct 17 14:24:26 2014 +0200
    12.2 +++ b/src/jdk/nashorn/internal/codegen/MethodEmitter.java	Mon Oct 20 12:06:36 2014 +0200
    12.3 @@ -71,6 +71,7 @@
    12.4  import static jdk.nashorn.internal.codegen.ObjectClassGenerator.PRIMITIVE_FIELD_TYPE;
    12.5  import static jdk.nashorn.internal.runtime.linker.NashornCallSiteDescriptor.CALLSITE_OPTIMISTIC;
    12.6  import static jdk.nashorn.internal.runtime.linker.NashornCallSiteDescriptor.CALLSITE_PROGRAM_POINT_SHIFT;
    12.7 +
    12.8  import java.io.PrintStream;
    12.9  import java.lang.reflect.Array;
   12.10  import java.util.Collection;
   12.11 @@ -88,11 +89,9 @@
   12.12  import jdk.nashorn.internal.codegen.types.BitwiseType;
   12.13  import jdk.nashorn.internal.codegen.types.NumericType;
   12.14  import jdk.nashorn.internal.codegen.types.Type;
   12.15 -import jdk.nashorn.internal.ir.BreakableNode;
   12.16  import jdk.nashorn.internal.ir.FunctionNode;
   12.17  import jdk.nashorn.internal.ir.IdentNode;
   12.18  import jdk.nashorn.internal.ir.JoinPredecessor;
   12.19 -import jdk.nashorn.internal.ir.LexicalContext;
   12.20  import jdk.nashorn.internal.ir.LiteralNode;
   12.21  import jdk.nashorn.internal.ir.LocalVariableConversion;
   12.22  import jdk.nashorn.internal.ir.RuntimeNode;
   12.23 @@ -1664,19 +1663,6 @@
   12.24      }
   12.25  
   12.26      /**
   12.27 -     * Goto, possibly when splitting is taking place. If
   12.28 -     * a splitNode exists, we need to handle the case that the
   12.29 -     * jump target is another method
   12.30 -     *
   12.31 -     * @param label destination label
   12.32 -     * @param targetNode the node to which the destination label belongs (the label is normally a break or continue
   12.33 -     * label)
   12.34 -     */
   12.35 -    void splitAwareGoto(final LexicalContext lc, final Label label, final BreakableNode targetNode) {
   12.36 -        _goto(label);
   12.37 -    }
   12.38 -
   12.39 -    /**
   12.40       * Perform a comparison of two number types that are popped from the stack
   12.41       *
   12.42       * @param isCmpG is this a dcmpg semantic, false if it's a dcmpl semantic
    13.1 --- a/src/jdk/nashorn/internal/codegen/OptimisticTypesCalculator.java	Fri Oct 17 14:24:26 2014 +0200
    13.2 +++ b/src/jdk/nashorn/internal/codegen/OptimisticTypesCalculator.java	Mon Oct 20 12:06:36 2014 +0200
    13.3 @@ -30,7 +30,6 @@
    13.4  import java.util.ArrayDeque;
    13.5  import java.util.BitSet;
    13.6  import java.util.Deque;
    13.7 -import jdk.nashorn.internal.IntDeque;
    13.8  import jdk.nashorn.internal.ir.AccessNode;
    13.9  import jdk.nashorn.internal.ir.BinaryNode;
   13.10  import jdk.nashorn.internal.ir.CallNode;
   13.11 @@ -49,7 +48,6 @@
   13.12  import jdk.nashorn.internal.ir.Node;
   13.13  import jdk.nashorn.internal.ir.Optimistic;
   13.14  import jdk.nashorn.internal.ir.PropertyNode;
   13.15 -import jdk.nashorn.internal.ir.SplitNode;
   13.16  import jdk.nashorn.internal.ir.Symbol;
   13.17  import jdk.nashorn.internal.ir.TernaryNode;
   13.18  import jdk.nashorn.internal.ir.UnaryNode;
   13.19 @@ -70,8 +68,6 @@
   13.20  
   13.21      // Per-function bit set of program points that must never be optimistic.
   13.22      final Deque<BitSet> neverOptimistic = new ArrayDeque<>();
   13.23 -    // Per-function depth of split nodes
   13.24 -    final IntDeque splitDepth = new IntDeque();
   13.25  
   13.26      OptimisticTypesCalculator(final Compiler compiler) {
   13.27          super(new LexicalContext());
   13.28 @@ -155,7 +151,6 @@
   13.29              return false;
   13.30          }
   13.31          neverOptimistic.push(new BitSet());
   13.32 -        splitDepth.push(0);
   13.33          return true;
   13.34      }
   13.35  
   13.36 @@ -190,19 +185,6 @@
   13.37      }
   13.38  
   13.39      @Override
   13.40 -    public boolean enterSplitNode(final SplitNode splitNode) {
   13.41 -        splitDepth.getAndIncrement();
   13.42 -        return true;
   13.43 -    }
   13.44 -
   13.45 -    @Override
   13.46 -    public Node leaveSplitNode(final SplitNode splitNode) {
   13.47 -        final int depth = splitDepth.decrementAndGet();
   13.48 -        assert depth >= 0;
   13.49 -        return splitNode;
   13.50 -    }
   13.51 -
   13.52 -    @Override
   13.53      public boolean enterVarNode(final VarNode varNode) {
   13.54          tagNeverOptimistic(varNode.getName());
   13.55          return true;
   13.56 @@ -226,16 +208,11 @@
   13.57      @Override
   13.58      public Node leaveFunctionNode(final FunctionNode functionNode) {
   13.59          neverOptimistic.pop();
   13.60 -        final int lastSplitDepth = splitDepth.pop();
   13.61 -        assert lastSplitDepth == 0;
   13.62          return functionNode.setState(lc, CompilationState.OPTIMISTIC_TYPES_ASSIGNED);
   13.63      }
   13.64  
   13.65      @Override
   13.66      public Node leaveIdentNode(final IdentNode identNode) {
   13.67 -        if(inSplitNode()) {
   13.68 -            return identNode;
   13.69 -        }
   13.70          final Symbol symbol = identNode.getSymbol();
   13.71          if(symbol == null) {
   13.72              assert identNode.isPropertyName();
   13.73 @@ -256,7 +233,7 @@
   13.74  
   13.75      private Expression leaveOptimistic(final Optimistic opt) {
   13.76          final int pp = opt.getProgramPoint();
   13.77 -        if(isValid(pp) && !inSplitNode() && !neverOptimistic.peek().get(pp)) {
   13.78 +        if(isValid(pp) && !neverOptimistic.peek().get(pp)) {
   13.79              return (Expression)opt.setType(compiler.getOptimisticType(opt));
   13.80          }
   13.81          return (Expression)opt;
   13.82 @@ -277,8 +254,4 @@
   13.83              tagNeverOptimistic(test.getExpression());
   13.84          }
   13.85      }
   13.86 -
   13.87 -    private boolean inSplitNode() {
   13.88 -        return splitDepth.peek() > 0;
   13.89 -    }
   13.90  }
    14.1 --- a/src/jdk/nashorn/internal/codegen/ProgramPoints.java	Fri Oct 17 14:24:26 2014 +0200
    14.2 +++ b/src/jdk/nashorn/internal/codegen/ProgramPoints.java	Mon Oct 20 12:06:36 2014 +0200
    14.3 @@ -85,7 +85,7 @@
    14.4  
    14.5      @Override
    14.6      public boolean enterVarNode(final VarNode varNode) {
    14.7 -        noProgramPoint.add(varNode.getAssignmentDest());
    14.8 +        noProgramPoint.add(varNode.getName());
    14.9          return true;
   14.10      }
   14.11  
    15.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    15.2 +++ b/src/jdk/nashorn/internal/codegen/ReplaceCompileUnits.java	Mon Oct 20 12:06:36 2014 +0200
    15.3 @@ -0,0 +1,85 @@
    15.4 +/*
    15.5 + * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
    15.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
    15.7 + *
    15.8 + * This code is free software; you can redistribute it and/or modify it
    15.9 + * under the terms of the GNU General Public License version 2 only, as
   15.10 + * published by the Free Software Foundation.  Oracle designates this
   15.11 + * particular file as subject to the "Classpath" exception as provided
   15.12 + * by Oracle in the LICENSE file that accompanied this code.
   15.13 + *
   15.14 + * This code is distributed in the hope that it will be useful, but WITHOUT
   15.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
   15.16 + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
   15.17 + * version 2 for more details (a copy is included in the LICENSE file that
   15.18 + * accompanied this code).
   15.19 + *
   15.20 + * You should have received a copy of the GNU General Public License version
   15.21 + * 2 along with this work; if not, write to the Free Software Foundation,
   15.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
   15.23 + *
   15.24 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
   15.25 + * or visit www.oracle.com if you need additional information or have any
   15.26 + * questions.
   15.27 + */
   15.28 +
   15.29 +package jdk.nashorn.internal.codegen;
   15.30 +
   15.31 +import java.util.ArrayList;
   15.32 +import java.util.List;
   15.33 +import jdk.nashorn.internal.ir.CompileUnitHolder;
   15.34 +import jdk.nashorn.internal.ir.FunctionNode;
   15.35 +import jdk.nashorn.internal.ir.FunctionNode.CompilationState;
   15.36 +import jdk.nashorn.internal.ir.LexicalContext;
   15.37 +import jdk.nashorn.internal.ir.LiteralNode;
   15.38 +import jdk.nashorn.internal.ir.LiteralNode.ArrayLiteralNode;
   15.39 +import jdk.nashorn.internal.ir.LiteralNode.ArrayLiteralNode.ArrayUnit;
   15.40 +import jdk.nashorn.internal.ir.Node;
   15.41 +import jdk.nashorn.internal.ir.visitor.NodeVisitor;
   15.42 +
   15.43 +/**
   15.44 + * Base class for a node visitor that replaces {@link CompileUnit}s in {@link CompileUnitHolder}s.
   15.45 + */
   15.46 +abstract class ReplaceCompileUnits extends NodeVisitor<LexicalContext> {
   15.47 +    ReplaceCompileUnits() {
   15.48 +        super(new LexicalContext());
   15.49 +    }
   15.50 +
   15.51 +    /**
   15.52 +     * Override to provide a replacement for an old compile unit.
   15.53 +     * @param oldUnit the old compile unit to replace
   15.54 +     * @return the compile unit's replacement.
   15.55 +     */
   15.56 +    abstract CompileUnit getReplacement(final CompileUnit oldUnit);
   15.57 +
   15.58 +    CompileUnit getExistingReplacement(final CompileUnitHolder node) {
   15.59 +        final CompileUnit oldUnit = node.getCompileUnit();
   15.60 +        assert oldUnit != null;
   15.61 +
   15.62 +        final CompileUnit newUnit = getReplacement(oldUnit);
   15.63 +        assert newUnit != null;
   15.64 +
   15.65 +        return newUnit;
   15.66 +    }
   15.67 +
   15.68 +    @Override
   15.69 +    public Node leaveFunctionNode(final FunctionNode node) {
   15.70 +        return node.setCompileUnit(lc, getExistingReplacement(node)).setState(lc, CompilationState.COMPILE_UNITS_REUSED);
   15.71 +    }
   15.72 +
   15.73 +    @Override
   15.74 +    public Node leaveLiteralNode(final LiteralNode<?> node) {
   15.75 +        if (node instanceof ArrayLiteralNode) {
   15.76 +            final ArrayLiteralNode aln = (ArrayLiteralNode)node;
   15.77 +            if (aln.getUnits() == null) {
   15.78 +                return node;
   15.79 +            }
   15.80 +            final List<ArrayUnit> newArrayUnits = new ArrayList<>();
   15.81 +            for (final ArrayUnit au : aln.getUnits()) {
   15.82 +                newArrayUnits.add(new ArrayUnit(getExistingReplacement(au), au.getLo(), au.getHi()));
   15.83 +            }
   15.84 +            return aln.setUnits(lc, newArrayUnits);
   15.85 +        }
   15.86 +        return node;
   15.87 +    }
   15.88 +}
    16.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    16.2 +++ b/src/jdk/nashorn/internal/codegen/SplitIntoFunctions.java	Mon Oct 20 12:06:36 2014 +0200
    16.3 @@ -0,0 +1,446 @@
    16.4 +/*
    16.5 + * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
    16.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
    16.7 + *
    16.8 + * This code is free software; you can redistribute it and/or modify it
    16.9 + * under the terms of the GNU General Public License version 2 only, as
   16.10 + * published by the Free Software Foundation.  Oracle designates this
   16.11 + * particular file as subject to the "Classpath" exception as provided
   16.12 + * by Oracle in the LICENSE file that accompanied this code.
   16.13 + *
   16.14 + * This code is distributed in the hope that it will be useful, but WITHOUT
   16.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
   16.16 + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
   16.17 + * version 2 for more details (a copy is included in the LICENSE file that
   16.18 + * accompanied this code).
   16.19 + *
   16.20 + * You should have received a copy of the GNU General Public License version
   16.21 + * 2 along with this work; if not, write to the Free Software Foundation,
   16.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
   16.23 + *
   16.24 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
   16.25 + * or visit www.oracle.com if you need additional information or have any
   16.26 + * questions.
   16.27 + */
   16.28 +
   16.29 +package jdk.nashorn.internal.codegen;
   16.30 +
   16.31 +import static jdk.nashorn.internal.ir.Node.NO_FINISH;
   16.32 +import static jdk.nashorn.internal.ir.Node.NO_LINE_NUMBER;
   16.33 +import static jdk.nashorn.internal.ir.Node.NO_TOKEN;
   16.34 +
   16.35 +import java.util.ArrayDeque;
   16.36 +import java.util.ArrayList;
   16.37 +import java.util.Arrays;
   16.38 +import java.util.Collections;
   16.39 +import java.util.Deque;
   16.40 +import java.util.List;
   16.41 +import java.util.Objects;
   16.42 +import jdk.nashorn.internal.ir.AccessNode;
   16.43 +import jdk.nashorn.internal.ir.BinaryNode;
   16.44 +import jdk.nashorn.internal.ir.Block;
   16.45 +import jdk.nashorn.internal.ir.BlockLexicalContext;
   16.46 +import jdk.nashorn.internal.ir.BreakNode;
   16.47 +import jdk.nashorn.internal.ir.CallNode;
   16.48 +import jdk.nashorn.internal.ir.CaseNode;
   16.49 +import jdk.nashorn.internal.ir.ContinueNode;
   16.50 +import jdk.nashorn.internal.ir.Expression;
   16.51 +import jdk.nashorn.internal.ir.ExpressionStatement;
   16.52 +import jdk.nashorn.internal.ir.FunctionNode;
   16.53 +import jdk.nashorn.internal.ir.GetSplitState;
   16.54 +import jdk.nashorn.internal.ir.IdentNode;
   16.55 +import jdk.nashorn.internal.ir.IfNode;
   16.56 +import jdk.nashorn.internal.ir.JumpStatement;
   16.57 +import jdk.nashorn.internal.ir.LiteralNode;
   16.58 +import jdk.nashorn.internal.ir.Node;
   16.59 +import jdk.nashorn.internal.ir.ReturnNode;
   16.60 +import jdk.nashorn.internal.ir.SetSplitState;
   16.61 +import jdk.nashorn.internal.ir.SplitNode;
   16.62 +import jdk.nashorn.internal.ir.SplitReturn;
   16.63 +import jdk.nashorn.internal.ir.Statement;
   16.64 +import jdk.nashorn.internal.ir.SwitchNode;
   16.65 +import jdk.nashorn.internal.ir.VarNode;
   16.66 +import jdk.nashorn.internal.ir.visitor.NodeVisitor;
   16.67 +import jdk.nashorn.internal.parser.Token;
   16.68 +import jdk.nashorn.internal.parser.TokenType;
   16.69 +
   16.70 +/**
   16.71 + * A node visitor that replaces {@link SplitNode}s with anonymous function invocations and some additional constructs
   16.72 + * to support control flow across splits. By using this transformation, split functions are translated into ordinary
   16.73 + * JavaScript functions with nested anonymous functions. The transformations however introduce several AST nodes that
   16.74 + * have no JavaScript source representations ({@link GetSplitState}, {@link SetSplitState}, and {@link SplitReturn}),
   16.75 + * and therefore such function is no longer reparseable from its source. For that reason, split functions and their
   16.76 + * fragments are serialized in-memory and deserialized when they need to be recompiled either for deoptimization or
   16.77 + * for type specialization.
   16.78 + * NOTE: all {@code leave*()} methods for statements are returning their input nodes. That way, they will not mutate
   16.79 + * the original statement list in the block containing the statement, which is fine, as it'll be replaced by the
   16.80 + * lexical context when the block is left. If we returned something else (e.g. null), we'd cause a mutation in the
   16.81 + * enclosing block's statement list that is otherwise overwritten later anyway.
   16.82 + */
   16.83 +final class SplitIntoFunctions extends NodeVisitor<BlockLexicalContext> {
   16.84 +    private static final int FALLTHROUGH_STATE = -1;
   16.85 +    private static final int RETURN_STATE = 0;
   16.86 +    private static final int BREAK_STATE = 1;
   16.87 +    private static final int FIRST_JUMP_STATE = 2;
   16.88 +
   16.89 +    private static final String THIS_NAME = CompilerConstants.THIS.symbolName();
   16.90 +    private static final String RETURN_NAME = CompilerConstants.RETURN.symbolName();
   16.91 +    // Used as the name of the formal parameter for passing the current value of :return symbol into a split fragment.
   16.92 +    private static final String RETURN_PARAM_NAME = RETURN_NAME + "-in";
   16.93 +
   16.94 +    private final Deque<FunctionState> functionStates = new ArrayDeque<>();
   16.95 +    private final Deque<SplitState> splitStates = new ArrayDeque<>();
   16.96 +    private final Namespace namespace;
   16.97 +
   16.98 +    private boolean artificialBlock = false;
   16.99 +
  16.100 +    // -1 is program; we need to use negative ones
  16.101 +    private int nextFunctionId = -2;
  16.102 +
  16.103 +    public SplitIntoFunctions(final Compiler compiler) {
  16.104 +        super(new BlockLexicalContext() {
  16.105 +            @Override
  16.106 +            protected Block afterSetStatements(Block block) {
  16.107 +                for(Statement stmt: block.getStatements()) {
  16.108 +                    assert !(stmt instanceof SplitNode);
  16.109 +                }
  16.110 +                return block;
  16.111 +            }
  16.112 +        });
  16.113 +        namespace = new Namespace(compiler.getScriptEnvironment().getNamespace());
  16.114 +    }
  16.115 +
  16.116 +    @Override
  16.117 +    public boolean enterFunctionNode(final FunctionNode functionNode) {
  16.118 +        functionStates.push(new FunctionState(functionNode));
  16.119 +        return true;
  16.120 +    }
  16.121 +
  16.122 +    @Override
  16.123 +    public Node leaveFunctionNode(final FunctionNode functionNode) {
  16.124 +        functionStates.pop();
  16.125 +        return functionNode;
  16.126 +    }
  16.127 +
  16.128 +    @Override
  16.129 +    protected Node leaveDefault(final Node node) {
  16.130 +        if (node instanceof Statement) {
  16.131 +            appendStatement((Statement)node);
  16.132 +        }
  16.133 +        return node;
  16.134 +    }
  16.135 +
  16.136 +    @Override
  16.137 +    public boolean enterSplitNode(final SplitNode splitNode) {
  16.138 +        getCurrentFunctionState().splitDepth++;
  16.139 +        splitStates.push(new SplitState(splitNode));
  16.140 +        return true;
  16.141 +    }
  16.142 +
  16.143 +    @Override
  16.144 +    public Node leaveSplitNode(final SplitNode splitNode) {
  16.145 +        // Replace the split node with an anonymous function expression call.
  16.146 +
  16.147 +        final FunctionState fnState = getCurrentFunctionState();
  16.148 +
  16.149 +        final String name = splitNode.getName();
  16.150 +        Block body = splitNode.getBody();
  16.151 +        final int firstLineNumber = body.getFirstStatementLineNumber();
  16.152 +        final long token = body.getToken();
  16.153 +        final int finish = body.getFinish();
  16.154 +
  16.155 +        final FunctionNode originalFn = fnState.fn;
  16.156 +        assert originalFn == lc.getCurrentFunction();
  16.157 +        final boolean isProgram = originalFn.isProgram();
  16.158 +
  16.159 +        // Change SplitNode({...}) into "function () { ... }", or "function (:return-in) () { ... }" (for program)
  16.160 +        final long newFnToken = Token.toDesc(TokenType.FUNCTION, nextFunctionId--, 0);
  16.161 +        final FunctionNode fn = new FunctionNode(
  16.162 +                originalFn.getSource(),
  16.163 +                body.getFirstStatementLineNumber(),
  16.164 +                newFnToken,
  16.165 +                finish,
  16.166 +                NO_TOKEN,
  16.167 +                namespace,
  16.168 +                createIdent(name),
  16.169 +                originalFn.getName() + "$" + name,
  16.170 +                isProgram ? Collections.singletonList(createReturnParamIdent()) : Collections.<IdentNode>emptyList(),
  16.171 +                FunctionNode.Kind.NORMAL,
  16.172 +                // We only need IS_SPLIT conservatively, in case it contains any array units so that we force
  16.173 +                // the :callee's existence, to force :scope to never be in a slot lower than 2. This is actually
  16.174 +                // quite a horrible hack to do with CodeGenerator.fixScopeSlot not trampling other parameters
  16.175 +                // and should go away once we no longer have array unit handling in codegen. Note however that
  16.176 +                // we still use IS_SPLIT as the criteria in CompilationPhase.SERIALIZE_SPLIT_PHASE.
  16.177 +                FunctionNode.IS_ANONYMOUS | FunctionNode.USES_ANCESTOR_SCOPE | FunctionNode.IS_SPLIT
  16.178 +        )
  16.179 +        .setBody(lc, body)
  16.180 +        .setCompileUnit(lc, splitNode.getCompileUnit())
  16.181 +        .copyCompilationState(lc, originalFn);
  16.182 +
  16.183 +        // Call the function:
  16.184 +        //     either "(function () { ... }).call(this)"
  16.185 +        //     or     "(function (:return-in) { ... }).call(this, :return)"
  16.186 +        // NOTE: Function.call() has optimized linking that basically does a pass-through to the function being invoked.
  16.187 +        // NOTE: CompilationPhase.PROGRAM_POINT_PHASE happens after this, so these calls are subject to optimistic
  16.188 +        // assumptions on their return value (when they return a value), as they should be.
  16.189 +        final IdentNode thisIdent = createIdent(THIS_NAME);
  16.190 +        final CallNode callNode = new CallNode(firstLineNumber, token, finish, new AccessNode(NO_TOKEN, NO_FINISH, fn, "call"),
  16.191 +                isProgram ? Arrays.<Expression>asList(thisIdent, createReturnIdent())
  16.192 +                          : Collections.<Expression>singletonList(thisIdent),
  16.193 +                false);
  16.194 +
  16.195 +        final SplitState splitState = splitStates.pop();
  16.196 +        fnState.splitDepth--;
  16.197 +
  16.198 +        final Expression callWithReturn;
  16.199 +        final boolean hasReturn = splitState.hasReturn;
  16.200 +        if (hasReturn && fnState.splitDepth > 0) {
  16.201 +            final SplitState parentSplit = splitStates.peek();
  16.202 +            if (parentSplit != null) {
  16.203 +                // Propagate hasReturn to parent split
  16.204 +                parentSplit.hasReturn = true;
  16.205 +            }
  16.206 +        }
  16.207 +        if (hasReturn || isProgram) {
  16.208 +            // capture return value: ":return = (function () { ... })();"
  16.209 +            callWithReturn = new BinaryNode(Token.recast(token, TokenType.ASSIGN), createReturnIdent(), callNode);
  16.210 +        } else {
  16.211 +            // no return value, just call : "(function () { ... })();"
  16.212 +            callWithReturn = callNode;
  16.213 +        }
  16.214 +        appendStatement(new ExpressionStatement(firstLineNumber, token, finish, callWithReturn));
  16.215 +
  16.216 +        Statement splitStateHandler;
  16.217 +
  16.218 +        final List<JumpStatement> jumpStatements = splitState.jumpStatements;
  16.219 +        final int jumpCount = jumpStatements.size();
  16.220 +        // There are jumps (breaks or continues) that need to be propagated outside the split node. We need to
  16.221 +        // set up a switch statement for them:
  16.222 +        // switch(:scope.getScopeState()) { ... }
  16.223 +        if (jumpCount > 0) {
  16.224 +            final List<CaseNode> cases = new ArrayList<>(jumpCount + (hasReturn ? 1 : 0));
  16.225 +            if (hasReturn) {
  16.226 +                // If the split node also contained a return, we'll slip it as a case in the switch statement
  16.227 +                addCase(cases, RETURN_STATE, createReturnFromSplit());
  16.228 +            }
  16.229 +            int i = FIRST_JUMP_STATE;
  16.230 +            for (final JumpStatement jump: jumpStatements) {
  16.231 +                addCase(cases, i++, enblockAndVisit(jump));
  16.232 +            }
  16.233 +            splitStateHandler = new SwitchNode(NO_LINE_NUMBER, token, finish, GetSplitState.INSTANCE, cases, null);
  16.234 +        } else {
  16.235 +            splitStateHandler = null;
  16.236 +        }
  16.237 +
  16.238 +        // As the switch statement itself is breakable, an unlabelled break can't be in the switch statement,
  16.239 +        // so we need to test for it separately.
  16.240 +        if (splitState.hasBreak) {
  16.241 +            // if(:scope.getScopeState() == Scope.BREAK) { break; }
  16.242 +            splitStateHandler = makeIfStateEquals(firstLineNumber, token, finish, BREAK_STATE,
  16.243 +                    enblockAndVisit(new BreakNode(NO_LINE_NUMBER, token, finish, null)), splitStateHandler);
  16.244 +        }
  16.245 +
  16.246 +        // Finally, if the split node had a return statement, but there were no external jumps, we didn't have
  16.247 +        // the switch statement to handle the return, so we need a separate if for it.
  16.248 +        if (hasReturn && jumpCount == 0) {
  16.249 +            // if (:scope.getScopeState() == Scope.RETURN) { return :return; }
  16.250 +            splitStateHandler = makeIfStateEquals(NO_LINE_NUMBER, token, finish, RETURN_STATE,
  16.251 +                    createReturnFromSplit(), splitStateHandler);
  16.252 +        }
  16.253 +
  16.254 +        if (splitStateHandler != null) {
  16.255 +            appendStatement(splitStateHandler);
  16.256 +        }
  16.257 +
  16.258 +        return splitNode;
  16.259 +    }
  16.260 +
  16.261 +    private static void addCase(final List<CaseNode> cases, final int i, final Block body) {
  16.262 +        cases.add(new CaseNode(NO_TOKEN, NO_FINISH, intLiteral(i), body));
  16.263 +    }
  16.264 +
  16.265 +    private static LiteralNode<Number> intLiteral(final int i) {
  16.266 +        return LiteralNode.newInstance(NO_TOKEN, NO_FINISH, i);
  16.267 +    }
  16.268 +
  16.269 +    private static Block createReturnFromSplit() {
  16.270 +        return new Block(NO_TOKEN, NO_FINISH, createReturnReturn());
  16.271 +    }
  16.272 +
  16.273 +    private static ReturnNode createReturnReturn() {
  16.274 +        return new ReturnNode(NO_LINE_NUMBER, NO_TOKEN, NO_FINISH, createReturnIdent());
  16.275 +    }
  16.276 +
  16.277 +    private static IdentNode createReturnIdent() {
  16.278 +        return createIdent(RETURN_NAME);
  16.279 +    }
  16.280 +
  16.281 +    private static IdentNode createReturnParamIdent() {
  16.282 +        return createIdent(RETURN_PARAM_NAME);
  16.283 +    }
  16.284 +
  16.285 +    private static IdentNode createIdent(final String name) {
  16.286 +        return new IdentNode(NO_TOKEN, NO_FINISH, name);
  16.287 +    }
  16.288 +
  16.289 +    private Block enblockAndVisit(final JumpStatement jump) {
  16.290 +        artificialBlock = true;
  16.291 +        final Block block = (Block)new Block(NO_TOKEN, NO_FINISH, jump).accept(this);
  16.292 +        artificialBlock = false;
  16.293 +        return block;
  16.294 +    }
  16.295 +
  16.296 +    private static IfNode makeIfStateEquals(final int lineNumber, final long token, final int finish,
  16.297 +            final int value, final Block pass, final Statement fail) {
  16.298 +        return new IfNode(lineNumber, token, finish,
  16.299 +                new BinaryNode(Token.recast(token, TokenType.EQ_STRICT),
  16.300 +                        GetSplitState.INSTANCE, intLiteral(value)),
  16.301 +                pass,
  16.302 +                fail == null ? null : new Block(NO_TOKEN, NO_FINISH, fail));
  16.303 +    }
  16.304 +
  16.305 +    @Override
  16.306 +    public boolean enterVarNode(VarNode varNode) {
  16.307 +        if (!inSplitNode()) {
  16.308 +            return super.enterVarNode(varNode);
  16.309 +        }
  16.310 +        assert !varNode.isBlockScoped(); //TODO: we must handle these too, but we currently don't
  16.311 +
  16.312 +        final Expression init = varNode.getInit();
  16.313 +        if (varNode.isAnonymousFunctionDeclaration()) {
  16.314 +            // We ain't moving anonymous function declarations.
  16.315 +            return super.enterVarNode(varNode);
  16.316 +        }
  16.317 +
  16.318 +        // Move a declaration-only var statement to the top of the outermost function.
  16.319 +        getCurrentFunctionState().varStatements.add(varNode.setInit(null));
  16.320 +        // If it had an initializer, replace it with an assignment expression statement. Note that "var" is a
  16.321 +        // statement, so it doesn't contribute to :return of the programs, therefore we are _not_ adding a
  16.322 +        // ":return = ..." assignment around the original assignment.
  16.323 +        if (init != null) {
  16.324 +            final long token = Token.recast(varNode.getToken(), TokenType.ASSIGN);
  16.325 +            new ExpressionStatement(varNode.getLineNumber(), token, varNode.getFinish(),
  16.326 +                    new BinaryNode(token, varNode.getName(), varNode.getInit())).accept(this);
  16.327 +        }
  16.328 +
  16.329 +        return false;
  16.330 +    }
  16.331 +
  16.332 +    @Override
  16.333 +    public Node leaveBlock(final Block block) {
  16.334 +        if (!artificialBlock) {
  16.335 +            if (lc.isFunctionBody()) {
  16.336 +                // Prepend declaration-only var statements to the top of the statement list.
  16.337 +                lc.prependStatements(getCurrentFunctionState().varStatements);
  16.338 +            } else if (lc.isSplitBody()) {
  16.339 +                appendSplitReturn(FALLTHROUGH_STATE, NO_LINE_NUMBER);
  16.340 +                if (getCurrentFunctionState().fn.isProgram()) {
  16.341 +                    // If we're splitting the program, make sure every shard ends with "return :return" and
  16.342 +                    // begins with ":return = :return-in;".
  16.343 +                    lc.prependStatement(new ExpressionStatement(NO_LINE_NUMBER, NO_TOKEN, NO_FINISH,
  16.344 +                            new BinaryNode(Token.toDesc(TokenType.ASSIGN, 0, 0), createReturnIdent(), createReturnParamIdent())));
  16.345 +                }
  16.346 +            }
  16.347 +        }
  16.348 +        return block;
  16.349 +    }
  16.350 +
  16.351 +    @Override
  16.352 +    public Node leaveBreakNode(final BreakNode breakNode) {
  16.353 +        return leaveJumpNode(breakNode);
  16.354 +    }
  16.355 +
  16.356 +    @Override
  16.357 +    public Node leaveContinueNode(final ContinueNode continueNode) {
  16.358 +        return leaveJumpNode(continueNode);
  16.359 +    }
  16.360 +
  16.361 +    private JumpStatement leaveJumpNode(final JumpStatement jump) {
  16.362 +        if (inSplitNode()) {
  16.363 +            final SplitState splitState = getCurrentSplitState();
  16.364 +            final SplitNode splitNode = splitState.splitNode;
  16.365 +            if (lc.isExternalTarget(splitNode, jump.getTarget(lc))) {
  16.366 +                appendSplitReturn(splitState.getSplitStateIndex(jump), jump.getLineNumber());
  16.367 +                return jump;
  16.368 +            }
  16.369 +        }
  16.370 +        appendStatement(jump);
  16.371 +        return jump;
  16.372 +    }
  16.373 +
  16.374 +    private void appendSplitReturn(final int splitState, final int lineNumber) {
  16.375 +        appendStatement(new SetSplitState(splitState, lineNumber));
  16.376 +        if (getCurrentFunctionState().fn.isProgram()) {
  16.377 +            // If we're splitting the program, make sure every fragment passes back :return
  16.378 +            appendStatement(createReturnReturn());
  16.379 +        } else {
  16.380 +            appendStatement(SplitReturn.INSTANCE);
  16.381 +        }
  16.382 +    }
  16.383 +
  16.384 +    @Override
  16.385 +    public Node leaveReturnNode(final ReturnNode returnNode) {
  16.386 +        if(inSplitNode()) {
  16.387 +            appendStatement(new SetSplitState(RETURN_STATE, returnNode.getLineNumber()));
  16.388 +            getCurrentSplitState().hasReturn = true;
  16.389 +        }
  16.390 +        appendStatement(returnNode);
  16.391 +        return returnNode;
  16.392 +    }
  16.393 +
  16.394 +    private void appendStatement(final Statement statement) {
  16.395 +        lc.appendStatement(statement);
  16.396 +    }
  16.397 +
  16.398 +    private boolean inSplitNode() {
  16.399 +        return getCurrentFunctionState().splitDepth > 0;
  16.400 +    }
  16.401 +
  16.402 +    private FunctionState getCurrentFunctionState() {
  16.403 +        return functionStates.peek();
  16.404 +    }
  16.405 +
  16.406 +    private SplitState getCurrentSplitState() {
  16.407 +        return splitStates.peek();
  16.408 +    }
  16.409 +
  16.410 +    private static class FunctionState {
  16.411 +        final FunctionNode fn;
  16.412 +        final List<Statement> varStatements = new ArrayList<>();
  16.413 +        int splitDepth;
  16.414 +
  16.415 +        FunctionState(final FunctionNode fn) {
  16.416 +            this.fn = fn;
  16.417 +        }
  16.418 +    }
  16.419 +
  16.420 +    private static class SplitState {
  16.421 +        final SplitNode splitNode;
  16.422 +        boolean hasReturn;
  16.423 +        boolean hasBreak;
  16.424 +
  16.425 +        final List<JumpStatement> jumpStatements = new ArrayList<>();
  16.426 +
  16.427 +        int getSplitStateIndex(final JumpStatement jump) {
  16.428 +            if (jump instanceof BreakNode && jump.getLabelName() == null) {
  16.429 +                // Unlabelled break is a special case
  16.430 +                hasBreak = true;
  16.431 +                return BREAK_STATE;
  16.432 +            }
  16.433 +
  16.434 +            int i = 0;
  16.435 +            for(final JumpStatement exJump: jumpStatements) {
  16.436 +                if (jump.getClass() == exJump.getClass() && Objects.equals(jump.getLabelName(), exJump.getLabelName())) {
  16.437 +                    return i + FIRST_JUMP_STATE;
  16.438 +                }
  16.439 +                ++i;
  16.440 +            }
  16.441 +            jumpStatements.add(jump);
  16.442 +            return i + FIRST_JUMP_STATE;
  16.443 +        }
  16.444 +
  16.445 +        SplitState(final SplitNode splitNode) {
  16.446 +            this.splitNode = splitNode;
  16.447 +        }
  16.448 +    }
  16.449 +}
    17.1 --- a/src/jdk/nashorn/internal/codegen/SplitMethodEmitter.java	Fri Oct 17 14:24:26 2014 +0200
    17.2 +++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
    17.3 @@ -1,102 +0,0 @@
    17.4 -/*
    17.5 - * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved.
    17.6 - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
    17.7 - *
    17.8 - * This code is free software; you can redistribute it and/or modify it
    17.9 - * under the terms of the GNU General Public License version 2 only, as
   17.10 - * published by the Free Software Foundation.  Oracle designates this
   17.11 - * particular file as subject to the "Classpath" exception as provided
   17.12 - * by Oracle in the LICENSE file that accompanied this code.
   17.13 - *
   17.14 - * This code is distributed in the hope that it will be useful, but WITHOUT
   17.15 - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
   17.16 - * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
   17.17 - * version 2 for more details (a copy is included in the LICENSE file that
   17.18 - * accompanied this code).
   17.19 - *
   17.20 - * You should have received a copy of the GNU General Public License version
   17.21 - * 2 along with this work; if not, write to the Free Software Foundation,
   17.22 - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
   17.23 - *
   17.24 - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
   17.25 - * or visit www.oracle.com if you need additional information or have any
   17.26 - * questions.
   17.27 - */
   17.28 -
   17.29 -package jdk.nashorn.internal.codegen;
   17.30 -
   17.31 -import java.util.ArrayList;
   17.32 -import java.util.List;
   17.33 -import jdk.internal.org.objectweb.asm.MethodVisitor;
   17.34 -import jdk.nashorn.internal.codegen.types.Type;
   17.35 -import jdk.nashorn.internal.ir.BreakableNode;
   17.36 -import jdk.nashorn.internal.ir.LexicalContext;
   17.37 -import jdk.nashorn.internal.ir.SplitNode;
   17.38 -
   17.39 -/**
   17.40 - * Emitter used for splitting methods. Needs to keep track of if there are jump targets
   17.41 - * outside the current split node. All external jump targets encountered at method
   17.42 - * emission are logged, and {@code CodeGenerator#leaveSplitNode(SplitNode)} creates
   17.43 - * an appropriate jump table when the SplitNode has been iterated through
   17.44 - */
   17.45 -public class SplitMethodEmitter extends MethodEmitter {
   17.46 -
   17.47 -    private final SplitNode splitNode;
   17.48 -
   17.49 -    private final List<Label> externalTargets = new ArrayList<>();
   17.50 -    /**
   17.51 -     * In addition to external target labels, we need to track the target breakables too as the code generator needs to
   17.52 -     * be able to correctly pop the scopes to the target, see {@link CodeGenerator#leaveSplitNode(SplitNode)}. Note that
   17.53 -     * this is only used within CodeGenerator, which doesn't mutate the AST, so keeping pointers to other nodes is not
   17.54 -     * incorrect.
   17.55 -     */
   17.56 -    private final List<BreakableNode> externalTargetNodes = new ArrayList<>();
   17.57 -
   17.58 -    SplitMethodEmitter(final ClassEmitter classEmitter, final MethodVisitor mv, final SplitNode splitNode) {
   17.59 -        super(classEmitter, mv);
   17.60 -        this.splitNode = splitNode;
   17.61 -    }
   17.62 -
   17.63 -    @Override
   17.64 -    void splitAwareGoto(final LexicalContext lc, final Label label, final BreakableNode targetNode) {
   17.65 -        assert splitNode != null;
   17.66 -        final int index = findExternalTarget(lc, label, targetNode);
   17.67 -        if (index >= 0) {
   17.68 -            setSplitState(index + 1); // 0 is ordinary return
   17.69 -            final Type retType = functionNode.getReturnType();
   17.70 -            loadUndefined(retType);
   17.71 -            _return(retType);
   17.72 -        } else {
   17.73 -            super.splitAwareGoto(lc, label, targetNode);
   17.74 -        }
   17.75 -    }
   17.76 -
   17.77 -    private int findExternalTarget(final LexicalContext lc, final Label label, final BreakableNode targetNode) {
   17.78 -        final int index = externalTargets.indexOf(label);
   17.79 -
   17.80 -        if (index >= 0) {
   17.81 -            return index;
   17.82 -        }
   17.83 -
   17.84 -        if (lc.isExternalTarget(splitNode, targetNode)) {
   17.85 -            externalTargets.add(label);
   17.86 -            externalTargetNodes.add(targetNode);
   17.87 -            return externalTargets.size() - 1;
   17.88 -        }
   17.89 -        return -1;
   17.90 -    }
   17.91 -
   17.92 -    @Override
   17.93 -    MethodEmitter registerReturn() {
   17.94 -        setHasReturn();
   17.95 -        return setSplitState(0);
   17.96 -    }
   17.97 -
   17.98 -    final List<Label> getExternalTargets() {
   17.99 -        return externalTargets;
  17.100 -    }
  17.101 -
  17.102 -    final List<BreakableNode> getExternalTargetNodes() {
  17.103 -        return externalTargetNodes;
  17.104 -    }
  17.105 -}
    18.1 --- a/src/jdk/nashorn/internal/ir/BlockLexicalContext.java	Fri Oct 17 14:24:26 2014 +0200
    18.2 +++ b/src/jdk/nashorn/internal/ir/BlockLexicalContext.java	Mon Oct 20 12:06:36 2014 +0200
    18.3 @@ -109,6 +109,16 @@
    18.4      }
    18.5  
    18.6      /**
    18.7 +     * Prepend a list of statement to the block being generated
    18.8 +     * @param statements a list of statements to prepend
    18.9 +     */
   18.10 +    public void prependStatements(final List<Statement> statements) {
   18.11 +        assert statements != null;
   18.12 +        sstack.peek().addAll(0, statements);
   18.13 +    }
   18.14 +
   18.15 +
   18.16 +    /**
   18.17       * Get the last statement that was emitted into a block
   18.18       * @return the last statement emitted
   18.19       */
    19.1 --- a/src/jdk/nashorn/internal/ir/FunctionNode.java	Fri Oct 17 14:24:26 2014 +0200
    19.2 +++ b/src/jdk/nashorn/internal/ir/FunctionNode.java	Mon Oct 20 12:06:36 2014 +0200
    19.3 @@ -109,7 +109,7 @@
    19.4      }
    19.5  
    19.6      /** Source of entity. */
    19.7 -    private final Source source;
    19.8 +    private transient final Source source;
    19.9  
   19.10      /**
   19.11       * Opaque object representing parser state at the end of the function. Used when reparsing outer functions
   19.12 @@ -143,7 +143,7 @@
   19.13      private final long lastToken;
   19.14  
   19.15      /** Method's namespace. */
   19.16 -    private final Namespace namespace;
   19.17 +    private transient final Namespace namespace;
   19.18  
   19.19      /** Current compilation state */
   19.20      @Ignore
   19.21 @@ -209,31 +209,23 @@
   19.22      /** Are we vararg, but do we just pass the arguments along to apply or call */
   19.23      public static final int HAS_APPLY_TO_CALL_SPECIALIZATION = 1 << 12;
   19.24  
   19.25 -    /** Does this function explicitly use the {@link CompilerConstants#RETURN} symbol? Some functions are known to
   19.26 -     * always use the return symbol, namely a function that is a program (as it must track its last executed expression
   19.27 -     * statement's value) as well as functions that are split (to communicate return values from inner to outer
   19.28 -     * partitions). Other functions normally don't use the return symbol (so we optimize away its slot), except in some
   19.29 -     * very special cases, e.g. when containing a return statement in a finally block. These special cases set this
   19.30 -     * flag. */
   19.31 -    public static final int USES_RETURN_SYMBOL = 1 << 13;
   19.32 -
   19.33      /**
   19.34       * Is this function the top-level program?
   19.35       */
   19.36 -    public static final int IS_PROGRAM = 1 << 14;
   19.37 +    public static final int IS_PROGRAM = 1 << 13;
   19.38  
   19.39      /**
   19.40       * Flag indicating whether this function uses the local variable symbol for itself. Only named function expressions
   19.41       * can have this flag set if they reference themselves (e.g. "(function f() { return f })". Declared functions will
   19.42       * use the symbol in their parent scope instead when they reference themselves by name.
   19.43       */
   19.44 -    public static final int USES_SELF_SYMBOL = 1 << 15;
   19.45 +    public static final int USES_SELF_SYMBOL = 1 << 14;
   19.46  
   19.47      /** Does this function use the "this" keyword? */
   19.48 -    public static final int USES_THIS = 1 << 16;
   19.49 +    public static final int USES_THIS = 1 << 15;
   19.50  
   19.51      /** Is this declared in a dynamic context */
   19.52 -    public static final int IN_DYNAMIC_CONTEXT = 1 << 17;
   19.53 +    public static final int IN_DYNAMIC_CONTEXT = 1 << 16;
   19.54  
   19.55      /**
   19.56       * The following flags are derived from directive comments within this function.
   19.57 @@ -241,28 +233,28 @@
   19.58       */
   19.59  
   19.60      /** parser, print parse tree */
   19.61 -    public static final int IS_PRINT_PARSE       = 1 << 18;
   19.62 +    public static final int IS_PRINT_PARSE       = 1 << 17;
   19.63      /** parser, print lower parse tree */
   19.64 -    public static final int IS_PRINT_LOWER_PARSE = 1 << 19;
   19.65 +    public static final int IS_PRINT_LOWER_PARSE = 1 << 18;
   19.66      /** parser, print AST */
   19.67 -    public static final int IS_PRINT_AST         = 1 << 20;
   19.68 +    public static final int IS_PRINT_AST         = 1 << 19;
   19.69      /** parser, print lower AST */
   19.70 -    public static final int IS_PRINT_LOWER_AST   = 1 << 21;
   19.71 +    public static final int IS_PRINT_LOWER_AST   = 1 << 20;
   19.72      /** parser, print symbols */
   19.73 -    public static final int IS_PRINT_SYMBOLS     = 1 << 22;
   19.74 +    public static final int IS_PRINT_SYMBOLS     = 1 << 21;
   19.75  
   19.76      // callsite tracing, profiling within this function
   19.77      /** profile callsites in this function? */
   19.78 -    public static final int IS_PROFILE         = 1 << 23;
   19.79 +    public static final int IS_PROFILE         = 1 << 22;
   19.80  
   19.81      /** trace callsite enterexit in this function? */
   19.82 -    public static final int IS_TRACE_ENTEREXIT = 1 << 24;
   19.83 +    public static final int IS_TRACE_ENTEREXIT = 1 << 23;
   19.84  
   19.85      /** trace callsite misses in this function? */
   19.86 -    public static final int IS_TRACE_MISSES    = 1 << 25;
   19.87 +    public static final int IS_TRACE_MISSES    = 1 << 24;
   19.88  
   19.89      /** trace callsite values in this function? */
   19.90 -    public static final int IS_TRACE_VALUES    = 1 << 26;
   19.91 +    public static final int IS_TRACE_VALUES    = 1 << 25;
   19.92  
   19.93      /**
   19.94       * Whether this function needs the callee {@link ScriptFunction} instance passed to its code as a
   19.95 @@ -270,7 +262,7 @@
   19.96       * Rather, it is always calculated (see {@link #needsCallee()}). {@link RecompilableScriptFunctionData}
   19.97       * will, however, cache the value of this flag.
   19.98       */
   19.99 -    public static final int NEEDS_CALLEE       = 1 << 27;
  19.100 +    public static final int NEEDS_CALLEE       = 1 << 26;
  19.101  
  19.102      /** extension callsite flags mask */
  19.103      public static final int EXTENSION_CALLSITE_FLAGS = IS_PRINT_PARSE |
  19.104 @@ -287,8 +279,8 @@
  19.105      /** Does this function potentially need "arguments"? Note that this is not a full test, as further negative check of REDEFINES_ARGS is needed. */
  19.106      private static final int MAYBE_NEEDS_ARGUMENTS = USES_ARGUMENTS | HAS_EVAL;
  19.107  
  19.108 -    /** Does this function need the parent scope? It needs it if either it or its descendants use variables from it, or have a deep eval. */
  19.109 -    private static final int NEEDS_PARENT_SCOPE = USES_ANCESTOR_SCOPE | HAS_DEEP_EVAL;
  19.110 +    /** Does this function need the parent scope? It needs it if either it or its descendants use variables from it, or have a deep eval, or it's the program. */
  19.111 +    public static final int NEEDS_PARENT_SCOPE = USES_ANCESTOR_SCOPE | HAS_DEEP_EVAL | IS_PROGRAM;
  19.112  
  19.113      /** What is the return type of this function? */
  19.114      private Type returnType = Type.UNKNOWN;
  19.115 @@ -352,7 +344,8 @@
  19.116          final Block body,
  19.117          final List<IdentNode> parameters,
  19.118          final int thisProperties,
  19.119 -        final Class<?> rootClass) {
  19.120 +        final Class<?> rootClass,
  19.121 +        final Source source, Namespace namespace) {
  19.122          super(functionNode);
  19.123  
  19.124          this.endParserState    = endParserState;
  19.125 @@ -367,11 +360,11 @@
  19.126          this.parameters       = parameters;
  19.127          this.thisProperties   = thisProperties;
  19.128          this.rootClass        = rootClass;
  19.129 +        this.source           = source;
  19.130 +        this.namespace        = namespace;
  19.131  
  19.132          // the fields below never change - they are final and assigned in constructor
  19.133 -        this.source          = functionNode.source;
  19.134          this.ident           = functionNode.ident;
  19.135 -        this.namespace       = functionNode.namespace;
  19.136          this.kind            = functionNode.kind;
  19.137          this.firstToken      = functionNode.firstToken;
  19.138      }
  19.139 @@ -437,6 +430,39 @@
  19.140      }
  19.141  
  19.142      /**
  19.143 +     * Sets the source and namespace for this function. It can only set a non-null source and namespace for a function
  19.144 +     * that currently has both a null source and a null namespace. This is used to re-set the source and namespace for
  19.145 +     * a deserialized function node.
  19.146 +     * @param source the source for the function.
  19.147 +     * @param namespace the namespace for the function
  19.148 +     * @return a new function node with the set source and namespace
  19.149 +     * @throws IllegalArgumentException if the specified source or namespace is null
  19.150 +     * @throws IllegalStateException if the function already has either a source or namespace set.
  19.151 +     */
  19.152 +    public FunctionNode initializeDeserialized(final Source source, final Namespace namespace) {
  19.153 +        if (source == null || namespace == null) {
  19.154 +            throw new IllegalArgumentException();
  19.155 +        } else if (this.source == source && this.namespace == namespace) {
  19.156 +            return this;
  19.157 +        } else if (this.source != null || this.namespace != null) {
  19.158 +            throw new IllegalStateException();
  19.159 +        }
  19.160 +        return new FunctionNode(
  19.161 +            this,
  19.162 +            lastToken,
  19.163 +            endParserState,
  19.164 +            flags,
  19.165 +            name,
  19.166 +            returnType,
  19.167 +            compileUnit,
  19.168 +            compilationState,
  19.169 +            body,
  19.170 +            parameters,
  19.171 +            thisProperties,
  19.172 +            rootClass, source, namespace);
  19.173 +    }
  19.174 +
  19.175 +    /**
  19.176       * Get the unique ID for this function within the script file.
  19.177       * @return the id
  19.178       */
  19.179 @@ -537,6 +563,28 @@
  19.180          }
  19.181          final EnumSet<CompilationState> newState = EnumSet.copyOf(this.compilationState);
  19.182          newState.add(state);
  19.183 +        return setCompilationState(lc, newState);
  19.184 +    }
  19.185 +
  19.186 +    /**
  19.187 +     * Copy a compilation state from an original function to this function. Used when creating synthetic
  19.188 +     * function nodes by the splitter.
  19.189 +     *
  19.190 +     * @param lc lexical context
  19.191 +     * @param original the original function node to copy compilation state from
  19.192 +     * @return function node or a new one if state was changed
  19.193 +     */
  19.194 +    public FunctionNode copyCompilationState(final LexicalContext lc, final FunctionNode original) {
  19.195 +        final EnumSet<CompilationState> origState = original.compilationState;
  19.196 +        if (!AssertsEnabled.assertsEnabled() || this.compilationState.containsAll(origState)) {
  19.197 +            return this;
  19.198 +        }
  19.199 +        final EnumSet<CompilationState> newState = EnumSet.copyOf(this.compilationState);
  19.200 +        newState.addAll(origState);
  19.201 +        return setCompilationState(lc, newState);
  19.202 +    }
  19.203 +
  19.204 +    private FunctionNode setCompilationState(final LexicalContext lc, final EnumSet<CompilationState> compilationState) {
  19.205          return Node.replaceInLexicalContext(
  19.206                  lc,
  19.207                  this,
  19.208 @@ -548,13 +596,14 @@
  19.209                          name,
  19.210                          returnType,
  19.211                          compileUnit,
  19.212 -                        newState,
  19.213 +                        compilationState,
  19.214                          body,
  19.215                          parameters,
  19.216                          thisProperties,
  19.217 -                        rootClass));
  19.218 +                        rootClass, source, namespace));
  19.219      }
  19.220  
  19.221 +
  19.222      /**
  19.223       * Create a unique name in the namespace of this FunctionNode
  19.224       * @param base prefix for name
  19.225 @@ -624,7 +673,7 @@
  19.226                          body,
  19.227                          parameters,
  19.228                          thisProperties,
  19.229 -                        rootClass));
  19.230 +                        rootClass, source, namespace));
  19.231      }
  19.232  
  19.233      @Override
  19.234 @@ -699,18 +748,11 @@
  19.235       * @return true if the function's generated Java method needs a {@code callee} parameter.
  19.236       */
  19.237      public boolean needsCallee() {
  19.238 +        // NOTE: we only need isSplit() here to ensure that :scope can never drop below slot 2 for splitting array units.
  19.239          return needsParentScope() || usesSelfSymbol() || isSplit() || (needsArguments() && !isStrict()) || hasOptimisticApplyToCall();
  19.240      }
  19.241  
  19.242      /**
  19.243 -     * Check if this function uses the return symbol
  19.244 -     * @return true if uses the return symbol
  19.245 -     */
  19.246 -    public boolean usesReturnSymbol() {
  19.247 -        return isProgram() || isSplit() || getFlag(USES_RETURN_SYMBOL);
  19.248 -    }
  19.249 -
  19.250 -    /**
  19.251       * Return {@code true} if this function makes use of the {@code this} object.
  19.252       *
  19.253       * @return true if function uses {@code this} object
  19.254 @@ -772,7 +814,7 @@
  19.255                          body,
  19.256                          parameters,
  19.257                          thisProperties,
  19.258 -                        rootClass));
  19.259 +                        rootClass, source, namespace));
  19.260      }
  19.261  
  19.262      /**
  19.263 @@ -840,7 +882,7 @@
  19.264       * @return true if the function needs parent scope.
  19.265       */
  19.266      public boolean needsParentScope() {
  19.267 -        return getFlag(NEEDS_PARENT_SCOPE) || isProgram();
  19.268 +        return getFlag(NEEDS_PARENT_SCOPE);
  19.269      }
  19.270  
  19.271      /**
  19.272 @@ -868,7 +910,7 @@
  19.273                          body,
  19.274                          parameters,
  19.275                          thisProperties,
  19.276 -                        rootClass));
  19.277 +                        rootClass, source, namespace));
  19.278      }
  19.279  
  19.280      /**
  19.281 @@ -929,7 +971,7 @@
  19.282                          body,
  19.283                          parameters,
  19.284                          thisProperties,
  19.285 -                        rootClass));
  19.286 +                        rootClass, source, namespace));
  19.287      }
  19.288  
  19.289      /**
  19.290 @@ -964,7 +1006,10 @@
  19.291                          compilationState,
  19.292                          body,
  19.293                          parameters,
  19.294 -                        thisProperties, rootClass));
  19.295 +                        thisProperties,
  19.296 +                        rootClass,
  19.297 +                        source,
  19.298 +                        namespace));
  19.299      }
  19.300  
  19.301      /**
  19.302 @@ -1000,7 +1045,9 @@
  19.303                          body,
  19.304                          parameters,
  19.305                          thisProperties,
  19.306 -                        rootClass));
  19.307 +                        rootClass,
  19.308 +                        source,
  19.309 +                        namespace));
  19.310      }
  19.311  
  19.312      /**
  19.313 @@ -1014,9 +1061,9 @@
  19.314      }
  19.315  
  19.316      /**
  19.317 -     * Checks if this function is a sub-function generated by splitting a larger one
  19.318 +     * Checks if this function is split into several smaller fragments.
  19.319       *
  19.320 -     * @return true if this function is split from a larger one
  19.321 +     * @return true if this function is split into several smaller fragments.
  19.322       */
  19.323      public boolean isSplit() {
  19.324          return getFlag(IS_SPLIT);
  19.325 @@ -1066,7 +1113,7 @@
  19.326                          body,
  19.327                          parameters,
  19.328                          thisProperties,
  19.329 -                        rootClass));
  19.330 +                        rootClass, source, namespace));
  19.331      }
  19.332  
  19.333      /**
  19.334 @@ -1145,7 +1192,7 @@
  19.335                  body,
  19.336                  parameters,
  19.337                  thisProperties,
  19.338 -                rootClass
  19.339 +                rootClass, source, namespace
  19.340                  ));
  19.341     }
  19.342  
  19.343 @@ -1193,7 +1240,7 @@
  19.344                          body,
  19.345                          parameters,
  19.346                          thisProperties,
  19.347 -                        rootClass));
  19.348 +                        rootClass, source, namespace));
  19.349      }
  19.350  
  19.351      /**
  19.352 @@ -1249,6 +1296,6 @@
  19.353                          body,
  19.354                          parameters,
  19.355                          thisProperties,
  19.356 -                        rootClass));
  19.357 +                        rootClass, source, namespace));
  19.358      }
  19.359  }
    20.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    20.2 +++ b/src/jdk/nashorn/internal/ir/GetSplitState.java	Mon Oct 20 12:06:36 2014 +0200
    20.3 @@ -0,0 +1,70 @@
    20.4 +/*
    20.5 + * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
    20.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
    20.7 + *
    20.8 + * This code is free software; you can redistribute it and/or modify it
    20.9 + * under the terms of the GNU General Public License version 2 only, as
   20.10 + * published by the Free Software Foundation.  Oracle designates this
   20.11 + * particular file as subject to the "Classpath" exception as provided
   20.12 + * by Oracle in the LICENSE file that accompanied this code.
   20.13 + *
   20.14 + * This code is distributed in the hope that it will be useful, but WITHOUT
   20.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
   20.16 + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
   20.17 + * version 2 for more details (a copy is included in the LICENSE file that
   20.18 + * accompanied this code).
   20.19 + *
   20.20 + * You should have received a copy of the GNU General Public License version
   20.21 + * 2 along with this work; if not, write to the Free Software Foundation,
   20.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
   20.23 + *
   20.24 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
   20.25 + * or visit www.oracle.com if you need additional information or have any
   20.26 + * questions.
   20.27 + */
   20.28 +
   20.29 +package jdk.nashorn.internal.ir;
   20.30 +
   20.31 +import java.util.function.Function;
   20.32 +import jdk.nashorn.internal.codegen.CompilerConstants;
   20.33 +import jdk.nashorn.internal.codegen.types.Type;
   20.34 +import jdk.nashorn.internal.ir.visitor.NodeVisitor;
   20.35 +import jdk.nashorn.internal.runtime.Scope;
   20.36 +
   20.37 +/**
   20.38 + * Synthetic AST node that represents loading of the scope object and invocation of the {@link Scope#getSplitState()}
   20.39 + * method on it. It has no JavaScript source representation and only occurs in synthetic functions created by
   20.40 + * the split-into-functions transformation.
   20.41 + */
   20.42 +public final class GetSplitState extends Expression {
   20.43 +    private static final long serialVersionUID = 1L;
   20.44 +
   20.45 +    /** The sole instance of this AST node. */
   20.46 +    public final static GetSplitState INSTANCE = new GetSplitState();
   20.47 +
   20.48 +    private GetSplitState() {
   20.49 +        super(NO_TOKEN, NO_FINISH);
   20.50 +    }
   20.51 +
   20.52 +    @Override
   20.53 +    public Type getType(final Function<Symbol, Type> localVariableTypes) {
   20.54 +        return Type.INT;
   20.55 +    }
   20.56 +
   20.57 +    @Override
   20.58 +    public Node accept(final NodeVisitor<? extends LexicalContext> visitor) {
   20.59 +        return visitor.enterGetSplitState(this) ? visitor.leaveGetSplitState(this) : this;
   20.60 +    }
   20.61 +
   20.62 +    @Override
   20.63 +    public void toString(final StringBuilder sb, final boolean printType) {
   20.64 +        if (printType) {
   20.65 +            sb.append("{I}");
   20.66 +        }
   20.67 +        sb.append(CompilerConstants.SCOPE.symbolName()).append('.').append(Scope.GET_SPLIT_STATE.name()).append("()");
   20.68 +    }
   20.69 +
   20.70 +    private Object readResolve() {
   20.71 +        return INSTANCE;
   20.72 +    }
   20.73 +}
    21.1 --- a/src/jdk/nashorn/internal/ir/LexicalContext.java	Fri Oct 17 14:24:26 2014 +0200
    21.2 +++ b/src/jdk/nashorn/internal/ir/LexicalContext.java	Mon Oct 20 12:06:36 2014 +0200
    21.3 @@ -440,6 +440,14 @@
    21.4      }
    21.5  
    21.6      /**
    21.7 +     * Is the topmost lexical context element body of a SplitNode?
    21.8 +     * @return true if it's the body of a split node.
    21.9 +     */
   21.10 +    public boolean isSplitBody() {
   21.11 +        return sp >= 2 && stack[sp - 1] instanceof Block && stack[sp - 2] instanceof SplitNode;
   21.12 +    }
   21.13 +
   21.14 +    /**
   21.15       * Get the parent function for a function in the lexical context
   21.16       * @param functionNode function for which to get parent
   21.17       * @return parent function of functionNode or null if none (e.g. if functionNode is the program)
   21.18 @@ -472,9 +480,6 @@
   21.19              final LexicalContextNode node = iter.next();
   21.20              if (node == until) {
   21.21                  break;
   21.22 -            } else if (node instanceof SplitNode) {
   21.23 -                // Don't bother popping scopes if we're going to do a return from a split method anyway.
   21.24 -                return 0;
   21.25              }
   21.26              assert !(node instanceof FunctionNode); // Can't go outside current function
   21.27              if (node instanceof WithNode || node instanceof Block && ((Block)node).needsScope()) {
    22.1 --- a/src/jdk/nashorn/internal/ir/LiteralNode.java	Fri Oct 17 14:24:26 2014 +0200
    22.2 +++ b/src/jdk/nashorn/internal/ir/LiteralNode.java	Mon Oct 20 12:06:36 2014 +0200
    22.3 @@ -672,13 +672,13 @@
    22.4          private static final class ArrayLiteralInitializer {
    22.5  
    22.6              static ArrayLiteralNode initialize(final ArrayLiteralNode node) {
    22.7 -                final Type elementType = computeElementType(node.value, node.elementType);
    22.8 +                final Type elementType = computeElementType(node.value);
    22.9                  final int[] postsets = computePostsets(node.value);
   22.10                  final Object presets = computePresets(node.value, elementType, postsets);
   22.11                  return new ArrayLiteralNode(node, node.value, elementType, postsets, presets, node.units);
   22.12              }
   22.13  
   22.14 -            private static Type computeElementType(final Expression[] value, final Type elementType) {
   22.15 +            private static Type computeElementType(final Expression[] value) {
   22.16                  Type widestElementType = Type.INT;
   22.17  
   22.18                  for (final Expression elem : value) {
    23.1 --- a/src/jdk/nashorn/internal/ir/Node.java	Fri Oct 17 14:24:26 2014 +0200
    23.2 +++ b/src/jdk/nashorn/internal/ir/Node.java	Mon Oct 20 12:06:36 2014 +0200
    23.3 @@ -38,6 +38,15 @@
    23.4  public abstract class Node implements Cloneable, Serializable {
    23.5      private static final long serialVersionUID = 1L;
    23.6  
    23.7 +    /** Constant used for synthetic AST nodes that have no line number. */
    23.8 +    public static final int NO_LINE_NUMBER = -1;
    23.9 +
   23.10 +    /** Constant used for synthetic AST nodes that have no token. */
   23.11 +    public static final long NO_TOKEN = 0L;
   23.12 +
   23.13 +    /** Constant used for synthetic AST nodes that have no finish. */
   23.14 +    public static final int NO_FINISH = 0;
   23.15 +
   23.16      /** Start of source range. */
   23.17      protected final int start;
   23.18  
    24.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    24.2 +++ b/src/jdk/nashorn/internal/ir/SetSplitState.java	Mon Oct 20 12:06:36 2014 +0200
    24.3 @@ -0,0 +1,70 @@
    24.4 +/*
    24.5 + * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
    24.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
    24.7 + *
    24.8 + * This code is free software; you can redistribute it and/or modify it
    24.9 + * under the terms of the GNU General Public License version 2 only, as
   24.10 + * published by the Free Software Foundation.  Oracle designates this
   24.11 + * particular file as subject to the "Classpath" exception as provided
   24.12 + * by Oracle in the LICENSE file that accompanied this code.
   24.13 + *
   24.14 + * This code is distributed in the hope that it will be useful, but WITHOUT
   24.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
   24.16 + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
   24.17 + * version 2 for more details (a copy is included in the LICENSE file that
   24.18 + * accompanied this code).
   24.19 + *
   24.20 + * You should have received a copy of the GNU General Public License version
   24.21 + * 2 along with this work; if not, write to the Free Software Foundation,
   24.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
   24.23 + *
   24.24 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
   24.25 + * or visit www.oracle.com if you need additional information or have any
   24.26 + * questions.
   24.27 + */
   24.28 +
   24.29 +package jdk.nashorn.internal.ir;
   24.30 +
   24.31 +import jdk.nashorn.internal.codegen.CompilerConstants;
   24.32 +import jdk.nashorn.internal.ir.visitor.NodeVisitor;
   24.33 +import jdk.nashorn.internal.runtime.Scope;
   24.34 +
   24.35 +/**
   24.36 + * Synthetic AST node that represents loading of the scope object and invocation of the {@link Scope#setSplitState(int)}
   24.37 + * method on it. It has no JavaScript source representation and only occurs in synthetic functions created by
   24.38 + * the split-into-functions transformation.
   24.39 + */
   24.40 +public final class SetSplitState extends Statement {
   24.41 +    private static final long serialVersionUID = 1L;
   24.42 +
   24.43 +    private final int state;
   24.44 +
   24.45 +    /**
   24.46 +     * Creates a new split state setter
   24.47 +     * @param state the state to set
   24.48 +     * @param lineNumber the line number where it is inserted
   24.49 +     */
   24.50 +    public SetSplitState(final int state, final int lineNumber) {
   24.51 +        super(lineNumber, NO_TOKEN, NO_FINISH);
   24.52 +        this.state = state;
   24.53 +    }
   24.54 +
   24.55 +    /**
   24.56 +     * Returns the state this setter sets.
   24.57 +     * @return the state this setter sets.
   24.58 +     */
   24.59 +    public int getState() {
   24.60 +        return state;
   24.61 +    }
   24.62 +
   24.63 +    @Override
   24.64 +    public Node accept(final NodeVisitor<? extends LexicalContext> visitor) {
   24.65 +        return visitor.enterSetSplitState(this) ? visitor.leaveSetSplitState(this) : this;
   24.66 +    }
   24.67 +
   24.68 +    @Override
   24.69 +    public void toString(final StringBuilder sb, final boolean printType) {
   24.70 +        sb.append(CompilerConstants.SCOPE.symbolName()).append('.').append(Scope.SET_SPLIT_STATE.name())
   24.71 +        .append('(').append(state).append(");");
   24.72 +    }
   24.73 +}
    25.1 --- a/src/jdk/nashorn/internal/ir/SplitNode.java	Fri Oct 17 14:24:26 2014 +0200
    25.2 +++ b/src/jdk/nashorn/internal/ir/SplitNode.java	Mon Oct 20 12:06:36 2014 +0200
    25.3 @@ -25,13 +25,10 @@
    25.4  
    25.5  package jdk.nashorn.internal.ir;
    25.6  
    25.7 -import java.util.ArrayList;
    25.8 -import java.util.Collections;
    25.9 -import java.util.HashMap;
   25.10 -import java.util.List;
   25.11 -import java.util.Map;
   25.12 +import java.io.IOException;
   25.13 +import java.io.NotSerializableException;
   25.14 +import java.io.ObjectOutputStream;
   25.15  import jdk.nashorn.internal.codegen.CompileUnit;
   25.16 -import jdk.nashorn.internal.codegen.Label;
   25.17  import jdk.nashorn.internal.ir.annotations.Immutable;
   25.18  import jdk.nashorn.internal.ir.visitor.NodeVisitor;
   25.19  
   25.20 @@ -39,7 +36,7 @@
   25.21   * Node indicating code is split across classes.
   25.22   */
   25.23  @Immutable
   25.24 -public class SplitNode extends LexicalContextStatement implements Labels, CompileUnitHolder {
   25.25 +public class SplitNode extends LexicalContextStatement implements CompileUnitHolder {
   25.26      private static final long serialVersionUID = 1L;
   25.27  
   25.28      /** Split node method name. */
   25.29 @@ -51,8 +48,6 @@
   25.30      /** Body of split code. */
   25.31      private final Block body;
   25.32  
   25.33 -    private Map<Label, JoinPredecessor> jumps;
   25.34 -
   25.35      /**
   25.36       * Constructor
   25.37       *
   25.38 @@ -67,19 +62,18 @@
   25.39          this.compileUnit = compileUnit;
   25.40      }
   25.41  
   25.42 -    private SplitNode(final SplitNode splitNode, final Block body, final CompileUnit compileUnit, final Map<Label, JoinPredecessor> jumps) {
   25.43 +    private SplitNode(final SplitNode splitNode, final Block body, final CompileUnit compileUnit) {
   25.44          super(splitNode);
   25.45          this.name        = splitNode.name;
   25.46          this.body        = body;
   25.47          this.compileUnit = compileUnit;
   25.48 -        this.jumps       = jumps;
   25.49      }
   25.50  
   25.51      /**
   25.52       * Get the body for this split node - i.e. the actual code it encloses
   25.53       * @return body for split node
   25.54       */
   25.55 -    public Node getBody() {
   25.56 +    public Block getBody() {
   25.57          return body;
   25.58      }
   25.59  
   25.60 @@ -87,7 +81,7 @@
   25.61          if (this.body == body) {
   25.62              return this;
   25.63          }
   25.64 -        return Node.replaceInLexicalContext(lc, this, new SplitNode(this, body, compileUnit, jumps));
   25.65 +        return Node.replaceInLexicalContext(lc, this, new SplitNode(this, body, compileUnit));
   25.66      }
   25.67  
   25.68      @Override
   25.69 @@ -133,33 +127,12 @@
   25.70          if (this.compileUnit == compileUnit) {
   25.71              return this;
   25.72          }
   25.73 -        return Node.replaceInLexicalContext(lc, this, new SplitNode(this, body, compileUnit, jumps));
   25.74 +        return Node.replaceInLexicalContext(lc, this, new SplitNode(this, body, compileUnit));
   25.75      }
   25.76  
   25.77 -    /**
   25.78 -     * Adds a jump that crosses this split node's boundary (it originates within the split node, and goes to a target
   25.79 -     * outside of it).
   25.80 -     * @param jumpOrigin the join predecessor that's the origin of the jump
   25.81 -     * @param targetLabel the label that's the target of the jump.
   25.82 -     */
   25.83 -    public void addJump(final JoinPredecessor jumpOrigin, final Label targetLabel) {
   25.84 -        if (jumps == null) {
   25.85 -            jumps = new HashMap<>();
   25.86 -        }
   25.87 -        jumps.put(targetLabel, jumpOrigin);
   25.88 -    }
   25.89 -
   25.90 -    /**
   25.91 -     * Returns the jump origin within this split node for a target.
   25.92 -     * @param targetLabel the target for which a jump origin is sought.
   25.93 -     * @return the jump origin, or null.
   25.94 -     */
   25.95 -    public JoinPredecessor getJumpOrigin(final Label targetLabel) {
   25.96 -        return jumps == null ? null : jumps.get(targetLabel);
   25.97 -    }
   25.98 -
   25.99 -    @Override
  25.100 -    public List<Label> getLabels() {
  25.101 -        return Collections.unmodifiableList(new ArrayList<>(jumps.keySet()));
  25.102 +    private void writeObject(final ObjectOutputStream out) throws IOException {
  25.103 +        // We are only serializing the AST after we run SplitIntoFunctions; no SplitNodes can remain for the
  25.104 +        // serialization.
  25.105 +        throw new NotSerializableException(getClass().getName());
  25.106      }
  25.107  }
    26.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    26.2 +++ b/src/jdk/nashorn/internal/ir/SplitReturn.java	Mon Oct 20 12:06:36 2014 +0200
    26.3 @@ -0,0 +1,64 @@
    26.4 +/*
    26.5 + * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
    26.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
    26.7 + *
    26.8 + * This code is free software; you can redistribute it and/or modify it
    26.9 + * under the terms of the GNU General Public License version 2 only, as
   26.10 + * published by the Free Software Foundation.  Oracle designates this
   26.11 + * particular file as subject to the "Classpath" exception as provided
   26.12 + * by Oracle in the LICENSE file that accompanied this code.
   26.13 + *
   26.14 + * This code is distributed in the hope that it will be useful, but WITHOUT
   26.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
   26.16 + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
   26.17 + * version 2 for more details (a copy is included in the LICENSE file that
   26.18 + * accompanied this code).
   26.19 + *
   26.20 + * You should have received a copy of the GNU General Public License version
   26.21 + * 2 along with this work; if not, write to the Free Software Foundation,
   26.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
   26.23 + *
   26.24 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
   26.25 + * or visit www.oracle.com if you need additional information or have any
   26.26 + * questions.
   26.27 + */
   26.28 +
   26.29 +package jdk.nashorn.internal.ir;
   26.30 +
   26.31 +import jdk.nashorn.internal.ir.visitor.NodeVisitor;
   26.32 +
   26.33 +/**
   26.34 + * Synthetic AST node that represents return from a split fragment of a split function for control flow reasons (break
   26.35 + * or continue into a target outside the current fragment). It has no JavaScript source representation and only occurs
   26.36 + * in synthetic functions created by the split-into-functions transformation. It is different from a return node in
   26.37 + * that the return value is irrelevant, and doesn't affect the function's return type calculation.
   26.38 + */
   26.39 +public final class SplitReturn extends Statement {
   26.40 +    private static final long serialVersionUID = 1L;
   26.41 +
   26.42 +    /** The sole instance of this AST node. */
   26.43 +    public static final SplitReturn INSTANCE = new SplitReturn();
   26.44 +
   26.45 +    private SplitReturn() {
   26.46 +        super(NO_LINE_NUMBER, NO_TOKEN, NO_FINISH);
   26.47 +    }
   26.48 +
   26.49 +    @Override
   26.50 +    public boolean isTerminal() {
   26.51 +        return true;
   26.52 +    }
   26.53 +
   26.54 +    @Override
   26.55 +    public Node accept(final NodeVisitor<? extends LexicalContext> visitor) {
   26.56 +        return visitor.enterSplitReturn(this) ? visitor.leaveSplitReturn(this) : this;
   26.57 +    }
   26.58 +
   26.59 +    @Override
   26.60 +    public void toString(StringBuilder sb, boolean printType) {
   26.61 +        sb.append(":splitreturn;");
   26.62 +    }
   26.63 +
   26.64 +    private Object readResolve() {
   26.65 +        return INSTANCE;
   26.66 +    }
   26.67 +}
    27.1 --- a/src/jdk/nashorn/internal/ir/Symbol.java	Fri Oct 17 14:24:26 2014 +0200
    27.2 +++ b/src/jdk/nashorn/internal/ir/Symbol.java	Mon Oct 20 12:06:36 2014 +0200
    27.3 @@ -97,7 +97,7 @@
    27.4      private int firstSlot = -1;
    27.5  
    27.6      /** Field number in scope or property; array index in varargs when not using arguments object. */
    27.7 -    private int fieldIndex;
    27.8 +    private int fieldIndex = -1;
    27.9  
   27.10      /** Number of times this symbol is used in code */
   27.11      private int useCount;
   27.12 @@ -135,28 +135,15 @@
   27.13       *
   27.14       * @param name  name of symbol
   27.15       * @param flags symbol flags
   27.16 -     * @param slot  bytecode slot for this symbol
   27.17       */
   27.18 -    protected Symbol(final String name, final int flags, final int slot) {
   27.19 +    public Symbol(final String name, final int flags) {
   27.20          this.name       = name;
   27.21          this.flags      = flags;
   27.22 -        this.firstSlot  = slot;
   27.23 -        this.fieldIndex = -1;
   27.24          if(shouldTrace()) {
   27.25              trace("CREATE SYMBOL " + name);
   27.26          }
   27.27      }
   27.28  
   27.29 -    /**
   27.30 -     * Constructor
   27.31 -     *
   27.32 -     * @param name  name of symbol
   27.33 -     * @param flags symbol flags
   27.34 -     */
   27.35 -    public Symbol(final String name, final int flags) {
   27.36 -        this(name, flags, -1);
   27.37 -    }
   27.38 -
   27.39      private static String align(final String string, final int max) {
   27.40          final StringBuilder sb = new StringBuilder();
   27.41          sb.append(string.substring(0, Math.min(string.length(), max)));
    28.1 --- a/src/jdk/nashorn/internal/ir/visitor/NodeVisitor.java	Fri Oct 17 14:24:26 2014 +0200
    28.2 +++ b/src/jdk/nashorn/internal/ir/visitor/NodeVisitor.java	Mon Oct 20 12:06:36 2014 +0200
    28.3 @@ -38,6 +38,7 @@
    28.4  import jdk.nashorn.internal.ir.ExpressionStatement;
    28.5  import jdk.nashorn.internal.ir.ForNode;
    28.6  import jdk.nashorn.internal.ir.FunctionNode;
    28.7 +import jdk.nashorn.internal.ir.GetSplitState;
    28.8  import jdk.nashorn.internal.ir.IdentNode;
    28.9  import jdk.nashorn.internal.ir.IfNode;
   28.10  import jdk.nashorn.internal.ir.IndexNode;
   28.11 @@ -50,7 +51,9 @@
   28.12  import jdk.nashorn.internal.ir.PropertyNode;
   28.13  import jdk.nashorn.internal.ir.ReturnNode;
   28.14  import jdk.nashorn.internal.ir.RuntimeNode;
   28.15 +import jdk.nashorn.internal.ir.SetSplitState;
   28.16  import jdk.nashorn.internal.ir.SplitNode;
   28.17 +import jdk.nashorn.internal.ir.SplitReturn;
   28.18  import jdk.nashorn.internal.ir.SwitchNode;
   28.19  import jdk.nashorn.internal.ir.TernaryNode;
   28.20  import jdk.nashorn.internal.ir.ThrowNode;
   28.21 @@ -390,6 +393,26 @@
   28.22      }
   28.23  
   28.24      /**
   28.25 +     * Callback for entering a {@link GetSplitState}.
   28.26 +     *
   28.27 +     * @param  getSplitState the get split state expression
   28.28 +     * @return true if traversal should continue and node children be traversed, false otherwise
   28.29 +     */
   28.30 +    public boolean enterGetSplitState(final GetSplitState getSplitState) {
   28.31 +        return enterDefault(getSplitState);
   28.32 +    }
   28.33 +
   28.34 +    /**
   28.35 +     * Callback for leaving a {@link GetSplitState}.
   28.36 +     *
   28.37 +     * @param  getSplitState the get split state expression
   28.38 +     * @return processed node, which will replace the original one, or the original node
   28.39 +     */
   28.40 +    public Node leaveGetSplitState(final GetSplitState getSplitState) {
   28.41 +        return leaveDefault(getSplitState);
   28.42 +    }
   28.43 +
   28.44 +    /**
   28.45       * Callback for entering an IdentNode
   28.46       *
   28.47       * @param  identNode the node
   28.48 @@ -570,6 +593,26 @@
   28.49      }
   28.50  
   28.51      /**
   28.52 +     * Callback for entering a {@link SetSplitState}.
   28.53 +     *
   28.54 +     * @param  setSplitState the set split state statement
   28.55 +     * @return true if traversal should continue and node children be traversed, false otherwise
   28.56 +     */
   28.57 +    public boolean enterSetSplitState(final SetSplitState setSplitState) {
   28.58 +        return enterDefault(setSplitState);
   28.59 +    }
   28.60 +
   28.61 +    /**
   28.62 +     * Callback for leaving a {@link SetSplitState}.
   28.63 +     *
   28.64 +     * @param  setSplitState the set split state expression
   28.65 +     * @return processed node, which will replace the original one, or the original node
   28.66 +     */
   28.67 +    public Node leaveSetSplitState(final SetSplitState setSplitState) {
   28.68 +        return leaveDefault(setSplitState);
   28.69 +    }
   28.70 +
   28.71 +    /**
   28.72       * Callback for entering a SplitNode
   28.73       *
   28.74       * @param  splitNode the node
   28.75 @@ -590,6 +633,26 @@
   28.76      }
   28.77  
   28.78      /**
   28.79 +     * Callback for entering a SplitReturn
   28.80 +     *
   28.81 +     * @param  splitReturn the node
   28.82 +     * @return true if traversal should continue and node children be traversed, false otherwise
   28.83 +     */
   28.84 +    public boolean enterSplitReturn(final SplitReturn splitReturn) {
   28.85 +        return enterDefault(splitReturn);
   28.86 +    }
   28.87 +
   28.88 +    /**
   28.89 +     * Callback for leaving a SplitReturn
   28.90 +     *
   28.91 +     * @param  splitReturn the node
   28.92 +     * @return processed node, which will replace the original one, or the original node
   28.93 +     */
   28.94 +    public Node leaveSplitReturn(final SplitReturn splitReturn) {
   28.95 +        return leaveDefault(splitReturn);
   28.96 +    }
   28.97 +
   28.98 +    /**
   28.99       * Callback for entering a SwitchNode
  28.100       *
  28.101       * @param  switchNode the node
    29.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    29.2 +++ b/src/jdk/nashorn/internal/runtime/AstDeserializer.java	Mon Oct 20 12:06:36 2014 +0200
    29.3 @@ -0,0 +1,47 @@
    29.4 +/*
    29.5 + * Copyright (c) 2010, 2014, Oracle and/or its affiliates. All rights reserved.
    29.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
    29.7 + *
    29.8 + * This code is free software; you can redistribute it and/or modify it
    29.9 + * under the terms of the GNU General Public License version 2 only, as
   29.10 + * published by the Free Software Foundation.  Oracle designates this
   29.11 + * particular file as subject to the "Classpath" exception as provided
   29.12 + * by Oracle in the LICENSE file that accompanied this code.
   29.13 + *
   29.14 + * This code is distributed in the hope that it will be useful, but WITHOUT
   29.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
   29.16 + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
   29.17 + * version 2 for more details (a copy is included in the LICENSE file that
   29.18 + * accompanied this code).
   29.19 + *
   29.20 + * You should have received a copy of the GNU General Public License version
   29.21 + * 2 along with this work; if not, write to the Free Software Foundation,
   29.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
   29.23 + *
   29.24 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
   29.25 + * or visit www.oracle.com if you need additional information or have any
   29.26 + * questions.
   29.27 + */
   29.28 +package jdk.nashorn.internal.runtime;
   29.29 +
   29.30 +import java.io.ByteArrayInputStream;
   29.31 +import java.io.IOException;
   29.32 +import java.io.ObjectInputStream;
   29.33 +import java.util.zip.InflaterInputStream;
   29.34 +import jdk.nashorn.internal.ir.FunctionNode;
   29.35 +
   29.36 +/**
   29.37 + * This static utility class performs deserialization of FunctionNode ASTs from a byte array.
   29.38 + * The format is a standard Java serialization stream, deflated.
   29.39 + */
   29.40 +final class AstDeserializer {
   29.41 +    static FunctionNode deserialize(final byte[] serializedAst) {
   29.42 +        try {
   29.43 +            return (FunctionNode)new ObjectInputStream(new InflaterInputStream(new ByteArrayInputStream(
   29.44 +                    serializedAst))).readObject();
   29.45 +        } catch (final ClassNotFoundException | IOException e) {
   29.46 +            // This is internal, can't happen
   29.47 +            throw new AssertionError("Unexpected exception deserializing function", e);
   29.48 +        }
   29.49 +    }
   29.50 +}
    30.1 --- a/src/jdk/nashorn/internal/runtime/CompiledFunction.java	Fri Oct 17 14:24:26 2014 +0200
    30.2 +++ b/src/jdk/nashorn/internal/runtime/CompiledFunction.java	Mon Oct 20 12:06:36 2014 +0200
    30.3 @@ -27,6 +27,7 @@
    30.4  import static jdk.nashorn.internal.lookup.Lookup.MH;
    30.5  import static jdk.nashorn.internal.runtime.UnwarrantedOptimismException.INVALID_PROGRAM_POINT;
    30.6  import static jdk.nashorn.internal.runtime.UnwarrantedOptimismException.isValid;
    30.7 +
    30.8  import java.lang.invoke.CallSite;
    30.9  import java.lang.invoke.MethodHandle;
   30.10  import java.lang.invoke.MethodHandles;
   30.11 @@ -786,6 +787,7 @@
   30.12          // isn't available, we'll use the old one bound into the call site.
   30.13          final OptimismInfo effectiveOptInfo = currentOptInfo != null ? currentOptInfo : oldOptInfo;
   30.14          FunctionNode fn = effectiveOptInfo.reparse();
   30.15 +        final boolean serialized = effectiveOptInfo.isSerialized();
   30.16          final Compiler compiler = effectiveOptInfo.getCompiler(fn, callSiteType, re); //set to non rest-of
   30.17  
   30.18          if (!shouldRecompile) {
   30.19 @@ -793,17 +795,17 @@
   30.20              // recompiled a deoptimized version for an inner invocation.
   30.21              // We still need to do the rest of from the beginning
   30.22              logRecompile("Rest-of compilation [STANDALONE] ", fn, callSiteType, effectiveOptInfo.invalidatedProgramPoints);
   30.23 -            return restOfHandle(effectiveOptInfo, compiler.compile(fn, CompilationPhases.COMPILE_ALL_RESTOF), currentOptInfo != null);
   30.24 +            return restOfHandle(effectiveOptInfo, compiler.compile(fn, serialized ? CompilationPhases.COMPILE_SERIALIZED_RESTOF : CompilationPhases.COMPILE_ALL_RESTOF), currentOptInfo != null);
   30.25          }
   30.26  
   30.27          logRecompile("Deoptimizing recompilation (up to bytecode) ", fn, callSiteType, effectiveOptInfo.invalidatedProgramPoints);
   30.28 -        fn = compiler.compile(fn, CompilationPhases.COMPILE_UPTO_BYTECODE);
   30.29 +        fn = compiler.compile(fn, serialized ? CompilationPhases.RECOMPILE_SERIALIZED_UPTO_BYTECODE : CompilationPhases.COMPILE_UPTO_BYTECODE);
   30.30          log.info("Reusable IR generated");
   30.31  
   30.32          // compile the rest of the function, and install it
   30.33          log.info("Generating and installing bytecode from reusable IR...");
   30.34          logRecompile("Rest-of compilation [CODE PIPELINE REUSE] ", fn, callSiteType, effectiveOptInfo.invalidatedProgramPoints);
   30.35 -        final FunctionNode normalFn = compiler.compile(fn, CompilationPhases.COMPILE_FROM_BYTECODE);
   30.36 +        final FunctionNode normalFn = compiler.compile(fn, CompilationPhases.GENERATE_BYTECODE_AND_INSTALL);
   30.37  
   30.38          if (effectiveOptInfo.data.usePersistentCodeCache()) {
   30.39              final RecompilableScriptFunctionData data = effectiveOptInfo.data;
   30.40 @@ -829,7 +831,7 @@
   30.41          constructor = null; // Will be regenerated when needed
   30.42  
   30.43          log.info("Done: ", invoker);
   30.44 -        final MethodHandle restOf = restOfHandle(effectiveOptInfo, compiler.compile(fn, CompilationPhases.COMPILE_FROM_BYTECODE_RESTOF), canBeDeoptimized);
   30.45 +        final MethodHandle restOf = restOfHandle(effectiveOptInfo, compiler.compile(fn, CompilationPhases.GENERATE_BYTECODE_AND_INSTALL_RESTOF), canBeDeoptimized);
   30.46  
   30.47          // Note that we only adjust the switch point after we set the invoker/constructor. This is important.
   30.48          if (canBeDeoptimized) {
   30.49 @@ -921,6 +923,10 @@
   30.50          FunctionNode reparse() {
   30.51              return data.reparse();
   30.52          }
   30.53 +
   30.54 +        boolean isSerialized() {
   30.55 +            return data.isSerialized();
   30.56 +        }
   30.57      }
   30.58  
   30.59      @SuppressWarnings("unused")
    31.1 --- a/src/jdk/nashorn/internal/runtime/RecompilableScriptFunctionData.java	Fri Oct 17 14:24:26 2014 +0200
    31.2 +++ b/src/jdk/nashorn/internal/runtime/RecompilableScriptFunctionData.java	Mon Oct 20 12:06:36 2014 +0200
    31.3 @@ -43,6 +43,7 @@
    31.4  import jdk.nashorn.internal.codegen.Compiler.CompilationPhases;
    31.5  import jdk.nashorn.internal.codegen.CompilerConstants;
    31.6  import jdk.nashorn.internal.codegen.FunctionSignature;
    31.7 +import jdk.nashorn.internal.codegen.Namespace;
    31.8  import jdk.nashorn.internal.codegen.ObjectClassGenerator.AllocatorDescriptor;
    31.9  import jdk.nashorn.internal.codegen.OptimisticTypesPersistence;
   31.10  import jdk.nashorn.internal.codegen.TypeMap;
   31.11 @@ -79,6 +80,9 @@
   31.12      /** Source from which FunctionNode was parsed. */
   31.13      private transient Source source;
   31.14  
   31.15 +    /** Serialized, compressed form of the AST. Used by split functions as they can't be reparsed from source. */
   31.16 +    private final byte[] serializedAst;
   31.17 +
   31.18      /** Token of this function within the source. */
   31.19      private final long token;
   31.20  
   31.21 @@ -127,6 +131,7 @@
   31.22       * @param nestedFunctions     nested function map
   31.23       * @param externalScopeDepths external scope depths
   31.24       * @param internalSymbols     internal symbols to method, defined in its scope
   31.25 +     * @param serializedAst       a serialized AST representation. Normally only used for split functions.
   31.26       */
   31.27      public RecompilableScriptFunctionData(
   31.28          final FunctionNode functionNode,
   31.29 @@ -134,7 +139,8 @@
   31.30          final AllocatorDescriptor allocationDescriptor,
   31.31          final Map<Integer, RecompilableScriptFunctionData> nestedFunctions,
   31.32          final Map<String, Integer> externalScopeDepths,
   31.33 -        final Set<String> internalSymbols) {
   31.34 +        final Set<String> internalSymbols,
   31.35 +        final byte[] serializedAst) {
   31.36  
   31.37          super(functionName(functionNode),
   31.38                Math.min(functionNode.getParameters().size(), MAX_ARITY),
   31.39 @@ -158,6 +164,7 @@
   31.40              nfn.setParent(this);
   31.41          }
   31.42  
   31.43 +        this.serializedAst = serializedAst;
   31.44          createLogger();
   31.45      }
   31.46  
   31.47 @@ -212,10 +219,7 @@
   31.48       */
   31.49      public int getExternalSymbolDepth(final String symbolName) {
   31.50          final Integer depth = externalScopeDepths.get(symbolName);
   31.51 -        if (depth == null) {
   31.52 -            return -1;
   31.53 -        }
   31.54 -        return depth;
   31.55 +        return depth == null ? -1 : depth;
   31.56      }
   31.57  
   31.58      /**
   31.59 @@ -354,8 +358,15 @@
   31.60          return allocationStrategy.allocate(map);
   31.61      }
   31.62  
   31.63 +    boolean isSerialized() {
   31.64 +        return serializedAst != null;
   31.65 +    }
   31.66 +
   31.67      FunctionNode reparse() {
   31.68 -        // NOTE: If we aren't recompiling the top-level program, we decrease functionNodeId 'cause we'll have a synthetic program node
   31.69 +        if (isSerialized()) {
   31.70 +            return deserialize();
   31.71 +        }
   31.72 +
   31.73          final int descPosition = Token.descPosition(token);
   31.74          final Context context = Context.getContextTrusted();
   31.75          final Parser parser = new Parser(
   31.76 @@ -363,8 +374,10 @@
   31.77              source,
   31.78              new Context.ThrowErrorManager(),
   31.79              isStrict(),
   31.80 +            // source starts at line 0, so even though lineNumber is the correct declaration line, back off
   31.81 +            // one to make it exclusive
   31.82              lineNumber - 1,
   31.83 -            context.getLogger(Parser.class)); // source starts at line 0, so even though lineNumber is the correct declaration line, back off one to make it exclusive
   31.84 +            context.getLogger(Parser.class));
   31.85  
   31.86          if (getFunctionFlag(FunctionNode.IS_ANONYMOUS)) {
   31.87              parser.setFunctionName(functionName);
   31.88 @@ -378,6 +391,17 @@
   31.89          return (isProgram() ? program : extractFunctionFromScript(program)).setName(null, functionName);
   31.90      }
   31.91  
   31.92 +    private FunctionNode deserialize() {
   31.93 +        final ScriptEnvironment env = installer.getOwner();
   31.94 +        final Timing timing = env._timing;
   31.95 +        final long t1 = System.nanoTime();
   31.96 +        try {
   31.97 +            return AstDeserializer.deserialize(serializedAst).initializeDeserialized(source, new Namespace(env.getNamespace()));
   31.98 +        } finally {
   31.99 +            timing.accumulateTime("'Deserialize'", System.nanoTime() - t1);
  31.100 +        }
  31.101 +    }
  31.102 +
  31.103      private boolean getFunctionFlag(final int flag) {
  31.104          return (functionFlags & flag) != 0;
  31.105      }
  31.106 @@ -486,7 +510,8 @@
  31.107  
  31.108          final FunctionNode fn = reparse();
  31.109          final Compiler compiler = getCompiler(fn, actualCallSiteType, runtimeScope);
  31.110 -        final FunctionNode compiledFn = compiler.compile(fn, CompilationPhases.COMPILE_ALL);
  31.111 +        final FunctionNode compiledFn = compiler.compile(fn,
  31.112 +                isSerialized() ? CompilationPhases.COMPILE_ALL_SERIALIZED : CompilationPhases.COMPILE_ALL);
  31.113  
  31.114          if (persist && !compiledFn.getFlag(FunctionNode.HAS_APPLY_TO_CALL_SPECIALIZATION)) {
  31.115              compiler.persistClassInfo(cacheKey, compiledFn);
  31.116 @@ -606,7 +631,7 @@
  31.117  
  31.118      MethodHandle lookupCodeMethod(final Class<?> codeClass, final MethodType targetType) {
  31.119          if (log.isEnabled()) {
  31.120 -            log.info("Looking up ", DebugLogger.quote(name), " type=", targetType);
  31.121 +            log.info("Looking up ", DebugLogger.quote(functionName), " type=", targetType);
  31.122          }
  31.123          return MH.findStatic(LOOKUP, codeClass, functionName, targetType);
  31.124      }
  31.125 @@ -817,6 +842,26 @@
  31.126          return true;
  31.127      }
  31.128  
  31.129 +    /**
  31.130 +     * Restores the {@link #getFunctionFlags()} flags to a function node. During on-demand compilation, we might need
  31.131 +     * to restore flags to a function node that was otherwise not subjected to a full compile pipeline (e.g. its parse
  31.132 +     * was skipped, or it's a nested function of a deserialized function.
  31.133 +     * @param lc current lexical context
  31.134 +     * @param fn the function node to restore flags onto
  31.135 +     * @return the transformed function node
  31.136 +     */
  31.137 +    public FunctionNode restoreFlags(final LexicalContext lc, final FunctionNode fn) {
  31.138 +        assert fn.getId() == functionNodeId;
  31.139 +        FunctionNode newFn = fn.setFlags(lc, functionFlags);
  31.140 +        // This compensates for missing markEval() in case the function contains an inner function
  31.141 +        // that contains eval(), that now we didn't discover since we skipped the inner function.
  31.142 +        if (newFn.hasNestedEval()) {
  31.143 +            assert newFn.hasScopeBlock();
  31.144 +            newFn = newFn.setBody(lc, newFn.getBody().setNeedsScope(null));
  31.145 +        }
  31.146 +        return newFn;
  31.147 +    }
  31.148 +
  31.149      private void readObject(final java.io.ObjectInputStream in) throws IOException, ClassNotFoundException {
  31.150          in.defaultReadObject();
  31.151          createLogger();

mercurial