changeset 1075:2a3502a38f8c

Merge
author lana
date Thu, 23 Oct 2014 13:45:22 -0700
parents bba8e963ccf2 41b5976633aa
children 871cd9451896
files src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/SplitMethodEmitter.java src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/arrays/NoTypeArrayData.java
diffstat 118 files changed, 3126 insertions(+), 1672 deletions(-) [+]
line wrap: on
line diff
--- a/bin/runopt.sh	Thu Oct 23 11:19:29 2014 -0700
+++ b/bin/runopt.sh	Thu Oct 23 13:45:22 2014 -0700
@@ -69,7 +69,6 @@
 
 if [ -z $JFR_FILENAME ]; then
     JFR_FILENAME="./nashorn_$(date|sed "s/ /_/g"|sed "s/:/_/g").jfr"
-    echo "Using default JFR filename: ${JFR_FILENAME}..."
 fi
 
 # Flight recorder
--- a/docs/DEVELOPER_README	Thu Oct 23 11:19:29 2014 -0700
+++ b/docs/DEVELOPER_README	Thu Oct 23 13:45:22 2014 -0700
@@ -25,6 +25,14 @@
 > java -Dnashorn.args="--lazy-complation --log=compiler" large-java-app-with-nashorn.jar 
 > ant -Dnashorn.args="--log=codegen" antjob
 
+SYSTEM PROPERTY: -Dnashorn.args.prepend=<string>
+
+This property behaves like nashorn.args, but adds the given arguments
+before the existing ones instead of after them. Later arguments will
+overwrite earlier ones, so this is useful for setting default arguments
+that can be overwritten.
+
+
 SYSTEM PROPERTY: -Dnashorn.unstable.relink.threshold=x
 
 This property controls how many call site misses are allowed before a 
@@ -42,533 +50,38 @@
 The default value is 0x8000 (32768).
 
 
-SYSTEM PROPERTY: -Dnashorn.compiler.intarithmetic
+SYSTEM PROPERTY: -Dnashorn.serialize.compression=<x>
 
-(and integer arithmetic in general)
+This property sets the compression level used when deflating serialized
+AST structures of anonymous split functions. Valid values range from 0 to 9,
+the default value is 4. Higher values will reduce memory size of serialized
+AST but increase CPU usage required for compression.
 
-<currently disabled - this is being refactored for update releases> 
 
-Arithmetic operations in Nashorn (except bitwise ones) typically
-coerce the operands to doubles (as per the JavaScript spec). To switch
-this off and remain in integer mode, for example for "var x = a&b; var
-y = c&d; var z = x*y;", use this flag. This will force the
-multiplication of variables that are ints to be done with the IMUL
-bytecode and the result "z" to become an int.
-
-WARNING: Note that is is experimental only to ensure that type support
-exists for all primitive types. The generated code is unsound. This
-will be the case until we do optimizations based on it. There is a CR
-in Nashorn to do better range analysis, and ensure that this is only
-done where the operation can't overflow into a wider type. Currently
-no overflow checking is done, so at the moment, until range analysis
-has been completed, this option is turned off.
-
-We've experimented by using int arithmetic for everything and putting
-overflow checks afterwards, which would recompute the operation with
-the correct precision, but have yet to find a configuration where this
-is faster than just using doubles directly, even if the int operation
-does not overflow. Getting access to a JVM intrinsic that does branch
-on overflow would probably alleviate this.
-
-The future:
-
-We are transitioning to an optimistic type system that uses int
-arithmetic everywhere until proven wrong. The problem here is mostly
-catch an overflow exception and rolling back the state to a new method
-with less optimistic assumptions for an operation at a particular
-program point. This will most likely not be in the Java 8.0 release
-but likely end up in an update release
-
-For Java 8, several java.lang.Math methods like addExact, subExact and
-mulExact are available to help us. Experiments intrinsifying these
-show a lot of promise, and we have devised a system that basically
-does on stack replacement with exceptions in bytecode to revert
-erroneous assumptions. An explanation of how this works and what we
-are doing can be found here:
-http://www.slideshare.net/lagergren/lagergren-jvmls2013final
-
-Experiments with this show significant ~x2-3 performance increases on
-pretty much everything, provided that optimistic assumptions don't
-fail much. It will affect warmup time negatively, depending on how
-many erroneous too optimistic assumptions are placed in the code at
-compile time. We don't think this will be much of an issue.
-
-For example for a small benchmark that repeatedly executes this
-method taken from the Crypto Octane benchmark 
-
-function am3(i,x,w,j,c,n) {
-  var this_array = this.array;
-  var w_array    = w.array;
-  var xl = x&0x3fff, xh = x>>14;
-  while(--n >= 0) {
-    var l = this_array[i]&0x3fff;
-    var h = this_array[i++]>>14;
-    var m = xh*l+h*xl;
-    l = xl*l+((m&0x3fff)<<14)+w_array[j]+c;
-    c = (l>>28)+(m>>14)+xh*h;
-    w_array[j++] = l&0xfffffff;
-  }
-
-  return c;
-}
-
-The performance increase more than doubles. We are also working hard
-with the code generation team in the Java Virtual Machine to fix
-things that are lacking in invokedynamic performance, which is another
-area where a lot of ongoing performance work takes place
-
-"Pessimistic" bytecode for am3, guaranteed to be semantically correct:
-
-// access flags 0x9
-  public static am3(Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
-   L0
-    LINENUMBER 12 L0
-    ALOAD 0
-    INVOKEDYNAMIC dyn:getProp|getElem|getMethod:array(Ljava/lang/Object;)Ljava/lang/Object; [
-      // handle kind 0x6 : INVOKESTATIC
-      jdk/nashorn/internal/runtime/linker/Bootstrap.bootstrap((Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;I)Ljava/lang/invoke/CallSite;)
-      // arguments:
-      0
-    ]
-    ASTORE 8
-   L1
-    LINENUMBER 13 L1
-    ALOAD 3
-    INVOKEDYNAMIC dyn:getProp|getElem|getMethod:array(Ljava/lang/Object;)Ljava/lang/Object; [
-      // handle kind 0x6 : INVOKESTATIC
-      jdk/nashorn/internal/runtime/linker/Bootstrap.bootstrap((Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;I)Ljava/lang/invoke/CallSite;)
-      // arguments:
-      0
-    ]
-    ASTORE 9
-   L2
-    LINENUMBER 14 L2
-    ALOAD 2
-    INVOKESTATIC jdk/nashorn/internal/runtime/JSType.toInt32 (Ljava/lang/Object;)I
-    SIPUSH 16383
-    IAND
-    ISTORE 10
-    ALOAD 2
-    INVOKESTATIC jdk/nashorn/internal/runtime/JSType.toInt32 (Ljava/lang/Object;)I
-    BIPUSH 14
-    ISHR
-    ISTORE 11
-   L3
-    LINENUMBER 15 L3
-    GOTO L4
-   L5
-    LINENUMBER 16 L5
-   FRAME FULL [java/lang/Object java/lang/Object java/lang/Object java/lang/Object java/lang/Object java/lang/Object java/lang/Double T java/lang/Object java/lang/Object I I] []
-    ALOAD 8
-    ALOAD 1
-    INVOKEDYNAMIC dyn:getElem|getProp|getMethod(Ljava/lang/Object;Ljava/lang/Object;)I [
-      // handle kind 0x6 : INVOKESTATIC
-      jdk/nashorn/internal/runtime/linker/Bootstrap.bootstrap((Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;I)Ljava/lang/invoke/CallSite;)
-      // arguments:
-      0
-    ]
-    SIPUSH 16383
-    IAND
-    INVOKESTATIC java/lang/Integer.valueOf (I)Ljava/lang/Integer;
-    ASTORE 12
-   L6
-    LINENUMBER 17 L6
-    ALOAD 8
-    ALOAD 1
-    INVOKESTATIC jdk/nashorn/internal/runtime/JSType.toNumber (Ljava/lang/Object;)D
-    DUP2
-    DCONST_1
-    DADD
-    INVOKESTATIC java/lang/Double.valueOf (D)Ljava/lang/Double;
-    ASTORE 1
-    INVOKEDYNAMIC dyn:getElem|getProp|getMethod(Ljava/lang/Object;D)I [
-      // handle kind 0x6 : INVOKESTATIC
-      jdk/nashorn/internal/runtime/linker/Bootstrap.bootstrap((Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;I)Ljava/lang/invoke/CallSite;)
-      // arguments:
-      0
-    ]
-    BIPUSH 14
-    ISHR
-    ISTORE 13
-   L7
-    LINENUMBER 18 L7
-    ILOAD 11
-    I2D
-    ALOAD 12
-    INVOKESTATIC jdk/nashorn/internal/runtime/JSType.toNumber (Ljava/lang/Object;)D
-    DMUL
-    ILOAD 13
-    I2D
-    ILOAD 10
-    I2D
-    DMUL
-    DADD
-    DSTORE 14
-   L8
-    LINENUMBER 19 L8
-    ILOAD 10
-    I2D
-    ALOAD 12
-    INVOKESTATIC jdk/nashorn/internal/runtime/JSType.toNumber (Ljava/lang/Object;)D
-    DMUL
-    DLOAD 14
-    INVOKESTATIC jdk/nashorn/internal/runtime/JSType.toInt32 (D)I
-    SIPUSH 16383
-    IAND
-    BIPUSH 14
-    ISHL
-    I2D
-    DADD
-    ALOAD 9
-    ALOAD 4
-    INVOKEDYNAMIC dyn:getElem|getProp|getMethod(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object; [
-      // handle kind 0x6 : INVOKESTATIC
-      jdk/nashorn/internal/runtime/linker/Bootstrap.bootstrap((Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;I)Ljava/lang/invoke/CallSite;)
-      // arguments:
-      0
-    ]
-    INVOKEDYNAMIC ADD:ODO_D(DLjava/lang/Object;)Ljava/lang/Object; [
-      // handle kind 0x6 : INVOKESTATIC
-      jdk/nashorn/internal/runtime/linker/Bootstrap.runtimeBootstrap((Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;)Ljava/lang/invoke/CallSite;)
-      // arguments: none
-    ]
-    ALOAD 5
-    INVOKEDYNAMIC ADD:OOO_I(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object; [
-      // handle kind 0x6 : INVOKESTATIC
-      jdk/nashorn/internal/runtime/linker/Bootstrap.runtimeBootstrap((Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;)Ljava/lang/invoke/CallSite;)
-      // arguments: none
-    ]
-    ASTORE 12
-   L9
-    LINENUMBER 20 L9
-    ALOAD 12
-    INVOKESTATIC jdk/nashorn/internal/runtime/JSType.toInt32 (Ljava/lang/Object;)I
-    BIPUSH 28
-    ISHR
-    I2D
-    DLOAD 14
-    INVOKESTATIC jdk/nashorn/internal/runtime/JSType.toInt32 (D)I
-    BIPUSH 14
-    ISHR
-    I2D
-    DADD
-    ILOAD 11
-    I2D
-    ILOAD 13
-    I2D
-    DMUL
-    DADD
-    INVOKESTATIC java/lang/Double.valueOf (D)Ljava/lang/Double;
-    ASTORE 5
-   L10
-    LINENUMBER 21 L10
-    ALOAD 9
-    ALOAD 4
-    INVOKESTATIC jdk/nashorn/internal/runtime/JSType.toNumber (Ljava/lang/Object;)D
-    DUP2
-    DCONST_1
-    DADD
-    INVOKESTATIC java/lang/Double.valueOf (D)Ljava/lang/Double;
-    ASTORE 4
-    ALOAD 12
-    INVOKESTATIC jdk/nashorn/internal/runtime/JSType.toInt32 (Ljava/lang/Object;)I
-    LDC 268435455
-    IAND
-    INVOKEDYNAMIC dyn:setElem|setProp(Ljava/lang/Object;DI)V [
-      // handle kind 0x6 : INVOKESTATIC
-      jdk/nashorn/internal/runtime/linker/Bootstrap.bootstrap((Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;I)Ljava/lang/invoke/CallSite;)
-      // arguments:
-      0
-    ]
-   L4
-   FRAME FULL [java/lang/Object java/lang/Object java/lang/Object java/lang/Object java/lang/Object java/lang/Object java/lang/Object T java/lang/Object java/lang/Object I I] []
-    ALOAD 6
-    INVOKESTATIC jdk/nashorn/internal/runtime/JSType.toNumber (Ljava/lang/Object;)D
-    LDC -1.0
-    DADD
-    DUP2
-    INVOKESTATIC java/lang/Double.valueOf (D)Ljava/lang/Double;
-    ASTORE 6
-    DCONST_0
-    DCMPL
-    IFGE L5
-   L11
-    LINENUMBER 24 L11
-    ALOAD 5
-    ARETURN
-
-"Optimistic" bytecode that requires invalidation on e.g overflow. Factor
-x2-3 speedup:
-
-public static am3(Ljava/lang/Object;IILjava/lang/Object;III)I
-   L0
-    LINENUMBER 12 L0
-    ALOAD 0
-    INVOKEDYNAMIC dyn:getProp|getElem|getMethod:array(Ljava/lang/Object;)Ljava/lang/Object; [
-      // handle kind 0x6 : INVOKESTATIC
-      jdk/nashorn/internal/runtime/linker/Bootstrap.bootstrap((Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;I)Ljava/lang/invoke/CallSite;)
-      // arguments:
-      0
-    ]
-    ASTORE 8
-   L1
-    LINENUMBER 13 L1
-    ALOAD 3
-    INVOKEDYNAMIC dyn:getProp|getElem|getMethod:array(Ljava/lang/Object;)Ljava/lang/Object; [
-      // handle kind 0x6 : INVOKESTATIC
-      jdk/nashorn/internal/runtime/linker/Bootstrap.bootstrap((Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;I)Ljava/lang/invoke/CallSite;)
-      // arguments:
-      0
-    ]
-    ASTORE 9
-   L2
-    LINENUMBER 14 L2
-    ILOAD 2
-    SIPUSH 16383
-    IAND
-    ISTORE 10
-    ILOAD 2
-    BIPUSH 14
-    ISHR
-    ISTORE 11
-   L3
-    LINENUMBER 15 L3
-    GOTO L4
-   L5
-    LINENUMBER 16 L5
-   FRAME FULL [java/lang/Object I I java/lang/Object I I I T java/lang/Object java/lang/Object I I] []
-    ALOAD 8
-    ILOAD 1
-    INVOKEDYNAMIC dyn:getElem|getProp|getMethod(Ljava/lang/Object;I)I [
-      // handle kind 0x6 : INVOKESTATIC
-      jdk/nashorn/internal/runtime/linker/Bootstrap.bootstrap((Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;I)Ljava/lang/invoke/CallSite;)
-      // arguments:
-      0
-    ]
-    SIPUSH 16383
-    IAND
-    ISTORE 12
-   L6
-    LINENUMBER 17 L6
-    ALOAD 8
-    ILOAD 1
-    DUP
-    ICONST_1
-    IADD
-    ISTORE 1
-    INVOKEDYNAMIC dyn:getElem|getProp|getMethod(Ljava/lang/Object;I)I [
-      // handle kind 0x6 : INVOKESTATIC
-      jdk/nashorn/internal/runtime/linker/Bootstrap.bootstrap((Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;I)Ljava/lang/invoke/CallSite;)
-      // arguments:
-      0
-    ]
-    BIPUSH 14
-    ISHR
-    ISTORE 13
-   L7
-    LINENUMBER 18 L7
-    ILOAD 11
-    ILOAD 12
-    BIPUSH 8
-    INVOKESTATIC jdk/nashorn/internal/runtime/JSType.mulExact (III)I
-    ILOAD 13
-    ILOAD 10
-    BIPUSH 9
-    INVOKESTATIC jdk/nashorn/internal/runtime/JSType.mulExact (III)I
-    IADD
-    ISTORE 14
-   L8
-    LINENUMBER 19 L8
-    ILOAD 10
-    ILOAD 12
-    BIPUSH 11
-    INVOKESTATIC jdk/nashorn/internal/runtime/JSType.mulExact (III)I
-    ILOAD 14
-    SIPUSH 16383
-    IAND
-    BIPUSH 14
-    ISHL
-    IADD
-    ALOAD 9
-    ILOAD 4
-    INVOKEDYNAMIC dyn:getElem|getProp|getMethod(Ljava/lang/Object;I)I [
-      // handle kind 0x6 : INVOKESTATIC
-      jdk/nashorn/internal/runtime/linker/Bootstrap.bootstrap((Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;I)Ljava/lang/invoke/CallSite;)
-      // arguments:
-      0
-    ]
-    IADD
-    ILOAD 5
-    IADD
-    ISTORE 12
-   L9
-    LINENUMBER 20 L9
-    ILOAD 12
-    BIPUSH 28
-    ISHR
-    ILOAD 14
-    BIPUSH 14
-    ISHR
-    IADD
-    ILOAD 11
-    ILOAD 13
-    BIPUSH 21
-    INVOKESTATIC jdk/nashorn/internal/runtime/JSType.mulExact (III)I
-    IADD
-    ISTORE 5
-   L10
-    LINENUMBER 21 L10
-    ALOAD 9
-    ILOAD 4
-    DUP
-    ICONST_1
-    IADD
-    ISTORE 4
-    ILOAD 12
-    LDC 268435455
-    IAND
-    INVOKEDYNAMIC dyn:setElem|setProp(Ljava/lang/Object;II)V [
-      // handle kind 0x6 : INVOKESTATIC
-      jdk/nashorn/internal/runtime/linker/Bootstrap.bootstrap((Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;I)Ljava/lang/invoke/CallSite;)
-      // arguments:
-      0
-    ]
-   L4
-   FRAME SAME
-    ILOAD 6
-    ICONST_M1
-    IADD
-    DUP
-    ISTORE 6
-    ICONST_0
-    IF_ICMPGE L5
-   L11
-    LINENUMBER 24 L11
-    ILOAD 5
-    IRETURN
-
-
-SYSTEM PROPERTY: -Dnashorn.codegen.debug, -Dnashorn.codegen.debug.trace=<x>
+SYSTEM PROPERTY: -Dnashorn.codegen.debug.trace=<x>
 
 See the description of the codegen logger below.
 
 
-SYSTEM_PROPERTY: -Dnashorn.fields.debug
+SYSTEM PROPERTY: -Dnashorn.fields.objects
 
-See the description on the fields logger below.
+When this property is true, Nashorn will only use object fields for
+AccessorProperties. This means that primitive values must be boxed
+when stored in a field, which is significantly slower than using
+primitive fields.
 
-
-SYSTEM PROPERTY: -Dnashorn.fields.dual
-
-When this property is true, Nashorn will attempt to use primitive
-fields for AccessorProperties (currently just AccessorProperties, not
-spill properties). Memory footprint for script objects will increase,
-as we need to maintain both a primitive field (a long) as well as an
-Object field for the property value. Ints are represented as the 32
-low bits of the long fields. Doubles are represented as the
-doubleToLongBits of their value. This way a single field can be used
-for all primitive types. Packing and unpacking doubles to their bit
-representation is intrinsified by the JVM and extremely fast.
-
-While dual fields in theory runs significantly faster than Object
-fields due to reduction of boxing and memory allocation overhead,
-there is still work to be done to make this a general purpose
-solution. Research is ongoing.
+By default, Nashorn uses dual object and long fields. Ints are
+represented as the 32 low bits of the long fields. Doubles are
+represented as the doubleToLongBits of their value. This way a
+single field can be used for all primitive types. Packing and
+unpacking doubles to their bit representation is intrinsified by
+the JVM and extremely fast.
 
 In the future, this might complement or be replaced by experimental
 feature sun.misc.TaggedArray, which has been discussed on the mlvm
 mailing list. TaggedArrays are basically a way to share data space
 between primitives and references, and have the GC understand this.
 
-As long as only primitive values are written to the fields and enough
-type information exists to make sure that any reads don't have to be
-uselessly boxed and unboxed, this is significantly faster than the
-standard "Objects only" approach that currently is the default. See
-test/examples/dual-fields-micro.js for an example that runs twice as
-fast with dual fields as without them. Here, the compiler, can
-determine that we are dealing with numbers only throughout the entire
-property life span of the properties involved.
-
-If a "real" object (not a boxed primitive) is written to a field that
-has a primitive representation, its callsite is relinked and an Object
-field is used forevermore for that particular field in that
-PropertyMap and its children, even if primitives are later assigned to
-it.
-
-As the amount of compile time type information is very small in a
-dynamic language like JavaScript, it is frequently the case that
-something has to be treated as an object, because we don't know any
-better. In reality though, it is often a boxed primitive is stored to
-an AccessorProperty. The fastest way to handle this soundly is to use
-a callsite typecheck and avoid blowing the field up to an Object. We
-never revert object fields to primitives. Ping-pong:ing back and forth
-between primitive representation and Object representation would cause
-fatal performance overhead, so this is not an option.
-
-For a general application the dual fields approach is still slower
-than objects only fields in some places, about the same in most cases,
-and significantly faster in very few. This is due the program using
-primitives, but we still can't prove it. For example "local_var a =
-call(); field = a;" may very well write a double to the field, but the
-compiler dare not guess a double type if field is a local variable,
-due to bytecode variables being strongly typed and later non
-interchangeable. To get around this, the entire method would have to
-be replaced and a continuation retained to restart from. We believe
-that the next steps we should go through are instead:
-
-1) Implement method specialization based on callsite, as it's quite
-frequently the case that numbers are passed around, but currently our
-function nodes just have object types visible to the compiler. For
-example "var b = 17; func(a,b,17)" is an example where two parameters
-can be specialized, but the main version of func might also be called
-from another callsite with func(x,y,"string").
-
-2) This requires lazy jitting as the functions have to be specialized
-per callsite.
-
-Even though "function square(x) { return x*x }" might look like a
-trivial function that can always only take doubles, this is not
-true. Someone might have overridden the valueOf for x so that the
-toNumber coercion has side effects. To fulfil JavaScript semantics,
-the coercion has to run twice for both terms of the multiplication
-even if they are the same object. This means that call site
-specialization is necessary, not parameter specialization on the form
-"function square(x) { var xd = (double)x; return xd*xd; }", as one
-might first think.
-
-Generating a method specialization for any variant of a function that
-we can determine by types at compile time is a combinatorial explosion
-of byte code (try it e.g. on all the variants of am3 in the Octane
-benchmark crypto.js). Thus, this needs to be lazy
-
-3) Optimistic callsite writes, something on the form
-
-x = y; //x is a field known to be a primitive. y is only an object as
-far as we can tell
-
-turns into
-
-try {
-  x = (int)y;
-} catch (X is not an integer field right now | ClassCastException e) {
-  x = y;
-}
-
-Mini POC shows that this is the key to a lot of dual field performance
-in seemingly trivial micros where one unknown object, in reality
-actually a primitive, foils it for us. Very common pattern. Once we
-are "all primitives", dual fields runs a lot faster than Object fields
-only.
-
-We still have to deal with objects vs primitives for local bytecode
-slots, possibly through code copying and versioning.
-
-The Future:
-
-We expect the usefulness of dual fields to increase significantly
-after the optimistic type system described in the section on 
-integer arithmetic above is implemented.
-
 
 SYSTEM PROPERTY: -Dnashorn.compiler.symbol.trace=[<x>[,*]], 
   -Dnashorn.compiler.symbol.stacktrace=[<x>[,*]]
@@ -628,6 +141,9 @@
 "identical" - this method compares two script objects for reference
 equality. It is a == Java comparison
 
+"equals" - Returns true if two objects are either referentially
+identical or equal as defined by java.lang.Object.equals.
+
 "dumpCounters" - will dump the debug counters' current values to
 stdout.
 
@@ -648,66 +164,66 @@
 when a callsite has to be relinked, due to a previous assumption of
 object layout being invalidated.
 
+"getContext" - return the current Nashorn context.
 
-SYSTEM PROPERTY: -Dnashorn.methodhandles.debug,
--Dnashorn.methodhandles.debug=create
+"equalWithoutType" - Returns true if if the two objects are both
+property maps, and they have identical properties in the same order,
+but allows the properties to differ in their types.
 
-If this property is enabled, each MethodHandle related call that uses
-the java.lang.invoke package gets its MethodHandle intercepted and an
-instrumentation printout of arguments and return value appended to
-it. This shows exactly which method handles are executed and from
-where. (Also MethodTypes and SwitchPoints). This can be augmented with
-more information, for example, instance count, by subclassing or
-further extending the TraceMethodHandleFactory implementation in
-MethodHandleFactory.java.
+"diffPropertyMaps" Returns a diagnostic string representing the difference
+of two property maps.
 
-If the property is specialized with "=create" as its option,
-instrumentation will be shown for method handles upon creation time
-rather than at runtime usage.
+"getClass" - Returns the Java class of an object, or undefined if null.
+
+"toJavaString" - Returns the Java toString representation of an object.
+
+"toIdentString" - Returns a string representation of an object consisting
+of its java class name and hash code.
+
+"getListenerCount" - Return the number of property listeners for a
+script object.
+
+"getEventQueueCapacity" - Get the capacity of the event queue.
+
+"setEventQueueCapacity" - Set the event queue capacity.
+
+"addRuntimeEvent" - Add a runtime event to the runtime event queue.
+The queue has a fixed size (see -Dnashorn.runtime.event.queue.size)
+and the oldest entry will be thrown out of the queue is about to overflow.
+
+"expandEventQueueCapacity" - Expands the event queue capacity,
+or truncates if capacity is lower than current capacity. Then only
+the newest entries are kept.
+
+"clearRuntimeEvents" - Clear the runtime event queue.
+
+"removeRuntimeEvent" - Remove a specific runtime event from the event queue.
+
+"getRuntimeEvents" - Return all runtime events in the queue as an array.
+
+"getLastRuntimeEvent" - Return the last runtime event in the queue.
 
 
 SYSTEM PROPERTY: -Dnashorn.methodhandles.debug.stacktrace
 
-This does the same as nashorn.methodhandles.debug, but when enabled
-also dumps the stack trace for every instrumented method handle
-operation. Warning: This is enormously verbose, but provides a pretty
+This enhances methodhandles logging (see below) to also dump the
+stack trace for every instrumented method handle operation.
+Warning: This is enormously verbose, but provides a pretty
 decent "grep:able" picture of where the calls are coming from.
 
-See the description of the codegen logger below for a more verbose
-description of this option
 
+SYSTEM PROPERTY: -Dnashorn.cce
 
-SYSTEM PROPERTY: -Dnashorn.scriptfunction.specialization.disable
+Setting this system property causes the Nashorn linker to rely on
+ClassCastExceptions for triggering a callsite relink. If not set, the linker
+will add an explicit instanceof guard.
 
-There are several "fast path" implementations of constructors and
-functions in the NativeObject classes that, in their original form,
-take a variable amount of arguments. Said functions are also declared
-to take Object parameters in their original form, as this is what the
-JavaScript specification mandates.
-However, we often know quite a lot more at a callsite of one of these
-functions. For example, Math.min is called with a fixed number (2) of
-integer arguments. The overhead of boxing these ints to Objects and
-folding them into an Object array for the generic varargs Math.min
-function is an order of magnitude slower than calling a specialized
-implementation of Math.min that takes two integers. Specialized
-functions and constructors are identified by the tag
-@SpecializedFunction and @SpecializedConstructor in the Nashorn
-code. The linker will link in the most appropriate (narrowest types,
-right number of types and least number of arguments) specialization if
-specializations are available.
 
-Every ScriptFunction may carry specializations that the linker can
-choose from. This framework will likely be extended for user defined
-functions. The compiler can often infer enough parameter type info
-from callsites for in order to generate simpler versions with less
-generic Object types. This feature depends on future lazy jitting, as
-there tend to be many calls to user defined functions, some where the
-callsite can be specialized, some where we mostly see object
-parameters even at the callsite.
+SYSTEM PROPERTY: -Dnashorn.spill.threshold=<x>
 
-If this system property is set to true, the linker will not attempt to
-use any specialized function or constructor for native objects, but
-just call the generic one.
+This property sets the number of fields in an object from which to use
+generic array based spill storage instead of Java fields. The default value
+is 256.
 
 
 SYSTEM PROPERTY: -Dnashorn.tcs.miss.samplePercent=<x>
@@ -719,8 +235,47 @@
 should be logged. Typically this is set to 1 or 5 (percent). 1% is the
 default value.
 
+SYSTEM PROPERTY: -Dnashorn.persistent.code.cache
 
-SYSTEM_PROPERTY: -Dnashorn.profilefile=<filename>
+This property can be used to set the directory where Nashorn stores
+serialized script classes generated with the -pcc/--persistent-code-cache
+option. The default directory name is "nashorn_code_cache".
+
+
+SYSTEM PROPERTY: -Dnashorn.typeInfo.maxFiles
+
+Maximum number of files to store in the type info cache. The type info cache
+is used to cache type data of JavaScript functions when running with
+optimistic types (-ot/--optimistic-types). There is one file per JavaScript
+function in the cache.
+
+The default value is 0 which means the feature is disabled. Setting this
+to something like 20000 is probably good enough for most applications and
+will usually cap the cache directory to about 80MB presuming a 4kB
+filesystem allocation unit. Set this to "unlimited" to run without limit.
+
+If the value is not 0 or "unlimited", Nashorn will spawn a cleanup thread
+that makes sure the number of files in the cache does not exceed the given
+value by deleting the least recently modified files.
+
+
+SYSTEM PROPERTY: -Dnashorn.typeInfo.cacheDir
+
+This property can be used to set the directory where Nashorn stores the
+type info cache when -Dnashorn.typeInfo.maxFiles is set to a nonzero
+value. The default location is platform specific. On Windows, it is
+"${java.io.tmpdir}\com.oracle.java.NashornTypeInfo". On Linux and
+Solaris it is "~/.cache/com.oracle.java.NashornTypeInfo". On Mac OS X,
+it is "~/Library/Caches/com.oracle.java.NashornTypeInfo".
+
+
+SYSTEM PROPERTY: -Dnashorn.typeInfo.cleanupDelaySeconds=<value>
+
+This sets the delay between cleanups of the typeInfo cache, in seconds.
+The default delay is 20 seconds.
+
+
+SYSTEM PROPERTY: -Dnashorn.profilefile=<filename>
 
 When running with the profile callsite options (-pcs), Nashorn will
 dump profiling data for all callsites to stderr as a shutdown hook. To
@@ -736,6 +291,11 @@
 an implementation based on Joni, the regular expression engine used by
 the JRuby project. The default value for this flag is "joni"
 
+SYSTEM PROPERTY: -Dnashorn.runtime.event.queue.size=<value>
+
+Nashorn provides a fixed sized runtime event queue for debugging purposes.
+See -Dnashorn.debug for methods to access the event queue.
+The default value is 1024.
 
 ===============
 2. The loggers.
@@ -767,7 +327,9 @@
 For example: --log=codegen,fields:finest is equivalent to
 --log=codegen:info --log=fields:finest
 
-The subsystems that currently support logging are:
+The following is an incomplete list of subsystems that currently
+support logging. Look for classes implementing
+jdk.nashorn.internal.runtime.logging.Loggable for more loggers.
 
 
 * compiler
@@ -780,6 +342,14 @@
 use.s
 
 
+* recompile
+
+This logger shows information about recompilation of scripts and
+functions at runtime. Recompilation may happen because a function
+was called with different parameter types, or because an optimistic
+assumption failed while executing a function with -ot/--optimistic-types.
+
+
 * codegen
 
 The code generator is the emitter stage of the code pipeline, and
@@ -836,25 +406,13 @@
 Lower is also responsible for determining control flow information
 like end points.
 
+* symbols
 
-* attr
+The symbols logger tracks the assignment os symbols to identifiers.
 
-The lowering annotates a FunctionNode with symbols for each identifier
-and transforms high level constructs into lower level ones, that the
-CodeGenerator consumes.
+* scopedepths
 
-Lower logging typically outputs things like post pass actions,
-insertions of casts because symbol types have been changed and type
-specialization information. Currently very little info is generated by
-this logger. This will probably change.
-
-
-* finalize
-
-This --log=finalize log option outputs information for type finalization,
-the third tier of the compiler. This means things like placement of 
-specialized scope nodes or explicit conversions. 
-
+This logs the calculation of scope depths for non-local symbols.
 
 * fields
 
@@ -896,6 +454,21 @@
 [time] 
 [time] Total runtime: 11994 ms (Non-runtime: 11027 ms [91%])
 
+* methodhandles
+
+If this logger is enabled, each MethodHandle related call that uses
+the java.lang.invoke package gets its MethodHandle intercepted and an
+instrumentation printout of arguments and return value appended to
+it. This shows exactly which method handles are executed and from
+where. (Also MethodTypes and SwitchPoints).
+
+* classcache
+
+This logger shows information about reusing code classes using the
+in-memory class cache. Nashorn will try to avoid compilation of
+scripts by using existing classes. This can significantly improve
+performance when repeatedly evaluating the same script.
+
 =======================
 3. Undocumented options
 =======================
--- a/make/build-nasgen.xml	Thu Oct 23 11:19:29 2014 -0700
+++ b/make/build-nasgen.xml	Thu Oct 23 13:45:22 2014 -0700
@@ -25,7 +25,7 @@
     <description>Builds and runs nasgen.</description>
     <import file="build.xml"/>
 
-    <target name="build-nasgen" depends="compile-asm">
+    <target name="build-nasgen" depends="prepare">
         <ant inheritAll="false" dir="${basedir}/buildtools/nasgen"
             antfile="build.xml" target="jar"/>
     </target>
--- a/make/build.xml	Thu Oct 23 11:19:29 2014 -0700
+++ b/make/build.xml	Thu Oct 23 13:45:22 2014 -0700
@@ -49,8 +49,6 @@
     <condition property="git.executable" value="/usr/local/bin/git" else="git">
       <available file="/usr/local/bin/git"/>
     </condition>
-    <!-- check if JDK already has ASM classes -->
-    <available property="asm.available" classname="jdk.internal.org.objectweb.asm.Type"/>
     <!-- check if testng.jar is avaiable -->
     <available property="testng.available" file="${file.reference.testng.jar}"/>
     <!-- check if Jemmy ang testng.jar are avaiable -->
@@ -78,8 +76,31 @@
       <istrue value="${jfr}"/>
     </condition>
   </target>
+
+  <!-- check minimum ant version required to be 1.8.4 -->
+  <target name="check-ant-version">
+    <property name="ant.version.required" value="1.8.4"/>
+    <antversion property="ant.current.version" />
+    <fail message="The current ant version, ${ant.current.version}, is too old. Please use 1.8.4 or above.">
+        <condition>
+            <not>
+                <antversion atleast="${ant.version.required}"/>
+            </not>
+        </condition>
+    </fail>
+  </target>
+
+  <target name="check-java-version">
+    <!-- look for a Class that is available only in jdk1.8 or above -->
+    <!-- core/exposed API class is better than an implementation class -->
+    <available property="jdk1.8+" classname="java.util.stream.Stream"/>
+
+    <!-- need jdk1.8 or above -->
+    <fail message="Unsupported Java version: ${ant.java.version}. Please use Java version 1.8 or greater." unless="jdk1.8+">
+    </fail>
+  </target>
   
-  <target name="init" depends="init-conditions, init-cc">
+  <target name="init" depends="check-ant-version, check-java-version, init-conditions, init-cc">
     <!-- extends jvm args -->
     <property name="run.test.jvmargs" value="${run.test.jvmargs.main} ${run.test.cc.jvmargs} ${jfr.options}"/>
     <property name="run.test.jvmargs.octane" value="${run.test.jvmargs.octane.main} ${run.test.cc.jvmargs} ${jfr.options}"/>
@@ -107,19 +128,7 @@
     <delete dir="${dist.dir}"/>
   </target>
 
-  <!-- do it only if ASM is not available -->
-  <target name="compile-asm" depends="prepare" unless="asm.available">
-    <javac srcdir="${jdk.asm.src.dir}"
-           destdir="${build.classes.dir}"
-           excludes="**/optimizer/* **/xml/* **/attrs/*"
-           source="${javac.source}"
-           target="${javac.target}"
-           debug="${javac.debug}"
-           encoding="${javac.encoding}"
-           includeantruntime="false"/>
-  </target>
-
-  <target name="compile" depends="compile-asm" description="Compiles nashorn">
+  <target name="compile" depends="prepare" description="Compiles nashorn">
     <javac srcdir="${src.dir}"
            destdir="${build.classes.dir}"
            classpath="${javac.classpath}"
--- a/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/ApplySpecialization.java	Thu Oct 23 11:19:29 2014 -0700
+++ b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/ApplySpecialization.java	Thu Oct 23 13:45:22 2014 -0700
@@ -27,6 +27,7 @@
 
 import static jdk.nashorn.internal.codegen.CompilerConstants.ARGUMENTS_VAR;
 import static jdk.nashorn.internal.codegen.CompilerConstants.EXPLODED_ARGUMENT_PREFIX;
+
 import java.lang.invoke.MethodType;
 import java.util.ArrayDeque;
 import java.util.ArrayList;
@@ -38,6 +39,7 @@
 import jdk.nashorn.internal.ir.CallNode;
 import jdk.nashorn.internal.ir.Expression;
 import jdk.nashorn.internal.ir.FunctionNode;
+import jdk.nashorn.internal.ir.FunctionNode.CompilationState;
 import jdk.nashorn.internal.ir.IdentNode;
 import jdk.nashorn.internal.ir.LexicalContext;
 import jdk.nashorn.internal.ir.Node;
@@ -321,7 +323,7 @@
 
         explodedArguments.pop();
 
-        return newFunctionNode;
+        return newFunctionNode.setState(lc, CompilationState.BUILTINS_TRANSFORMED);
     }
 
     private static boolean isApply(final CallNode callNode) {
--- a/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/AssignSymbols.java	Thu Oct 23 11:19:29 2014 -0700
+++ b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/AssignSymbols.java	Thu Oct 23 13:45:22 2014 -0700
@@ -76,7 +76,6 @@
 import jdk.nashorn.internal.ir.Node;
 import jdk.nashorn.internal.ir.RuntimeNode;
 import jdk.nashorn.internal.ir.RuntimeNode.Request;
-import jdk.nashorn.internal.ir.SplitNode;
 import jdk.nashorn.internal.ir.Statement;
 import jdk.nashorn.internal.ir.SwitchNode;
 import jdk.nashorn.internal.ir.Symbol;
@@ -135,9 +134,6 @@
         if (!(functionNode.hasScopeBlock() || functionNode.needsParentScope())) {
             functionNode.compilerConstant(SCOPE).setNeedsSlot(false);
         }
-        if (!functionNode.usesReturnSymbol()) {
-            functionNode.compilerConstant(RETURN).setNeedsSlot(false);
-        }
         // Named function expressions that end up not referencing themselves won't need a local slot for the self symbol.
         if(!functionNode.isDeclared() && !functionNode.usesSelfSymbol() && !functionNode.isAnonymous()) {
             final Symbol selfSymbol = functionNode.getBody().getExistingSymbol(functionNode.getIdent().getName());
@@ -1014,7 +1010,7 @@
         boolean previousWasBlock = false;
         for (final Iterator<LexicalContextNode> it = lc.getAllNodes(); it.hasNext();) {
             final LexicalContextNode node = it.next();
-            if (node instanceof FunctionNode || node instanceof SplitNode || isSplitArray(node)) {
+            if (node instanceof FunctionNode || isSplitArray(node)) {
                 // We reached the function boundary or a splitting boundary without seeing a definition for the symbol.
                 // It needs to be in scope.
                 return true;
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/AstSerializer.java	Thu Oct 23 13:45:22 2014 -0700
@@ -0,0 +1,71 @@
+/*
+ * Copyright (c) 2010, 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package jdk.nashorn.internal.codegen;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.ObjectOutputStream;
+import java.util.Collections;
+import java.util.zip.Deflater;
+import java.util.zip.DeflaterOutputStream;
+import jdk.nashorn.internal.ir.Block;
+import jdk.nashorn.internal.ir.FunctionNode;
+import jdk.nashorn.internal.ir.LexicalContext;
+import jdk.nashorn.internal.ir.Node;
+import jdk.nashorn.internal.ir.Statement;
+import jdk.nashorn.internal.ir.visitor.NodeVisitor;
+import jdk.nashorn.internal.runtime.options.Options;
+
+/**
+ * This static utility class performs serialization of FunctionNode ASTs to a byte array.
+ * The format is a standard Java serialization stream, deflated.
+ */
+final class AstSerializer {
+    // Experimentally, we concluded that compression level 4 gives a good tradeoff between serialization speed
+    // and size.
+    private static final int COMPRESSION_LEVEL = Options.getIntProperty("nashorn.serialize.compression", 4);
+    static byte[] serialize(final FunctionNode fn) {
+        final ByteArrayOutputStream out = new ByteArrayOutputStream();
+        try (final ObjectOutputStream oout = new ObjectOutputStream(new DeflaterOutputStream(out,
+                new Deflater(COMPRESSION_LEVEL)))) {
+            oout.writeObject(removeInnerFunctionBodies(fn));
+        } catch (final IOException e) {
+            throw new AssertionError("Unexpected exception serializing function", e);
+        }
+        return out.toByteArray();
+    }
+
+    private static FunctionNode removeInnerFunctionBodies(final FunctionNode fn) {
+        return (FunctionNode)fn.accept(new NodeVisitor<LexicalContext>(new LexicalContext()) {
+            @Override
+            public Node leaveBlock(final Block block) {
+                if (lc.isFunctionBody() && lc.getFunction(block) != lc.getOutermostFunction()) {
+                    return block.setStatements(lc, Collections.<Statement>emptyList());
+                }
+                return super.leaveBlock(block);
+            }
+        });
+    }
+}
--- a/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/ClassEmitter.java	Thu Oct 23 11:19:29 2014 -0700
+++ b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/ClassEmitter.java	Thu Oct 23 13:45:22 2014 -0700
@@ -51,6 +51,7 @@
 import static jdk.nashorn.internal.codegen.CompilerConstants.methodDescriptor;
 import static jdk.nashorn.internal.codegen.CompilerConstants.typeDescriptor;
 import static jdk.nashorn.internal.codegen.CompilerConstants.virtualCallNoLookup;
+
 import java.io.ByteArrayOutputStream;
 import java.io.PrintWriter;
 import java.security.AccessController;
@@ -64,7 +65,6 @@
 import jdk.internal.org.objectweb.asm.util.TraceClassVisitor;
 import jdk.nashorn.internal.codegen.types.Type;
 import jdk.nashorn.internal.ir.FunctionNode;
-import jdk.nashorn.internal.ir.SplitNode;
 import jdk.nashorn.internal.ir.debug.NashornClassReader;
 import jdk.nashorn.internal.ir.debug.NashornTextifier;
 import jdk.nashorn.internal.runtime.Context;
@@ -476,12 +476,6 @@
         methodsStarted.remove(method);
     }
 
-    SplitMethodEmitter method(final SplitNode splitNode, final String methodName, final Class<?> rtype, final Class<?>... ptypes) {
-        methodCount++;
-        methodNames.add(methodName);
-        return new SplitMethodEmitter(this, methodVisitor(EnumSet.of(Flag.PUBLIC, Flag.STATIC), methodName, rtype, ptypes), splitNode);
-    }
-
     /**
      * Add a new method to the class - defaults to public method
      *
--- a/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/CodeGenerator.java	Thu Oct 23 11:19:29 2014 -0700
+++ b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/CodeGenerator.java	Thu Oct 23 13:45:22 2014 -0700
@@ -34,9 +34,7 @@
 import static jdk.nashorn.internal.codegen.CompilerConstants.GET_STRING;
 import static jdk.nashorn.internal.codegen.CompilerConstants.QUICK_PREFIX;
 import static jdk.nashorn.internal.codegen.CompilerConstants.REGEX_PREFIX;
-import static jdk.nashorn.internal.codegen.CompilerConstants.RETURN;
 import static jdk.nashorn.internal.codegen.CompilerConstants.SCOPE;
-import static jdk.nashorn.internal.codegen.CompilerConstants.SPLIT_ARRAY_ARG;
 import static jdk.nashorn.internal.codegen.CompilerConstants.SPLIT_PREFIX;
 import static jdk.nashorn.internal.codegen.CompilerConstants.THIS;
 import static jdk.nashorn.internal.codegen.CompilerConstants.VARARGS;
@@ -99,10 +97,10 @@
 import jdk.nashorn.internal.ir.ForNode;
 import jdk.nashorn.internal.ir.FunctionNode;
 import jdk.nashorn.internal.ir.FunctionNode.CompilationState;
+import jdk.nashorn.internal.ir.GetSplitState;
 import jdk.nashorn.internal.ir.IdentNode;
 import jdk.nashorn.internal.ir.IfNode;
 import jdk.nashorn.internal.ir.IndexNode;
-import jdk.nashorn.internal.ir.JoinPredecessor;
 import jdk.nashorn.internal.ir.JoinPredecessorExpression;
 import jdk.nashorn.internal.ir.JumpStatement;
 import jdk.nashorn.internal.ir.LabelNode;
@@ -121,7 +119,8 @@
 import jdk.nashorn.internal.ir.ReturnNode;
 import jdk.nashorn.internal.ir.RuntimeNode;
 import jdk.nashorn.internal.ir.RuntimeNode.Request;
-import jdk.nashorn.internal.ir.SplitNode;
+import jdk.nashorn.internal.ir.SetSplitState;
+import jdk.nashorn.internal.ir.SplitReturn;
 import jdk.nashorn.internal.ir.Statement;
 import jdk.nashorn.internal.ir.SwitchNode;
 import jdk.nashorn.internal.ir.Symbol;
@@ -493,8 +492,7 @@
         //walk up the chain from starting block and when we bump into the current function boundary, add the external
         //information.
         final FunctionNode fn   = lc.getCurrentFunction();
-        final int          fnId = fn.getId();
-        final int externalDepth = compiler.getScriptFunctionData(fnId).getExternalSymbolDepth(symbol.getName());
+        final int externalDepth = compiler.getScriptFunctionData(fn.getId()).getExternalSymbolDepth(symbol.getName());
 
         //count the number of scopes from this place to the start of the function
 
@@ -554,10 +552,10 @@
     }
 
     MethodEmitter loadBinaryOperands(final BinaryNode binaryNode) {
-        return loadBinaryOperands(binaryNode.lhs(), binaryNode.rhs(), TypeBounds.UNBOUNDED.notWiderThan(binaryNode.getWidestOperandType()), false);
+        return loadBinaryOperands(binaryNode.lhs(), binaryNode.rhs(), TypeBounds.UNBOUNDED.notWiderThan(binaryNode.getWidestOperandType()), false, false);
     }
 
-    private MethodEmitter loadBinaryOperands(final Expression lhs, final Expression rhs, final TypeBounds explicitOperandBounds, final boolean baseAlreadyOnStack) {
+    private MethodEmitter loadBinaryOperands(final Expression lhs, final Expression rhs, final TypeBounds explicitOperandBounds, final boolean baseAlreadyOnStack, final boolean forceConversionSeparation) {
         // ECMAScript 5.1 specification (sections 11.5-11.11 and 11.13) prescribes that when evaluating a binary
         // expression "LEFT op RIGHT", the order of operations must be: LOAD LEFT, LOAD RIGHT, CONVERT LEFT, CONVERT
         // RIGHT, EXECUTE OP. Unfortunately, doing it in this order defeats potential optimizations that arise when we
@@ -574,15 +572,34 @@
         final Type narrowestOperandType = Type.narrowest(Type.widest(lhs.getType(), rhs.getType()), explicitOperandBounds.widest);
         final TypeBounds operandBounds = explicitOperandBounds.notNarrowerThan(narrowestOperandType);
         if (noToPrimitiveConversion(lhs.getType(), explicitOperandBounds.widest) || rhs.isLocal()) {
-            // Can reorder. Combine load and convert into single operations.
-            loadExpression(lhs, operandBounds, baseAlreadyOnStack);
-            loadExpression(rhs, operandBounds, false);
+            // Can reorder. We might still need to separate conversion, but at least we can do it with reordering
+            if (forceConversionSeparation) {
+                // Can reorder, but can't move conversion into the operand as the operation depends on operands
+                // exact types for its overflow guarantees. E.g. with {L}{%I}expr1 {L}* {L}{%I}expr2 we are not allowed
+                // to merge {L}{%I} into {%L}, as that can cause subsequent overflows; test for JDK-8058610 contains
+                // concrete cases where this could happen.
+                final TypeBounds safeConvertBounds = TypeBounds.UNBOUNDED.notNarrowerThan(narrowestOperandType);
+                loadExpression(lhs, safeConvertBounds, baseAlreadyOnStack);
+                method.convert(operandBounds.within(method.peekType()));
+                loadExpression(rhs, safeConvertBounds, false);
+                method.convert(operandBounds.within(method.peekType()));
+            } else {
+                // Can reorder and move conversion into the operand. Combine load and convert into single operations.
+                loadExpression(lhs, operandBounds, baseAlreadyOnStack);
+                loadExpression(rhs, operandBounds, false);
+            }
         } else {
             // Can't reorder. Load and convert separately.
             final TypeBounds safeConvertBounds = TypeBounds.UNBOUNDED.notNarrowerThan(narrowestOperandType);
             loadExpression(lhs, safeConvertBounds, baseAlreadyOnStack);
+            final Type lhsType = method.peekType();
             loadExpression(rhs, safeConvertBounds, false);
-            method.swap().convert(operandBounds.within(method.peekType())).swap().convert(operandBounds.within(method.peekType()));
+            final Type convertedLhsType = operandBounds.within(method.peekType());
+            if (convertedLhsType != lhsType) {
+                // Do it conditionally, so that if conversion is a no-op we don't introduce a SWAP, SWAP.
+                method.swap().convert(convertedLhsType).swap();
+            }
+            method.convert(operandBounds.within(method.peekType()));
         }
         assert Type.generic(method.peekType()) == operandBounds.narrowest;
         assert Type.generic(method.peekType(1)) == operandBounds.narrowest;
@@ -633,19 +650,11 @@
         }
 
         TypeBounds booleanToInt() {
-            return maybeNew(booleanToInt(narrowest), booleanToInt(widest));
+            return maybeNew(CodeGenerator.booleanToInt(narrowest), CodeGenerator.booleanToInt(widest));
         }
 
         TypeBounds objectToNumber() {
-            return maybeNew(objectToNumber(narrowest), objectToNumber(widest));
-        }
-
-        private static Type booleanToInt(final Type t) {
-            return t == Type.BOOLEAN ? Type.INT : t;
-        }
-
-        private static Type objectToNumber(final Type t) {
-            return t.isObject() ? Type.NUMBER : t;
+            return maybeNew(CodeGenerator.objectToNumber(narrowest), CodeGenerator.objectToNumber(widest));
         }
 
         Type within(final Type type) {
@@ -664,6 +673,14 @@
         }
     }
 
+    private static Type booleanToInt(final Type t) {
+        return t == Type.BOOLEAN ? Type.INT : t;
+    }
+
+    private static Type objectToNumber(final Type t) {
+        return t.isObject() ? Type.NUMBER : t;
+    }
+
     MethodEmitter loadExpressionAsType(final Expression expr, final Type type) {
         if(type == Type.BOOLEAN) {
             return loadExpressionAsBoolean(expr);
@@ -1048,6 +1065,13 @@
             }
 
             @Override
+            public boolean enterGetSplitState(final GetSplitState getSplitState) {
+                method.loadScope();
+                method.invoke(Scope.GET_SPLIT_STATE);
+                return false;
+            }
+
+            @Override
             public boolean enterDefault(final Node otherNode) {
                 // Must have handled all expressions that can legally be encountered.
                 throw new AssertionError(otherNode.getClass().getName());
@@ -1219,7 +1243,7 @@
         popScopesUntil(target);
         final Label targetLabel = jump.getTargetLabel(target);
         targetLabel.markAsBreakTarget();
-        method.splitAwareGoto(lc, targetLabel, target);
+        method._goto(targetLabel);
 
         return false;
     }
@@ -2029,10 +2053,10 @@
     }
 
     private void lineNumber(final int lineNumber) {
-        if (lineNumber != lastLineNumber) {
+        if (lineNumber != lastLineNumber && lineNumber != Node.NO_LINE_NUMBER) {
             method.lineNumber(lineNumber);
-        }
-        lastLineNumber = lineNumber;
+            lastLineNumber = lineNumber;
+        }
     }
 
     int getLastLineNumber() {
@@ -2079,13 +2103,14 @@
                 method.begin();
 
                 defineCommonSplitMethodParameters();
-                defineSplitMethodParameter(3, arrayType);
-
-                fixScopeSlot(currentFunction);
+                defineSplitMethodParameter(CompilerConstants.SPLIT_ARRAY_ARG.slot(), arrayType);
+
+                // NOTE: when this is no longer needed, SplitIntoFunctions will no longer have to add IS_SPLIT
+                // to synthetic functions, and FunctionNode.needsCallee() will no longer need to test for isSplit().
+                final int arraySlot = fixScopeSlot(currentFunction, 3);
 
                 lc.enterSplitNode();
 
-                final int arraySlot = SPLIT_ARRAY_ARG.slot();
                 for (int i = arrayUnit.getLo(); i < arrayUnit.getHi(); i++) {
                     method.load(arrayType, arraySlot);
                     storeElement(nodes, elementType, postsets[i]);
@@ -2700,73 +2725,6 @@
         method.convert(newRuntimeNode.getType());
     }
 
-    @Override
-    public boolean enterSplitNode(final SplitNode splitNode) {
-        if(!method.isReachable()) {
-            return false;
-        }
-
-        final CompileUnit splitCompileUnit = splitNode.getCompileUnit();
-
-        final FunctionNode fn   = lc.getCurrentFunction();
-        final String className  = splitCompileUnit.getUnitClassName();
-        final String name       = splitNode.getName();
-
-        final Type returnType = fn.getReturnType();
-
-        final Class<?>   rtype          = fn.getReturnType().getTypeClass();
-        final boolean    needsArguments = fn.needsArguments();
-        final Class<?>[] ptypes         = needsArguments ?
-                new Class<?>[] {ScriptFunction.class, Object.class, ScriptObject.class, ScriptObject.class} :
-                new Class<?>[] {ScriptFunction.class, Object.class, ScriptObject.class};
-
-        final MethodEmitter caller = method;
-        unit = lc.pushCompileUnit(splitCompileUnit);
-
-        final Call splitCall = staticCallNoLookup(
-            className,
-            name,
-            methodDescriptor(rtype, ptypes));
-
-        final MethodEmitter splitEmitter =
-                splitCompileUnit.getClassEmitter().method(
-                        splitNode,
-                        name,
-                        rtype,
-                        ptypes);
-
-        pushMethodEmitter(splitEmitter);
-        method.setFunctionNode(fn);
-
-        assert fn.needsCallee() : "split function should require callee";
-        caller.loadCompilerConstant(CALLEE);
-        caller.loadCompilerConstant(THIS);
-        caller.loadCompilerConstant(SCOPE);
-        if (needsArguments) {
-            caller.loadCompilerConstant(ARGUMENTS);
-        }
-        caller.invoke(splitCall);
-        caller.storeCompilerConstant(RETURN, returnType);
-
-        method.begin();
-
-        defineCommonSplitMethodParameters();
-        if(needsArguments) {
-            defineSplitMethodParameter(3, ARGUMENTS);
-        }
-
-        // Copy scope to its target slot as first thing because the original slot could be used by return symbol.
-        fixScopeSlot(fn);
-
-        final int returnSlot = fn.compilerConstant(RETURN).getSlot(returnType);
-        method.defineBlockLocalVariable(returnSlot, returnSlot + returnType.getSlots());
-        method.loadUndefined(returnType);
-        method.storeCompilerConstant(RETURN, returnType);
-
-        lc.enterSplitNode();
-        return true;
-    }
-
     private void defineCommonSplitMethodParameters() {
         defineSplitMethodParameter(0, CALLEE);
         defineSplitMethodParameter(1, THIS);
@@ -2782,114 +2740,40 @@
         method.onLocalStore(type, slot);
     }
 
-    private void fixScopeSlot(final FunctionNode functionNode) {
+    private int fixScopeSlot(final FunctionNode functionNode, final int extraSlot) {
         // TODO hack to move the scope to the expected slot (needed because split methods reuse the same slots as the root method)
         final int actualScopeSlot = functionNode.compilerConstant(SCOPE).getSlot(SCOPE_TYPE);
         final int defaultScopeSlot = SCOPE.slot();
+        int newExtraSlot = extraSlot;
         if (actualScopeSlot != defaultScopeSlot) {
-            method.defineBlockLocalVariable(actualScopeSlot, actualScopeSlot + 1);
+            if (actualScopeSlot == extraSlot) {
+                newExtraSlot = extraSlot + 1;
+                method.defineBlockLocalVariable(newExtraSlot, newExtraSlot + 1);
+                method.load(Type.OBJECT, extraSlot);
+                method.storeHidden(Type.OBJECT, newExtraSlot);
+            } else {
+                method.defineBlockLocalVariable(actualScopeSlot, actualScopeSlot + 1);
+            }
             method.load(SCOPE_TYPE, defaultScopeSlot);
             method.storeCompilerConstant(SCOPE);
         }
+        return newExtraSlot;
     }
 
     @Override
-    public Node leaveSplitNode(final SplitNode splitNode) {
-        assert method instanceof SplitMethodEmitter;
-        lc.exitSplitNode();
-        final boolean hasReturn = method.hasReturn();
-        final SplitMethodEmitter splitMethod = ((SplitMethodEmitter)method);
-        final List<Label> targets = splitMethod.getExternalTargets();
-        final boolean hasControlFlow = hasReturn || !targets.isEmpty();
-        final List<BreakableNode> targetNodes  = splitMethod.getExternalTargetNodes();
-        final Type returnType = lc.getCurrentFunction().getReturnType();
-
-        try {
-            // Wrap up this method.
-
-            if(method.isReachable()) {
-                if (hasControlFlow) {
-                    method.setSplitState(-1);
-                }
-                method.loadCompilerConstant(RETURN, returnType);
-                method._return(returnType);
-            }
-            method.end();
-
-            lc.releaseSlots();
-
-            unit   = lc.popCompileUnit(splitNode.getCompileUnit());
-            popMethodEmitter();
-
-        } catch (final Throwable t) {
-            Context.printStackTrace(t);
-            final VerifyError e = new VerifyError("Code generation bug in \"" + splitNode.getName() + "\": likely stack misaligned: " + t + " " + getCurrentSource().getName());
-            e.initCause(t);
-            throw e;
-        }
-
-        //no external jump targets or return in switch node
-        if (!hasControlFlow) {
-            return splitNode;
-        }
-
-        // Handle return from split method if there was one.
-        final MethodEmitter caller = method;
-        final int     targetCount = targets.size();
-
-        caller.loadScope();
-        caller.invoke(Scope.GET_SPLIT_STATE);
-
-        final Label breakLabel = new Label("no_split_state");
-        // Split state is -1 for no split state, 0 for return, 1..n+1 for break/continue
-
-        //the common case is that we don't need a switch
-        if (targetCount == 0) {
-            assert hasReturn;
-            caller.ifne(breakLabel);
-            //has to be zero
-            caller.label(new Label("split_return"));
-            caller.loadCompilerConstant(RETURN, returnType);
-            caller._return(returnType);
-            caller.label(breakLabel);
-        } else {
-            assert !targets.isEmpty();
-
-            final int     low         = hasReturn ? 0 : 1;
-            final int     labelCount  = targetCount + 1 - low;
-            final Label[] labels      = new Label[labelCount];
-
-            for (int i = 0; i < labelCount; i++) {
-                labels[i] = new Label(i == 0 ? "split_return" : "split_" + targets.get(i - 1));
-            }
-            caller.tableswitch(low, targetCount, breakLabel, labels);
-            for (int i = low; i <= targetCount; i++) {
-                caller.label(labels[i - low]);
-                if (i == 0) {
-                    caller.loadCompilerConstant(RETURN, returnType);
-                    caller._return(returnType);
-                } else {
-                    final BreakableNode targetNode = targetNodes.get(i - 1);
-                    final Label label = targets.get(i - 1);
-                    if (!lc.isExternalTarget(splitNode, targetNode)) {
-                        final JoinPredecessor jumpOrigin = splitNode.getJumpOrigin(label);
-                        if(jumpOrigin != null) {
-                            method.beforeJoinPoint(jumpOrigin);
-                        }
-                        popScopesUntil(targetNode);
-                    }
-                    caller.splitAwareGoto(lc, label, targetNode);
-                }
-            }
-            caller.label(breakLabel);
-        }
-
-        // If split has a return and caller is itself a split method it needs to propagate the return.
-        if (hasReturn) {
-            caller.setHasReturn();
-        }
-
-        return splitNode;
+    public boolean enterSplitReturn(final SplitReturn splitReturn) {
+        if (method.isReachable()) {
+            method.loadUndefined(lc.getCurrentFunction().getReturnType())._return();
+        }
+        return false;
+    }
+
+    @Override
+    public boolean enterSetSplitState(final SetSplitState setSplitState) {
+        if (method.isReachable()) {
+            method.setSplitState(setSplitState.getState());
+        }
+        return false;
     }
 
     @Override
@@ -3678,13 +3562,15 @@
             void loadStack() {
                 final TypeBounds operandBounds;
                 final boolean isOptimistic = isValid(getProgramPoint());
+                boolean forceConversionSeparation = false;
                 if(isOptimistic) {
                     operandBounds = new TypeBounds(binaryNode.getType(), Type.OBJECT);
                 } else {
                     // Non-optimistic, non-FP +. Allow it to overflow.
                     operandBounds = new TypeBounds(binaryNode.getWidestOperandType(), Type.OBJECT);
+                    forceConversionSeparation = binaryNode.getWidestOperationType().narrowerThan(resultBounds.widest);
                 }
-                loadBinaryOperands(binaryNode.lhs(), binaryNode.rhs(), operandBounds, false);
+                loadBinaryOperands(binaryNode.lhs(), binaryNode.rhs(), operandBounds, false, forceConversionSeparation);
             }
 
             @Override
@@ -3795,12 +3681,21 @@
         @Override
         protected void evaluate() {
             final Expression lhs = assignNode.lhs();
-            final Type widest = assignNode.isTokenType(TokenType.ASSIGN_ADD) ? Type.OBJECT : assignNode.getWidestOperationType();
+            final Expression rhs = assignNode.rhs();
+            final Type widestOperationType = assignNode.getWidestOperationType();
+            final Type widest = assignNode.isTokenType(TokenType.ASSIGN_ADD) ? Type.OBJECT : widestOperationType;
             final TypeBounds bounds = new TypeBounds(assignNode.getType(), widest);
             new OptimisticOperation(assignNode, bounds) {
                 @Override
                 void loadStack() {
-                    loadBinaryOperands(lhs, assignNode.rhs(), bounds, true);
+                    final boolean forceConversionSeparation;
+                    if (isValid(getProgramPoint()) || widestOperationType == Type.NUMBER) {
+                        forceConversionSeparation = false;
+                    } else {
+                        final Type operandType = Type.widest(booleanToInt(objectToNumber(lhs.getType())), booleanToInt(objectToNumber(rhs.getType())));
+                        forceConversionSeparation = operandType.narrowerThan(widestOperationType);
+                    }
+                    loadBinaryOperands(lhs, rhs, bounds, true, forceConversionSeparation);
                 }
                 @Override
                 void consumeStack() {
@@ -3823,7 +3718,7 @@
 
         @Override
         protected void evaluate() {
-            loadBinaryOperands(assignNode.lhs(), assignNode.rhs(), TypeBounds.UNBOUNDED.notWiderThan(assignNode.getWidestOperandType()), true);
+            loadBinaryOperands(assignNode.lhs(), assignNode.rhs(), TypeBounds.UNBOUNDED.notWiderThan(assignNode.getWidestOperandType()), true, false);
             op();
         }
     }
@@ -3946,6 +3841,7 @@
                 @Override
                 void loadStack() {
                     final TypeBounds operandBounds;
+                    boolean forceConversionSeparation = false;
                     if(numericBounds.narrowest == Type.NUMBER) {
                         // Result should be double always. Propagate it into the operands so we don't have lots of I2D
                         // and L2D after operand evaluation.
@@ -3963,9 +3859,10 @@
                             // Non-optimistic, non-FP subtraction or multiplication. Allow them to overflow.
                             operandBounds = new TypeBounds(Type.narrowest(node.getWidestOperandType(),
                                     numericBounds.widest), Type.NUMBER);
+                            forceConversionSeparation = node.getWidestOperationType().narrowerThan(numericBounds.widest);
                         }
                     }
-                    loadBinaryOperands(node.lhs(), node.rhs(), operandBounds, false);
+                    loadBinaryOperands(node.lhs(), node.rhs(), operandBounds, false, forceConversionSeparation);
                 }
 
                 @Override
@@ -4379,11 +4276,7 @@
     private void newFunctionObject(final FunctionNode functionNode, final boolean addInitializer) {
         assert lc.peek() == functionNode;
 
-        final int fnId = functionNode.getId();
-
-        final RecompilableScriptFunctionData data = compiler.getScriptFunctionData(fnId);
-
-        assert data != null : functionNode.getName() + " has no data";
+        final RecompilableScriptFunctionData data = compiler.getScriptFunctionData(functionNode.getId());
 
         if (functionNode.isProgram() && !compiler.isOnDemandCompilation()) {
             final CompileUnit fnUnit = functionNode.getCompileUnit();
--- a/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/CompilationPhase.java	Thu Oct 23 11:19:29 2014 -0700
+++ b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/CompilationPhase.java	Thu Oct 23 13:45:22 2014 -0700
@@ -38,12 +38,11 @@
 import static jdk.nashorn.internal.ir.FunctionNode.CompilationState.SPLIT;
 import static jdk.nashorn.internal.ir.FunctionNode.CompilationState.SYMBOLS_ASSIGNED;
 import static jdk.nashorn.internal.runtime.logging.DebugLogger.quote;
+
 import java.io.PrintWriter;
-import java.util.ArrayList;
 import java.util.EnumSet;
 import java.util.HashMap;
 import java.util.LinkedHashMap;
-import java.util.List;
 import java.util.Map;
 import java.util.Map.Entry;
 import java.util.Set;
@@ -53,10 +52,7 @@
 import jdk.nashorn.internal.ir.FunctionNode.CompilationState;
 import jdk.nashorn.internal.ir.LexicalContext;
 import jdk.nashorn.internal.ir.LiteralNode;
-import jdk.nashorn.internal.ir.LiteralNode.ArrayLiteralNode;
-import jdk.nashorn.internal.ir.LiteralNode.ArrayLiteralNode.ArrayUnit;
 import jdk.nashorn.internal.ir.Node;
-import jdk.nashorn.internal.ir.SplitNode;
 import jdk.nashorn.internal.ir.debug.ASTWriter;
 import jdk.nashorn.internal.ir.debug.PrintVisitor;
 import jdk.nashorn.internal.ir.visitor.NodeVisitor;
@@ -81,7 +77,7 @@
                 PARSED)) {
         @Override
         FunctionNode transform(final Compiler compiler, final CompilationPhases phases, final FunctionNode fn) {
-            return (FunctionNode)fn.accept(new FoldConstants(compiler));
+            return transformFunction(fn, new FoldConstants(compiler));
         }
 
         @Override
@@ -104,7 +100,7 @@
                 CONSTANT_FOLDED)) {
         @Override
         FunctionNode transform(final Compiler compiler, final CompilationPhases phases, final FunctionNode fn) {
-            return (FunctionNode)fn.accept(new Lower(compiler));
+            return transformFunction(fn, new Lower(compiler));
         }
 
         @Override
@@ -118,23 +114,6 @@
      * optimistic ops a program point so that an UnwarrantedException knows from where
      * a guess went wrong when creating the continuation to roll back this execution
      */
-    PROGRAM_POINT_PHASE(
-            EnumSet.of(
-                INITIALIZED,
-                PARSED,
-                CONSTANT_FOLDED,
-                LOWERED)) {
-        @Override
-        FunctionNode transform(final Compiler compiler, final CompilationPhases phases, final FunctionNode fn) {
-            return (FunctionNode)fn.accept(new ProgramPoints());
-        }
-
-        @Override
-        public String toString() {
-            return "'Program Point Calculation'";
-        }
-    },
-
     TRANSFORM_BUILTINS_PHASE(
             EnumSet.of(
                     INITIALIZED,
@@ -144,13 +123,7 @@
         //we only do this if we have a param type map, otherwise this is not a specialized recompile
         @Override
         FunctionNode transform(final Compiler compiler, final CompilationPhases phases, final FunctionNode fn) {
-            final FunctionNode newFunctionNode = (FunctionNode)fn.accept(new ApplySpecialization(compiler));
-            return (FunctionNode)newFunctionNode.accept(new NodeVisitor<LexicalContext>(new LexicalContext()) {
-                @Override
-                public Node leaveFunctionNode(final FunctionNode node) {
-                    return node.setState(lc, BUILTINS_TRANSFORMED);
-                }
-            });
+            return setStates(transformFunction(fn, new ApplySpecialization(compiler)), BUILTINS_TRANSFORMED);
         }
 
         @Override
@@ -177,7 +150,7 @@
             FunctionNode newFunctionNode;
 
             //ensure elementTypes, postsets and presets exist for splitter and arraynodes
-            newFunctionNode = (FunctionNode)fn.accept(new NodeVisitor<LexicalContext>(new LexicalContext()) {
+            newFunctionNode = transformFunction(fn, new NodeVisitor<LexicalContext>(new LexicalContext()) {
                 @Override
                 public LiteralNode<?> leaveLiteralNode(final LiteralNode<?> literalNode) {
                     return literalNode.initialize(lc);
@@ -185,7 +158,7 @@
             });
 
             newFunctionNode = new Splitter(compiler, newFunctionNode, outermostCompileUnit).split(newFunctionNode, true);
-
+            newFunctionNode = transformFunction(newFunctionNode, new SplitIntoFunctions(compiler));
             assert newFunctionNode.getCompileUnit() == outermostCompileUnit : "fn=" + fn.getName() + ", fn.compileUnit (" + newFunctionNode.getCompileUnit() + ") != " + outermostCompileUnit;
             assert newFunctionNode.isStrict() == compiler.isStrict() : "functionNode.isStrict() != compiler.isStrict() for " + quote(newFunctionNode.getName());
 
@@ -198,6 +171,52 @@
         }
     },
 
+    PROGRAM_POINT_PHASE(
+            EnumSet.of(
+                    INITIALIZED,
+                    PARSED,
+                    CONSTANT_FOLDED,
+                    LOWERED,
+                    BUILTINS_TRANSFORMED,
+                    SPLIT)) {
+        @Override
+        FunctionNode transform(final Compiler compiler, final CompilationPhases phases, final FunctionNode fn) {
+            return transformFunction(fn, new ProgramPoints());
+        }
+
+        @Override
+        public String toString() {
+            return "'Program Point Calculation'";
+        }
+    },
+
+    SERIALIZE_SPLIT_PHASE(
+            EnumSet.of(
+                    INITIALIZED,
+                    PARSED,
+                    CONSTANT_FOLDED,
+                    LOWERED,
+                    BUILTINS_TRANSFORMED,
+                    SPLIT)) {
+        @Override
+        FunctionNode transform(final Compiler compiler, final CompilationPhases phases, final FunctionNode fn) {
+            return transformFunction(fn, new NodeVisitor<LexicalContext>(new LexicalContext()) {
+                @Override
+                public boolean enterFunctionNode(final FunctionNode functionNode) {
+                    if (functionNode.isSplit()) {
+                        compiler.serializeAst(functionNode);
+                    }
+                    return true;
+                }
+            });
+        }
+
+        @Override
+        public String toString() {
+            return "'Serialize Split Functions'";
+        }
+    },
+
     SYMBOL_ASSIGNMENT_PHASE(
             EnumSet.of(
                     INITIALIZED,
@@ -208,7 +227,7 @@
                     SPLIT)) {
         @Override
         FunctionNode transform(final Compiler compiler, final CompilationPhases phases, final FunctionNode fn) {
-            return (FunctionNode)fn.accept(new AssignSymbols(compiler));
+            return transformFunction(fn, new AssignSymbols(compiler));
         }
 
         @Override
@@ -228,7 +247,7 @@
                     SYMBOLS_ASSIGNED)) {
         @Override
         FunctionNode transform(final Compiler compiler, final CompilationPhases phases, final FunctionNode fn) {
-            return (FunctionNode)fn.accept(new FindScopeDepths(compiler));
+            return transformFunction(fn, new FindScopeDepths(compiler));
         }
 
         @Override
@@ -250,7 +269,7 @@
         @Override
         FunctionNode transform(final Compiler compiler, final CompilationPhases phases, final FunctionNode fn) {
             if (compiler.useOptimisticTypes()) {
-                return (FunctionNode)fn.accept(new OptimisticTypesCalculator(compiler));
+                return transformFunction(fn, new OptimisticTypesCalculator(compiler));
             }
             return setStates(fn, OPTIMISTIC_TYPES_ASSIGNED);
         }
@@ -274,8 +293,7 @@
                     OPTIMISTIC_TYPES_ASSIGNED)) {
         @Override
         FunctionNode transform(final Compiler compiler, final CompilationPhases phases, final FunctionNode fn) {
-            final FunctionNode newFunctionNode = (FunctionNode)fn.accept(new LocalVariableTypesCalculator(compiler));
-
+            final FunctionNode newFunctionNode = transformFunction(fn, new LocalVariableTypesCalculator(compiler));
             final ScriptEnvironment senv = compiler.getScriptEnvironment();
             final PrintWriter       err  = senv.getErr();
 
@@ -330,13 +348,7 @@
 
             for (final CompileUnit oldUnit : compiler.getCompileUnits()) {
                 assert map.get(oldUnit) == null;
-                final StringBuilder sb = new StringBuilder(compiler.nextCompileUnitName());
-                if (phases.isRestOfCompilation()) {
-                    sb.append("$restOf");
-                }
-                //it's ok to not copy the initCount, methodCount and clinitCount here, as codegen is what
-                //fills those out anyway. Thus no need for a copy constructor
-                final CompileUnit newUnit = compiler.createCompileUnit(sb.toString(), oldUnit.getWeight());
+                final CompileUnit newUnit = createNewCompileUnit(compiler, phases);
                 log.fine("Creating new compile unit ", oldUnit, " => ", newUnit);
                 map.put(oldUnit, newUnit);
                 assert newUnit != null;
@@ -350,47 +362,10 @@
             //replace old compile units in function nodes, if any are assigned,
             //for example by running the splitter on this function node in a previous
             //partial code generation
-            final FunctionNode newFunctionNode = (FunctionNode)fn.accept(new NodeVisitor<LexicalContext>(new LexicalContext()) {
+            final FunctionNode newFunctionNode = transformFunction(fn, new ReplaceCompileUnits() {
                 @Override
-                public Node leaveFunctionNode(final FunctionNode node) {
-                    final CompileUnit oldUnit = node.getCompileUnit();
-                    assert oldUnit != null : "no compile unit in function node";
-
-                    final CompileUnit newUnit = map.get(oldUnit);
-                    assert newUnit != null : "old unit has no mapping to new unit " + oldUnit;
-
-                    log.fine("Replacing compile unit: ", oldUnit, " => ", newUnit, " in ", quote(node.getName()));
-                    return node.setCompileUnit(lc, newUnit).setState(lc, CompilationState.COMPILE_UNITS_REUSED);
-                }
-
-                @Override
-                public Node leaveSplitNode(final SplitNode node) {
-                    final CompileUnit oldUnit = node.getCompileUnit();
-                    assert oldUnit != null : "no compile unit in function node";
-
-                    final CompileUnit newUnit = map.get(oldUnit);
-                    assert newUnit != null : "old unit has no mapping to new unit " + oldUnit;
-
-                    log.fine("Replacing compile unit: ", oldUnit, " => ", newUnit, " in ", quote(node.getName()));
-                    return node.setCompileUnit(lc, newUnit);
-                }
-
-                @Override
-                public Node leaveLiteralNode(final LiteralNode<?> node) {
-                    if (node instanceof ArrayLiteralNode) {
-                        final ArrayLiteralNode aln = (ArrayLiteralNode)node;
-                        if (aln.getUnits() == null) {
-                            return node;
-                        }
-                        final List<ArrayUnit> newArrayUnits = new ArrayList<>();
-                        for (final ArrayUnit au : aln.getUnits()) {
-                            final CompileUnit newUnit = map.get(au.getCompileUnit());
-                            assert newUnit != null;
-                            newArrayUnits.add(new ArrayUnit(newUnit, au.getLo(), au.getHi()));
-                        }
-                        return aln.setUnits(lc, newArrayUnits);
-                    }
-                    return node;
+                CompileUnit getReplacement(CompileUnit original) {
+                    return map.get(original);
                 }
 
                 @Override
@@ -408,7 +383,59 @@
         }
     },
 
-     /**
+    REINITIALIZE_SERIALIZED(
+            EnumSet.of(
+                    INITIALIZED,
+                    PARSED,
+                    CONSTANT_FOLDED,
+                    LOWERED,
+                    BUILTINS_TRANSFORMED,
+                    SPLIT)) {
+        @Override
+        FunctionNode transform(final Compiler compiler, final CompilationPhases phases, final FunctionNode fn) {
+            final Set<CompileUnit> unitSet = CompileUnit.createCompileUnitSet();
+            final Map<CompileUnit, CompileUnit> unitMap = new HashMap<>();
+
+            // Ensure that the FunctionNode's compile unit is the first in the list of new units. Install phase
+            // will use that as the root class.
+            createCompileUnit(fn.getCompileUnit(), unitSet, unitMap, compiler, phases);
+
+            final FunctionNode newFn = transformFunction(fn, new ReplaceCompileUnits() {
+                @Override
+                CompileUnit getReplacement(final CompileUnit oldUnit) {
+                    final CompileUnit existing = unitMap.get(oldUnit);
+                    if (existing != null) {
+                        return existing;
+                    }
+                    return createCompileUnit(oldUnit, unitSet, unitMap, compiler, phases);
+                }
+
+                @Override
+                public Node leaveFunctionNode(final FunctionNode fn2) {
+                    return super.leaveFunctionNode(
+                            // restore flags for deserialized nested function nodes
+                            compiler.getScriptFunctionData(fn2.getId()).restoreFlags(lc, fn2));
+                };
+            });
+            compiler.replaceCompileUnits(unitSet);
+            return newFn;
+        }
+
+        private CompileUnit createCompileUnit(final CompileUnit oldUnit, final Set<CompileUnit> unitSet,
+                final Map<CompileUnit, CompileUnit> unitMap, final Compiler compiler, final CompilationPhases phases) {
+            final CompileUnit newUnit = createNewCompileUnit(compiler, phases);
+            unitMap.put(oldUnit, newUnit);
+            unitSet.add(newUnit);
+            return newUnit;
+        }
+
+        @Override
+        public String toString() {
+            return "'Deserialize'";
+        }
+    },
+
+    /**
      * Bytecode generation:
      *
      * Generate the byte code class(es) resulting from the compiled FunctionNode
@@ -443,7 +470,7 @@
             try {
                 // Explicitly set BYTECODE_GENERATED here; it can not be set in case of skipping codegen for :program
                 // in the lazy + optimistic world. See CodeGenerator.skipFunction().
-                newFunctionNode = ((FunctionNode)newFunctionNode.accept(codegen)).setState(null, BYTECODE_GENERATED);
+                newFunctionNode = transformFunction(newFunctionNode, codegen).setState(null, BYTECODE_GENERATED);
                 codegen.generateScopeCalls();
             } catch (final VerifyError e) {
                 if (senv._verify_code || senv._print_code) {
@@ -615,7 +642,7 @@
         if (!AssertsEnabled.assertsEnabled()) {
             return functionNode;
         }
-        return (FunctionNode)functionNode.accept(new NodeVisitor<LexicalContext>(new LexicalContext()) {
+        return transformFunction(functionNode, new NodeVisitor<LexicalContext>(new LexicalContext()) {
             @Override
             public Node leaveFunctionNode(final FunctionNode fn) {
                 return fn.setState(lc, state);
@@ -701,4 +728,17 @@
         return end(compiler, transform(compiler, phases, begin(compiler, functionNode)));
     }
 
+    private static FunctionNode transformFunction(final FunctionNode fn, final NodeVisitor<?> visitor) {
+        return (FunctionNode) fn.accept(visitor);
+    }
+
+    private static CompileUnit createNewCompileUnit(final Compiler compiler, final CompilationPhases phases) {
+        final StringBuilder sb = new StringBuilder(compiler.nextCompileUnitName());
+        if (phases.isRestOfCompilation()) {
+            sb.append("$restOf");
+        }
+        //it's ok to not copy the initCount, methodCount and clinitCount here, as codegen is what
+        //fills those out anyway. Thus no need for a copy constructor
+        return compiler.createCompileUnit(sb.toString(), 0);
+    }
 }
--- a/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/CompileUnit.java	Thu Oct 23 11:19:29 2014 -0700
+++ b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/CompileUnit.java	Thu Oct 23 13:45:22 2014 -0700
@@ -25,24 +25,31 @@
 
 package jdk.nashorn.internal.codegen;
 
+import java.io.Serializable;
 import java.util.Set;
 import java.util.TreeSet;
+import jdk.nashorn.internal.ir.CompileUnitHolder;
 
 /**
- * Used to track split class compilation.
- */
-public final class CompileUnit implements Comparable<CompileUnit> {
+  * Used to track split class compilation. Note that instances of the class are serializable, but all fields are
+  * transient, making the serialized version of the class only useful for tracking the referential topology of other
+  * AST nodes referencing the same or different compile units. We do want to preserve this topology though as
+  * {@link CompileUnitHolder}s in a deserialized AST will undergo reinitialization.
+  */
+public final class CompileUnit implements Comparable<CompileUnit>, Serializable {
+    private static final long serialVersionUID = 1L;
+
     /** Current class name */
-    private final String className;
+    private transient final String className;
 
     /** Current class generator */
-    private ClassEmitter classEmitter;
+    private transient ClassEmitter classEmitter;
 
-    private long weight;
+    private transient long weight;
 
-    private Class<?> clazz;
+    private transient Class<?> clazz;
 
-    private boolean isUsed;
+    private transient boolean isUsed;
 
     private static int emittedUnitCount;
 
@@ -122,14 +129,6 @@
     }
 
     /**
-     * Get the current weight of the compile unit.
-     * @return the unit's weight
-     */
-    long getWeight() {
-        return weight;
-    }
-
-    /**
      * Check if this compile unit can hold {@code weight} more units of weight
      * @param w weight to check if can be added
      * @return true if weight fits in this compile unit
@@ -155,7 +154,7 @@
     }
 
     private static String shortName(final String name) {
-        return name.lastIndexOf('/') == -1 ? name : name.substring(name.lastIndexOf('/') + 1);
+        return name == null ? null : name.lastIndexOf('/') == -1 ? name : name.substring(name.lastIndexOf('/') + 1);
     }
 
     @Override
--- a/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/Compiler.java	Thu Oct 23 11:19:29 2014 -0700
+++ b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/Compiler.java	Thu Oct 23 13:45:22 2014 -0700
@@ -32,15 +32,16 @@
 import static jdk.nashorn.internal.codegen.CompilerConstants.THIS;
 import static jdk.nashorn.internal.codegen.CompilerConstants.VARARGS;
 import static jdk.nashorn.internal.runtime.logging.DebugLogger.quote;
+
 import java.io.File;
 import java.lang.invoke.MethodType;
+import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collections;
 import java.util.Comparator;
 import java.util.HashMap;
 import java.util.Iterator;
 import java.util.LinkedHashMap;
-import java.util.LinkedList;
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
@@ -159,75 +160,142 @@
      */
     private static final int COMPILE_UNIT_NAME_BUFFER_SIZE = 32;
 
+    private final Map<Integer, byte[]> serializedAsts = new HashMap<>();
+
     /**
      * Compilation phases that a compilation goes through
      */
     public static class CompilationPhases implements Iterable<CompilationPhase> {
 
-        /** Singleton that describes a standard eager compilation - this includes code installation */
-        public final static CompilationPhases COMPILE_ALL = new CompilationPhases(
-                "Compile all",
-                new CompilationPhase[] {
-                        CompilationPhase.CONSTANT_FOLDING_PHASE,
-                        CompilationPhase.LOWERING_PHASE,
-                        CompilationPhase.PROGRAM_POINT_PHASE,
-                        CompilationPhase.TRANSFORM_BUILTINS_PHASE,
-                        CompilationPhase.SPLITTING_PHASE,
-                        CompilationPhase.SYMBOL_ASSIGNMENT_PHASE,
-                        CompilationPhase.SCOPE_DEPTH_COMPUTATION_PHASE,
-                        CompilationPhase.OPTIMISTIC_TYPE_ASSIGNMENT_PHASE,
-                        CompilationPhase.LOCAL_VARIABLE_TYPE_CALCULATION_PHASE,
-                        CompilationPhase.BYTECODE_GENERATION_PHASE,
-                        CompilationPhase.INSTALL_PHASE
-                });
+        /**
+         * Singleton that describes compilation up to the phase where a function can be serialized.
+         */
+        private final static CompilationPhases COMPILE_UPTO_SERIALIZABLE = new CompilationPhases(
+                "Common initial phases",
+                CompilationPhase.CONSTANT_FOLDING_PHASE,
+                CompilationPhase.LOWERING_PHASE,
+                CompilationPhase.TRANSFORM_BUILTINS_PHASE,
+                CompilationPhase.SPLITTING_PHASE,
+                CompilationPhase.PROGRAM_POINT_PHASE,
+                CompilationPhase.SERIALIZE_SPLIT_PHASE
+                );
 
-        /** Compile all for a rest of method */
-        public final static CompilationPhases COMPILE_ALL_RESTOF =
-                COMPILE_ALL.setDescription("Compile all, rest of").addAfter(CompilationPhase.LOCAL_VARIABLE_TYPE_CALCULATION_PHASE, CompilationPhase.REUSE_COMPILE_UNITS_PHASE);
+        private final static CompilationPhases COMPILE_SERIALIZABLE_UPTO_BYTECODE = new CompilationPhases(
+                "After common phases, before bytecode generator",
+                CompilationPhase.SYMBOL_ASSIGNMENT_PHASE,
+                CompilationPhase.SCOPE_DEPTH_COMPUTATION_PHASE,
+                CompilationPhase.OPTIMISTIC_TYPE_ASSIGNMENT_PHASE,
+                CompilationPhase.LOCAL_VARIABLE_TYPE_CALCULATION_PHASE
+                );
 
-        /** Singleton that describes a standard eager compilation, but no installation, for example used by --compile-only */
-        public final static CompilationPhases COMPILE_ALL_NO_INSTALL =
-                COMPILE_ALL.
-                removeLast().
-                setDescription("Compile without install");
-
-        /** Singleton that describes compilation up to the CodeGenerator, but not actually generating code */
-        public final static CompilationPhases COMPILE_UPTO_BYTECODE =
-                COMPILE_ALL.
-                removeLast().
-                removeLast().
-                setDescription("Compile upto bytecode");
+        /**
+         * Singleton that describes additional steps to be taken after deserializing, all the way up to (but not
+         * including) generating and installing code.
+         */
+        public final static CompilationPhases RECOMPILE_SERIALIZED_UPTO_BYTECODE = new CompilationPhases(
+                "Recompile serialized function up to bytecode",
+                CompilationPhase.REINITIALIZE_SERIALIZED,
+                COMPILE_SERIALIZABLE_UPTO_BYTECODE
+                );
 
         /**
          * Singleton that describes back end of method generation, given that we have generated the normal
          * method up to CodeGenerator as in {@link CompilationPhases#COMPILE_UPTO_BYTECODE}
          */
-        public final static CompilationPhases COMPILE_FROM_BYTECODE = new CompilationPhases(
+        public final static CompilationPhases GENERATE_BYTECODE_AND_INSTALL = new CompilationPhases(
                 "Generate bytecode and install",
-                new CompilationPhase[] {
-                        CompilationPhase.BYTECODE_GENERATION_PHASE,
-                        CompilationPhase.INSTALL_PHASE
-                });
+                CompilationPhase.BYTECODE_GENERATION_PHASE,
+                CompilationPhase.INSTALL_PHASE
+                );
+
+        /** Singleton that describes compilation up to the CodeGenerator, but not actually generating code */
+        public final static CompilationPhases COMPILE_UPTO_BYTECODE = new CompilationPhases(
+                "Compile upto bytecode",
+                COMPILE_UPTO_SERIALIZABLE,
+                COMPILE_SERIALIZABLE_UPTO_BYTECODE);
+
+        /** Singleton that describes a standard eager compilation, but no installation, for example used by --compile-only */
+        public final static CompilationPhases COMPILE_ALL_NO_INSTALL = new CompilationPhases(
+                "Compile without install",
+                COMPILE_UPTO_BYTECODE,
+                CompilationPhase.BYTECODE_GENERATION_PHASE);
+
+        /** Singleton that describes a standard eager compilation - this includes code installation */
+        public final static CompilationPhases COMPILE_ALL = new CompilationPhases(
+                "Full eager compilation",
+                COMPILE_UPTO_BYTECODE,
+                GENERATE_BYTECODE_AND_INSTALL);
+
+        /** Singleton that describes a full compilation - this includes code installation - from serialized state*/
+        public final static CompilationPhases COMPILE_ALL_SERIALIZED = new CompilationPhases(
+                "Eager compilation from serializaed state",
+                RECOMPILE_SERIALIZED_UPTO_BYTECODE,
+                GENERATE_BYTECODE_AND_INSTALL);
 
         /**
          * Singleton that describes restOf method generation, given that we have generated the normal
          * method up to CodeGenerator as in {@link CompilationPhases#COMPILE_UPTO_BYTECODE}
          */
-        public final static CompilationPhases COMPILE_FROM_BYTECODE_RESTOF =
-                COMPILE_FROM_BYTECODE.
-                addFirst(CompilationPhase.REUSE_COMPILE_UNITS_PHASE).
-                setDescription("Generate bytecode and install - RestOf method");
+        public final static CompilationPhases GENERATE_BYTECODE_AND_INSTALL_RESTOF = new CompilationPhases(
+                "Generate bytecode and install - RestOf method",
+                CompilationPhase.REUSE_COMPILE_UNITS_PHASE,
+                GENERATE_BYTECODE_AND_INSTALL);
+
+        /** Compile all for a rest of method */
+        public final static CompilationPhases COMPILE_ALL_RESTOF = new CompilationPhases(
+                "Compile all, rest of",
+                COMPILE_UPTO_BYTECODE,
+                GENERATE_BYTECODE_AND_INSTALL_RESTOF);
+
+        /** Compile from serialized for a rest of method */
+        public final static CompilationPhases COMPILE_SERIALIZED_RESTOF = new CompilationPhases(
+                "Compile serialized, rest of",
+                RECOMPILE_SERIALIZED_UPTO_BYTECODE,
+                GENERATE_BYTECODE_AND_INSTALL_RESTOF);
 
         private final List<CompilationPhase> phases;
 
         private final String desc;
 
         private CompilationPhases(final String desc, final CompilationPhase... phases) {
+            this(desc, Arrays.asList(phases));
+        }
+
+        private CompilationPhases(final String desc, final CompilationPhases base, final CompilationPhase... phases) {
+            this(desc, concat(base.phases, Arrays.asList(phases)));
+        }
+
+        private CompilationPhases(final String desc, final CompilationPhase first, final CompilationPhases rest) {
+            this(desc, concat(Collections.singletonList(first), rest.phases));
+        }
+
+        private CompilationPhases(final String desc, final CompilationPhases base) {
+            this(desc, base.phases);
+        }
+
+        private CompilationPhases(final String desc, final CompilationPhases... bases) {
+            this(desc, concatPhases(bases));
+        }
+
+        private CompilationPhases(final String desc, final List<CompilationPhase> phases) {
             this.desc = desc;
+            this.phases = phases;
+        }
 
-            final List<CompilationPhase> newPhases = new LinkedList<>();
-            newPhases.addAll(Arrays.asList(phases));
-            this.phases = Collections.unmodifiableList(newPhases);
+        private static List<CompilationPhase> concatPhases(final CompilationPhases[] bases) {
+            final ArrayList<CompilationPhase> l = new ArrayList<>();
+            for(final CompilationPhases base: bases) {
+                l.addAll(base.phases);
+            }
+            l.trimToSize();
+            return l;
+        }
+
+        private static <T> List<T> concat(final List<T> l1, final List<T> l2) {
+            final ArrayList<T> l = new ArrayList<>(l1);
+            l.addAll(l2);
+            l.trimToSize();
+            return l;
         }
 
         @Override
@@ -235,45 +303,6 @@
             return "'" + desc + "' " + phases.toString();
         }
 
-        private CompilationPhases setDescription(final String desc) {
-            return new CompilationPhases(desc, phases.toArray(new CompilationPhase[phases.size()]));
-        }
-
-        private CompilationPhases removeLast() {
-            final LinkedList<CompilationPhase> list = new LinkedList<>(phases);
-            list.removeLast();
-            return new CompilationPhases(desc, list.toArray(new CompilationPhase[list.size()]));
-        }
-
-        private CompilationPhases addFirst(final CompilationPhase phase) {
-            if (phases.contains(phase)) {
-                return this;
-            }
-            final LinkedList<CompilationPhase> list = new LinkedList<>(phases);
-            list.addFirst(phase);
-            return new CompilationPhases(desc, list.toArray(new CompilationPhase[list.size()]));
-        }
-
-        @SuppressWarnings("unused") //TODO I'll use this soon
-        private CompilationPhases replace(final CompilationPhase phase, final CompilationPhase newPhase) {
-            final LinkedList<CompilationPhase> list = new LinkedList<>();
-            for (final CompilationPhase p : phases) {
-                list.add(p == phase ? newPhase : p);
-            }
-            return new CompilationPhases(desc, list.toArray(new CompilationPhase[list.size()]));
-        }
-
-        private CompilationPhases addAfter(final CompilationPhase phase, final CompilationPhase newPhase) {
-            final LinkedList<CompilationPhase> list = new LinkedList<>();
-            for (final CompilationPhase p : phases) {
-                list.add(p);
-                if (p == phase) {
-                    list.add(newPhase);
-                }
-            }
-            return new CompilationPhases(desc, list.toArray(new CompilationPhase[list.size()]));
-        }
-
         boolean contains(final CompilationPhase phase) {
             return phases.contains(phase);
         }
@@ -284,7 +313,7 @@
         }
 
         boolean isRestOfCompilation() {
-            return this == COMPILE_ALL_RESTOF || this == COMPILE_FROM_BYTECODE_RESTOF;
+            return this == COMPILE_ALL_RESTOF || this == GENERATE_BYTECODE_AND_INSTALL_RESTOF || this == COMPILE_SERIALIZED_RESTOF;
         }
 
         String getDesc() {
@@ -749,6 +778,14 @@
         compileUnits.addAll(newUnits);
     }
 
+    void serializeAst(final FunctionNode fn) {
+        serializedAsts.put(fn.getId(), AstSerializer.serialize(fn));
+    }
+
+    byte[] removeSerializedAst(final int fnId) {
+        return serializedAsts.remove(fnId);
+    }
+
     CompileUnit findUnit(final long weight) {
         for (final CompileUnit unit : compileUnits) {
             if (unit.canHold(weight)) {
@@ -771,7 +808,10 @@
     }
 
     RecompilableScriptFunctionData getScriptFunctionData(final int functionId) {
-        return compiledFunction == null ? null : compiledFunction.getScriptFunctionData(functionId);
+        assert compiledFunction != null;
+        final RecompilableScriptFunctionData fn = compiledFunction.getScriptFunctionData(functionId);
+        assert fn != null : functionId;
+        return fn;
     }
 
     boolean isGlobalSymbol(final FunctionNode fn, final String name) {
--- a/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/FindScopeDepths.java	Thu Oct 23 11:19:29 2014 -0700
+++ b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/FindScopeDepths.java	Thu Oct 23 13:45:22 2014 -0700
@@ -187,7 +187,6 @@
 
         if (compiler.isOnDemandCompilation()) {
             final RecompilableScriptFunctionData data = compiler.getScriptFunctionData(newFunctionNode.getId());
-            assert data != null : newFunctionNode.getName() + " lacks data";
             if (data.inDynamicContext()) {
                 log.fine("Reviving scriptfunction ", quote(name), " as defined in previous (now lost) dynamic scope.");
                 newFunctionNode = newFunctionNode.setInDynamicContext(lc);
@@ -202,7 +201,7 @@
 
         //create recompilable scriptfunctiondata
         final int fnId = newFunctionNode.getId();
-        final Map<Integer, RecompilableScriptFunctionData> nestedFunctions = fnIdToNestedFunctions.get(fnId);
+        final Map<Integer, RecompilableScriptFunctionData> nestedFunctions = fnIdToNestedFunctions.remove(fnId);
 
         assert nestedFunctions != null;
         // Generate the object class and property map in case this function is ever used as constructor
@@ -212,8 +211,8 @@
                 new AllocatorDescriptor(newFunctionNode.getThisProperties()),
                 nestedFunctions,
                 externalSymbolDepths.get(fnId),
-                internalSymbols.get(fnId)
-                );
+                internalSymbols.get(fnId),
+                compiler.removeSerializedAst(fnId));
 
         if (lc.getOutermostFunction() != newFunctionNode) {
             final FunctionNode parentFn = lc.getParentFunction(newFunctionNode);
--- a/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/Label.java	Thu Oct 23 11:19:29 2014 -0700
+++ b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/Label.java	Thu Oct 23 13:45:22 2014 -0700
@@ -24,6 +24,7 @@
  */
 package jdk.nashorn.internal.codegen;
 
+import java.io.Serializable;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.BitSet;
@@ -39,7 +40,9 @@
  *
  * see -Dnashorn.codegen.debug, --log=codegen
  */
-public final class Label {
+public final class Label implements Serializable {
+    private static final long serialVersionUID = 1L;
+
     //byte code generation evaluation type stack for consistency check
     //and correct opcode selection. one per label as a label may be a
     //join point
@@ -491,7 +494,7 @@
     private final String name;
 
     /** Type stack at this label */
-    private Label.Stack stack;
+    private transient Label.Stack stack;
 
     /** ASM representation of this label */
     private jdk.internal.org.objectweb.asm.Label label;
@@ -500,9 +503,9 @@
     private final int id;
 
     /** Is this label reachable (anything ever jumped to it)? */
-    private boolean reachable;
+    private transient boolean reachable;
 
-    private boolean breakTarget;
+    private transient boolean breakTarget;
 
     /**
      * Constructor
--- a/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/LocalVariableTypesCalculator.java	Thu Oct 23 11:19:29 2014 -0700
+++ b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/LocalVariableTypesCalculator.java	Thu Oct 23 13:45:22 2014 -0700
@@ -72,7 +72,7 @@
 import jdk.nashorn.internal.ir.ReturnNode;
 import jdk.nashorn.internal.ir.RuntimeNode;
 import jdk.nashorn.internal.ir.RuntimeNode.Request;
-import jdk.nashorn.internal.ir.SplitNode;
+import jdk.nashorn.internal.ir.SplitReturn;
 import jdk.nashorn.internal.ir.Statement;
 import jdk.nashorn.internal.ir.SwitchNode;
 import jdk.nashorn.internal.ir.Symbol;
@@ -361,10 +361,6 @@
     // Synthetic return node that we must insert at the end of the function if it's end is reachable.
     private ReturnNode syntheticReturn;
 
-    // Topmost current split node (if any)
-    private SplitNode topSplit;
-    private boolean split;
-
     private boolean alreadyEnteredTopLevelFunction;
 
     // LvarType and conversion information gathered during the top-down pass; applied to nodes in the bottom-up pass.
@@ -477,22 +473,7 @@
             return false;
         }
         final BreakableNode target = jump.getTarget(lc);
-        return splitAwareJumpToLabel(jump, target, jump.getTargetLabel(target));
-    }
-
-    private boolean splitAwareJumpToLabel(final JumpStatement jumpStatement, final BreakableNode target, final Label targetLabel) {
-        final JoinPredecessor jumpOrigin;
-        if(topSplit != null && lc.isExternalTarget(topSplit, target)) {
-            // If the jump target is outside the topmost split node, then we'll create a synthetic jump origin in the
-            // split node.
-            jumpOrigin = new JoinPredecessorExpression();
-            topSplit.addJump(jumpOrigin, targetLabel);
-        } else {
-            // Otherwise, the original jump statement is the jump origin
-            jumpOrigin = jumpStatement;
-        }
-
-        jumpToLabel(jumpOrigin, targetLabel, getBreakTargetTypes(target));
+        jumpToLabel(jump, jump.getTargetLabel(target), getBreakTargetTypes(target));
         doesNotContinueSequentially();
         return false;
     }
@@ -703,18 +684,9 @@
     }
 
     @Override
-    public boolean enterSplitNode(final SplitNode splitNode) {
-        if(!reachable) {
-            return false;
-        }
-        // Need to visit inside of split nodes. While it's true that they don't have local variables, we need to visit
-        // breaks, continues, and returns in them.
-        if(topSplit == null) {
-            topSplit = splitNode;
-        }
-        split = true;
-        setType(getCompilerConstantSymbol(lc.getCurrentFunction(), CompilerConstants.RETURN), LvarType.UNDEFINED);
-        return true;
+    public boolean enterSplitReturn(final SplitReturn splitReturn) {
+        doesNotContinueSequentially();
+        return false;
     }
 
     @Override
@@ -1116,15 +1088,6 @@
         if(returnType.isUnknown()) {
             returnType = Type.OBJECT;
         }
-
-        if(split) {
-            // If the function is split, the ":return" symbol is used and needs a slot. Note we can't mark the return
-            // symbol as used in enterSplitNode, as we don't know the final return type of the function earlier than
-            // here.
-            final Symbol retSymbol = getCompilerConstantSymbol(lc.getCurrentFunction(), CompilerConstants.RETURN);
-            retSymbol.setHasSlotFor(returnType);
-            retSymbol.setNeedsSlot(true);
-        }
     }
 
     private void createSyntheticReturn(final Block body) {
--- a/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/Lower.java	Thu Oct 23 11:19:29 2014 -0700
+++ b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/Lower.java	Thu Oct 23 13:45:22 2014 -0700
@@ -352,8 +352,6 @@
     private Node spliceFinally(final TryNode tryNode, final List<ThrowNode> rethrows, final Block finallyBody) {
         assert tryNode.getFinallyBody() == null;
 
-        final LexicalContext lowerLc = lc;
-
         final TryNode newTryNode = (TryNode)tryNode.accept(new NodeVisitor<LexicalContext>(new LexicalContext()) {
             final List<Node> insideTry = new ArrayList<>();
 
@@ -406,7 +404,6 @@
                     //still in the try block, store it in a result value and return it afterwards
                     resultNode = new IdentNode(Lower.this.compilerConstant(RETURN));
                     newStatements.add(new ExpressionStatement(returnNode.getLineNumber(), returnNode.getToken(), returnNode.getFinish(), new BinaryNode(Token.recast(returnNode.getToken(), TokenType.ASSIGN), resultNode, expr)));
-                    lowerLc.setFlag(lowerLc.getCurrentFunction(), FunctionNode.USES_RETURN_SYMBOL);
                 } else {
                     resultNode = null;
                 }
--- a/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/MethodEmitter.java	Thu Oct 23 11:19:29 2014 -0700
+++ b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/MethodEmitter.java	Thu Oct 23 13:45:22 2014 -0700
@@ -71,6 +71,7 @@
 import static jdk.nashorn.internal.codegen.ObjectClassGenerator.PRIMITIVE_FIELD_TYPE;
 import static jdk.nashorn.internal.runtime.linker.NashornCallSiteDescriptor.CALLSITE_OPTIMISTIC;
 import static jdk.nashorn.internal.runtime.linker.NashornCallSiteDescriptor.CALLSITE_PROGRAM_POINT_SHIFT;
+
 import java.io.PrintStream;
 import java.lang.reflect.Array;
 import java.util.Collection;
@@ -88,11 +89,9 @@
 import jdk.nashorn.internal.codegen.types.BitwiseType;
 import jdk.nashorn.internal.codegen.types.NumericType;
 import jdk.nashorn.internal.codegen.types.Type;
-import jdk.nashorn.internal.ir.BreakableNode;
 import jdk.nashorn.internal.ir.FunctionNode;
 import jdk.nashorn.internal.ir.IdentNode;
 import jdk.nashorn.internal.ir.JoinPredecessor;
-import jdk.nashorn.internal.ir.LexicalContext;
 import jdk.nashorn.internal.ir.LiteralNode;
 import jdk.nashorn.internal.ir.LocalVariableConversion;
 import jdk.nashorn.internal.ir.RuntimeNode;
@@ -1663,19 +1662,6 @@
     }
 
     /**
-     * Goto, possibly when splitting is taking place. If
-     * a splitNode exists, we need to handle the case that the
-     * jump target is another method
-     *
-     * @param label destination label
-     * @param targetNode the node to which the destination label belongs (the label is normally a break or continue
-     * label)
-     */
-    void splitAwareGoto(final LexicalContext lc, final Label label, final BreakableNode targetNode) {
-        _goto(label);
-    }
-
-    /**
      * Perform a comparison of two number types that are popped from the stack
      *
      * @param isCmpG is this a dcmpg semantic, false if it's a dcmpl semantic
--- a/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/OptimisticTypesCalculator.java	Thu Oct 23 11:19:29 2014 -0700
+++ b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/OptimisticTypesCalculator.java	Thu Oct 23 13:45:22 2014 -0700
@@ -30,7 +30,6 @@
 import java.util.ArrayDeque;
 import java.util.BitSet;
 import java.util.Deque;
-import jdk.nashorn.internal.IntDeque;
 import jdk.nashorn.internal.ir.AccessNode;
 import jdk.nashorn.internal.ir.BinaryNode;
 import jdk.nashorn.internal.ir.CallNode;
@@ -49,7 +48,6 @@
 import jdk.nashorn.internal.ir.Node;
 import jdk.nashorn.internal.ir.Optimistic;
 import jdk.nashorn.internal.ir.PropertyNode;
-import jdk.nashorn.internal.ir.SplitNode;
 import jdk.nashorn.internal.ir.Symbol;
 import jdk.nashorn.internal.ir.TernaryNode;
 import jdk.nashorn.internal.ir.UnaryNode;
@@ -70,8 +68,6 @@
 
     // Per-function bit set of program points that must never be optimistic.
     final Deque<BitSet> neverOptimistic = new ArrayDeque<>();
-    // Per-function depth of split nodes
-    final IntDeque splitDepth = new IntDeque();
 
     OptimisticTypesCalculator(final Compiler compiler) {
         super(new LexicalContext());
@@ -155,7 +151,6 @@
             return false;
         }
         neverOptimistic.push(new BitSet());
-        splitDepth.push(0);
         return true;
     }
 
@@ -190,19 +185,6 @@
     }
 
     @Override
-    public boolean enterSplitNode(final SplitNode splitNode) {
-        splitDepth.getAndIncrement();
-        return true;
-    }
-
-    @Override
-    public Node leaveSplitNode(final SplitNode splitNode) {
-        final int depth = splitDepth.decrementAndGet();
-        assert depth >= 0;
-        return splitNode;
-    }
-
-    @Override
     public boolean enterVarNode(final VarNode varNode) {
         tagNeverOptimistic(varNode.getName());
         return true;
@@ -226,16 +208,11 @@
     @Override
     public Node leaveFunctionNode(final FunctionNode functionNode) {
         neverOptimistic.pop();
-        final int lastSplitDepth = splitDepth.pop();
-        assert lastSplitDepth == 0;
         return functionNode.setState(lc, CompilationState.OPTIMISTIC_TYPES_ASSIGNED);
     }
 
     @Override
     public Node leaveIdentNode(final IdentNode identNode) {
-        if(inSplitNode()) {
-            return identNode;
-        }
         final Symbol symbol = identNode.getSymbol();
         if(symbol == null) {
             assert identNode.isPropertyName();
@@ -256,7 +233,7 @@
 
     private Expression leaveOptimistic(final Optimistic opt) {
         final int pp = opt.getProgramPoint();
-        if(isValid(pp) && !inSplitNode() && !neverOptimistic.peek().get(pp)) {
+        if(isValid(pp) && !neverOptimistic.peek().get(pp)) {
             return (Expression)opt.setType(compiler.getOptimisticType(opt));
         }
         return (Expression)opt;
@@ -277,8 +254,4 @@
             tagNeverOptimistic(test.getExpression());
         }
     }
-
-    private boolean inSplitNode() {
-        return splitDepth.peek() > 0;
-    }
 }
--- a/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/ProgramPoints.java	Thu Oct 23 11:19:29 2014 -0700
+++ b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/ProgramPoints.java	Thu Oct 23 13:45:22 2014 -0700
@@ -85,7 +85,7 @@
 
     @Override
     public boolean enterVarNode(final VarNode varNode) {
-        noProgramPoint.add(varNode.getAssignmentDest());
+        noProgramPoint.add(varNode.getName());
         return true;
     }
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/ReplaceCompileUnits.java	Thu Oct 23 13:45:22 2014 -0700
@@ -0,0 +1,85 @@
+/*
+ * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.nashorn.internal.codegen;
+
+import java.util.ArrayList;
+import java.util.List;
+import jdk.nashorn.internal.ir.CompileUnitHolder;
+import jdk.nashorn.internal.ir.FunctionNode;
+import jdk.nashorn.internal.ir.FunctionNode.CompilationState;
+import jdk.nashorn.internal.ir.LexicalContext;
+import jdk.nashorn.internal.ir.LiteralNode;
+import jdk.nashorn.internal.ir.LiteralNode.ArrayLiteralNode;
+import jdk.nashorn.internal.ir.LiteralNode.ArrayLiteralNode.ArrayUnit;
+import jdk.nashorn.internal.ir.Node;
+import jdk.nashorn.internal.ir.visitor.NodeVisitor;
+
+/**
+ * Base class for a node visitor that replaces {@link CompileUnit}s in {@link CompileUnitHolder}s.
+ */
+abstract class ReplaceCompileUnits extends NodeVisitor<LexicalContext> {
+    ReplaceCompileUnits() {
+        super(new LexicalContext());
+    }
+
+    /**
+     * Override to provide a replacement for an old compile unit.
+     * @param oldUnit the old compile unit to replace
+     * @return the compile unit's replacement.
+     */
+    abstract CompileUnit getReplacement(final CompileUnit oldUnit);
+
+    CompileUnit getExistingReplacement(final CompileUnitHolder node) {
+        final CompileUnit oldUnit = node.getCompileUnit();
+        assert oldUnit != null;
+
+        final CompileUnit newUnit = getReplacement(oldUnit);
+        assert newUnit != null;
+
+        return newUnit;
+    }
+
+    @Override
+    public Node leaveFunctionNode(final FunctionNode node) {
+        return node.setCompileUnit(lc, getExistingReplacement(node)).setState(lc, CompilationState.COMPILE_UNITS_REUSED);
+    }
+
+    @Override
+    public Node leaveLiteralNode(final LiteralNode<?> node) {
+        if (node instanceof ArrayLiteralNode) {
+            final ArrayLiteralNode aln = (ArrayLiteralNode)node;
+            if (aln.getUnits() == null) {
+                return node;
+            }
+            final List<ArrayUnit> newArrayUnits = new ArrayList<>();
+            for (final ArrayUnit au : aln.getUnits()) {
+                newArrayUnits.add(new ArrayUnit(getExistingReplacement(au), au.getLo(), au.getHi()));
+            }
+            return aln.setUnits(lc, newArrayUnits);
+        }
+        return node;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/SplitIntoFunctions.java	Thu Oct 23 13:45:22 2014 -0700
@@ -0,0 +1,450 @@
+/*
+ * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.nashorn.internal.codegen;
+
+import static jdk.nashorn.internal.ir.Node.NO_FINISH;
+import static jdk.nashorn.internal.ir.Node.NO_LINE_NUMBER;
+import static jdk.nashorn.internal.ir.Node.NO_TOKEN;
+
+import java.util.ArrayDeque;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.Deque;
+import java.util.List;
+import java.util.Objects;
+import jdk.nashorn.internal.ir.AccessNode;
+import jdk.nashorn.internal.ir.BinaryNode;
+import jdk.nashorn.internal.ir.Block;
+import jdk.nashorn.internal.ir.BlockLexicalContext;
+import jdk.nashorn.internal.ir.BreakNode;
+import jdk.nashorn.internal.ir.CallNode;
+import jdk.nashorn.internal.ir.CaseNode;
+import jdk.nashorn.internal.ir.ContinueNode;
+import jdk.nashorn.internal.ir.Expression;
+import jdk.nashorn.internal.ir.ExpressionStatement;
+import jdk.nashorn.internal.ir.FunctionNode;
+import jdk.nashorn.internal.ir.FunctionNode.CompilationState;
+import jdk.nashorn.internal.ir.GetSplitState;
+import jdk.nashorn.internal.ir.IdentNode;
+import jdk.nashorn.internal.ir.IfNode;
+import jdk.nashorn.internal.ir.JumpStatement;
+import jdk.nashorn.internal.ir.LiteralNode;
+import jdk.nashorn.internal.ir.Node;
+import jdk.nashorn.internal.ir.ReturnNode;
+import jdk.nashorn.internal.ir.SetSplitState;
+import jdk.nashorn.internal.ir.SplitNode;
+import jdk.nashorn.internal.ir.SplitReturn;
+import jdk.nashorn.internal.ir.Statement;
+import jdk.nashorn.internal.ir.SwitchNode;
+import jdk.nashorn.internal.ir.VarNode;
+import jdk.nashorn.internal.ir.visitor.NodeVisitor;
+import jdk.nashorn.internal.parser.Token;
+import jdk.nashorn.internal.parser.TokenType;
+
+/**
+ * A node visitor that replaces {@link SplitNode}s with anonymous function invocations and some additional constructs
+ * to support control flow across splits. By using this transformation, split functions are translated into ordinary
+ * JavaScript functions with nested anonymous functions. The transformations however introduce several AST nodes that
+ * have no JavaScript source representations ({@link GetSplitState}, {@link SetSplitState}, and {@link SplitReturn}),
+ * and therefore such function is no longer reparseable from its source. For that reason, split functions and their
+ * fragments are serialized in-memory and deserialized when they need to be recompiled either for deoptimization or
+ * for type specialization.
+ * NOTE: all {@code leave*()} methods for statements are returning their input nodes. That way, they will not mutate
+ * the original statement list in the block containing the statement, which is fine, as it'll be replaced by the
+ * lexical context when the block is left. If we returned something else (e.g. null), we'd cause a mutation in the
+ * enclosing block's statement list that is otherwise overwritten later anyway.
+ */
+final class SplitIntoFunctions extends NodeVisitor<BlockLexicalContext> {
+    private static final int FALLTHROUGH_STATE = -1;
+    private static final int RETURN_STATE = 0;
+    private static final int BREAK_STATE = 1;
+    private static final int FIRST_JUMP_STATE = 2;
+
+    private static final String THIS_NAME = CompilerConstants.THIS.symbolName();
+    private static final String RETURN_NAME = CompilerConstants.RETURN.symbolName();
+    // Used as the name of the formal parameter for passing the current value of :return symbol into a split fragment.
+    private static final String RETURN_PARAM_NAME = RETURN_NAME + "-in";
+
+    private final Deque<FunctionState> functionStates = new ArrayDeque<>();
+    private final Deque<SplitState> splitStates = new ArrayDeque<>();
+    private final Namespace namespace;
+
+    private boolean artificialBlock = false;
+
+    // -1 is program; we need to use negative ones
+    private int nextFunctionId = -2;
+
+    public SplitIntoFunctions(final Compiler compiler) {
+        super(new BlockLexicalContext() {
+            @Override
+            protected Block afterSetStatements(Block block) {
+                for(Statement stmt: block.getStatements()) {
+                    assert !(stmt instanceof SplitNode);
+                }
+                return block;
+            }
+        });
+        namespace = new Namespace(compiler.getScriptEnvironment().getNamespace());
+    }
+
+    @Override
+    public boolean enterFunctionNode(final FunctionNode functionNode) {
+        functionStates.push(new FunctionState(functionNode));
+        return true;
+    }
+
+    @Override
+    public Node leaveFunctionNode(final FunctionNode functionNode) {
+        functionStates.pop();
+        return functionNode;
+    }
+
+    @Override
+    protected Node leaveDefault(final Node node) {
+        if (node instanceof Statement) {
+            appendStatement((Statement)node);
+        }
+        return node;
+    }
+
+    @Override
+    public boolean enterSplitNode(final SplitNode splitNode) {
+        getCurrentFunctionState().splitDepth++;
+        splitStates.push(new SplitState(splitNode));
+        return true;
+    }
+
+    @Override
+    public Node leaveSplitNode(final SplitNode splitNode) {
+        // Replace the split node with an anonymous function expression call.
+
+        final FunctionState fnState = getCurrentFunctionState();
+
+        final String name = splitNode.getName();
+        Block body = splitNode.getBody();
+        final int firstLineNumber = body.getFirstStatementLineNumber();
+        final long token = body.getToken();
+        final int finish = body.getFinish();
+
+        final FunctionNode originalFn = fnState.fn;
+        assert originalFn == lc.getCurrentFunction();
+        final boolean isProgram = originalFn.isProgram();
+
+        // Change SplitNode({...}) into "function () { ... }", or "function (:return-in) () { ... }" (for program)
+        final long newFnToken = Token.toDesc(TokenType.FUNCTION, nextFunctionId--, 0);
+        final FunctionNode fn = new FunctionNode(
+                originalFn.getSource(),
+                body.getFirstStatementLineNumber(),
+                newFnToken,
+                finish,
+                newFnToken,
+                NO_TOKEN,
+                namespace,
+                createIdent(name),
+                originalFn.getName() + "$" + name,
+                isProgram ? Collections.singletonList(createReturnParamIdent()) : Collections.<IdentNode>emptyList(),
+                FunctionNode.Kind.NORMAL,
+                // We only need IS_SPLIT conservatively, in case it contains any array units so that we force
+                // the :callee's existence, to force :scope to never be in a slot lower than 2. This is actually
+                // quite a horrible hack to do with CodeGenerator.fixScopeSlot not trampling other parameters
+                // and should go away once we no longer have array unit handling in codegen. Note however that
+                // we still use IS_SPLIT as the criteria in CompilationPhase.SERIALIZE_SPLIT_PHASE.
+                FunctionNode.IS_ANONYMOUS | FunctionNode.USES_ANCESTOR_SCOPE | FunctionNode.IS_SPLIT,
+                body,
+                CompilationState.INITIALIZED,
+                null
+        )
+        .setCompileUnit(lc, splitNode.getCompileUnit())
+        .copyCompilationState(lc, originalFn);
+
+        // Call the function:
+        //     either "(function () { ... }).call(this)"
+        //     or     "(function (:return-in) { ... }).call(this, :return)"
+        // NOTE: Function.call() has optimized linking that basically does a pass-through to the function being invoked.
+        // NOTE: CompilationPhase.PROGRAM_POINT_PHASE happens after this, so these calls are subject to optimistic
+        // assumptions on their return value (when they return a value), as they should be.
+        final IdentNode thisIdent = createIdent(THIS_NAME);
+        final CallNode callNode = new CallNode(firstLineNumber, token, finish, new AccessNode(NO_TOKEN, NO_FINISH, fn, "call"),
+                isProgram ? Arrays.<Expression>asList(thisIdent, createReturnIdent())
+                          : Collections.<Expression>singletonList(thisIdent),
+                false);
+
+        final SplitState splitState = splitStates.pop();
+        fnState.splitDepth--;
+
+        final Expression callWithReturn;
+        final boolean hasReturn = splitState.hasReturn;
+        if (hasReturn && fnState.splitDepth > 0) {
+            final SplitState parentSplit = splitStates.peek();
+            if (parentSplit != null) {
+                // Propagate hasReturn to parent split
+                parentSplit.hasReturn = true;
+            }
+        }
+        if (hasReturn || isProgram) {
+            // capture return value: ":return = (function () { ... })();"
+            callWithReturn = new BinaryNode(Token.recast(token, TokenType.ASSIGN), createReturnIdent(), callNode);
+        } else {
+            // no return value, just call : "(function () { ... })();"
+            callWithReturn = callNode;
+        }
+        appendStatement(new ExpressionStatement(firstLineNumber, token, finish, callWithReturn));
+
+        Statement splitStateHandler;
+
+        final List<JumpStatement> jumpStatements = splitState.jumpStatements;
+        final int jumpCount = jumpStatements.size();
+        // There are jumps (breaks or continues) that need to be propagated outside the split node. We need to
+        // set up a switch statement for them:
+        // switch(:scope.getScopeState()) { ... }
+        if (jumpCount > 0) {
+            final List<CaseNode> cases = new ArrayList<>(jumpCount + (hasReturn ? 1 : 0));
+            if (hasReturn) {
+                // If the split node also contained a return, we'll slip it as a case in the switch statement
+                addCase(cases, RETURN_STATE, createReturnFromSplit());
+            }
+            int i = FIRST_JUMP_STATE;
+            for (final JumpStatement jump: jumpStatements) {
+                addCase(cases, i++, enblockAndVisit(jump));
+            }
+            splitStateHandler = new SwitchNode(NO_LINE_NUMBER, token, finish, GetSplitState.INSTANCE, cases, null);
+        } else {
+            splitStateHandler = null;
+        }
+
+        // As the switch statement itself is breakable, an unlabelled break can't be in the switch statement,
+        // so we need to test for it separately.
+        if (splitState.hasBreak) {
+            // if(:scope.getScopeState() == Scope.BREAK) { break; }
+            splitStateHandler = makeIfStateEquals(firstLineNumber, token, finish, BREAK_STATE,
+                    enblockAndVisit(new BreakNode(NO_LINE_NUMBER, token, finish, null)), splitStateHandler);
+        }
+
+        // Finally, if the split node had a return statement, but there were no external jumps, we didn't have
+        // the switch statement to handle the return, so we need a separate if for it.
+        if (hasReturn && jumpCount == 0) {
+            // if (:scope.getScopeState() == Scope.RETURN) { return :return; }
+            splitStateHandler = makeIfStateEquals(NO_LINE_NUMBER, token, finish, RETURN_STATE,
+                    createReturnFromSplit(), splitStateHandler);
+        }
+
+        if (splitStateHandler != null) {
+            appendStatement(splitStateHandler);
+        }
+
+        return splitNode;
+    }
+
+    private static void addCase(final List<CaseNode> cases, final int i, final Block body) {
+        cases.add(new CaseNode(NO_TOKEN, NO_FINISH, intLiteral(i), body));
+    }
+
+    private static LiteralNode<Number> intLiteral(final int i) {
+        return LiteralNode.newInstance(NO_TOKEN, NO_FINISH, i);
+    }
+
+    private static Block createReturnFromSplit() {
+        return new Block(NO_TOKEN, NO_FINISH, createReturnReturn());
+    }
+
+    private static ReturnNode createReturnReturn() {
+        return new ReturnNode(NO_LINE_NUMBER, NO_TOKEN, NO_FINISH, createReturnIdent());
+    }
+
+    private static IdentNode createReturnIdent() {
+        return createIdent(RETURN_NAME);
+    }
+
+    private static IdentNode createReturnParamIdent() {
+        return createIdent(RETURN_PARAM_NAME);
+    }
+
+    private static IdentNode createIdent(final String name) {
+        return new IdentNode(NO_TOKEN, NO_FINISH, name);
+    }
+
+    private Block enblockAndVisit(final JumpStatement jump) {
+        artificialBlock = true;
+        final Block block = (Block)new Block(NO_TOKEN, NO_FINISH, jump).accept(this);
+        artificialBlock = false;
+        return block;
+    }
+
+    private static IfNode makeIfStateEquals(final int lineNumber, final long token, final int finish,
+            final int value, final Block pass, final Statement fail) {
+        return new IfNode(lineNumber, token, finish,
+                new BinaryNode(Token.recast(token, TokenType.EQ_STRICT),
+                        GetSplitState.INSTANCE, intLiteral(value)),
+                pass,
+                fail == null ? null : new Block(NO_TOKEN, NO_FINISH, fail));
+    }
+
+    @Override
+    public boolean enterVarNode(VarNode varNode) {
+        if (!inSplitNode()) {
+            return super.enterVarNode(varNode);
+        }
+        assert !varNode.isBlockScoped(); //TODO: we must handle these too, but we currently don't
+
+        final Expression init = varNode.getInit();
+        if (varNode.isAnonymousFunctionDeclaration()) {
+            // We ain't moving anonymous function declarations.
+            return super.enterVarNode(varNode);
+        }
+
+        // Move a declaration-only var statement to the top of the outermost function.
+        getCurrentFunctionState().varStatements.add(varNode.setInit(null));
+        // If it had an initializer, replace it with an assignment expression statement. Note that "var" is a
+        // statement, so it doesn't contribute to :return of the programs, therefore we are _not_ adding a
+        // ":return = ..." assignment around the original assignment.
+        if (init != null) {
+            final long token = Token.recast(varNode.getToken(), TokenType.ASSIGN);
+            new ExpressionStatement(varNode.getLineNumber(), token, varNode.getFinish(),
+                    new BinaryNode(token, varNode.getName(), varNode.getInit())).accept(this);
+        }
+
+        return false;
+    }
+
+    @Override
+    public Node leaveBlock(final Block block) {
+        if (!artificialBlock) {
+            if (lc.isFunctionBody()) {
+                // Prepend declaration-only var statements to the top of the statement list.
+                lc.prependStatements(getCurrentFunctionState().varStatements);
+            } else if (lc.isSplitBody()) {
+                appendSplitReturn(FALLTHROUGH_STATE, NO_LINE_NUMBER);
+                if (getCurrentFunctionState().fn.isProgram()) {
+                    // If we're splitting the program, make sure every shard ends with "return :return" and
+                    // begins with ":return = :return-in;".
+                    lc.prependStatement(new ExpressionStatement(NO_LINE_NUMBER, NO_TOKEN, NO_FINISH,
+                            new BinaryNode(Token.toDesc(TokenType.ASSIGN, 0, 0), createReturnIdent(), createReturnParamIdent())));
+                }
+            }
+        }
+        return block;
+    }
+
+    @Override
+    public Node leaveBreakNode(final BreakNode breakNode) {
+        return leaveJumpNode(breakNode);
+    }
+
+    @Override
+    public Node leaveContinueNode(final ContinueNode continueNode) {
+        return leaveJumpNode(continueNode);
+    }
+
+    private JumpStatement leaveJumpNode(final JumpStatement jump) {
+        if (inSplitNode()) {
+            final SplitState splitState = getCurrentSplitState();
+            final SplitNode splitNode = splitState.splitNode;
+            if (lc.isExternalTarget(splitNode, jump.getTarget(lc))) {
+                appendSplitReturn(splitState.getSplitStateIndex(jump), jump.getLineNumber());
+                return jump;
+            }
+        }
+        appendStatement(jump);
+        return jump;
+    }
+
+    private void appendSplitReturn(final int splitState, final int lineNumber) {
+        appendStatement(new SetSplitState(splitState, lineNumber));
+        if (getCurrentFunctionState().fn.isProgram()) {
+            // If we're splitting the program, make sure every fragment passes back :return
+            appendStatement(createReturnReturn());
+        } else {
+            appendStatement(SplitReturn.INSTANCE);
+        }
+    }
+
+    @Override
+    public Node leaveReturnNode(final ReturnNode returnNode) {
+        if(inSplitNode()) {
+            appendStatement(new SetSplitState(RETURN_STATE, returnNode.getLineNumber()));
+            getCurrentSplitState().hasReturn = true;
+        }
+        appendStatement(returnNode);
+        return returnNode;
+    }
+
+    private void appendStatement(final Statement statement) {
+        lc.appendStatement(statement);
+    }
+
+    private boolean inSplitNode() {
+        return getCurrentFunctionState().splitDepth > 0;
+    }
+
+    private FunctionState getCurrentFunctionState() {
+        return functionStates.peek();
+    }
+
+    private SplitState getCurrentSplitState() {
+        return splitStates.peek();
+    }
+
+    private static class FunctionState {
+        final FunctionNode fn;
+        final List<Statement> varStatements = new ArrayList<>();
+        int splitDepth;
+
+        FunctionState(final FunctionNode fn) {
+            this.fn = fn;
+        }
+    }
+
+    private static class SplitState {
+        final SplitNode splitNode;
+        boolean hasReturn;
+        boolean hasBreak;
+
+        final List<JumpStatement> jumpStatements = new ArrayList<>();
+
+        int getSplitStateIndex(final JumpStatement jump) {
+            if (jump instanceof BreakNode && jump.getLabelName() == null) {
+                // Unlabelled break is a special case
+                hasBreak = true;
+                return BREAK_STATE;
+            }
+
+            int i = 0;
+            for(final JumpStatement exJump: jumpStatements) {
+                if (jump.getClass() == exJump.getClass() && Objects.equals(jump.getLabelName(), exJump.getLabelName())) {
+                    return i + FIRST_JUMP_STATE;
+                }
+                ++i;
+            }
+            jumpStatements.add(jump);
+            return i + FIRST_JUMP_STATE;
+        }
+
+        SplitState(final SplitNode splitNode) {
+            this.splitNode = splitNode;
+        }
+    }
+}
--- a/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/SplitMethodEmitter.java	Thu Oct 23 11:19:29 2014 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,102 +0,0 @@
-/*
- * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.  Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-package jdk.nashorn.internal.codegen;
-
-import java.util.ArrayList;
-import java.util.List;
-import jdk.internal.org.objectweb.asm.MethodVisitor;
-import jdk.nashorn.internal.codegen.types.Type;
-import jdk.nashorn.internal.ir.BreakableNode;
-import jdk.nashorn.internal.ir.LexicalContext;
-import jdk.nashorn.internal.ir.SplitNode;
-
-/**
- * Emitter used for splitting methods. Needs to keep track of if there are jump targets
- * outside the current split node. All external jump targets encountered at method
- * emission are logged, and {@code CodeGenerator#leaveSplitNode(SplitNode)} creates
- * an appropriate jump table when the SplitNode has been iterated through
- */
-public class SplitMethodEmitter extends MethodEmitter {
-
-    private final SplitNode splitNode;
-
-    private final List<Label> externalTargets = new ArrayList<>();
-    /**
-     * In addition to external target labels, we need to track the target breakables too as the code generator needs to
-     * be able to correctly pop the scopes to the target, see {@link CodeGenerator#leaveSplitNode(SplitNode)}. Note that
-     * this is only used within CodeGenerator, which doesn't mutate the AST, so keeping pointers to other nodes is not
-     * incorrect.
-     */
-    private final List<BreakableNode> externalTargetNodes = new ArrayList<>();
-
-    SplitMethodEmitter(final ClassEmitter classEmitter, final MethodVisitor mv, final SplitNode splitNode) {
-        super(classEmitter, mv);
-        this.splitNode = splitNode;
-    }
-
-    @Override
-    void splitAwareGoto(final LexicalContext lc, final Label label, final BreakableNode targetNode) {
-        assert splitNode != null;
-        final int index = findExternalTarget(lc, label, targetNode);
-        if (index >= 0) {
-            setSplitState(index + 1); // 0 is ordinary return
-            final Type retType = functionNode.getReturnType();
-            loadUndefined(retType);
-            _return(retType);
-        } else {
-            super.splitAwareGoto(lc, label, targetNode);
-        }
-    }
-
-    private int findExternalTarget(final LexicalContext lc, final Label label, final BreakableNode targetNode) {
-        final int index = externalTargets.indexOf(label);
-
-        if (index >= 0) {
-            return index;
-        }
-
-        if (lc.isExternalTarget(splitNode, targetNode)) {
-            externalTargets.add(label);
-            externalTargetNodes.add(targetNode);
-            return externalTargets.size() - 1;
-        }
-        return -1;
-    }
-
-    @Override
-    MethodEmitter registerReturn() {
-        setHasReturn();
-        return setSplitState(0);
-    }
-
-    final List<Label> getExternalTargets() {
-        return externalTargets;
-    }
-
-    final List<BreakableNode> getExternalTargetNodes() {
-        return externalTargetNodes;
-    }
-}
--- a/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/types/ArrayType.java	Thu Oct 23 11:19:29 2014 -0700
+++ b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/types/ArrayType.java	Thu Oct 23 13:45:22 2014 -0700
@@ -37,6 +37,7 @@
  * This is an array type, i.e. OBJECT_ARRAY, NUMBER_ARRAY.
  */
 public class ArrayType extends ObjectType implements BytecodeArrayOps {
+    private static final long serialVersionUID = 1L;
 
     /**
      * Constructor
--- a/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/types/BitwiseType.java	Thu Oct 23 11:19:29 2014 -0700
+++ b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/types/BitwiseType.java	Thu Oct 23 13:45:22 2014 -0700
@@ -29,6 +29,7 @@
  * This class represents a numeric type that can be used for bit operations.
  */
 public abstract class BitwiseType extends NumericType implements BytecodeBitwiseOps {
+    private static final long serialVersionUID = 1L;
 
     /**
      * Constructor
--- a/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/types/BooleanType.java	Thu Oct 23 11:19:29 2014 -0700
+++ b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/types/BooleanType.java	Thu Oct 23 13:45:22 2014 -0700
@@ -69,6 +69,7 @@
  * The boolean type class
  */
 public final class BooleanType extends Type {
+    private static final long serialVersionUID = 1L;
 
     private static final CompilerConstants.Call VALUE_OF = staticCallNoLookup(Boolean.class, "valueOf", Boolean.class, boolean.class);
     private static final CompilerConstants.Call TO_STRING = staticCallNoLookup(Boolean.class, "toString", String.class, boolean.class);
--- a/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/types/IntType.java	Thu Oct 23 11:19:29 2014 -0700
+++ b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/types/IntType.java	Thu Oct 23 13:45:22 2014 -0700
@@ -60,6 +60,7 @@
  * Type class: INT
  */
 class IntType extends BitwiseType {
+    private static final long serialVersionUID = 1L;
 
     private static final CompilerConstants.Call TO_STRING = staticCallNoLookup(Integer.class, "toString", String.class, int.class);
     private static final CompilerConstants.Call VALUE_OF  = staticCallNoLookup(Integer.class, "valueOf", Integer.class, int.class);
--- a/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/types/LongType.java	Thu Oct 23 11:19:29 2014 -0700
+++ b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/types/LongType.java	Thu Oct 23 13:45:22 2014 -0700
@@ -54,6 +54,7 @@
  * Type class: LONG
  */
 class LongType extends BitwiseType {
+    private static final long serialVersionUID = 1L;
 
     private static final CompilerConstants.Call VALUE_OF = staticCallNoLookup(Long.class, "valueOf", Long.class, long.class);
 
--- a/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/types/NumberType.java	Thu Oct 23 11:19:29 2014 -0700
+++ b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/types/NumberType.java	Thu Oct 23 13:45:22 2014 -0700
@@ -46,6 +46,7 @@
 import jdk.nashorn.internal.runtime.JSType;
 
 class NumberType extends NumericType {
+    private static final long serialVersionUID = 1L;
 
     private static final CompilerConstants.Call VALUE_OF = staticCallNoLookup(Double.class, "valueOf", Double.class, double.class);
 
--- a/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/types/NumericType.java	Thu Oct 23 11:19:29 2014 -0700
+++ b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/types/NumericType.java	Thu Oct 23 13:45:22 2014 -0700
@@ -29,6 +29,8 @@
  * This is a numeric type, i.e. NUMBER, LONG, INT, INT32.
  */
 public abstract class NumericType extends Type implements BytecodeNumericOps {
+    private static final long serialVersionUID = 1L;
+
     /**
      * Constructor
      *
--- a/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/types/ObjectType.java	Thu Oct 23 11:19:29 2014 -0700
+++ b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/types/ObjectType.java	Thu Oct 23 13:45:22 2014 -0700
@@ -47,6 +47,7 @@
  * contain a class that is a more specialized object
  */
 class ObjectType extends Type {
+    private static final long serialVersionUID = 1L;
 
     protected ObjectType() {
         this(Object.class);
--- a/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/types/Type.java	Thu Oct 23 11:19:29 2014 -0700
+++ b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/types/Type.java	Thu Oct 23 13:45:22 2014 -0700
@@ -47,9 +47,11 @@
 import static jdk.internal.org.objectweb.asm.Opcodes.T_INT;
 import static jdk.internal.org.objectweb.asm.Opcodes.T_LONG;
 import static jdk.nashorn.internal.codegen.CompilerConstants.staticCallNoLookup;
+
 import java.io.DataInput;
 import java.io.DataOutput;
 import java.io.IOException;
+import java.io.Serializable;
 import java.lang.invoke.CallSite;
 import java.lang.invoke.MethodHandle;
 import java.lang.invoke.MethodHandles;
@@ -88,19 +90,20 @@
  * INTs rather than OBJECTs
  */
 
-public abstract class Type implements Comparable<Type>, BytecodeOps {
+public abstract class Type implements Comparable<Type>, BytecodeOps, Serializable {
+    private static final long serialVersionUID = 1L;
 
     /** Human readable name for type */
-    private final String name;
+    private transient final String name;
 
     /** Descriptor for type */
-    private final String descriptor;
+    private transient final String descriptor;
 
     /** The "weight" of the type. Used for picking widest/least specific common type */
-    private final int weight;
+    private transient final int weight;
 
     /** How many bytecode slots does this type occupy */
-    private final int slots;
+    private transient final int slots;
 
     /** The class for this type */
     private final Class<?> clazz;
@@ -113,7 +116,7 @@
             Collections.synchronizedMap(new WeakHashMap<Class<?>, jdk.internal.org.objectweb.asm.Type>());
 
     /** Internal ASM type for this Type - computed once at construction */
-    private final jdk.internal.org.objectweb.asm.Type internalType;
+    private transient final jdk.internal.org.objectweb.asm.Type internalType;
 
     /** Weights are used to decide which types are "wider" than other types */
     protected static final int MIN_WEIGHT = -1;
@@ -583,6 +586,7 @@
     public int getSlots() {
         return slots;
     }
+
     /**
      * Returns the widest or most common of two types
      *
@@ -606,6 +610,18 @@
     }
 
     /**
+     * Returns the widest or most common of two types, given as classes
+     *
+     * @param type0 type one
+     * @param type1 type two
+     *
+     * @return the widest type
+     */
+    public static Class<?> widest(final Class<?> type0, final Class<?> type1) {
+        return widest(Type.typeFor(type0), Type.typeFor(type1)).getTypeClass();
+    }
+
+    /**
      * When doing widening for return types of a function or a ternary operator, it is not valid to widen a boolean to
      * anything other than object. Note that this wouldn't be necessary if {@code Type.widest} did not allow
      * boolean-to-number widening. Eventually, we should address it there, but it affects too many other parts of the
@@ -934,6 +950,8 @@
      * This is the singleton for integer arrays
      */
     public static final ArrayType INT_ARRAY = new ArrayType(int[].class) {
+        private static final long serialVersionUID = 1L;
+
         @Override
         public void astore(final MethodVisitor method) {
             method.visitInsn(IASTORE);
@@ -961,6 +979,8 @@
      * This is the singleton for long arrays
      */
     public static final ArrayType LONG_ARRAY = new ArrayType(long[].class) {
+        private static final long serialVersionUID = 1L;
+
         @Override
         public void astore(final MethodVisitor method) {
             method.visitInsn(LASTORE);
@@ -988,6 +1008,8 @@
      * This is the singleton for numeric arrays
      */
     public static final ArrayType NUMBER_ARRAY = new ArrayType(double[].class) {
+        private static final long serialVersionUID = 1L;
+
         @Override
         public void astore(final MethodVisitor method) {
             method.visitInsn(DASTORE);
@@ -1022,6 +1044,8 @@
 
     /** This type, always an object type, just a toString override */
     public static final Type THIS = new ObjectType() {
+        private static final long serialVersionUID = 1L;
+
         @Override
         public String toString() {
             return "this";
@@ -1030,6 +1054,8 @@
 
     /** Scope type, always an object type, just a toString override */
     public static final Type SCOPE = new ObjectType() {
+        private static final long serialVersionUID = 1L;
+
         @Override
         public String toString() {
             return "scope";
@@ -1041,6 +1067,7 @@
     }
 
     private abstract static class ValueLessType extends Type {
+        private static final long serialVersionUID = 1L;
 
         ValueLessType(final String name) {
             super(name, Unknown.class, MIN_WEIGHT, 1);
@@ -1092,6 +1119,8 @@
      * inference. It has the minimum type width
      */
     public static final Type UNKNOWN = new ValueLessType("<unknown>") {
+        private static final long serialVersionUID = 1L;
+
         @Override
         public String getDescriptor() {
             return "<unknown>";
@@ -1108,6 +1137,7 @@
      * inference. It has the minimum type width
      */
     public static final Type SLOT_2 = new ValueLessType("<slot_2>") {
+        private static final long serialVersionUID = 1L;
 
         @Override
         public String getDescriptor() {
@@ -1124,4 +1154,8 @@
         cache.put(type.getTypeClass(), type);
         return type;
     }
+
+    protected final Object readResolve() {
+        return Type.typeFor(clazz);
+    }
 }
--- a/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/AccessNode.java	Thu Oct 23 11:19:29 2014 -0700
+++ b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/AccessNode.java	Thu Oct 23 13:45:22 2014 -0700
@@ -34,6 +34,8 @@
  */
 @Immutable
 public final class AccessNode extends BaseNode {
+    private static final long serialVersionUID = 1L;
+
     /** Property name. */
     private final String property;
 
--- a/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/BaseNode.java	Thu Oct 23 11:19:29 2014 -0700
+++ b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/BaseNode.java	Thu Oct 23 13:45:22 2014 -0700
@@ -39,6 +39,7 @@
  */
 @Immutable
 public abstract class BaseNode extends Expression implements FunctionCall, Optimistic {
+    private static final long serialVersionUID = 1L;
 
     /** Base Node. */
     protected final Expression base;
--- a/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/BinaryNode.java	Thu Oct 23 11:19:29 2014 -0700
+++ b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/BinaryNode.java	Thu Oct 23 13:45:22 2014 -0700
@@ -43,6 +43,8 @@
  */
 @Immutable
 public final class BinaryNode extends Expression implements Assignment<Expression>, Optimistic {
+    private static final long serialVersionUID = 1L;
+
     // Placeholder for "undecided optimistic ADD type". Unfortunately, we can't decide the type of ADD during optimistic
     // type calculation as it can have local variables as its operands that will decide its ultimate type.
     private static final Type OPTIMISTIC_UNDECIDED_TYPE = Type.typeFor(new Object(){/*empty*/}.getClass());
@@ -56,8 +58,8 @@
 
     private final Type type;
 
-    private Type cachedType;
-    private Object cachedTypeFunction;
+    private transient Type cachedType;
+    private transient Object cachedTypeFunction;
 
     @Ignore
     private static final Set<TokenType> CAN_OVERFLOW =
--- a/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/Block.java	Thu Oct 23 11:19:29 2014 -0700
+++ b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/Block.java	Thu Oct 23 13:45:22 2014 -0700
@@ -42,6 +42,8 @@
  */
 @Immutable
 public class Block extends Node implements BreakableNode, Terminal, Flags<Block> {
+    private static final long serialVersionUID = 1L;
+
     /** List of statements */
     protected final List<Statement> statements;
 
--- a/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/BlockLexicalContext.java	Thu Oct 23 11:19:29 2014 -0700
+++ b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/BlockLexicalContext.java	Thu Oct 23 13:45:22 2014 -0700
@@ -109,6 +109,16 @@
     }
 
     /**
+     * Prepend a list of statement to the block being generated
+     * @param statements a list of statements to prepend
+     */
+    public void prependStatements(final List<Statement> statements) {
+        assert statements != null;
+        sstack.peek().addAll(0, statements);
+    }
+
+
+    /**
      * Get the last statement that was emitted into a block
      * @return the last statement emitted
      */
--- a/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/BlockStatement.java	Thu Oct 23 11:19:29 2014 -0700
+++ b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/BlockStatement.java	Thu Oct 23 13:45:22 2014 -0700
@@ -32,6 +32,8 @@
  * Represents a block used as a statement.
  */
 public class BlockStatement extends Statement {
+    private static final long serialVersionUID = 1L;
+
     /** Block to execute. */
     private final Block block;
 
--- a/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/BreakNode.java	Thu Oct 23 11:19:29 2014 -0700
+++ b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/BreakNode.java	Thu Oct 23 13:45:22 2014 -0700
@@ -34,6 +34,7 @@
  */
 @Immutable
 public final class BreakNode extends JumpStatement {
+    private static final long serialVersionUID = 1L;
 
     /**
      * Constructor
--- a/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/BreakableStatement.java	Thu Oct 23 11:19:29 2014 -0700
+++ b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/BreakableStatement.java	Thu Oct 23 13:45:22 2014 -0700
@@ -32,6 +32,7 @@
 
 @Immutable
 abstract class BreakableStatement extends LexicalContextStatement implements BreakableNode {
+    private static final long serialVersionUID = 1L;
 
     /** break label. */
     protected final Label breakLabel;
--- a/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/CallNode.java	Thu Oct 23 11:19:29 2014 -0700
+++ b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/CallNode.java	Thu Oct 23 13:45:22 2014 -0700
@@ -27,6 +27,7 @@
 
 import static jdk.nashorn.internal.runtime.UnwarrantedOptimismException.INVALID_PROGRAM_POINT;
 
+import java.io.Serializable;
 import java.util.Collections;
 import java.util.List;
 import java.util.function.Function;
@@ -40,6 +41,7 @@
  */
 @Immutable
 public final class CallNode extends LexicalContextExpression implements Optimistic {
+    private static final long serialVersionUID = 1L;
 
     /** Function identifier or function body. */
     private final Expression function;
@@ -64,7 +66,8 @@
     /**
      * Arguments to be passed to builtin {@code eval} function
      */
-    public static class EvalArgs {
+    public static class EvalArgs implements Serializable {
+        private static final long serialVersionUID = 1L;
         private final List<Expression> args;
 
         /** location string for the eval call */
--- a/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/CaseNode.java	Thu Oct 23 11:19:29 2014 -0700
+++ b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/CaseNode.java	Thu Oct 23 13:45:22 2014 -0700
@@ -37,6 +37,8 @@
  */
 @Immutable
 public final class CaseNode extends Node implements JoinPredecessor, Labels, Terminal {
+    private static final long serialVersionUID = 1L;
+
     /** Test expression. */
     private final Expression test;
 
--- a/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/CatchNode.java	Thu Oct 23 11:19:29 2014 -0700
+++ b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/CatchNode.java	Thu Oct 23 13:45:22 2014 -0700
@@ -33,6 +33,8 @@
  */
 @Immutable
 public final class CatchNode extends Statement {
+    private static final long serialVersionUID = 1L;
+
     /** Exception identifier. */
     private final IdentNode exception;
 
--- a/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/ContinueNode.java	Thu Oct 23 11:19:29 2014 -0700
+++ b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/ContinueNode.java	Thu Oct 23 13:45:22 2014 -0700
@@ -34,6 +34,8 @@
  */
 @Immutable
 public class ContinueNode extends JumpStatement {
+    private static final long serialVersionUID = 1L;
+
     /**
      * Constructor
      *
@@ -80,4 +82,3 @@
         return ((LoopNode)target).getContinueLabel();
     }
 }
-
--- a/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/EmptyNode.java	Thu Oct 23 11:19:29 2014 -0700
+++ b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/EmptyNode.java	Thu Oct 23 13:45:22 2014 -0700
@@ -33,6 +33,7 @@
  */
 @Immutable
 public final class EmptyNode extends Statement {
+    private static final long serialVersionUID = 1L;
 
     /**
      * Constructor
--- a/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/Expression.java	Thu Oct 23 11:19:29 2014 -0700
+++ b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/Expression.java	Thu Oct 23 13:45:22 2014 -0700
@@ -35,6 +35,8 @@
  *
  */
 public abstract class Expression extends Node {
+    private static final long serialVersionUID = 1L;
+
     static final String OPT_IDENTIFIER = "%";
 
     private static final Function<Symbol, Type> UNKNOWN_LOCALS = new Function<Symbol, Type>() {
--- a/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/ExpressionStatement.java	Thu Oct 23 11:19:29 2014 -0700
+++ b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/ExpressionStatement.java	Thu Oct 23 13:45:22 2014 -0700
@@ -35,6 +35,8 @@
  */
 @Immutable
 public final class ExpressionStatement extends Statement {
+    private static final long serialVersionUID = 1L;
+
     /** Expression to execute. */
     private final Expression expression;
 
--- a/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/ForNode.java	Thu Oct 23 11:19:29 2014 -0700
+++ b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/ForNode.java	Thu Oct 23 13:45:22 2014 -0700
@@ -33,6 +33,8 @@
  */
 @Immutable
 public final class ForNode extends LoopNode {
+    private static final long serialVersionUID = 1L;
+
     /** Initialize expression for an ordinary for statement, or the LHS expression receiving iterated-over values in a
      * for-in statement. */
     private final Expression init;
--- a/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/FunctionNode.java	Thu Oct 23 11:19:29 2014 -0700
+++ b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/FunctionNode.java	Thu Oct 23 13:45:22 2014 -0700
@@ -31,6 +31,7 @@
 import static jdk.nashorn.internal.runtime.linker.NashornCallSiteDescriptor.CALLSITE_TRACE_ENTEREXIT;
 import static jdk.nashorn.internal.runtime.linker.NashornCallSiteDescriptor.CALLSITE_TRACE_MISSES;
 import static jdk.nashorn.internal.runtime.linker.NashornCallSiteDescriptor.CALLSITE_TRACE_VALUES;
+
 import java.util.Collections;
 import java.util.EnumSet;
 import java.util.Iterator;
@@ -57,6 +58,8 @@
  */
 @Immutable
 public final class FunctionNode extends LexicalContextExpression implements Flags<FunctionNode>, CompileUnitHolder {
+    private static final long serialVersionUID = 1L;
+
     /** Type used for all FunctionNodes */
     public static final Type FUNCTION_TYPE = Type.typeFor(ScriptFunction.class);
 
@@ -107,7 +110,7 @@
     }
 
     /** Source of entity. */
-    private final Source source;
+    private transient final Source source;
 
     /**
      * Opaque object representing parser state at the end of the function. Used when reparsing outer functions
@@ -141,7 +144,7 @@
     private final long lastToken;
 
     /** Method's namespace. */
-    private final Namespace namespace;
+    private transient final Namespace namespace;
 
     /** Current compilation state */
     @Ignore
@@ -207,31 +210,23 @@
     /** Are we vararg, but do we just pass the arguments along to apply or call */
     public static final int HAS_APPLY_TO_CALL_SPECIALIZATION = 1 << 12;
 
-    /** Does this function explicitly use the {@link CompilerConstants#RETURN} symbol? Some functions are known to
-     * always use the return symbol, namely a function that is a program (as it must track its last executed expression
-     * statement's value) as well as functions that are split (to communicate return values from inner to outer
-     * partitions). Other functions normally don't use the return symbol (so we optimize away its slot), except in some
-     * very special cases, e.g. when containing a return statement in a finally block. These special cases set this
-     * flag. */
-    public static final int USES_RETURN_SYMBOL = 1 << 13;
-
     /**
      * Is this function the top-level program?
      */
-    public static final int IS_PROGRAM = 1 << 14;
+    public static final int IS_PROGRAM = 1 << 13;
 
     /**
      * Flag indicating whether this function uses the local variable symbol for itself. Only named function expressions
      * can have this flag set if they reference themselves (e.g. "(function f() { return f })". Declared functions will
      * use the symbol in their parent scope instead when they reference themselves by name.
      */
-    public static final int USES_SELF_SYMBOL = 1 << 15;
+    public static final int USES_SELF_SYMBOL = 1 << 14;
 
     /** Does this function use the "this" keyword? */
-    public static final int USES_THIS = 1 << 16;
+    public static final int USES_THIS = 1 << 15;
 
     /** Is this declared in a dynamic context */
-    public static final int IN_DYNAMIC_CONTEXT = 1 << 17;
+    public static final int IN_DYNAMIC_CONTEXT = 1 << 16;
 
     /**
      * The following flags are derived from directive comments within this function.
@@ -239,28 +234,28 @@
      */
 
     /** parser, print parse tree */
-    public static final int IS_PRINT_PARSE       = 1 << 18;
+    public static final int IS_PRINT_PARSE       = 1 << 17;
     /** parser, print lower parse tree */
-    public static final int IS_PRINT_LOWER_PARSE = 1 << 19;
+    public static final int IS_PRINT_LOWER_PARSE = 1 << 18;
     /** parser, print AST */
-    public static final int IS_PRINT_AST         = 1 << 20;
+    public static final int IS_PRINT_AST         = 1 << 19;
     /** parser, print lower AST */
-    public static final int IS_PRINT_LOWER_AST   = 1 << 21;
+    public static final int IS_PRINT_LOWER_AST   = 1 << 20;
     /** parser, print symbols */
-    public static final int IS_PRINT_SYMBOLS     = 1 << 22;
+    public static final int IS_PRINT_SYMBOLS     = 1 << 21;
 
     // callsite tracing, profiling within this function
     /** profile callsites in this function? */
-    public static final int IS_PROFILE         = 1 << 23;
+    public static final int IS_PROFILE         = 1 << 22;
 
     /** trace callsite enterexit in this function? */
-    public static final int IS_TRACE_ENTEREXIT = 1 << 24;
+    public static final int IS_TRACE_ENTEREXIT = 1 << 23;
 
     /** trace callsite misses in this function? */
-    public static final int IS_TRACE_MISSES    = 1 << 25;
+    public static final int IS_TRACE_MISSES    = 1 << 24;
 
     /** trace callsite values in this function? */
-    public static final int IS_TRACE_VALUES    = 1 << 26;
+    public static final int IS_TRACE_VALUES    = 1 << 25;
 
     /**
      * Whether this function needs the callee {@link ScriptFunction} instance passed to its code as a
@@ -268,7 +263,7 @@
      * Rather, it is always calculated (see {@link #needsCallee()}). {@link RecompilableScriptFunctionData}
      * will, however, cache the value of this flag.
      */
-    public static final int NEEDS_CALLEE       = 1 << 27;
+    public static final int NEEDS_CALLEE       = 1 << 26;
 
     /** extension callsite flags mask */
     public static final int EXTENSION_CALLSITE_FLAGS = IS_PRINT_PARSE |
@@ -285,8 +280,8 @@
     /** Does this function potentially need "arguments"? Note that this is not a full test, as further negative check of REDEFINES_ARGS is needed. */
     private static final int MAYBE_NEEDS_ARGUMENTS = USES_ARGUMENTS | HAS_EVAL;
 
-    /** 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. */
-    private static final int NEEDS_PARENT_SCOPE = USES_ANCESTOR_SCOPE | HAS_DEEP_EVAL;
+    /** 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. */
+    public static final int NEEDS_PARENT_SCOPE = USES_ANCESTOR_SCOPE | HAS_DEEP_EVAL | IS_PROGRAM;
 
     /** What is the return type of this function? */
     private Type returnType = Type.UNKNOWN;
@@ -358,7 +353,8 @@
         final Block body,
         final List<IdentNode> parameters,
         final int thisProperties,
-        final Class<?> rootClass) {
+        final Class<?> rootClass,
+        final Source source, Namespace namespace) {
         super(functionNode);
 
         this.endParserState    = endParserState;
@@ -373,11 +369,11 @@
         this.parameters       = parameters;
         this.thisProperties   = thisProperties;
         this.rootClass        = rootClass;
+        this.source           = source;
+        this.namespace        = namespace;
 
         // the fields below never change - they are final and assigned in constructor
-        this.source          = functionNode.source;
         this.ident           = functionNode.ident;
-        this.namespace       = functionNode.namespace;
         this.kind            = functionNode.kind;
         this.firstToken      = functionNode.firstToken;
     }
@@ -443,6 +439,39 @@
     }
 
     /**
+     * Sets the source and namespace for this function. It can only set a non-null source and namespace for a function
+     * that currently has both a null source and a null namespace. This is used to re-set the source and namespace for
+     * a deserialized function node.
+     * @param source the source for the function.
+     * @param namespace the namespace for the function
+     * @return a new function node with the set source and namespace
+     * @throws IllegalArgumentException if the specified source or namespace is null
+     * @throws IllegalStateException if the function already has either a source or namespace set.
+     */
+    public FunctionNode initializeDeserialized(final Source source, final Namespace namespace) {
+        if (source == null || namespace == null) {
+            throw new IllegalArgumentException();
+        } else if (this.source == source && this.namespace == namespace) {
+            return this;
+        } else if (this.source != null || this.namespace != null) {
+            throw new IllegalStateException();
+        }
+        return new FunctionNode(
+            this,
+            lastToken,
+            endParserState,
+            flags,
+            name,
+            returnType,
+            compileUnit,
+            compilationState,
+            body,
+            parameters,
+            thisProperties,
+            rootClass, source, namespace);
+    }
+
+    /**
      * Get the unique ID for this function within the script file.
      * @return the id
      */
@@ -543,6 +572,28 @@
         }
         final EnumSet<CompilationState> newState = EnumSet.copyOf(this.compilationState);
         newState.add(state);
+        return setCompilationState(lc, newState);
+    }
+
+    /**
+     * Copy a compilation state from an original function to this function. Used when creating synthetic
+     * function nodes by the splitter.
+     *
+     * @param lc lexical context
+     * @param original the original function node to copy compilation state from
+     * @return function node or a new one if state was changed
+     */
+    public FunctionNode copyCompilationState(final LexicalContext lc, final FunctionNode original) {
+        final EnumSet<CompilationState> origState = original.compilationState;
+        if (!AssertsEnabled.assertsEnabled() || this.compilationState.containsAll(origState)) {
+            return this;
+        }
+        final EnumSet<CompilationState> newState = EnumSet.copyOf(this.compilationState);
+        newState.addAll(origState);
+        return setCompilationState(lc, newState);
+    }
+
+    private FunctionNode setCompilationState(final LexicalContext lc, final EnumSet<CompilationState> compilationState) {
         return Node.replaceInLexicalContext(
                 lc,
                 this,
@@ -554,13 +605,14 @@
                         name,
                         returnType,
                         compileUnit,
-                        newState,
+                        compilationState,
                         body,
                         parameters,
                         thisProperties,
-                        rootClass));
+                        rootClass, source, namespace));
     }
 
+
     /**
      * Create a unique name in the namespace of this FunctionNode
      * @param base prefix for name
@@ -630,7 +682,7 @@
                         body,
                         parameters,
                         thisProperties,
-                        rootClass));
+                        rootClass, source, namespace));
     }
 
     @Override
@@ -705,18 +757,11 @@
      * @return true if the function's generated Java method needs a {@code callee} parameter.
      */
     public boolean needsCallee() {
+        // NOTE: we only need isSplit() here to ensure that :scope can never drop below slot 2 for splitting array units.
         return needsParentScope() || usesSelfSymbol() || isSplit() || (needsArguments() && !isStrict()) || hasOptimisticApplyToCall();
     }
 
     /**
-     * Check if this function uses the return symbol
-     * @return true if uses the return symbol
-     */
-    public boolean usesReturnSymbol() {
-        return isProgram() || isSplit() || getFlag(USES_RETURN_SYMBOL);
-    }
-
-    /**
      * Return {@code true} if this function makes use of the {@code this} object.
      *
      * @return true if function uses {@code this} object
@@ -778,7 +823,7 @@
                         body,
                         parameters,
                         thisProperties,
-                        rootClass));
+                        rootClass, source, namespace));
     }
 
     /**
@@ -846,7 +891,7 @@
      * @return true if the function needs parent scope.
      */
     public boolean needsParentScope() {
-        return getFlag(NEEDS_PARENT_SCOPE) || isProgram();
+        return getFlag(NEEDS_PARENT_SCOPE);
     }
 
     /**
@@ -874,7 +919,7 @@
                         body,
                         parameters,
                         thisProperties,
-                        rootClass));
+                        rootClass, source, namespace));
     }
 
     /**
@@ -951,7 +996,7 @@
                         body,
                         parameters,
                         thisProperties,
-                        rootClass));
+                        rootClass, source, namespace));
     }
 
     /**
@@ -965,9 +1010,9 @@
     }
 
     /**
-     * Checks if this function is a sub-function generated by splitting a larger one
+     * Checks if this function is split into several smaller fragments.
      *
-     * @return true if this function is split from a larger one
+     * @return true if this function is split into several smaller fragments.
      */
     public boolean isSplit() {
         return getFlag(IS_SPLIT);
@@ -1017,7 +1062,7 @@
                         body,
                         parameters,
                         thisProperties,
-                        rootClass));
+                        rootClass, source, namespace));
     }
 
     /**
@@ -1096,7 +1141,7 @@
                 body,
                 parameters,
                 thisProperties,
-                rootClass
+                rootClass, source, namespace
                 ));
    }
 
@@ -1144,7 +1189,7 @@
                         body,
                         parameters,
                         thisProperties,
-                        rootClass));
+                        rootClass, source, namespace));
     }
 
     /**
@@ -1200,6 +1245,6 @@
                         body,
                         parameters,
                         thisProperties,
-                        rootClass));
+                        rootClass, source, namespace));
     }
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/GetSplitState.java	Thu Oct 23 13:45:22 2014 -0700
@@ -0,0 +1,70 @@
+/*
+ * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.nashorn.internal.ir;
+
+import java.util.function.Function;
+import jdk.nashorn.internal.codegen.CompilerConstants;
+import jdk.nashorn.internal.codegen.types.Type;
+import jdk.nashorn.internal.ir.visitor.NodeVisitor;
+import jdk.nashorn.internal.runtime.Scope;
+
+/**
+ * Synthetic AST node that represents loading of the scope object and invocation of the {@link Scope#getSplitState()}
+ * method on it. It has no JavaScript source representation and only occurs in synthetic functions created by
+ * the split-into-functions transformation.
+ */
+public final class GetSplitState extends Expression {
+    private static final long serialVersionUID = 1L;
+
+    /** The sole instance of this AST node. */
+    public final static GetSplitState INSTANCE = new GetSplitState();
+
+    private GetSplitState() {
+        super(NO_TOKEN, NO_FINISH);
+    }
+
+    @Override
+    public Type getType(final Function<Symbol, Type> localVariableTypes) {
+        return Type.INT;
+    }
+
+    @Override
+    public Node accept(final NodeVisitor<? extends LexicalContext> visitor) {
+        return visitor.enterGetSplitState(this) ? visitor.leaveGetSplitState(this) : this;
+    }
+
+    @Override
+    public void toString(final StringBuilder sb, final boolean printType) {
+        if (printType) {
+            sb.append("{I}");
+        }
+        sb.append(CompilerConstants.SCOPE.symbolName()).append('.').append(Scope.GET_SPLIT_STATE.name()).append("()");
+    }
+
+    private Object readResolve() {
+        return INSTANCE;
+    }
+}
--- a/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/IdentNode.java	Thu Oct 23 11:19:29 2014 -0700
+++ b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/IdentNode.java	Thu Oct 23 13:45:22 2014 -0700
@@ -42,6 +42,8 @@
  */
 @Immutable
 public final class IdentNode extends Expression implements PropertyKey, FunctionCall, Optimistic, JoinPredecessor {
+    private static final long serialVersionUID = 1L;
+
     private static final int PROPERTY_NAME     = 1 << 0;
     private static final int INITIALIZED_HERE  = 1 << 1;
     private static final int FUNCTION          = 1 << 2;
--- a/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/IfNode.java	Thu Oct 23 11:19:29 2014 -0700
+++ b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/IfNode.java	Thu Oct 23 13:45:22 2014 -0700
@@ -33,6 +33,8 @@
  */
 @Immutable
 public final class IfNode extends Statement implements JoinPredecessor {
+    private static final long serialVersionUID = 1L;
+
     /** Test expression. */
     private final Expression test;
 
--- a/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/IndexNode.java	Thu Oct 23 11:19:29 2014 -0700
+++ b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/IndexNode.java	Thu Oct 23 13:45:22 2014 -0700
@@ -33,6 +33,8 @@
  */
 @Immutable
 public final class IndexNode extends BaseNode {
+    private static final long serialVersionUID = 1L;
+
     /** Property index. */
     private final Expression index;
 
--- a/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/JoinPredecessorExpression.java	Thu Oct 23 11:19:29 2014 -0700
+++ b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/JoinPredecessorExpression.java	Thu Oct 23 13:45:22 2014 -0700
@@ -33,6 +33,7 @@
  * A wrapper for an expression that is in a position to be a join predecessor.
  */
 public class JoinPredecessorExpression extends Expression implements JoinPredecessor {
+    private static final long serialVersionUID = 1L;
 
     private final Expression expression;
     private final LocalVariableConversion conversion;
--- a/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/JumpStatement.java	Thu Oct 23 11:19:29 2014 -0700
+++ b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/JumpStatement.java	Thu Oct 23 13:45:22 2014 -0700
@@ -31,6 +31,7 @@
  * Common base class for jump statements (e.g. {@code break} and {@code continue}).
  */
 public abstract class JumpStatement extends Statement implements JoinPredecessor {
+    private static final long serialVersionUID = 1L;
 
     private final String labelName;
     private final LocalVariableConversion conversion;
--- a/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/LabelNode.java	Thu Oct 23 11:19:29 2014 -0700
+++ b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/LabelNode.java	Thu Oct 23 13:45:22 2014 -0700
@@ -35,6 +35,8 @@
  */
 @Immutable
 public final class LabelNode extends LexicalContextStatement implements JoinPredecessor {
+    private static final long serialVersionUID = 1L;
+
     /** Label ident. */
     private final String labelName;
 
--- a/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/LexicalContext.java	Thu Oct 23 11:19:29 2014 -0700
+++ b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/LexicalContext.java	Thu Oct 23 13:45:22 2014 -0700
@@ -440,6 +440,14 @@
     }
 
     /**
+     * Is the topmost lexical context element body of a SplitNode?
+     * @return true if it's the body of a split node.
+     */
+    public boolean isSplitBody() {
+        return sp >= 2 && stack[sp - 1] instanceof Block && stack[sp - 2] instanceof SplitNode;
+    }
+
+    /**
      * Get the parent function for a function in the lexical context
      * @param functionNode function for which to get parent
      * @return parent function of functionNode or null if none (e.g. if functionNode is the program)
@@ -472,9 +480,6 @@
             final LexicalContextNode node = iter.next();
             if (node == until) {
                 break;
-            } else if (node instanceof SplitNode) {
-                // Don't bother popping scopes if we're going to do a return from a split method anyway.
-                return 0;
             }
             assert !(node instanceof FunctionNode); // Can't go outside current function
             if (node instanceof WithNode || node instanceof Block && ((Block)node).needsScope()) {
--- a/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/LexicalContextExpression.java	Thu Oct 23 11:19:29 2014 -0700
+++ b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/LexicalContextExpression.java	Thu Oct 23 13:45:22 2014 -0700
@@ -28,6 +28,7 @@
 import jdk.nashorn.internal.ir.visitor.NodeVisitor;
 
 abstract class LexicalContextExpression extends Expression implements LexicalContextNode {
+    private static final long serialVersionUID = 1L;
 
     LexicalContextExpression(final LexicalContextExpression expr) {
         super(expr);
--- a/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/LexicalContextStatement.java	Thu Oct 23 11:19:29 2014 -0700
+++ b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/LexicalContextStatement.java	Thu Oct 23 13:45:22 2014 -0700
@@ -28,6 +28,8 @@
 import jdk.nashorn.internal.ir.visitor.NodeVisitor;
 
 abstract class LexicalContextStatement extends Statement implements LexicalContextNode {
+    private static final long serialVersionUID = 1L;
+
     /**
      * Constructor
      *
--- a/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/LiteralNode.java	Thu Oct 23 11:19:29 2014 -0700
+++ b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/LiteralNode.java	Thu Oct 23 13:45:22 2014 -0700
@@ -25,6 +25,7 @@
 
 package jdk.nashorn.internal.ir;
 
+import java.io.Serializable;
 import java.util.Arrays;
 import java.util.Collections;
 import java.util.List;
@@ -49,6 +50,8 @@
  */
 @Immutable
 public abstract class LiteralNode<T> extends Expression implements PropertyKey {
+    private static final long serialVersionUID = 1L;
+
     /** Literal value */
     protected final T value;
 
@@ -270,6 +273,8 @@
      * @param <T> the literal type
      */
     public static class PrimitiveLiteralNode<T> extends LiteralNode<T> {
+        private static final long serialVersionUID = 1L;
+
         private PrimitiveLiteralNode(final long token, final int finish, final T value) {
             super(token, finish, value);
         }
@@ -304,6 +309,7 @@
 
     @Immutable
     private static final class BooleanLiteralNode extends PrimitiveLiteralNode<Boolean> {
+        private static final long serialVersionUID = 1L;
 
         private BooleanLiteralNode(final long token, final int finish, final boolean value) {
             super(Token.recast(token, value ? TokenType.TRUE : TokenType.FALSE), finish, value);
@@ -356,6 +362,7 @@
 
     @Immutable
     private static final class NumberLiteralNode extends PrimitiveLiteralNode<Number> {
+        private static final long serialVersionUID = 1L;
 
         private final Type type = numberGetType(value);
 
@@ -418,6 +425,8 @@
     }
 
     private static class UndefinedLiteralNode extends PrimitiveLiteralNode<Undefined> {
+        private static final long serialVersionUID = 1L;
+
         private UndefinedLiteralNode(final long token, final int finish) {
             super(Token.recast(token, TokenType.OBJECT), finish, ScriptRuntime.UNDEFINED);
         }
@@ -454,6 +463,8 @@
 
     @Immutable
     private static class StringLiteralNode extends PrimitiveLiteralNode<String> {
+        private static final long serialVersionUID = 1L;
+
         private StringLiteralNode(final long token, final int finish, final String value) {
             super(Token.recast(token, TokenType.STRING), finish, value);
         }
@@ -497,6 +508,8 @@
 
     @Immutable
     private static class LexerTokenLiteralNode extends LiteralNode<LexerToken> {
+        private static final long serialVersionUID = 1L;
+
         private LexerTokenLiteralNode(final long token, final int finish, final LexerToken value) {
             super(Token.recast(token, TokenType.STRING), finish, value); //TODO is string the correct token type here?
         }
@@ -560,6 +573,7 @@
     }
 
     private static final class NullLiteralNode extends PrimitiveLiteralNode<Object> {
+        private static final long serialVersionUID = 1L;
 
         private NullLiteralNode(final long token, final int finish) {
             super(Token.recast(token, TokenType.OBJECT), finish, null);
@@ -590,6 +604,7 @@
      */
     @Immutable
     public static final class ArrayLiteralNode extends LiteralNode<Expression[]> implements LexicalContextNode {
+        private static final long serialVersionUID = 1L;
 
         /** Array element type. */
         private final Type elementType;
@@ -607,7 +622,9 @@
          * An ArrayUnit is a range in an ArrayLiteral. ArrayLiterals can
          * be split if they are too large, for bytecode generation reasons
          */
-        public static final class ArrayUnit implements CompileUnitHolder {
+        public static final class ArrayUnit implements CompileUnitHolder, Serializable {
+            private static final long serialVersionUID = 1L;
+
             /** Compile unit associated with the postsets range. */
             private final CompileUnit compileUnit;
 
@@ -655,13 +672,13 @@
         private static final class ArrayLiteralInitializer {
 
             static ArrayLiteralNode initialize(final ArrayLiteralNode node) {
-                final Type elementType = computeElementType(node.value, node.elementType);
+                final Type elementType = computeElementType(node.value);
                 final int[] postsets = computePostsets(node.value);
                 final Object presets = computePresets(node.value, elementType, postsets);
                 return new ArrayLiteralNode(node, node.value, elementType, postsets, presets, node.units);
             }
 
-            private static Type computeElementType(final Expression[] value, final Type elementType) {
+            private static Type computeElementType(final Expression[] value) {
                 Type widestElementType = Type.INT;
 
                 for (final Expression elem : value) {
--- a/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/LoopNode.java	Thu Oct 23 11:19:29 2014 -0700
+++ b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/LoopNode.java	Thu Oct 23 13:45:22 2014 -0700
@@ -34,6 +34,8 @@
  * A loop node, for example a while node, do while node or for node
  */
 public abstract class LoopNode extends BreakableStatement {
+    private static final long serialVersionUID = 1L;
+
     /** loop continue label. */
     protected final Label continueLabel;
 
--- a/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/Node.java	Thu Oct 23 11:19:29 2014 -0700
+++ b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/Node.java	Thu Oct 23 13:45:22 2014 -0700
@@ -25,6 +25,7 @@
 
 package jdk.nashorn.internal.ir;
 
+import java.io.Serializable;
 import java.util.ArrayList;
 import java.util.List;
 import jdk.nashorn.internal.ir.visitor.NodeVisitor;
@@ -34,7 +35,18 @@
 /**
  * Nodes are used to compose Abstract Syntax Trees.
  */
-public abstract class Node implements Cloneable {
+public abstract class Node implements Cloneable, Serializable {
+    private static final long serialVersionUID = 1L;
+
+    /** Constant used for synthetic AST nodes that have no line number. */
+    public static final int NO_LINE_NUMBER = -1;
+
+    /** Constant used for synthetic AST nodes that have no token. */
+    public static final long NO_TOKEN = 0L;
+
+    /** Constant used for synthetic AST nodes that have no finish. */
+    public static final int NO_FINISH = 0;
+
     /** Start of source range. */
     protected final int start;
 
--- a/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/ObjectNode.java	Thu Oct 23 11:19:29 2014 -0700
+++ b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/ObjectNode.java	Thu Oct 23 13:45:22 2014 -0700
@@ -37,6 +37,7 @@
  */
 @Immutable
 public final class ObjectNode extends Expression {
+    private static final long serialVersionUID = 1L;
 
     /** Literal elements. */
     private final List<PropertyNode> elements;
--- a/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/PropertyNode.java	Thu Oct 23 11:19:29 2014 -0700
+++ b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/PropertyNode.java	Thu Oct 23 13:45:22 2014 -0700
@@ -33,6 +33,7 @@
  */
 @Immutable
 public final class PropertyNode extends Node {
+    private static final long serialVersionUID = 1L;
 
     /** Property key. */
     private final PropertyKey key;
--- a/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/ReturnNode.java	Thu Oct 23 11:19:29 2014 -0700
+++ b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/ReturnNode.java	Thu Oct 23 13:45:22 2014 -0700
@@ -36,6 +36,8 @@
  */
 @Immutable
 public class ReturnNode extends Statement {
+    private static final long serialVersionUID = 1L;
+
     /** Optional expression. */
     private final Expression expression;
 
--- a/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/RuntimeNode.java	Thu Oct 23 11:19:29 2014 -0700
+++ b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/RuntimeNode.java	Thu Oct 23 13:45:22 2014 -0700
@@ -42,6 +42,7 @@
  */
 @Immutable
 public class RuntimeNode extends Expression implements Optimistic {
+    private static final long serialVersionUID = 1L;
 
     /**
      * Request enum used for meta-information about the runtime request
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/SetSplitState.java	Thu Oct 23 13:45:22 2014 -0700
@@ -0,0 +1,70 @@
+/*
+ * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.nashorn.internal.ir;
+
+import jdk.nashorn.internal.codegen.CompilerConstants;
+import jdk.nashorn.internal.ir.visitor.NodeVisitor;
+import jdk.nashorn.internal.runtime.Scope;
+
+/**
+ * Synthetic AST node that represents loading of the scope object and invocation of the {@link Scope#setSplitState(int)}
+ * method on it. It has no JavaScript source representation and only occurs in synthetic functions created by
+ * the split-into-functions transformation.
+ */
+public final class SetSplitState extends Statement {
+    private static final long serialVersionUID = 1L;
+
+    private final int state;
+
+    /**
+     * Creates a new split state setter
+     * @param state the state to set
+     * @param lineNumber the line number where it is inserted
+     */
+    public SetSplitState(final int state, final int lineNumber) {
+        super(lineNumber, NO_TOKEN, NO_FINISH);
+        this.state = state;
+    }
+
+    /**
+     * Returns the state this setter sets.
+     * @return the state this setter sets.
+     */
+    public int getState() {
+        return state;
+    }
+
+    @Override
+    public Node accept(final NodeVisitor<? extends LexicalContext> visitor) {
+        return visitor.enterSetSplitState(this) ? visitor.leaveSetSplitState(this) : this;
+    }
+
+    @Override
+    public void toString(final StringBuilder sb, final boolean printType) {
+        sb.append(CompilerConstants.SCOPE.symbolName()).append('.').append(Scope.SET_SPLIT_STATE.name())
+        .append('(').append(state).append(");");
+    }
+}
--- a/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/SplitNode.java	Thu Oct 23 11:19:29 2014 -0700
+++ b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/SplitNode.java	Thu Oct 23 13:45:22 2014 -0700
@@ -25,13 +25,10 @@
 
 package jdk.nashorn.internal.ir;
 
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
+import java.io.IOException;
+import java.io.NotSerializableException;
+import java.io.ObjectOutputStream;
 import jdk.nashorn.internal.codegen.CompileUnit;
-import jdk.nashorn.internal.codegen.Label;
 import jdk.nashorn.internal.ir.annotations.Immutable;
 import jdk.nashorn.internal.ir.visitor.NodeVisitor;
 
@@ -39,7 +36,9 @@
  * Node indicating code is split across classes.
  */
 @Immutable
-public class SplitNode extends LexicalContextStatement implements Labels, CompileUnitHolder {
+public class SplitNode extends LexicalContextStatement implements CompileUnitHolder {
+    private static final long serialVersionUID = 1L;
+
     /** Split node method name. */
     private final String name;
 
@@ -49,8 +48,6 @@
     /** Body of split code. */
     private final Block body;
 
-    private Map<Label, JoinPredecessor> jumps;
-
     /**
      * Constructor
      *
@@ -65,19 +62,18 @@
         this.compileUnit = compileUnit;
     }
 
-    private SplitNode(final SplitNode splitNode, final Block body, final CompileUnit compileUnit, final Map<Label, JoinPredecessor> jumps) {
+    private SplitNode(final SplitNode splitNode, final Block body, final CompileUnit compileUnit) {
         super(splitNode);
         this.name        = splitNode.name;
         this.body        = body;
         this.compileUnit = compileUnit;
-        this.jumps       = jumps;
     }
 
     /**
      * Get the body for this split node - i.e. the actual code it encloses
      * @return body for split node
      */
-    public Node getBody() {
+    public Block getBody() {
         return body;
     }
 
@@ -85,7 +81,7 @@
         if (this.body == body) {
             return this;
         }
-        return Node.replaceInLexicalContext(lc, this, new SplitNode(this, body, compileUnit, jumps));
+        return Node.replaceInLexicalContext(lc, this, new SplitNode(this, body, compileUnit));
     }
 
     @Override
@@ -131,33 +127,12 @@
         if (this.compileUnit == compileUnit) {
             return this;
         }
-        return Node.replaceInLexicalContext(lc, this, new SplitNode(this, body, compileUnit, jumps));
+        return Node.replaceInLexicalContext(lc, this, new SplitNode(this, body, compileUnit));
     }
 
-    /**
-     * Adds a jump that crosses this split node's boundary (it originates within the split node, and goes to a target
-     * outside of it).
-     * @param jumpOrigin the join predecessor that's the origin of the jump
-     * @param targetLabel the label that's the target of the jump.
-     */
-    public void addJump(final JoinPredecessor jumpOrigin, final Label targetLabel) {
-        if (jumps == null) {
-            jumps = new HashMap<>();
-        }
-        jumps.put(targetLabel, jumpOrigin);
-    }
-
-    /**
-     * Returns the jump origin within this split node for a target.
-     * @param targetLabel the target for which a jump origin is sought.
-     * @return the jump origin, or null.
-     */
-    public JoinPredecessor getJumpOrigin(final Label targetLabel) {
-        return jumps == null ? null : jumps.get(targetLabel);
-    }
-
-    @Override
-    public List<Label> getLabels() {
-        return Collections.unmodifiableList(new ArrayList<>(jumps.keySet()));
+    private void writeObject(final ObjectOutputStream out) throws IOException {
+        // We are only serializing the AST after we run SplitIntoFunctions; no SplitNodes can remain for the
+        // serialization.
+        throw new NotSerializableException(getClass().getName());
     }
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/SplitReturn.java	Thu Oct 23 13:45:22 2014 -0700
@@ -0,0 +1,64 @@
+/*
+ * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.nashorn.internal.ir;
+
+import jdk.nashorn.internal.ir.visitor.NodeVisitor;
+
+/**
+ * Synthetic AST node that represents return from a split fragment of a split function for control flow reasons (break
+ * or continue into a target outside the current fragment). It has no JavaScript source representation and only occurs
+ * in synthetic functions created by the split-into-functions transformation. It is different from a return node in
+ * that the return value is irrelevant, and doesn't affect the function's return type calculation.
+ */
+public final class SplitReturn extends Statement {
+    private static final long serialVersionUID = 1L;
+
+    /** The sole instance of this AST node. */
+    public static final SplitReturn INSTANCE = new SplitReturn();
+
+    private SplitReturn() {
+        super(NO_LINE_NUMBER, NO_TOKEN, NO_FINISH);
+    }
+
+    @Override
+    public boolean isTerminal() {
+        return true;
+    }
+
+    @Override
+    public Node accept(final NodeVisitor<? extends LexicalContext> visitor) {
+        return visitor.enterSplitReturn(this) ? visitor.leaveSplitReturn(this) : this;
+    }
+
+    @Override
+    public void toString(StringBuilder sb, boolean printType) {
+        sb.append(":splitreturn;");
+    }
+
+    private Object readResolve() {
+        return INSTANCE;
+    }
+}
--- a/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/Statement.java	Thu Oct 23 11:19:29 2014 -0700
+++ b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/Statement.java	Thu Oct 23 13:45:22 2014 -0700
@@ -31,6 +31,7 @@
  * location information is the Statement
  */
 public abstract class Statement extends Node implements Terminal {
+    private static final long serialVersionUID = 1L;
 
     private final int lineNumber;
 
--- a/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/SwitchNode.java	Thu Oct 23 11:19:29 2014 -0700
+++ b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/SwitchNode.java	Thu Oct 23 13:45:22 2014 -0700
@@ -37,6 +37,8 @@
  */
 @Immutable
 public final class SwitchNode extends BreakableStatement {
+    private static final long serialVersionUID = 1L;
+
     /** Switch expression. */
     private final Expression expression;
 
--- a/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/Symbol.java	Thu Oct 23 11:19:29 2014 -0700
+++ b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/Symbol.java	Thu Oct 23 13:45:22 2014 -0700
@@ -97,7 +97,7 @@
     private int firstSlot = -1;
 
     /** Field number in scope or property; array index in varargs when not using arguments object. */
-    private int fieldIndex;
+    private int fieldIndex = -1;
 
     /** Number of times this symbol is used in code */
     private int useCount;
@@ -135,28 +135,15 @@
      *
      * @param name  name of symbol
      * @param flags symbol flags
-     * @param slot  bytecode slot for this symbol
      */
-    protected Symbol(final String name, final int flags, final int slot) {
+    public Symbol(final String name, final int flags) {
         this.name       = name;
         this.flags      = flags;
-        this.firstSlot  = slot;
-        this.fieldIndex = -1;
         if(shouldTrace()) {
             trace("CREATE SYMBOL " + name);
         }
     }
 
-    /**
-     * Constructor
-     *
-     * @param name  name of symbol
-     * @param flags symbol flags
-     */
-    public Symbol(final String name, final int flags) {
-        this(name, flags, -1);
-    }
-
     private static String align(final String string, final int max) {
         final StringBuilder sb = new StringBuilder();
         sb.append(string.substring(0, Math.min(string.length(), max)));
--- a/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/TernaryNode.java	Thu Oct 23 11:19:29 2014 -0700
+++ b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/TernaryNode.java	Thu Oct 23 13:45:22 2014 -0700
@@ -37,6 +37,8 @@
  */
 @Immutable
 public final class TernaryNode extends Expression {
+    private static final long serialVersionUID = 1L;
+
     private final Expression test;
     private final JoinPredecessorExpression trueExpr;
     private final JoinPredecessorExpression falseExpr;
--- a/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/ThrowNode.java	Thu Oct 23 11:19:29 2014 -0700
+++ b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/ThrowNode.java	Thu Oct 23 13:45:22 2014 -0700
@@ -33,6 +33,8 @@
  */
 @Immutable
 public final class ThrowNode extends Statement implements JoinPredecessor {
+    private static final long serialVersionUID = 1L;
+
     /** Exception expression. */
     private final Expression expression;
 
--- a/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/TryNode.java	Thu Oct 23 11:19:29 2014 -0700
+++ b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/TryNode.java	Thu Oct 23 13:45:22 2014 -0700
@@ -36,6 +36,8 @@
  */
 @Immutable
 public final class TryNode extends Statement implements JoinPredecessor {
+    private static final long serialVersionUID = 1L;
+
     /** Try statements. */
     private final Block body;
 
--- a/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/UnaryNode.java	Thu Oct 23 11:19:29 2014 -0700
+++ b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/UnaryNode.java	Thu Oct 23 13:45:22 2014 -0700
@@ -46,6 +46,8 @@
  */
 @Immutable
 public final class UnaryNode extends Expression implements Assignment<Expression>, Optimistic {
+    private static final long serialVersionUID = 1L;
+
     /** Right hand side argument. */
     private final Expression expression;
 
--- a/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/VarNode.java	Thu Oct 23 11:19:29 2014 -0700
+++ b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/VarNode.java	Thu Oct 23 13:45:22 2014 -0700
@@ -34,6 +34,8 @@
  */
 @Immutable
 public final class VarNode extends Statement implements Assignment<IdentNode> {
+    private static final long serialVersionUID = 1L;
+
     /** Var name. */
     private final IdentNode name;
 
--- a/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/WhileNode.java	Thu Oct 23 11:19:29 2014 -0700
+++ b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/WhileNode.java	Thu Oct 23 13:45:22 2014 -0700
@@ -34,6 +34,8 @@
  */
 @Immutable
 public final class WhileNode extends LoopNode {
+    private static final long serialVersionUID = 1L;
+
 
     /** is this a do while node ? */
     private final boolean isDoWhile;
--- a/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/WithNode.java	Thu Oct 23 11:19:29 2014 -0700
+++ b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/WithNode.java	Thu Oct 23 13:45:22 2014 -0700
@@ -33,6 +33,8 @@
  */
 @Immutable
 public final class WithNode extends LexicalContextStatement {
+    private static final long serialVersionUID = 1L;
+
    /** This expression. */
     private final Expression expression;
 
--- a/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/visitor/NodeVisitor.java	Thu Oct 23 11:19:29 2014 -0700
+++ b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/visitor/NodeVisitor.java	Thu Oct 23 13:45:22 2014 -0700
@@ -38,6 +38,7 @@
 import jdk.nashorn.internal.ir.ExpressionStatement;
 import jdk.nashorn.internal.ir.ForNode;
 import jdk.nashorn.internal.ir.FunctionNode;
+import jdk.nashorn.internal.ir.GetSplitState;
 import jdk.nashorn.internal.ir.IdentNode;
 import jdk.nashorn.internal.ir.IfNode;
 import jdk.nashorn.internal.ir.IndexNode;
@@ -50,7 +51,9 @@
 import jdk.nashorn.internal.ir.PropertyNode;
 import jdk.nashorn.internal.ir.ReturnNode;
 import jdk.nashorn.internal.ir.RuntimeNode;
+import jdk.nashorn.internal.ir.SetSplitState;
 import jdk.nashorn.internal.ir.SplitNode;
+import jdk.nashorn.internal.ir.SplitReturn;
 import jdk.nashorn.internal.ir.SwitchNode;
 import jdk.nashorn.internal.ir.TernaryNode;
 import jdk.nashorn.internal.ir.ThrowNode;
@@ -390,6 +393,26 @@
     }
 
     /**
+     * Callback for entering a {@link GetSplitState}.
+     *
+     * @param  getSplitState the get split state expression
+     * @return true if traversal should continue and node children be traversed, false otherwise
+     */
+    public boolean enterGetSplitState(final GetSplitState getSplitState) {
+        return enterDefault(getSplitState);
+    }
+
+    /**
+     * Callback for leaving a {@link GetSplitState}.
+     *
+     * @param  getSplitState the get split state expression
+     * @return processed node, which will replace the original one, or the original node
+     */
+    public Node leaveGetSplitState(final GetSplitState getSplitState) {
+        return leaveDefault(getSplitState);
+    }
+
+    /**
      * Callback for entering an IdentNode
      *
      * @param  identNode the node
@@ -570,6 +593,26 @@
     }
 
     /**
+     * Callback for entering a {@link SetSplitState}.
+     *
+     * @param  setSplitState the set split state statement
+     * @return true if traversal should continue and node children be traversed, false otherwise
+     */
+    public boolean enterSetSplitState(final SetSplitState setSplitState) {
+        return enterDefault(setSplitState);
+    }
+
+    /**
+     * Callback for leaving a {@link SetSplitState}.
+     *
+     * @param  setSplitState the set split state expression
+     * @return processed node, which will replace the original one, or the original node
+     */
+    public Node leaveSetSplitState(final SetSplitState setSplitState) {
+        return leaveDefault(setSplitState);
+    }
+
+    /**
      * Callback for entering a SplitNode
      *
      * @param  splitNode the node
@@ -590,6 +633,26 @@
     }
 
     /**
+     * Callback for entering a SplitReturn
+     *
+     * @param  splitReturn the node
+     * @return true if traversal should continue and node children be traversed, false otherwise
+     */
+    public boolean enterSplitReturn(final SplitReturn splitReturn) {
+        return enterDefault(splitReturn);
+    }
+
+    /**
+     * Callback for leaving a SplitReturn
+     *
+     * @param  splitReturn the node
+     * @return processed node, which will replace the original one, or the original node
+     */
+    public Node leaveSplitReturn(final SplitReturn splitReturn) {
+        return leaveDefault(splitReturn);
+    }
+
+    /**
      * Callback for entering a SwitchNode
      *
      * @param  switchNode the node
--- a/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/lookup/MethodHandleFactory.java	Thu Oct 23 11:19:29 2014 -0700
+++ b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/lookup/MethodHandleFactory.java	Thu Oct 23 13:45:22 2014 -0700
@@ -48,7 +48,7 @@
 /**
  * This class is abstraction for all method handle, switchpoint and method type
  * operations. This enables the functionality interface to be subclassed and
- * intrumensted, as it has been proven vital to keep the number of method
+ * instrumented, as it has been proven vital to keep the number of method
  * handles in the system down.
  *
  * All operations of the above type should go through this class, and not
--- a/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeArray.java	Thu Oct 23 11:19:29 2014 -0700
+++ b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeArray.java	Thu Oct 23 13:45:22 2014 -0700
@@ -92,9 +92,10 @@
     private static final Object CALL_CMP                 = new Object();
     private static final Object TO_LOCALE_STRING         = new Object();
 
-    private SwitchPoint   lengthMadeNotWritableSwitchPoint;
-    private PushLinkLogic pushLinkLogic;
-    private PopLinkLogic  popLinkLogic;
+    private SwitchPoint     lengthMadeNotWritableSwitchPoint;
+    private PushLinkLogic   pushLinkLogic;
+    private PopLinkLogic    popLinkLogic;
+    private ConcatLinkLogic concatLinkLogic;
 
     /**
      * Index for the modification SwitchPoint that triggers when length
@@ -130,7 +131,9 @@
         this(ArrayData.allocate(array.length));
 
         ArrayData arrayData = this.getArray();
-        arrayData.ensure(array.length - 1);
+        if (array.length > 0) {
+            arrayData.ensure(array.length - 1);
+        }
 
         for (int index = 0; index < array.length; index++) {
             final Object value = array[index];
@@ -757,12 +760,86 @@
      * ECMA 15.4.4.4 Array.prototype.concat ( [ item1 [ , item2 [ , ... ] ] ] )
      *
      * @param self self reference
+     * @param arg argument
+     * @return resulting NativeArray
+     */
+    @SpecializedFunction(linkLogic=ConcatLinkLogic.class)
+    public static NativeArray concat(final Object self, final int arg) {
+        final ContinuousArrayData newData = getContinuousArrayDataCCE(self, Integer.class).copy(); //get at least an integer data copy of this data
+        newData.fastPush(arg); //add an integer to its end
+        return new NativeArray(newData);
+    }
+
+    /**
+     * ECMA 15.4.4.4 Array.prototype.concat ( [ item1 [ , item2 [ , ... ] ] ] )
+     *
+     * @param self self reference
+     * @param arg argument
+     * @return resulting NativeArray
+     */
+    @SpecializedFunction(linkLogic=ConcatLinkLogic.class)
+    public static NativeArray concat(final Object self, final long arg) {
+        final ContinuousArrayData newData = getContinuousArrayDataCCE(self, Long.class).copy(); //get at least a long array data copy of this data
+        newData.fastPush(arg); //add a long at the end
+        return new NativeArray(newData);
+    }
+
+    /**
+     * ECMA 15.4.4.4 Array.prototype.concat ( [ item1 [ , item2 [ , ... ] ] ] )
+     *
+     * @param self self reference
+     * @param arg argument
+     * @return resulting NativeArray
+     */
+    @SpecializedFunction(linkLogic=ConcatLinkLogic.class)
+    public static NativeArray concat(final Object self, final double arg) {
+        final ContinuousArrayData newData = getContinuousArrayDataCCE(self, Double.class).copy(); //get at least a number array data copy of this data
+        newData.fastPush(arg); //add a double at the end
+        return new NativeArray(newData);
+    }
+
+    /**
+     * ECMA 15.4.4.4 Array.prototype.concat ( [ item1 [ , item2 [ , ... ] ] ] )
+     *
+     * @param self self reference
+     * @param arg argument
+     * @return resulting NativeArray
+     */
+    @SpecializedFunction(linkLogic=ConcatLinkLogic.class)
+    public static NativeArray concat(final Object self, final Object arg) {
+        //arg is [NativeArray] of same type.
+        final ContinuousArrayData selfData = getContinuousArrayDataCCE(self);
+        final ContinuousArrayData newData;
+
+        if (arg instanceof NativeArray) {
+            final ContinuousArrayData argData = (ContinuousArrayData)((NativeArray)arg).getArray();
+            if (argData.isEmpty()) {
+                newData = selfData.copy();
+            } else if (selfData.isEmpty()) {
+                newData = argData.copy();
+            } else {
+                final Class<?> widestElementType = selfData.widest(argData).getBoxedElementType();
+                newData = ((ContinuousArrayData)selfData.convert(widestElementType)).fastConcat((ContinuousArrayData)argData.convert(widestElementType));
+            }
+        } else {
+            newData = getContinuousArrayDataCCE(self, Object.class).copy();
+            newData.fastPush(arg);
+        }
+
+        return new NativeArray(newData);
+    }
+
+    /**
+     * ECMA 15.4.4.4 Array.prototype.concat ( [ item1 [ , item2 [ , ... ] ] ] )
+     *
+     * @param self self reference
      * @param args arguments
      * @return resulting NativeArray
      */
     @Function(attributes = Attribute.NOT_ENUMERABLE, arity = 1)
     public static NativeArray concat(final Object self, final Object... args) {
         final ArrayList<Object> list = new ArrayList<>();
+
         concatToList(list, Global.toObject(self));
 
         for (final Object obj : args) {
@@ -1692,13 +1769,15 @@
             return pushLinkLogic == null ? new PushLinkLogic(this) : pushLinkLogic;
         } else if (clazz == PopLinkLogic.class) {
             return popLinkLogic == null ? new PopLinkLogic(this) : pushLinkLogic;
+        } else if (clazz == ConcatLinkLogic.class) {
+            return concatLinkLogic == null ? new ConcatLinkLogic(this) : concatLinkLogic;
         }
         return null;
     }
 
     @Override
     public boolean hasPerInstanceAssumptions() {
-        return true; //length switchpoint
+        return true; //length writable switchpoint
     }
 
     /**
@@ -1798,6 +1877,40 @@
     }
 
     /**
+     * This is linker logic for optimistic concatenations
+     */
+    private static final class ConcatLinkLogic extends ArrayLinkLogic {
+        private ConcatLinkLogic(final NativeArray array) {
+            super(array);
+        }
+
+        @Override
+        public boolean canLink(final Object self, final CallSiteDescriptor desc, final LinkRequest request) {
+            final Object[] args = request.getArguments();
+
+            if (args.length != 3) { //single argument check
+                return false;
+            }
+
+            final ContinuousArrayData selfData = getContinuousArrayData(self);
+            if (selfData == null) {
+                return false;
+            }
+
+            final Object arg = args[2];
+            //args[2] continuousarray or non arraydata, let past non array datas
+            if (arg instanceof NativeArray) {
+                final ContinuousArrayData argData = getContinuousArrayData(arg);
+                if (argData == null) {
+                    return false;
+                }
+            }
+
+            return true;
+        }
+    }
+
+    /**
      * This is linker logic for optimistic pushes
      */
     private static final class PushLinkLogic extends ArrayLinkLogic {
@@ -1864,6 +1977,14 @@
         throw new ClassCastException();
     }
 
+    private static final ContinuousArrayData getContinuousArrayDataCCE(final Object self) {
+        try {
+            return (ContinuousArrayData)((NativeArray)self).getArray();
+         } catch (final NullPointerException e) {
+             throw new ClassCastException();
+         }
+    }
+
     private static final ContinuousArrayData getContinuousArrayDataCCE(final Object self, final Class<?> elementType) {
         try {
            return (ContinuousArrayData)((NativeArray)self).getArray(elementType); //ensure element type can fit "elementType"
--- a/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeFloat32Array.java	Thu Oct 23 11:19:29 2014 -0700
+++ b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeFloat32Array.java	Thu Oct 23 13:45:22 2014 -0700
@@ -90,6 +90,11 @@
         }
 
         @Override
+        public Class<?> getBoxedElementType() {
+            return Double.class;
+        }
+
+        @Override
         protected MethodHandle getGetElem() {
             return GET_ELEM;
         }
--- a/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeFloat64Array.java	Thu Oct 23 11:19:29 2014 -0700
+++ b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeFloat64Array.java	Thu Oct 23 13:45:22 2014 -0700
@@ -99,6 +99,11 @@
             return double.class;
         }
 
+        @Override
+        public Class<?> getBoxedElementType() {
+            return Double.class;
+        }
+
         private double getElem(final int index) {
             try {
                 return nb.get(index);
--- a/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeInt16Array.java	Thu Oct 23 11:19:29 2014 -0700
+++ b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeInt16Array.java	Thu Oct 23 13:45:22 2014 -0700
@@ -100,6 +100,11 @@
             return int.class;
         }
 
+        @Override
+        public Class<?> getBoxedElementType() {
+            return Integer.class;
+        }
+
         private int getElem(final int index) {
             try {
                 return nb.get(index);
--- a/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeInt32Array.java	Thu Oct 23 11:19:29 2014 -0700
+++ b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeInt32Array.java	Thu Oct 23 13:45:22 2014 -0700
@@ -118,6 +118,11 @@
         }
 
         @Override
+        public Class<?> getBoxedElementType() {
+            return Integer.class;
+        }
+
+        @Override
         public int getInt(final int index) {
             return getElem(index);
         }
--- a/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeInt8Array.java	Thu Oct 23 11:19:29 2014 -0700
+++ b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeInt8Array.java	Thu Oct 23 13:45:22 2014 -0700
@@ -98,6 +98,11 @@
             return int.class;
         }
 
+        @Override
+        public Class<?> getBoxedElementType() {
+            return Integer.class;
+        }
+
         private int getElem(final int index) {
             try {
                 return nb.get(index);
--- a/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeObject.java	Thu Oct 23 11:19:29 2014 -0700
+++ b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeObject.java	Thu Oct 23 13:45:22 2014 -0700
@@ -28,7 +28,6 @@
 import static jdk.nashorn.internal.lookup.Lookup.MH;
 import static jdk.nashorn.internal.runtime.ECMAErrors.typeError;
 import static jdk.nashorn.internal.runtime.ScriptRuntime.UNDEFINED;
-
 import java.lang.invoke.MethodHandle;
 import java.lang.invoke.MethodHandles;
 import java.lang.invoke.MethodType;
--- a/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeUint16Array.java	Thu Oct 23 11:19:29 2014 -0700
+++ b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeUint16Array.java	Thu Oct 23 13:45:22 2014 -0700
@@ -124,6 +124,11 @@
         }
 
         @Override
+        public Class<?> getBoxedElementType() {
+            return Integer.class;
+        }
+
+        @Override
         public int getInt(final int index) {
             return getElem(index);
         }
--- a/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeUint32Array.java	Thu Oct 23 11:19:29 2014 -0700
+++ b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeUint32Array.java	Thu Oct 23 13:45:22 2014 -0700
@@ -133,6 +133,11 @@
         }
 
         @Override
+        public Class<?> getBoxedElementType() {
+            return Integer.class;
+        }
+
+        @Override
         public int getInt(final int index) {
             return (int)getLong(index);
         }
--- a/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeUint8Array.java	Thu Oct 23 11:19:29 2014 -0700
+++ b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeUint8Array.java	Thu Oct 23 13:45:22 2014 -0700
@@ -124,6 +124,11 @@
         }
 
         @Override
+        public Class<?> getBoxedElementType() {
+            return Integer.class;
+        }
+
+        @Override
         public int getInt(final int index) {
             return getElem(index);
         }
--- a/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeUint8ClampedArray.java	Thu Oct 23 11:19:29 2014 -0700
+++ b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeUint8ClampedArray.java	Thu Oct 23 13:45:22 2014 -0700
@@ -103,6 +103,11 @@
             return int.class;
         }
 
+        @Override
+        public Class<?> getBoxedElementType() {
+            return int.class;
+        }
+
         private int getElem(final int index) {
             try {
                 return nb.get(index) & 0xff;
--- a/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/parser/JSONParser.java	Thu Oct 23 11:19:29 2014 -0700
+++ b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/parser/JSONParser.java	Thu Oct 23 13:45:22 2014 -0700
@@ -32,7 +32,6 @@
 import static jdk.nashorn.internal.parser.TokenType.RBRACE;
 import static jdk.nashorn.internal.parser.TokenType.RBRACKET;
 import static jdk.nashorn.internal.parser.TokenType.STRING;
-
 import java.util.ArrayList;
 import java.util.List;
 import jdk.nashorn.internal.ir.Expression;
--- a/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/parser/Lexer.java	Thu Oct 23 11:19:29 2014 -0700
+++ b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/parser/Lexer.java	Thu Oct 23 13:45:22 2014 -0700
@@ -46,6 +46,7 @@
 import static jdk.nashorn.internal.parser.TokenType.STRING;
 import static jdk.nashorn.internal.parser.TokenType.XML;
 
+import java.io.Serializable;
 import jdk.nashorn.internal.runtime.ECMAErrors;
 import jdk.nashorn.internal.runtime.ErrorManager;
 import jdk.nashorn.internal.runtime.JSErrorType;
@@ -1717,7 +1718,9 @@
      * Helper class for Lexer tokens, e.g XML or RegExp tokens.
      * This is the abstract superclass
      */
-    public static abstract class LexerToken {
+    public static abstract class LexerToken implements Serializable {
+        private static final long serialVersionUID = 1L;
+
         private final String expression;
 
         /**
@@ -1741,6 +1744,8 @@
      * Temporary container for regular expressions.
      */
     public static class RegexToken extends LexerToken {
+        private static final long serialVersionUID = 1L;
+
         /** Options. */
         private final String options;
 
@@ -1773,6 +1778,7 @@
      * Temporary container for XML expression.
      */
     public static class XMLToken extends LexerToken {
+        private static final long serialVersionUID = 1L;
 
         /**
          * Constructor.
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/AstDeserializer.java	Thu Oct 23 13:45:22 2014 -0700
@@ -0,0 +1,47 @@
+/*
+ * Copyright (c) 2010, 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package jdk.nashorn.internal.runtime;
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.util.zip.InflaterInputStream;
+import jdk.nashorn.internal.ir.FunctionNode;
+
+/**
+ * This static utility class performs deserialization of FunctionNode ASTs from a byte array.
+ * The format is a standard Java serialization stream, deflated.
+ */
+final class AstDeserializer {
+    static FunctionNode deserialize(final byte[] serializedAst) {
+        try {
+            return (FunctionNode)new ObjectInputStream(new InflaterInputStream(new ByteArrayInputStream(
+                    serializedAst))).readObject();
+        } catch (final ClassNotFoundException | IOException e) {
+            // This is internal, can't happen
+            throw new AssertionError("Unexpected exception deserializing function", e);
+        }
+    }
+}
--- a/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/CompiledFunction.java	Thu Oct 23 11:19:29 2014 -0700
+++ b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/CompiledFunction.java	Thu Oct 23 13:45:22 2014 -0700
@@ -27,6 +27,7 @@
 import static jdk.nashorn.internal.lookup.Lookup.MH;
 import static jdk.nashorn.internal.runtime.UnwarrantedOptimismException.INVALID_PROGRAM_POINT;
 import static jdk.nashorn.internal.runtime.UnwarrantedOptimismException.isValid;
+
 import java.lang.invoke.CallSite;
 import java.lang.invoke.MethodHandle;
 import java.lang.invoke.MethodHandles;
@@ -786,6 +787,7 @@
         // isn't available, we'll use the old one bound into the call site.
         final OptimismInfo effectiveOptInfo = currentOptInfo != null ? currentOptInfo : oldOptInfo;
         FunctionNode fn = effectiveOptInfo.reparse();
+        final boolean serialized = effectiveOptInfo.isSerialized();
         final Compiler compiler = effectiveOptInfo.getCompiler(fn, callSiteType, re); //set to non rest-of
 
         if (!shouldRecompile) {
@@ -793,17 +795,17 @@
             // recompiled a deoptimized version for an inner invocation.
             // We still need to do the rest of from the beginning
             logRecompile("Rest-of compilation [STANDALONE] ", fn, callSiteType, effectiveOptInfo.invalidatedProgramPoints);
-            return restOfHandle(effectiveOptInfo, compiler.compile(fn, CompilationPhases.COMPILE_ALL_RESTOF), currentOptInfo != null);
+            return restOfHandle(effectiveOptInfo, compiler.compile(fn, serialized ? CompilationPhases.COMPILE_SERIALIZED_RESTOF : CompilationPhases.COMPILE_ALL_RESTOF), currentOptInfo != null);
         }
 
         logRecompile("Deoptimizing recompilation (up to bytecode) ", fn, callSiteType, effectiveOptInfo.invalidatedProgramPoints);
-        fn = compiler.compile(fn, CompilationPhases.COMPILE_UPTO_BYTECODE);
+        fn = compiler.compile(fn, serialized ? CompilationPhases.RECOMPILE_SERIALIZED_UPTO_BYTECODE : CompilationPhases.COMPILE_UPTO_BYTECODE);
         log.info("Reusable IR generated");
 
         // compile the rest of the function, and install it
         log.info("Generating and installing bytecode from reusable IR...");
         logRecompile("Rest-of compilation [CODE PIPELINE REUSE] ", fn, callSiteType, effectiveOptInfo.invalidatedProgramPoints);
-        final FunctionNode normalFn = compiler.compile(fn, CompilationPhases.COMPILE_FROM_BYTECODE);
+        final FunctionNode normalFn = compiler.compile(fn, CompilationPhases.GENERATE_BYTECODE_AND_INSTALL);
 
         if (effectiveOptInfo.data.usePersistentCodeCache()) {
             final RecompilableScriptFunctionData data = effectiveOptInfo.data;
@@ -829,7 +831,7 @@
         constructor = null; // Will be regenerated when needed
 
         log.info("Done: ", invoker);
-        final MethodHandle restOf = restOfHandle(effectiveOptInfo, compiler.compile(fn, CompilationPhases.COMPILE_FROM_BYTECODE_RESTOF), canBeDeoptimized);
+        final MethodHandle restOf = restOfHandle(effectiveOptInfo, compiler.compile(fn, CompilationPhases.GENERATE_BYTECODE_AND_INSTALL_RESTOF), canBeDeoptimized);
 
         // Note that we only adjust the switch point after we set the invoker/constructor. This is important.
         if (canBeDeoptimized) {
@@ -921,6 +923,10 @@
         FunctionNode reparse() {
             return data.reparse();
         }
+
+        boolean isSerialized() {
+            return data.isSerialized();
+        }
     }
 
     @SuppressWarnings("unused")
--- a/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/Context.java	Thu Oct 23 11:19:29 2014 -0700
+++ b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/Context.java	Thu Oct 23 13:45:22 2014 -0700
@@ -150,6 +150,13 @@
         private final Context      context;
         private final ScriptLoader loader;
         private final CodeSource   codeSource;
+        private int usageCount = 0;
+        private int bytesDefined = 0;
+
+        // We reuse this installer for 10 compilations or 200000 defined bytes. Usually the first condition
+        // will occur much earlier, the second is a safety measure for very large scripts/functions.
+        private final static int MAX_USAGES = 10;
+        private final static int MAX_BYTES_DEFINED = 200_000;
 
         private ContextCodeInstaller(final Context context, final ScriptLoader loader, final CodeSource codeSource) {
             this.context    = context;
@@ -168,6 +175,8 @@
 
         @Override
         public Class<?> install(final String className, final byte[] bytecode) {
+            usageCount++;
+            bytesDefined += bytecode.length;
             final String   binaryName = Compiler.binaryName(className);
             return loader.installClass(binaryName, bytecode, codeSource);
         }
@@ -225,6 +234,10 @@
 
         @Override
         public CodeInstaller<ScriptEnvironment> withNewLoader() {
+            // Reuse this installer if we're within our limits.
+            if (usageCount < MAX_USAGES && bytesDefined < MAX_BYTES_DEFINED) {
+                return this;
+            }
             return new ContextCodeInstaller(context, context.createNewLoader(), codeSource);
         }
 
--- a/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/JSType.java	Thu Oct 23 11:19:29 2014 -0700
+++ b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/JSType.java	Thu Oct 23 13:45:22 2014 -0700
@@ -29,7 +29,6 @@
 import static jdk.nashorn.internal.codegen.ObjectClassGenerator.OBJECT_FIELDS_ONLY;
 import static jdk.nashorn.internal.lookup.Lookup.MH;
 import static jdk.nashorn.internal.runtime.ECMAErrors.typeError;
-
 import java.lang.invoke.MethodHandle;
 import java.lang.invoke.MethodHandles;
 import java.lang.reflect.Array;
@@ -1776,6 +1775,23 @@
     }
 
     /**
+     * Returns the boxed version of a primitive class
+     * @param clazz the class
+     * @return the boxed type of clazz, or unchanged if not primitive
+     */
+    public static Class<?> getBoxedClass(final Class<?> clazz) {
+        if (clazz == int.class) {
+            return Integer.class;
+        } else if (clazz == long.class) {
+            return Long.class;
+        } else if (clazz == double.class) {
+            return Double.class;
+        }
+        assert !clazz.isPrimitive();
+        return clazz;
+    }
+
+    /**
      * Create a method handle constant of the correct primitive type
      * for a constant object
      * @param o object
--- a/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/RecompilableScriptFunctionData.java	Thu Oct 23 11:19:29 2014 -0700
+++ b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/RecompilableScriptFunctionData.java	Thu Oct 23 13:45:22 2014 -0700
@@ -43,6 +43,7 @@
 import jdk.nashorn.internal.codegen.Compiler.CompilationPhases;
 import jdk.nashorn.internal.codegen.CompilerConstants;
 import jdk.nashorn.internal.codegen.FunctionSignature;
+import jdk.nashorn.internal.codegen.Namespace;
 import jdk.nashorn.internal.codegen.ObjectClassGenerator.AllocatorDescriptor;
 import jdk.nashorn.internal.codegen.OptimisticTypesPersistence;
 import jdk.nashorn.internal.codegen.TypeMap;
@@ -79,6 +80,9 @@
     /** Source from which FunctionNode was parsed. */
     private transient Source source;
 
+    /** Serialized, compressed form of the AST. Used by split functions as they can't be reparsed from source. */
+    private final byte[] serializedAst;
+
     /** Token of this function within the source. */
     private final long token;
 
@@ -127,6 +131,7 @@
      * @param nestedFunctions     nested function map
      * @param externalScopeDepths external scope depths
      * @param internalSymbols     internal symbols to method, defined in its scope
+     * @param serializedAst       a serialized AST representation. Normally only used for split functions.
      */
     public RecompilableScriptFunctionData(
         final FunctionNode functionNode,
@@ -134,7 +139,8 @@
         final AllocatorDescriptor allocationDescriptor,
         final Map<Integer, RecompilableScriptFunctionData> nestedFunctions,
         final Map<String, Integer> externalScopeDepths,
-        final Set<String> internalSymbols) {
+        final Set<String> internalSymbols,
+        final byte[] serializedAst) {
 
         super(functionName(functionNode),
               Math.min(functionNode.getParameters().size(), MAX_ARITY),
@@ -158,6 +164,7 @@
             nfn.setParent(this);
         }
 
+        this.serializedAst = serializedAst;
         createLogger();
     }
 
@@ -212,10 +219,7 @@
      */
     public int getExternalSymbolDepth(final String symbolName) {
         final Integer depth = externalScopeDepths.get(symbolName);
-        if (depth == null) {
-            return -1;
-        }
-        return depth;
+        return depth == null ? -1 : depth;
     }
 
     /**
@@ -354,8 +358,15 @@
         return allocationStrategy.allocate(map);
     }
 
+    boolean isSerialized() {
+        return serializedAst != null;
+    }
+
     FunctionNode reparse() {
-        // NOTE: If we aren't recompiling the top-level program, we decrease functionNodeId 'cause we'll have a synthetic program node
+        if (isSerialized()) {
+            return deserialize();
+        }
+
         final int descPosition = Token.descPosition(token);
         final Context context = Context.getContextTrusted();
         final Parser parser = new Parser(
@@ -363,8 +374,10 @@
             source,
             new Context.ThrowErrorManager(),
             isStrict(),
+            // source starts at line 0, so even though lineNumber is the correct declaration line, back off
+            // one to make it exclusive
             lineNumber - 1,
-            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
+            context.getLogger(Parser.class));
 
         if (getFunctionFlag(FunctionNode.IS_ANONYMOUS)) {
             parser.setFunctionName(functionName);
@@ -378,6 +391,17 @@
         return (isProgram() ? program : extractFunctionFromScript(program)).setName(null, functionName);
     }
 
+    private FunctionNode deserialize() {
+        final ScriptEnvironment env = installer.getOwner();
+        final Timing timing = env._timing;
+        final long t1 = System.nanoTime();
+        try {
+            return AstDeserializer.deserialize(serializedAst).initializeDeserialized(source, new Namespace(env.getNamespace()));
+        } finally {
+            timing.accumulateTime("'Deserialize'", System.nanoTime() - t1);
+        }
+    }
+
     private boolean getFunctionFlag(final int flag) {
         return (functionFlags & flag) != 0;
     }
@@ -486,7 +510,8 @@
 
         final FunctionNode fn = reparse();
         final Compiler compiler = getCompiler(fn, actualCallSiteType, runtimeScope);
-        final FunctionNode compiledFn = compiler.compile(fn, CompilationPhases.COMPILE_ALL);
+        final FunctionNode compiledFn = compiler.compile(fn,
+                isSerialized() ? CompilationPhases.COMPILE_ALL_SERIALIZED : CompilationPhases.COMPILE_ALL);
 
         if (persist && !compiledFn.getFlag(FunctionNode.HAS_APPLY_TO_CALL_SPECIALIZATION)) {
             compiler.persistClassInfo(cacheKey, compiledFn);
@@ -606,7 +631,7 @@
 
     MethodHandle lookupCodeMethod(final Class<?> codeClass, final MethodType targetType) {
         if (log.isEnabled()) {
-            log.info("Looking up ", DebugLogger.quote(name), " type=", targetType);
+            log.info("Looking up ", DebugLogger.quote(functionName), " type=", targetType);
         }
         return MH.findStatic(LOOKUP, codeClass, functionName, targetType);
     }
@@ -817,6 +842,26 @@
         return true;
     }
 
+    /**
+     * Restores the {@link #getFunctionFlags()} flags to a function node. During on-demand compilation, we might need
+     * to restore flags to a function node that was otherwise not subjected to a full compile pipeline (e.g. its parse
+     * was skipped, or it's a nested function of a deserialized function.
+     * @param lc current lexical context
+     * @param fn the function node to restore flags onto
+     * @return the transformed function node
+     */
+    public FunctionNode restoreFlags(final LexicalContext lc, final FunctionNode fn) {
+        assert fn.getId() == functionNodeId;
+        FunctionNode newFn = fn.setFlags(lc, functionFlags);
+        // This compensates for missing markEval() in case the function contains an inner function
+        // that contains eval(), that now we didn't discover since we skipped the inner function.
+        if (newFn.hasNestedEval()) {
+            assert newFn.hasScopeBlock();
+            newFn = newFn.setBody(lc, newFn.getBody().setNeedsScope(null));
+        }
+        return newFn;
+    }
+
     private void readObject(final java.io.ObjectInputStream in) throws IOException, ClassNotFoundException {
         in.defaultReadObject();
         createLogger();
--- a/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/ScriptObject.java	Thu Oct 23 11:19:29 2014 -0700
+++ b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/ScriptObject.java	Thu Oct 23 13:45:22 2014 -0700
@@ -692,8 +692,7 @@
         assert isValidArrayIndex(index) : "invalid array index";
         final long longIndex = ArrayIndex.toLongIndex(index);
         doesNotHaveEnsureDelete(longIndex, getArray().length(), false);
-        setArray(getArray().ensure(longIndex));
-        setArray(getArray().set(index, value, false));
+        setArray(getArray().ensure(longIndex).set(index,value, false));
     }
 
     private void checkIntegerKey(final String key) {
@@ -1462,9 +1461,8 @@
 
         //invalidate any fast array setters
         final ArrayData array = getArray();
-        if (array != null) {
-            array.invalidateSetters();
-        }
+        assert array != null;
+        setArray(ArrayData.preventExtension(array));
         return this;
     }
 
@@ -2645,20 +2643,22 @@
       * @param newLength new length to set
       */
     public final void setLength(final long newLength) {
-       final long arrayLength = getArray().length();
-       if (newLength == arrayLength) {
-           return;
-       }
-
-       if (newLength > arrayLength) {
-           setArray(getArray().ensure(newLength - 1));
-            if (getArray().canDelete(arrayLength, newLength - 1, false)) {
-               setArray(getArray().delete(arrayLength, newLength - 1));
-           }
-           return;
-       }
-
-       if (newLength < arrayLength) {
+        ArrayData data = getArray();
+        final long arrayLength = data.length();
+        if (newLength == arrayLength) {
+            return;
+        }
+
+        if (newLength > arrayLength) {
+            data = data.ensure(newLength - 1);
+            if (data.canDelete(arrayLength, newLength - 1, false)) {
+               data = data.delete(arrayLength, newLength - 1);
+            }
+            setArray(data);
+            return;
+        }
+
+        if (newLength < arrayLength) {
            long actualLength = newLength;
 
            // Check for numeric keys in property map and delete them or adjust length, depending on whether
@@ -2680,8 +2680,8 @@
                }
            }
 
-           setArray(getArray().shrink(actualLength));
-           getArray().setLength(actualLength);
+           setArray(data.shrink(actualLength));
+           data.setLength(actualLength);
        }
     }
 
@@ -3194,8 +3194,9 @@
         final int    index        = getArrayIndex(primitiveKey);
 
         if (isValidArrayIndex(index)) {
-            if (getArray().has(index)) {
-                setArray(getArray().set(index, value, NashornCallSiteDescriptor.isStrictFlag(callSiteFlags)));
+            final ArrayData data = getArray();
+            if (data.has(index)) {
+                setArray(data.set(index, value, NashornCallSiteDescriptor.isStrictFlag(callSiteFlags)));
             } else {
                 doesNotHave(index, value, callSiteFlags);
             }
@@ -3213,8 +3214,9 @@
         final int    index        = getArrayIndex(primitiveKey);
 
         if (isValidArrayIndex(index)) {
-            if (getArray().has(index)) {
-                setArray(getArray().set(index, value, NashornCallSiteDescriptor.isStrictFlag(callSiteFlags)));
+            final ArrayData data = getArray();
+            if (data.has(index)) {
+                setArray(data.set(index, value, NashornCallSiteDescriptor.isStrictFlag(callSiteFlags)));
             } else {
                 doesNotHave(index, value, callSiteFlags);
             }
@@ -3232,8 +3234,9 @@
         final int    index        = getArrayIndex(primitiveKey);
 
         if (isValidArrayIndex(index)) {
-            if (getArray().has(index)) {
-                setArray(getArray().set(index, value, NashornCallSiteDescriptor.isStrictFlag(callSiteFlags)));
+            final ArrayData data = getArray();
+            if (data.has(index)) {
+                setArray(data.set(index, value, NashornCallSiteDescriptor.isStrictFlag(callSiteFlags)));
             } else {
                 doesNotHave(index, value, callSiteFlags);
             }
@@ -3251,8 +3254,9 @@
         final int    index        = getArrayIndex(primitiveKey);
 
         if (isValidArrayIndex(index)) {
-            if (getArray().has(index)) {
-                setArray(getArray().set(index, value, NashornCallSiteDescriptor.isStrictFlag(callSiteFlags)));
+            final ArrayData data = getArray();
+            if (data.has(index)) {
+                setArray(data.set(index, value, NashornCallSiteDescriptor.isStrictFlag(callSiteFlags)));
             } else {
                 doesNotHave(index, value, callSiteFlags);
             }
@@ -3269,8 +3273,9 @@
         final int index = getArrayIndex(key);
 
         if (isValidArrayIndex(index)) {
-            if (getArray().has(index)) {
-                setArray(getArray().set(index, value, NashornCallSiteDescriptor.isStrictFlag(callSiteFlags)));
+            final ArrayData data = getArray();
+            if (data.has(index)) {
+                setArray(data.set(index, value, NashornCallSiteDescriptor.isStrictFlag(callSiteFlags)));
             } else {
                 doesNotHave(index, value, callSiteFlags);
             }
@@ -3287,8 +3292,9 @@
         final int index = getArrayIndex(key);
 
         if (isValidArrayIndex(index)) {
-            if (getArray().has(index)) {
-                setArray(getArray().set(index, value, NashornCallSiteDescriptor.isStrictFlag(callSiteFlags)));
+            final ArrayData data = getArray();
+            if (data.has(index)) {
+                setArray(data.set(index, value, NashornCallSiteDescriptor.isStrictFlag(callSiteFlags)));
             } else {
                 doesNotHave(index, value, callSiteFlags);
             }
@@ -3305,8 +3311,9 @@
         final int index = getArrayIndex(key);
 
         if (isValidArrayIndex(index)) {
-            if (getArray().has(index)) {
-                setArray(getArray().set(index, value, NashornCallSiteDescriptor.isStrictFlag(callSiteFlags)));
+            final ArrayData data = getArray();
+            if (data.has(index)) {
+                setArray(data.set(index, value, NashornCallSiteDescriptor.isStrictFlag(callSiteFlags)));
             } else {
                 doesNotHave(index, value, callSiteFlags);
             }
@@ -3323,8 +3330,9 @@
         final int index = getArrayIndex(key);
 
         if (isValidArrayIndex(index)) {
-            if (getArray().has(index)) {
-                setArray(getArray().set(index, value, NashornCallSiteDescriptor.isStrictFlag(callSiteFlags)));
+            final ArrayData data = getArray();
+            if (data.has(index)) {
+                setArray(data.set(index, value, NashornCallSiteDescriptor.isStrictFlag(callSiteFlags)));
             } else {
                 doesNotHave(index, value, callSiteFlags);
             }
@@ -3341,8 +3349,9 @@
         final int index = getArrayIndex(key);
 
         if (isValidArrayIndex(index)) {
-            if (getArray().has(index)) {
-                setArray(getArray().set(index, value, NashornCallSiteDescriptor.isStrictFlag(callSiteFlags)));
+            final ArrayData data = getArray();
+            if (data.has(index)) {
+                setArray(data.set(index, value, NashornCallSiteDescriptor.isStrictFlag(callSiteFlags)));
             } else {
                 doesNotHave(index, value, callSiteFlags);
             }
@@ -3359,8 +3368,9 @@
         final int index = getArrayIndex(key);
 
         if (isValidArrayIndex(index)) {
-            if (getArray().has(index)) {
-                setArray(getArray().set(index, value, NashornCallSiteDescriptor.isStrictFlag(callSiteFlags)));
+            final ArrayData data = getArray();
+            if (data.has(index)) {
+                setArray(data.set(index, value, NashornCallSiteDescriptor.isStrictFlag(callSiteFlags)));
             } else {
                 doesNotHave(index, value, callSiteFlags);
             }
@@ -3377,8 +3387,9 @@
         final int index = getArrayIndex(key);
 
         if (isValidArrayIndex(index)) {
-            if (getArray().has(index)) {
-                setArray(getArray().set(index, value, NashornCallSiteDescriptor.isStrictFlag(callSiteFlags)));
+            final ArrayData data = getArray();
+            if (data.has(index)) {
+                setArray(data.set(index, value, NashornCallSiteDescriptor.isStrictFlag(callSiteFlags)));
             } else {
                 doesNotHave(index, value, callSiteFlags);
             }
@@ -3395,8 +3406,9 @@
         final int index = getArrayIndex(key);
 
         if (isValidArrayIndex(index)) {
-            if (getArray().has(index)) {
-                setArray(getArray().set(index, value, NashornCallSiteDescriptor.isStrictFlag(callSiteFlags)));
+            final ArrayData data = getArray();
+            if (data.has(index)) {
+                setArray(data.set(index, value, NashornCallSiteDescriptor.isStrictFlag(callSiteFlags)));
             } else {
                 doesNotHave(index, value, callSiteFlags);
             }
@@ -3413,7 +3425,8 @@
         final int index = getArrayIndex(key);
         if (isValidArrayIndex(index)) {
             if (getArray().has(index)) {
-                setArray(getArray().set(index, value, NashornCallSiteDescriptor.isStrictFlag(callSiteFlags)));
+                final ArrayData data = getArray();
+                setArray(data.set(index, value, NashornCallSiteDescriptor.isStrictFlag(callSiteFlags)));
             } else {
                 doesNotHave(index, value, callSiteFlags);
             }
@@ -3429,8 +3442,9 @@
         final int index = getArrayIndex(key);
 
         if (isValidArrayIndex(index)) {
-            if (getArray().has(index)) {
-                setArray(getArray().set(index, value, NashornCallSiteDescriptor.isStrictFlag(callSiteFlags)));
+            final ArrayData data = getArray();
+            if (data.has(index)) {
+                setArray(data.set(index, value, NashornCallSiteDescriptor.isStrictFlag(callSiteFlags)));
             } else {
                 doesNotHave(index, value, callSiteFlags);
             }
@@ -3447,8 +3461,9 @@
         final int index = getArrayIndex(key);
 
         if (isValidArrayIndex(index)) {
-            if (getArray().has(index)) {
-                setArray(getArray().set(index, value, NashornCallSiteDescriptor.isStrictFlag(callSiteFlags)));
+            final ArrayData data = getArray();
+            if (data.has(index)) {
+                setArray(data.set(index, value, NashornCallSiteDescriptor.isStrictFlag(callSiteFlags)));
             } else {
                 doesNotHave(index, value, callSiteFlags);
             }
@@ -3465,8 +3480,9 @@
         final int index = getArrayIndex(key);
 
         if (isValidArrayIndex(index)) {
-            if (getArray().has(index)) {
-                setArray(getArray().set(index, value, NashornCallSiteDescriptor.isStrictFlag(callSiteFlags)));
+            final ArrayData data = getArray();
+            if (data.has(index)) {
+                setArray(data.set(index, value, NashornCallSiteDescriptor.isStrictFlag(callSiteFlags)));
             } else {
                 doesNotHave(index, value, callSiteFlags);
             }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/arrays/AnyElements.java	Thu Oct 23 13:45:22 2014 -0700
@@ -0,0 +1,38 @@
+/*
+ * Copyright (c) 2010, 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package jdk.nashorn.internal.runtime.arrays;
+
+/**
+ * Marker interface for any ContinuousArray with any elements
+ * Used for type checks that throw ClassCastExceptions and force relinks
+ * for fast NativeArray specializations of builtin methods
+ */
+public interface AnyElements {
+    /**
+     * Return a numeric weight of the element type - wider is higher
+     * @return element type weight
+     */
+    public int getElementWeight();
+}
\ No newline at end of file
--- a/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/arrays/ArrayData.java	Thu Oct 23 11:19:29 2014 -0700
+++ b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/arrays/ArrayData.java	Thu Oct 23 13:45:22 2014 -0700
@@ -28,6 +28,7 @@
 import static jdk.nashorn.internal.codegen.CompilerConstants.staticCall;
 import java.lang.invoke.MethodHandle;
 import java.lang.invoke.MethodHandles;
+import java.lang.reflect.Array;
 import java.nio.ByteBuffer;
 import jdk.internal.dynalink.CallSiteDescriptor;
 import jdk.internal.dynalink.linker.GuardedInvocation;
@@ -37,6 +38,7 @@
 import jdk.nashorn.internal.objects.Global;
 import jdk.nashorn.internal.runtime.JSType;
 import jdk.nashorn.internal.runtime.PropertyDescriptor;
+import jdk.nashorn.internal.runtime.ScriptRuntime;
 import jdk.nashorn.internal.runtime.UnwarrantedOptimismException;
 
 /**
@@ -49,10 +51,180 @@
     /** Mask for getting a chunk */
     protected static final int CHUNK_MASK = CHUNK_SIZE - 1;
 
+    /** Untouched data - still link callsites as IntArrayData, but expands to
+     *  a proper ArrayData when we try to write to it */
+    public static final ArrayData EMPTY_ARRAY = new UntouchedArrayData();
+
     /**
      * Immutable empty array to get ScriptObjects started.
+     * Use the same array and convert it to mutable as soon as it is modified
      */
-    public static final ArrayData EMPTY_ARRAY = new NoTypeArrayData();
+    private static class UntouchedArrayData extends ContinuousArrayData {
+        private UntouchedArrayData() {
+            this(0);
+        }
+
+        private UntouchedArrayData(final int length) {
+            super(length);
+        }
+
+        private ArrayData toRealArrayData() {
+            return toRealArrayData(0);
+        }
+
+        private ArrayData toRealArrayData(final int index) {
+            final IntArrayData newData = new IntArrayData(index + 1);
+            if (index == 0) {
+                return newData;
+            }
+            return new DeletedRangeArrayFilter(newData, 0, index);
+        }
+
+        @Override
+        public ContinuousArrayData copy() {
+            return new UntouchedArrayData((int)length);
+        }
+
+        @Override
+        public Object asArrayOfType(final Class<?> componentType) {
+            return Array.newInstance(componentType, 0);
+        }
+
+        @Override
+        public Object[] asObjectArray() {
+            return ScriptRuntime.EMPTY_ARRAY;
+        }
+
+        @Override
+        public ArrayData ensure(final long safeIndex) {
+            if (safeIndex > 0L) {
+                return toRealArrayData((int)safeIndex).ensure(safeIndex);
+           }
+           return this;
+        }
+
+        @Override
+        public ArrayData convert(final Class<?> type) {
+            return toRealArrayData(0).convert(type);
+        }
+
+        @Override
+        public void shiftLeft(final int by) {
+            //nop, always empty or we wouldn't be of this class
+        }
+
+        @Override
+        public ArrayData shiftRight(final int by) {
+            return this; //always empty or we wouldn't be of this class
+        }
+
+        @Override
+        public ArrayData shrink(final long newLength) {
+            return this;
+        }
+
+        @Override
+        public ArrayData set(final int index, final Object value, final boolean strict) {
+            return toRealArrayData(index).set(index, value, strict);
+        }
+
+        @Override
+        public ArrayData set(final int index, final int value, final boolean strict) {
+            return toRealArrayData(index).set(index, value, strict);
+        }
+
+        @Override
+        public ArrayData set(final int index, final long value, final boolean strict) {
+            return toRealArrayData(index).set(index, value, strict);
+        }
+
+        @Override
+        public ArrayData set(final int index, final double value, final boolean strict) {
+            return toRealArrayData(index).set(index, value, strict);
+        }
+
+        @Override
+        public int getInt(final int index) {
+            throw new ArrayIndexOutOfBoundsException(index); //empty
+        }
+
+        @Override
+        public long getLong(final int index) {
+            throw new ArrayIndexOutOfBoundsException(index); //empty
+        }
+
+        @Override
+        public double getDouble(final int index) {
+            throw new ArrayIndexOutOfBoundsException(index); //empty
+        }
+
+        @Override
+        public Object getObject(final int index) {
+            throw new ArrayIndexOutOfBoundsException(index); //empty
+        }
+
+        @Override
+        public boolean has(final int index) {
+            return false; //empty
+        }
+
+        @Override
+        public ArrayData delete(final int index) {
+            return new DeletedRangeArrayFilter(this, index, index);
+        }
+
+        @Override
+        public ArrayData delete(final long fromIndex, final long toIndex) {
+            return new DeletedRangeArrayFilter(this, fromIndex, toIndex);
+        }
+
+        @Override
+        public Object pop() {
+            return ScriptRuntime.UNDEFINED;
+        }
+
+        @Override
+        public ArrayData push(final boolean strict, final Object item) {
+            return toRealArrayData().push(strict, item);
+        }
+
+        @Override
+        public ArrayData slice(final long from, final long to) {
+            return this; //empty
+        }
+
+        @Override
+        public ContinuousArrayData fastConcat(final ContinuousArrayData otherData) {
+            return otherData.copy();
+        }
+
+        //no need to override fastPopInt, as the default behavior is to throw classcast exception so we
+        //can relink and return an undefined, this is the IntArrayData default behavior
+        @Override
+        public String toString() {
+            return getClass().getSimpleName();
+        }
+
+        @Override
+        public MethodHandle getElementGetter(final Class<?> returnType, final int programPoint) {
+            return null;
+        }
+
+        @Override
+        public MethodHandle getElementSetter(final Class<?> elementType) {
+            return null;
+        }
+
+        @Override
+        public Class<?> getElementType() {
+            return int.class;
+        }
+
+        @Override
+        public Class<?> getBoxedElementType() {
+            return Integer.class;
+        }
+    };
 
     /**
      * Length of the array data. Not necessarily length of the wrapped array.
@@ -77,7 +249,7 @@
      * Factory method for unspecified array - start as int
      * @return ArrayData
      */
-    public static ArrayData initialArray() {
+    public final static ArrayData initialArray() {
         return new IntArrayData();
     }
 
@@ -92,33 +264,22 @@
         throw new UnwarrantedOptimismException(data.getObject(index), programPoint);
     }
 
-    private static int alignUp(final int size) {
+    /**
+     * Align an array size up to the nearest array chunk size
+     * @param size size required
+     * @return size given, always >= size
+     */
+    protected final static int alignUp(final int size) {
         return size + CHUNK_SIZE - 1 & ~(CHUNK_SIZE - 1);
     }
 
     /**
-     * Generic invalidation hook for script object to have call sites to this array indexing
-     * relinked, e.g. when a native array is marked as non extensible
-     */
-    public void invalidateGetters() {
-        //subclass responsibility
-    }
-
-    /**
-     * Generic invalidation hook for script object to have call sites to this array indexing
-     * relinked, e.g. when a native array is marked as non extensible
-     */
-    public void invalidateSetters() {
-        //subclass responsibility
-    }
-
-    /**
      * Factory method for unspecified array with given length - start as int array data
      *
      * @param length the initial length
      * @return ArrayData
      */
-    public static ArrayData allocate(final int length) {
+    public static final ArrayData allocate(final int length) {
         if (length == 0) {
             return new IntArrayData();
         } else if (length >= SparseArrayData.MAX_DENSE_LENGTH) {
@@ -134,7 +295,7 @@
      * @param  array the array
      * @return ArrayData wrapping this array
      */
-    public static ArrayData allocate(final Object array) {
+    public static final ArrayData allocate(final Object array) {
         final Class<?> clazz = array.getClass();
 
         if (clazz == int[].class) {
@@ -154,7 +315,7 @@
      * @param array the array to use for initial elements
      * @return the ArrayData
      */
-    public static ArrayData allocate(final int[] array) {
+    public static final ArrayData allocate(final int[] array) {
          return new IntArrayData(array, array.length);
     }
 
@@ -164,7 +325,7 @@
      * @param array the array to use for initial elements
      * @return the ArrayData
      */
-    public static ArrayData allocate(final long[] array) {
+    public static final ArrayData allocate(final long[] array) {
         return new LongArrayData(array, array.length);
     }
 
@@ -174,7 +335,7 @@
      * @param array the array to use for initial elements
      * @return the ArrayData
      */
-    public static ArrayData allocate(final double[] array) {
+    public static final ArrayData allocate(final double[] array) {
         return new NumberArrayData(array, array.length);
     }
 
@@ -184,7 +345,7 @@
      * @param array the array to use for initial elements
      * @return the ArrayData
      */
-    public static ArrayData allocate(final Object[] array) {
+    public static final ArrayData allocate(final Object[] array) {
         return new ObjectArrayData(array, array.length);
     }
 
@@ -194,7 +355,7 @@
      * @param buf the nio ByteBuffer to wrap
      * @return the ArrayData
      */
-    public static ArrayData allocate(final ByteBuffer buf) {
+    public static final ArrayData allocate(final ByteBuffer buf) {
         return new ByteBufferArrayData(buf);
     }
 
@@ -204,7 +365,7 @@
      * @param underlying  the underlying ArrayData to wrap in the freeze filter
      * @return the frozen ArrayData
      */
-    public static ArrayData freeze(final ArrayData underlying) {
+    public static final ArrayData freeze(final ArrayData underlying) {
         return new FrozenArrayFilter(underlying);
     }
 
@@ -214,11 +375,21 @@
      * @param underlying  the underlying ArrayData to wrap in the seal filter
      * @return the sealed ArrayData
      */
-    public static ArrayData seal(final ArrayData underlying) {
+    public static final ArrayData seal(final ArrayData underlying) {
         return new SealedArrayFilter(underlying);
     }
 
     /**
+     * Prevent this array from being extended
+     *
+     * @param  underlying the underlying ArrayData to wrap in the non extensible filter
+     * @return new array data, filtered
+     */
+    public static final ArrayData preventExtension(final ArrayData underlying) {
+        return new NonExtensibleArrayFilter(underlying);
+    }
+
+    /**
      * Return the length of the array data. This may differ from the actual
      * length of the array this wraps as length may be set or gotten as any
      * other JavaScript Property
@@ -728,5 +899,4 @@
     public GuardedInvocation findFastSetIndexMethod(final Class<? extends ArrayData> clazz, final CallSiteDescriptor desc, final LinkRequest request) { // array, index, value
         return null;
     }
-
 }
--- a/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/arrays/ContinuousArrayData.java	Thu Oct 23 11:19:29 2014 -0700
+++ b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/arrays/ContinuousArrayData.java	Thu Oct 23 13:45:22 2014 -0700
@@ -1,5 +1,4 @@
 /*
- * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -30,7 +29,6 @@
 import static jdk.nashorn.internal.runtime.JSType.getAccessorTypeIndex;
 import static jdk.nashorn.internal.runtime.UnwarrantedOptimismException.INVALID_PROGRAM_POINT;
 import static jdk.nashorn.internal.runtime.UnwarrantedOptimismException.isValid;
-
 import java.lang.invoke.MethodHandle;
 import java.lang.invoke.MethodHandles;
 import java.lang.invoke.MethodType;
@@ -50,9 +48,6 @@
  */
 @Logger(name="arrays")
 public abstract class ContinuousArrayData extends ArrayData {
-
-    private SwitchPoint sp;
-
     /**
      * Constructor
      * @param length length (elementLength)
@@ -61,18 +56,6 @@
         super(length);
     }
 
-    private SwitchPoint ensureSwitchPointExists() {
-        if (sp == null){
-            sp = new SwitchPoint();
-        }
-        return sp;
-    }
-
-    @Override
-    public void invalidateSetters() {
-        SwitchPoint.invalidateAll(new SwitchPoint[] { ensureSwitchPointExists() });
-    }
-
     /**
      * Check if we can put one more element at the end of this continous
      * array without reallocating, or if we are overwriting an already
@@ -86,6 +69,14 @@
     }
 
     /**
+     * Check if an arraydata is empty
+     * @return true if empty
+     */
+    public boolean isEmpty() {
+        return length == 0L;
+    }
+
+    /**
      * Return element getter for a certain type at a certain program point
      * @param returnType   return type
      * @param programPoint program point
@@ -109,13 +100,16 @@
      * @param index index to check - currently only int indexes
      * @return index
      */
-    protected int throwHas(final int index) {
+    protected final int throwHas(final int index) {
         if (!has(index)) {
             throw new ClassCastException();
         }
         return index;
     }
 
+    @Override
+    public abstract ContinuousArrayData copy();
+
     /**
      * Returns the type used to store an element in this array
      * @return element type
@@ -128,6 +122,25 @@
     }
 
     /**
+     * Returns the boxed type of the type used to store an element in this array
+     * @return element type
+     */
+    public abstract Class<?> getBoxedElementType();
+
+    /**
+     * Get the widest element type of two arrays. This can be done faster in subclasses, but
+     * this works for all ContinuousArrayDatas and for where more optimal checks haven't been
+     * implemented.
+     *
+     * @param otherData another ContinuousArrayData
+     * @return the widest boxed element type
+     */
+    public ContinuousArrayData widest(final ContinuousArrayData otherData) {
+        final Class<?> elementType = getElementType();
+        return Type.widest(elementType, otherData.getElementType()) == elementType ? this : otherData;
+    }
+
+    /**
      * Look up a continuous array element getter
      * @param get          getter, sometimes combined with a has check that throws CCE on failure for relink
      * @param returnType   return type
@@ -256,12 +269,7 @@
             final Object[]        args  = request.getArguments();
             final int             index = (int)args[args.length - 2];
 
-            //sp may be invalidated by e.g. preventExtensions before the first setter is linked
-            //then it is already created. otherwise, create it here to guard against future
-            //invalidations
-            ensureSwitchPointExists();
-
-            if (!sp.hasBeenInvalidated() && hasRoomFor(index)) {
+            if (hasRoomFor(index)) {
                 MethodHandle setElement = getElementSetter(elementType); //Z(continuousarraydata, int, int), return true if successful
                 if (setElement != null) {
                     //else we are dealing with a wider type than supported by this callsite
@@ -269,7 +277,7 @@
                     getArray   = MH.asType(getArray, getArray.type().changeReturnType(getClass()));
                     setElement = MH.filterArguments(setElement, 0, getArray);
                     final MethodHandle guard = MH.insertArguments(FAST_ACCESS_GUARD, 0, clazz);
-                    return new GuardedInvocation(setElement, guard, sp, ClassCastException.class); //CCE if not a scriptObject anymore
+                    return new GuardedInvocation(setElement, guard, (SwitchPoint)null, ClassCastException.class); //CCE if not a scriptObject anymore
                 }
             }
         }
@@ -344,4 +352,13 @@
     public Object fastPopObject() {
         throw new ClassCastException(String.valueOf(getClass())); //type is wrong, relink
     }
+
+    /**
+     * Specialization - fast concat implementation
+     * @param otherData data to concat
+     * @return new arraydata
+     */
+    public ContinuousArrayData fastConcat(final ContinuousArrayData otherData) {
+        throw new ClassCastException(String.valueOf(getClass()) + " != " + String.valueOf(otherData.getClass()));
+    }
 }
--- a/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/arrays/IntArrayData.java	Thu Oct 23 11:19:29 2014 -0700
+++ b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/arrays/IntArrayData.java	Thu Oct 23 13:45:22 2014 -0700
@@ -26,7 +26,6 @@
 package jdk.nashorn.internal.runtime.arrays;
 
 import static jdk.nashorn.internal.codegen.CompilerConstants.specialCall;
-
 import java.lang.invoke.MethodHandle;
 import java.lang.invoke.MethodHandles;
 import java.util.Arrays;
@@ -57,17 +56,32 @@
      * @param array an int array
      * @param length a length, not necessarily array.length
      */
-    IntArrayData(final int array[], final int length) {
+    IntArrayData(final int[] array, final int length) {
         super(length);
-        assert array.length >= length;
+        assert array == null || array.length >= length;
         this.array = array;
     }
 
     @Override
-    public Class<?> getElementType() {
+    public final Class<?> getElementType() {
         return int.class;
     }
 
+    @Override
+    public final Class<?> getBoxedElementType() {
+        return Integer.class;
+    }
+
+    @Override
+    public final int getElementWeight() {
+        return 1;
+    }
+
+    @Override
+    public final ContinuousArrayData widest(final ContinuousArrayData otherData) {
+        return otherData;
+    }
+
     private static final MethodHandle HAS_GET_ELEM = specialCall(MethodHandles.lookup(), IntArrayData.class, "getElem", int.class, int.class).methodHandle();
     private static final MethodHandle SET_ELEM     = specialCall(MethodHandles.lookup(), IntArrayData.class, "setElem", void.class, int.class, int.class).methodHandle();
 
@@ -104,7 +118,7 @@
     }
 
     @Override
-    public ArrayData copy() {
+    public IntArrayData copy() {
         return new IntArrayData(array.clone(), (int)length);
     }
 
@@ -165,8 +179,7 @@
     public ArrayData convert(final Class<?> type) {
         if (type == Integer.class) {
             return this;
-        }
-        if (type == Long.class) {
+        } else if (type == Long.class) {
             return convertToLong();
         } else if (type == Double.class) {
             return convertToDouble();
@@ -209,8 +222,7 @@
 
     @Override
     public ArrayData shrink(final long newLength) {
-        Arrays.fill(array, (int) newLength, array.length, 0);
-
+        Arrays.fill(array, (int)newLength, array.length, 0);
         return this;
     }
 
@@ -322,10 +334,7 @@
 
     @Override
     public ArrayData slice(final long from, final long to) {
-        final long start     = from < 0 ? from + length : from;
-        final long newLength = to - start;
-
-        return new IntArrayData(Arrays.copyOfRange(array, (int)from, (int)to), (int)newLength);
+        return new IntArrayData(Arrays.copyOfRange(array, (int)from, (int)to), (int)(to - (from < 0 ? from + length : from)));
     }
 
     @Override
@@ -347,7 +356,13 @@
             throw new UnsupportedOperationException();
         }
         final ArrayData returnValue = removed == 0 ?
-                EMPTY_ARRAY : new IntArrayData(Arrays.copyOfRange(array, start, start + removed), removed);
+                EMPTY_ARRAY :
+                new IntArrayData(
+                        Arrays.copyOfRange(
+                                array,
+                                start,
+                                start + removed),
+                        removed);
 
         if (newLength != oldLength) {
             final int[] newArray;
@@ -403,4 +418,26 @@
     public Object fastPopObject() {
         return fastPopInt();
     }
+
+    @Override
+    public ContinuousArrayData fastConcat(final ContinuousArrayData otherData) {
+        final int   otherLength = (int)otherData.length;
+        final int   thisLength  = (int)length;
+        assert otherLength > 0 && thisLength > 0;
+
+        final int[] otherArray  = ((IntArrayData)otherData).array;
+        final int   newLength   = otherLength + thisLength;
+        final int[] newArray    = new int[ArrayData.alignUp(newLength)];
+
+        System.arraycopy(array, 0, newArray, 0, thisLength);
+        System.arraycopy(otherArray, 0, newArray, thisLength, otherLength);
+
+        return new IntArrayData(newArray, newLength);
+    }
+
+    @Override
+    public String toString() {
+        assert length <= array.length : length + " > " + array.length;
+        return getClass().getSimpleName() + ':' + Arrays.toString(Arrays.copyOf(array, (int)length));
+    }
 }
--- a/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/arrays/LongArrayData.java	Thu Oct 23 11:19:29 2014 -0700
+++ b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/arrays/LongArrayData.java	Thu Oct 23 13:45:22 2014 -0700
@@ -52,16 +52,31 @@
     LongArrayData(final long array[], final int length) {
         super(length);
         assert array.length >= length;
-        this.array  = array;
+        this.array = array;
     }
 
     @Override
-    public Class<?> getElementType() {
+    public final Class<?> getElementType() {
         return long.class;
     }
 
     @Override
-    public ArrayData copy() {
+    public final Class<?> getBoxedElementType() {
+        return Long.class;
+    }
+
+    @Override
+    public final ContinuousArrayData widest(final ContinuousArrayData otherData) {
+        return otherData instanceof IntElements ? this : otherData;
+    }
+
+    @Override
+    public final int getElementWeight() {
+        return 2;
+    }
+
+    @Override
+    public LongArrayData copy() {
         return new LongArrayData(array.clone(), (int)length);
     }
 
@@ -101,7 +116,7 @@
     }
 
     @Override
-    public ArrayData convert(final Class<?> type) {
+    public ContinuousArrayData convert(final Class<?> type) {
         if (type == Integer.class || type == Long.class) {
             return this;
         }
@@ -145,8 +160,7 @@
 
     @Override
     public ArrayData shrink(final long newLength) {
-        Arrays.fill(array, (int) newLength, array.length, 0);
-
+        Arrays.fill(array, (int)newLength, array.length, 0L);
         return this;
     }
 
@@ -359,4 +373,37 @@
     public Object fastPopObject() {
         return fastPopLong();
     }
+
+    @Override
+    public ContinuousArrayData fastConcat(final ContinuousArrayData otherData) {
+        final int   otherLength = (int)otherData.length;
+        final int   thisLength  = (int)length;
+        assert otherLength > 0 && thisLength > 0;
+
+        final long[] otherArray  = ((LongArrayData)otherData).array;
+        final int    newLength   = otherLength + thisLength;
+        final long[] newArray   = new long[ArrayData.alignUp(newLength)];
+
+        System.arraycopy(array, 0, newArray, 0, thisLength);
+        System.arraycopy(otherArray, 0, newArray, thisLength, otherLength);
+
+        return new LongArrayData(newArray, newLength);
+    }
+
+    @Override
+    public String toString() {
+        assert length <= array.length : length + " > " + array.length;
+
+        final StringBuilder sb = new StringBuilder(getClass().getSimpleName()).
+                append(": [");
+        for (int i = 0; i < length; i++) {
+            sb.append(array[i]).append('L'); //make sure L suffix is on elements, to discriminate this from IntArrayData.toString()
+            if (i + 1 < length) {
+                sb.append(", ");
+            }
+        }
+        sb.append(']');
+
+        return sb.toString();
+    }
 }
--- a/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/arrays/NoTypeArrayData.java	Thu Oct 23 11:19:29 2014 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,186 +0,0 @@
-/*
- * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.  Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-package jdk.nashorn.internal.runtime.arrays;
-
-import java.lang.reflect.Array;
-import jdk.nashorn.internal.runtime.ScriptRuntime;
-
-/**
- * Place holding array data for non-array objects.  Activates a true array when
- * accessed.  Should only exist as a singleton defined in ArrayData.
- */
-final class NoTypeArrayData extends ArrayData {
-    NoTypeArrayData() {
-        super(0);
-    }
-
-    NoTypeArrayData(final long length) {
-         super(length);
-    }
-
-    @Override
-    public Object[] asObjectArray() {
-        return ScriptRuntime.EMPTY_ARRAY;
-    }
-
-    @Override
-    public ArrayData copy() {
-        return new NoTypeArrayData();
-    }
-
-    @Override
-    public Object asArrayOfType(final Class<?> componentType) {
-        return Array.newInstance(componentType, 0);
-    }
-
-    @Override
-    public ArrayData convert(final Class<?> type) {
-        final long len = length;
-        final ArrayData arrayData;
-        if (type == Long.class) {
-            arrayData = new LongArrayData(new long[ArrayData.nextSize((int)len)], (int)len);
-        } else if (type == Double.class) {
-            arrayData = new NumberArrayData(new double[ArrayData.nextSize((int)len)], (int)len);
-        } else if (type == Integer.class) {
-            arrayData = new IntArrayData(new int[ArrayData.nextSize((int)len)], (int)len);
-        } else {
-            assert !type.isPrimitive();
-            arrayData = new ObjectArrayData(new Object[ArrayData.nextSize((int)len)], (int)len);
-        }
-        return length == 0 ? arrayData : new DeletedRangeArrayFilter(arrayData, 0, len - 1);
-    }
-
-    @Override
-    public void shiftLeft(final int by) {
-        //empty
-    }
-
-    @Override
-    public ArrayData shiftRight(final int by) {
-        return this;
-    }
-
-    @Override
-    public ArrayData ensure(final long safeIndex) {
-        if (safeIndex >= SparseArrayData.MAX_DENSE_LENGTH) {
-            return new SparseArrayData(this, safeIndex + 1);
-        }
-
-        // Don't trample the shared EMPTY_ARRAY.
-        if (length == 0) {
-            return new NoTypeArrayData(Math.max(safeIndex + 1, length));
-        }
-
-        setLength(Math.max(safeIndex + 1, length));
-        return this;
-    }
-
-    @Override
-    public ArrayData shrink(final long newLength) {
-        return this;
-    }
-
-    @Override
-    public ArrayData set(final int index, final Object value, final boolean strict) {
-        ArrayData newData;
-
-        if (value instanceof Double) {
-            newData = convert(Double.class);
-        } else if (value instanceof Long) {
-            newData = convert(Long.class);
-        } else if (value instanceof Integer) {
-            newData = convert(Integer.class);
-        } else {
-            assert !(value instanceof Number);
-            newData = convert(value == null ? Object.class : value.getClass());
-        }
-
-        return newData.set(index, value, strict);
-    }
-
-    @Override
-    public ArrayData set(final int index, final int value, final boolean strict) {
-        final ArrayData newData = convert(Integer.class);
-        return newData.set(index, value, strict);
-    }
-
-    @Override
-    public ArrayData set(final int index, final long value, final boolean strict) {
-        final ArrayData newData = convert(Long.class);
-        return newData.set(index, value, strict);
-    }
-
-    @Override
-    public ArrayData set(final int index, final double value, final boolean strict) {
-        final ArrayData newData = convert(Double.class);
-        return newData.set(index, value, strict);
-    }
-
-    @Override
-    public int getInt(final int index) {
-        throw new ArrayIndexOutOfBoundsException(index);
-    }
-
-    @Override
-    public long getLong(final int index) {
-        throw new ArrayIndexOutOfBoundsException(index);
-    }
-
-    @Override
-    public double getDouble(final int index) {
-        throw new ArrayIndexOutOfBoundsException(index);
-    }
-
-    @Override
-    public Object getObject(final int index) {
-        throw new ArrayIndexOutOfBoundsException(index);
-    }
-
-    @Override
-    public boolean has(final int index) {
-        return false;
-    }
-
-    @Override
-    public ArrayData delete(final int index) {
-        return new DeletedRangeArrayFilter(this, index, index);
-    }
-
-    @Override
-    public ArrayData delete(final long fromIndex, final long toIndex) {
-        return new DeletedRangeArrayFilter(this, fromIndex, toIndex);
-    }
-
-    @Override
-    public Object pop() {
-        return ScriptRuntime.UNDEFINED;
-    }
-
-    @Override
-    public ArrayData slice(final long from, final long to) {
-        return this;
-    }
-}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/arrays/NonExtensibleArrayFilter.java	Thu Oct 23 13:45:22 2014 -0700
@@ -0,0 +1,68 @@
+package jdk.nashorn.internal.runtime.arrays;
+
+import static jdk.nashorn.internal.runtime.ECMAErrors.typeError;
+import jdk.nashorn.internal.objects.Global;
+import jdk.nashorn.internal.runtime.ScriptRuntime;
+
+/**
+ * Filter class that wrap arrays that have been tagged non extensible
+ */
+public class NonExtensibleArrayFilter extends ArrayFilter {
+
+    /**
+     * Constructor
+     * @param underlying array
+     */
+    public NonExtensibleArrayFilter(final ArrayData underlying) {
+        super(underlying);
+    }
+
+    @Override
+    public ArrayData copy() {
+        return new NonExtensibleArrayFilter(underlying.copy());
+    }
+
+    @Override
+    public ArrayData slice(final long from, final long to) {
+        return new NonExtensibleArrayFilter(underlying.slice(from, to));
+    }
+
+    private ArrayData extensionCheck(final boolean strict, final int index) {
+        if (!strict) {
+            return this;
+        }
+        throw typeError(Global.instance(), "object.non.extensible", String.valueOf(index), ScriptRuntime.safeToString(this));
+    }
+
+    @Override
+    public ArrayData set(final int index, final Object value, final boolean strict) {
+        if (has(index)) {
+            return underlying.set(index, value, strict);
+        }
+        return extensionCheck(strict, index);
+    }
+
+    @Override
+    public ArrayData set(final int index, final int value, final boolean strict) {
+        if (has(index)) {
+            return underlying.set(index, value, strict);
+        }
+        return extensionCheck(strict, index);
+    }
+
+    @Override
+    public ArrayData set(final int index, final long value, final boolean strict) {
+        if (has(index)) {
+            return underlying.set(index, value, strict);
+        }
+        return extensionCheck(strict, index);
+    }
+
+    @Override
+    public ArrayData set(final int index, final double value, final boolean strict) {
+        if (has(index)) {
+            return underlying.set(index, value, strict);
+        }
+        return extensionCheck(strict, index);
+    }
+}
--- a/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/arrays/NumberArrayData.java	Thu Oct 23 11:19:29 2014 -0700
+++ b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/arrays/NumberArrayData.java	Thu Oct 23 13:45:22 2014 -0700
@@ -48,19 +48,34 @@
      * @param array an int array
      * @param length a length, not necessarily array.length
      */
-    NumberArrayData(final double array[], final int length) {
+    NumberArrayData(final double[] array, final int length) {
         super(length);
         assert array.length >= length;
-        this.array  = array;
+        this.array = array;
     }
 
     @Override
-    public Class<?> getElementType() {
+    public final Class<?> getElementType() {
         return double.class;
     }
 
     @Override
-    public ArrayData copy() {
+    public final Class<?> getBoxedElementType() {
+        return Double.class;
+    }
+
+    @Override
+    public final int getElementWeight() {
+        return 3;
+    }
+
+    @Override
+    public final ContinuousArrayData widest(final ContinuousArrayData otherData) {
+        return otherData instanceof IntOrLongElements ? this : otherData;
+    }
+
+    @Override
+    public NumberArrayData copy() {
         return new NumberArrayData(array.clone(), (int)length);
     }
 
@@ -88,7 +103,7 @@
     }
 
     @Override
-    public ArrayData convert(final Class<?> type) {
+    public ContinuousArrayData convert(final Class<?> type) {
         if (type != Double.class && type != Integer.class && type != Long.class) {
             final int len = (int)length;
             return new ObjectArrayData(toObjectArray(false), len);
@@ -129,7 +144,7 @@
 
     @Override
     public ArrayData shrink(final long newLength) {
-        Arrays.fill(array, (int) newLength, array.length, 0.0);
+        Arrays.fill(array, (int)newLength, array.length, 0.0);
         return this;
     }
 
@@ -334,4 +349,26 @@
     public Object fastPopObject() {
         return fastPopDouble();
     }
+
+    @Override
+    public ContinuousArrayData fastConcat(final ContinuousArrayData otherData) {
+        final int   otherLength = (int)otherData.length;
+        final int   thisLength  = (int)length;
+        assert otherLength > 0 && thisLength > 0;
+
+        final double[] otherArray = ((NumberArrayData)otherData).array;
+        final int      newLength  = otherLength + thisLength;
+        final double[] newArray   = new double[ArrayData.alignUp(newLength)];
+
+        System.arraycopy(array, 0, newArray, 0, thisLength);
+        System.arraycopy(otherArray, 0, newArray, thisLength, otherLength);
+
+        return new NumberArrayData(newArray, newLength);
+    }
+
+    @Override
+    public String toString() {
+        assert length <= array.length : length + " > " + array.length;
+        return getClass().getSimpleName() + ':' + Arrays.toString(Arrays.copyOf(array, (int)length));
+    }
 }
--- a/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/arrays/NumericElements.java	Thu Oct 23 11:19:29 2014 -0700
+++ b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/arrays/NumericElements.java	Thu Oct 23 13:45:22 2014 -0700
@@ -30,6 +30,6 @@
  * Used for type checks that throw ClassCastExceptions and force relinks
  * for fast NativeArray specializations of builtin methods
  */
-public interface NumericElements {
+public interface NumericElements extends AnyElements {
     //empty
 }
--- a/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/arrays/ObjectArrayData.java	Thu Oct 23 11:19:29 2014 -0700
+++ b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/arrays/ObjectArrayData.java	Thu Oct 23 13:45:22 2014 -0700
@@ -37,7 +37,7 @@
  * Implementation of {@link ArrayData} as soon as an Object has been
  * written to the array
  */
-final class ObjectArrayData extends ContinuousArrayData {
+final class ObjectArrayData extends ContinuousArrayData implements AnyElements {
 
     /**
      * The wrapped array
@@ -49,19 +49,34 @@
      * @param array an int array
      * @param length a length, not necessarily array.length
      */
-    ObjectArrayData(final Object array[], final int length) {
+    ObjectArrayData(final Object[] array, final int length) {
         super(length);
         assert array.length >= length;
         this.array  = array;
     }
 
     @Override
-    public Class<?> getElementType() {
+    public final Class<?> getElementType() {
         return Object.class;
     }
 
     @Override
-    public ArrayData copy() {
+    public final Class<?> getBoxedElementType() {
+        return getElementType();
+    }
+
+    @Override
+    public final int getElementWeight() {
+        return 4;
+    }
+
+    @Override
+    public final ContinuousArrayData widest(final ContinuousArrayData otherData) {
+        return otherData instanceof NumericElements ? this : otherData;
+    }
+
+    @Override
+    public ObjectArrayData copy() {
         return new ObjectArrayData(array.clone(), (int)length);
     }
 
@@ -79,7 +94,7 @@
     }
 
     @Override
-    public ArrayData convert(final Class<?> type) {
+    public ObjectArrayData convert(final Class<?> type) {
         return this;
     }
 
@@ -325,4 +340,26 @@
 
         return returnValue;
     }
+
+    @Override
+    public ContinuousArrayData fastConcat(final ContinuousArrayData otherData) {
+        final int   otherLength = (int)otherData.length;
+        final int   thisLength  = (int)length;
+        assert otherLength > 0 && thisLength > 0;
+
+        final Object[] otherArray = ((ObjectArrayData)otherData).array;
+        final int      newLength  = otherLength + thisLength;
+        final Object[] newArray   = new Object[ArrayData.alignUp(newLength)];
+
+        System.arraycopy(array, 0, newArray, 0, thisLength);
+        System.arraycopy(otherArray, 0, newArray, thisLength, otherLength);
+
+        return new ObjectArrayData(newArray, newLength);
+    }
+
+    @Override
+    public String toString() {
+        assert length <= array.length : length + " > " + array.length;
+        return getClass().getSimpleName() + ':' + Arrays.toString(Arrays.copyOf(array, (int)length));
+    }
 }
--- a/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/arrays/TypedArrayData.java	Thu Oct 23 11:19:29 2014 -0700
+++ b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/arrays/TypedArrayData.java	Thu Oct 23 13:45:22 2014 -0700
@@ -88,7 +88,7 @@
     }
 
     @Override
-    public ArrayData copy() {
+    public TypedArrayData<T> copy() {
         throw new UnsupportedOperationException();
     }
 
@@ -133,7 +133,7 @@
     }
 
     @Override
-    public ArrayData convert(final Class<?> type) {
+    public TypedArrayData<T> convert(final Class<?> type) {
         throw new UnsupportedOperationException();
     }
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/script/basic/JDK-8058610.js	Thu Oct 23 13:45:22 2014 -0700
@@ -0,0 +1,77 @@
+/*
+ * Copyright (c) 2014 Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ * 
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ * 
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ * 
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ * 
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/**
+ * JDK-8058610: must not let long operations overflow
+ *
+ * @test
+ * @run
+ */
+
+function mul(x) { 
+    return x.foo * x.bar; 
+} 
+print("=== mul ===")
+print(mul({foo: 2147483647,  bar: 2147483647})); // 2^31
+print(mul({foo: 17179869184, bar: 2147483647})); // 2^34
+
+function self_mul(x) {
+    return x.foo *= x.bar; 
+}
+print("=== self_mul ===")
+print(self_mul({foo: 2147483647,  bar: 2147483647})); // 2^31
+print(self_mul({foo: 17179869184, bar: 2147483647})); // 2^34
+
+// We'll need to use this function to obtain long values larger in 
+// magnitude than those precisely representable in a double (2^53), 
+// as Nashorn's parser will reify such literals as a double. For 
+// overflow on add and sub we need (2^63)-1.
+var parseLong = Java.type("java.lang.Long").parseLong;
+
+function sub(x) {
+    return x.foo - x.bar;
+}
+print("=== sub ===")
+print(sub({foo: 2147483647,  bar: -2147483647})); // 2^31
+print(sub({foo: parseLong("9223372036854775807"), bar: parseLong("-9223372036854775807")})); // 2^63-1
+
+function self_sub(x) {
+    return x.foo -= x.bar;
+}
+print("=== self_sub ===")
+print(self_sub({foo: 2147483647,  bar: -2147483647})); // 2^31
+print(self_sub({foo: parseLong("9223372036854775807"), bar: parseLong("-9223372036854775807")})); // 2^63-1
+
+function add(x) {
+    return x.foo + x.bar;
+}
+print("=== add ===")
+print(add({foo: 2147483647,  bar: 2147483647})); // 2^31
+print(add({foo: parseLong("9223372036854775807"), bar: parseLong("9223372036854775807")})); // 2^63-1
+
+function self_add(x) {
+    return x.foo += x.bar;
+}
+print("=== self_add ===")
+print(self_add({foo: 2147483647,  bar: 2147483647})); // 2^31
+print(self_add({foo: parseLong("9223372036854775807"), bar: parseLong("9223372036854775807")})); // 2^63-1
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/script/basic/JDK-8058610.js.EXPECTED	Thu Oct 23 13:45:22 2014 -0700
@@ -0,0 +1,18 @@
+=== mul ===
+4611686014132420600
+36893488130239234000
+=== self_mul ===
+4611686014132420600
+36893488130239234000
+=== sub ===
+4294967294
+18446744073709552000
+=== self_sub ===
+4294967294
+18446744073709552000
+=== add ===
+4294967294
+18446744073709552000
+=== self_add ===
+4294967294
+18446744073709552000
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/script/basic/JDK-8061391.js	Thu Oct 23 13:45:22 2014 -0700
@@ -0,0 +1,151 @@
+/*
+ * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/**
+ * JDK-8061391 - Checks that the optimistic builtin for concat is semantically
+ * correct.
+ *
+ * @test
+ * @run
+ */
+
+var maxJavaInt = 0x7fffffff;
+
+var ia = [1, 2, 3, 4];
+var la = [maxJavaInt + 1000, maxJavaInt + 2000, maxJavaInt + 3000, maxJavaInt + 4000];
+var da = [1.1, 2.2, 3.3, 4.4];
+var oa = ["one", "two", "three", "four"];  
+
+var aa = [ia, la, da, oa];
+
+function concats() {
+    print("shared callsite");
+
+    print(ia);
+    print(la);
+    print(da);
+    print(oa);
+    print(aa);
+    
+    for (var i = 0; i < aa.length; i++) {
+	print(aa[i].concat(aa[i][0]));
+	for (var j = 0; j < aa.length ; j++) {
+	    print(aa[i].concat(aa[j]));
+	}
+    }
+}
+
+function concats_inline() {
+    print("separate callsites");
+
+    print(ia);
+    print(la);
+    print(da);
+    print(oa);
+    print(aa);
+    
+    print(aa[0].concat(aa[0]));
+    print(aa[0].concat(aa[1]));
+    print(aa[0].concat(aa[2]));
+    print(aa[0].concat(aa[3]));
+    print(aa[0].concat(aa[0][0]));    
+
+    print(aa[1].concat(aa[0]));
+    print(aa[1].concat(aa[1]));
+    print(aa[1].concat(aa[2]));
+    print(aa[1].concat(aa[3]));
+    print(aa[1].concat(aa[1][0]));    
+
+    print(aa[2].concat(aa[0]));
+    print(aa[2].concat(aa[1]));
+    print(aa[2].concat(aa[2]));
+    print(aa[2].concat(aa[3]));
+    print(aa[2].concat(aa[2][0]));    
+
+    print(aa[3].concat(aa[0]));
+    print(aa[3].concat(aa[1]));
+    print(aa[3].concat(aa[2]));
+    print(aa[3].concat(aa[3]));
+    print(aa[3].concat(aa[3][0]));    
+}
+
+concats();
+concats_inline();
+
+print();
+var oldia = ia.slice(0); //clone ia
+print("oldia = " + oldia);
+ia[10] = "sparse";
+print("oldia = " + oldia);
+
+print();
+print("Redoing with sparse arrays");
+
+concats();
+concats_inline();
+
+ia = oldia;
+print("Restored ia = " + ia);
+
+function concat_expand() {
+    print("concat type expansion");
+    print(ia.concat(la));
+    print(ia.concat(da));
+    print(ia.concat(oa));
+    print(la.concat(ia));
+    print(la.concat(da));
+    print(la.concat(oa));
+    print(da.concat(ia));
+    print(da.concat(la));
+    print(da.concat(oa));
+}
+
+print();
+concat_expand();
+
+print();
+
+function concat_varargs() {
+    print("concat varargs");
+    print(ia.concat(la)); //fast
+    print(ia.concat(la, da, oa)); //slow
+    var slow = ia.concat(1, maxJavaInt * 2, 4711.17, function() { print("hello, world") }); //slow
+    print(slow);
+    return slow;
+}
+
+var slow = concat_varargs();
+
+print();
+print("sanity checks");
+slow.map(
+	 function(elem) {
+	     if (elem instanceof Function) {
+		 elem();
+	     } else {
+		 print((typeof elem) + " = " + elem);
+	     }
+	 });
+
+print(ia.concat({key: "value"}));
+print(ia.concat({key: "value"}, {key2: "value2"}));
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/script/basic/JDK-8061391.js.EXPECTED	Thu Oct 23 13:45:22 2014 -0700
@@ -0,0 +1,138 @@
+shared callsite
+1,2,3,4
+2147484647,2147485647,2147486647,2147487647
+1.1,2.2,3.3,4.4
+one,two,three,four
+1,2,3,4,2147484647,2147485647,2147486647,2147487647,1.1,2.2,3.3,4.4,one,two,three,four
+1,2,3,4,1
+1,2,3,4,1,2,3,4
+1,2,3,4,2147484647,2147485647,2147486647,2147487647
+1,2,3,4,1.1,2.2,3.3,4.4
+1,2,3,4,one,two,three,four
+2147484647,2147485647,2147486647,2147487647,2147484647
+2147484647,2147485647,2147486647,2147487647,1,2,3,4
+2147484647,2147485647,2147486647,2147487647,2147484647,2147485647,2147486647,2147487647
+2147484647,2147485647,2147486647,2147487647,1.1,2.2,3.3,4.4
+2147484647,2147485647,2147486647,2147487647,one,two,three,four
+1.1,2.2,3.3,4.4,1.1
+1.1,2.2,3.3,4.4,1,2,3,4
+1.1,2.2,3.3,4.4,2147484647,2147485647,2147486647,2147487647
+1.1,2.2,3.3,4.4,1.1,2.2,3.3,4.4
+1.1,2.2,3.3,4.4,one,two,three,four
+one,two,three,four,one
+one,two,three,four,1,2,3,4
+one,two,three,four,2147484647,2147485647,2147486647,2147487647
+one,two,three,four,1.1,2.2,3.3,4.4
+one,two,three,four,one,two,three,four
+separate callsites
+1,2,3,4
+2147484647,2147485647,2147486647,2147487647
+1.1,2.2,3.3,4.4
+one,two,three,four
+1,2,3,4,2147484647,2147485647,2147486647,2147487647,1.1,2.2,3.3,4.4,one,two,three,four
+1,2,3,4,1,2,3,4
+1,2,3,4,2147484647,2147485647,2147486647,2147487647
+1,2,3,4,1.1,2.2,3.3,4.4
+1,2,3,4,one,two,three,four
+1,2,3,4,1
+2147484647,2147485647,2147486647,2147487647,1,2,3,4
+2147484647,2147485647,2147486647,2147487647,2147484647,2147485647,2147486647,2147487647
+2147484647,2147485647,2147486647,2147487647,1.1,2.2,3.3,4.4
+2147484647,2147485647,2147486647,2147487647,one,two,three,four
+2147484647,2147485647,2147486647,2147487647,2147484647
+1.1,2.2,3.3,4.4,1,2,3,4
+1.1,2.2,3.3,4.4,2147484647,2147485647,2147486647,2147487647
+1.1,2.2,3.3,4.4,1.1,2.2,3.3,4.4
+1.1,2.2,3.3,4.4,one,two,three,four
+1.1,2.2,3.3,4.4,1.1
+one,two,three,four,1,2,3,4
+one,two,three,four,2147484647,2147485647,2147486647,2147487647
+one,two,three,four,1.1,2.2,3.3,4.4
+one,two,three,four,one,two,three,four
+one,two,three,four,one
+
+oldia = 1,2,3,4
+oldia = 1,2,3,4
+
+Redoing with sparse arrays
+shared callsite
+1,2,3,4,,,,,,,sparse
+2147484647,2147485647,2147486647,2147487647
+1.1,2.2,3.3,4.4
+one,two,three,four
+1,2,3,4,,,,,,,sparse,2147484647,2147485647,2147486647,2147487647,1.1,2.2,3.3,4.4,one,two,three,four
+1,2,3,4,,,,,,,sparse,1
+1,2,3,4,,,,,,,sparse,1,2,3,4,,,,,,,sparse
+1,2,3,4,,,,,,,sparse,2147484647,2147485647,2147486647,2147487647
+1,2,3,4,,,,,,,sparse,1.1,2.2,3.3,4.4
+1,2,3,4,,,,,,,sparse,one,two,three,four
+2147484647,2147485647,2147486647,2147487647,2147484647
+2147484647,2147485647,2147486647,2147487647,1,2,3,4,,,,,,,sparse
+2147484647,2147485647,2147486647,2147487647,2147484647,2147485647,2147486647,2147487647
+2147484647,2147485647,2147486647,2147487647,1.1,2.2,3.3,4.4
+2147484647,2147485647,2147486647,2147487647,one,two,three,four
+1.1,2.2,3.3,4.4,1.1
+1.1,2.2,3.3,4.4,1,2,3,4,,,,,,,sparse
+1.1,2.2,3.3,4.4,2147484647,2147485647,2147486647,2147487647
+1.1,2.2,3.3,4.4,1.1,2.2,3.3,4.4
+1.1,2.2,3.3,4.4,one,two,three,four
+one,two,three,four,one
+one,two,three,four,1,2,3,4,,,,,,,sparse
+one,two,three,four,2147484647,2147485647,2147486647,2147487647
+one,two,three,four,1.1,2.2,3.3,4.4
+one,two,three,four,one,two,three,four
+separate callsites
+1,2,3,4,,,,,,,sparse
+2147484647,2147485647,2147486647,2147487647
+1.1,2.2,3.3,4.4
+one,two,three,four
+1,2,3,4,,,,,,,sparse,2147484647,2147485647,2147486647,2147487647,1.1,2.2,3.3,4.4,one,two,three,four
+1,2,3,4,,,,,,,sparse,1,2,3,4,,,,,,,sparse
+1,2,3,4,,,,,,,sparse,2147484647,2147485647,2147486647,2147487647
+1,2,3,4,,,,,,,sparse,1.1,2.2,3.3,4.4
+1,2,3,4,,,,,,,sparse,one,two,three,four
+1,2,3,4,,,,,,,sparse,1
+2147484647,2147485647,2147486647,2147487647,1,2,3,4,,,,,,,sparse
+2147484647,2147485647,2147486647,2147487647,2147484647,2147485647,2147486647,2147487647
+2147484647,2147485647,2147486647,2147487647,1.1,2.2,3.3,4.4
+2147484647,2147485647,2147486647,2147487647,one,two,three,four
+2147484647,2147485647,2147486647,2147487647,2147484647
+1.1,2.2,3.3,4.4,1,2,3,4,,,,,,,sparse
+1.1,2.2,3.3,4.4,2147484647,2147485647,2147486647,2147487647
+1.1,2.2,3.3,4.4,1.1,2.2,3.3,4.4
+1.1,2.2,3.3,4.4,one,two,three,four
+1.1,2.2,3.3,4.4,1.1
+one,two,three,four,1,2,3,4,,,,,,,sparse
+one,two,three,four,2147484647,2147485647,2147486647,2147487647
+one,two,three,four,1.1,2.2,3.3,4.4
+one,two,three,four,one,two,three,four
+one,two,three,four,one
+Restored ia = 1,2,3,4
+
+concat type expansion
+1,2,3,4,2147484647,2147485647,2147486647,2147487647
+1,2,3,4,1.1,2.2,3.3,4.4
+1,2,3,4,one,two,three,four
+2147484647,2147485647,2147486647,2147487647,1,2,3,4
+2147484647,2147485647,2147486647,2147487647,1.1,2.2,3.3,4.4
+2147484647,2147485647,2147486647,2147487647,one,two,three,four
+1.1,2.2,3.3,4.4,1,2,3,4
+1.1,2.2,3.3,4.4,2147484647,2147485647,2147486647,2147487647
+1.1,2.2,3.3,4.4,one,two,three,four
+
+concat varargs
+1,2,3,4,2147484647,2147485647,2147486647,2147487647
+1,2,3,4,2147484647,2147485647,2147486647,2147487647,1.1,2.2,3.3,4.4,one,two,three,four
+1,2,3,4,1,4294967294,4711.17,function() { print("hello, world") }
+
+sanity checks
+number = 1
+number = 2
+number = 3
+number = 4
+number = 1
+number = 4294967294
+number = 4711.17
+hello, world
+1,2,3,4,[object Object]
+1,2,3,4,[object Object],[object Object]
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/script/basic/JDK-8061391_2.js	Thu Oct 23 13:45:22 2014 -0700
@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) 2010, 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/**
+ * Array extension check
+ *
+ * @test
+ * @run
+ */
+
+"use strict";
+var a = [1,2,3];
+Object.preventExtensions(a);
+try {
+    a[4] = 4;
+    print(a);
+} catch (e) {
+    if (!(e instanceof TypeError)) {
+	print("TypeError expected but got e");
+    }
+}
+
+if (a[0] != 1) {
+    throw "element 0 is wrong";
+}
+if (a[1] != 2) {
+    throw "element 1 is wrong";
+}
+if (a[2] != 3) {
+    throw "element 2 is wrong";
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/script/basic/JDK-8061391_3.js	Thu Oct 23 13:45:22 2014 -0700
@@ -0,0 +1,44 @@
+/*
+ * Copyright (c) 2010, 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/**
+ * Array extension check
+ *
+ * @test
+ * @run
+ */
+
+var a = [1,2,3];
+Object.preventExtensions(a);
+a[4] = 4;
+print(a);
+if (a[0] != 1) {
+    throw "element 0 is wrong";
+}
+if (a[1] != 2) {
+    throw "element 1 is wrong";
+}
+if (a[2] != 3) {
+    throw "element 2 is wrong";
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/script/basic/JDK-8061391_3.js.EXPECTED	Thu Oct 23 13:45:22 2014 -0700
@@ -0,0 +1,1 @@
+1,2,3
--- a/test/src/jdk/nashorn/internal/test/framework/ParallelTestRunner.java	Thu Oct 23 11:19:29 2014 -0700
+++ b/test/src/jdk/nashorn/internal/test/framework/ParallelTestRunner.java	Thu Oct 23 13:45:22 2014 -0700
@@ -78,7 +78,8 @@
     // ParallelTestRunner-specific
     private static final String    TEST_JS_THREADS     = "test.js.threads";
     private static final String    TEST_JS_REPORT_FILE = "test.js.report.file";
-    private static final int       THREADS             = Integer.getInteger(TEST_JS_THREADS, Runtime.getRuntime().availableProcessors());
+    // test262 does a lot of eval's and the JVM hates multithreaded class definition, so lower thread count is usually faster.
+    private static final int       THREADS = Integer.getInteger(TEST_JS_THREADS, Runtime.getRuntime().availableProcessors() > 4 ? 4 : 2);
 
     private final List<ScriptRunnable> tests    = new ArrayList<>();
     private final Set<String>      orphans  = new TreeSet<>();