changeset 1075:12805076fc70

Merge
author erikj
date Mon, 27 Oct 2014 11:16:19 +0100
parents ba58226976dd bba8e963ccf2
children 23d881bb7a79
files src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/Context.java src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/RecompilableScriptFunctionData.java
diffstat 71 files changed, 2181 insertions(+), 566 deletions(-) [+]
line wrap: on
line diff
--- a/.hgignore	Tue Oct 21 14:24:16 2014 +0100
+++ b/.hgignore	Mon Oct 27 11:16:19 2014 +0100
@@ -26,3 +26,5 @@
 test/lib/testng.jar
 test/script/external/*
 .project
+.externalToolBuilders/*
+.settings/*
--- a/.hgtags	Tue Oct 21 14:24:16 2014 +0100
+++ b/.hgtags	Mon Oct 27 11:16:19 2014 +0100
@@ -269,3 +269,4 @@
 b374d8910e7f8de2b7ecacee9ae4cad88f23feab jdk9-b33
 4ece2dad8c37f520f1ccc1cf84870f362c8eb9d6 jdk9-b34
 63b8da4c958c3bbadfff082c547983f5daa50c0f jdk9-b35
+10fe62bc188476abb025e55f55128cbfecf24584 jdk9-b36
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/bin/runopt.sh	Mon Oct 27 11:16:19 2014 +0100
@@ -0,0 +1,137 @@
+#!/bin/sh
+#
+# 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.
+#
+
+###########################################################################################
+# This is a helper script to evaluate nashorn with optimistic types
+# it produces a flight recording for every run, and uses the best 
+# known flags for performance for the current configration
+###########################################################################################
+
+# Flags to enable assertions, we need the system assertions too, since
+# this script runs Nashorn in the BCP to override any nashorn.jar that might
+# reside in your $JAVA_HOME/jre/lib/ext/nashorn.jar
+#
+ENABLE_ASSERTIONS_FLAGS="-ea -esa"
+
+# Flags to instrument lambdaform computation, caching, interpretation and compilation
+# Default compile threshold for lambdaforms is 30
+#
+#LAMBDAFORM_FLAGS="\
+#    -Djava.lang.invoke.MethodHandle.COMPILE_THRESHOLD=3 \
+#    -Djava.lang.invoke.MethodHandle.DUMP_CLASS_FILES=true \
+#    -Djava.lang.invoke.MethodHandle.TRACE_METHOD_LINKAGE=true \
+#    -Djava.lang.invoke.MethodHandle.TRACE_INTERPRETER=true"
+
+# Flags to run trusted tests from the Nashorn test suite
+#
+#TRUSTED_TEST_FLAGS="\
+#-Djava.security.manager \
+#-Djava.security.policy=../build/nashorn.policy -Dnashorn.debug"
+
+# Testing out new code optimizations using the generic hotspot "new code" parameter
+#
+#USE_NEW_CODE_FLAGS=-XX:+UnlockDiagnosticVMOptions -XX:+UseNewCode
+
+#
+#-Dnashorn.typeInfo.disabled=false \
+# and for Nashorn options: 
+# --class-cache-size=0 --persistent-code-cache=false 
+
+# Unique timestamped file name for JFR recordings. For JFR, we also have to
+# crank up the stack cutoff depth to 1024, because of ridiculously long lambda form
+# stack traces.
+#
+# It is also recommended that you go into $JAVA_HOME/jre/lib/jfr/default.jfc and
+# set the "method-sampling-interval" Normal and Maximum sample time as low as you
+# can go (10 ms on most platforms). The default is normally higher. The increased
+# sampling overhead is usually negligible for Nashorn runs, but the data is better
+
+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
+#
+# see above - already in place, copy the flags down here to disable
+ENABLE_FLIGHT_RECORDER_FLAGS="\
+    -XX:+UnlockCommercialFeatures \
+    -XX:+FlightRecorder \
+    -XX:FlightRecorderOptions=defaultrecording=true,disk=true,dumponexit=true,dumponexitpath=$JFR_FILENAME,stackdepth=1024"
+
+# Type specialization and math intrinsic replacement should be enabled by default in 8u20 and nine,
+# keeping this flag around for experimental reasons. Replace + with - to switch it off
+#
+#ENABLE_TYPE_SPECIALIZATION_FLAGS=-XX:+UseTypeSpeculation
+
+# Same with math intrinsics. They should be enabled by default in 8u20 and 9, so
+# this disables them if needed
+#
+#DISABLE_MATH_INTRINSICS_FLAGS=-XX:-UseMathExactIntrinsics
+
+# Add timing to time the compilation phases.
+#ENABLE_TIME_FLAGS=--log=time
+
+# Add ShowHiddenFrames to get lambda form internals on the stack traces
+#ENABLE_SHOW_HIDDEN_FRAMES_FLAGS=-XX:+ShowHiddenFrames
+
+# Add print optoassembly to get an asm dump. This requires 1) a debug build, not product,
+# That tired compilation is switched off, for C2 only output and that the number of
+# compiler threads is set to 1 for determinsm.
+#
+#PRINT_ASM_FLAGS=-XX:+PrintOptoAssembly -XX:-TieredCompilation -XX:CICompilerCount=1 \
+
+# Tier compile threasholds. Default value is 10. (1-100 is useful for experiments)
+#TIER_COMPILATION_THRESHOLD_FLAGS=-XX:IncreaseFirstTierCompileThresholdAt=10
+
+# Directory where to look for nashorn.jar in a dist folder. The default is "..", assuming
+# that we run the script from the make dir
+DIR=..
+NASHORN_JAR=$DIR/dist/nashorn.jar
+
+
+# The built Nashorn jar is placed first in the bootclasspath to override the JDK
+# nashorn.jar in $JAVA_HOME/jre/lib/ext. Thus, we also need -esa, as assertions in
+# nashorn count as system assertions in this configuration
+
+# Type profiling default level is 111, 222 adds some compile time, but is faster
+
+$JAVA_HOME/bin/java \
+$ENABLE_ASSERTIONS_FLAGS \
+$LAMBDAFORM_FLAGS \
+$TRUSTED_FLAGS \
+$USE_NEW_CODE_FLAGS \
+$ENABLE_SHOW_HIDDEN_FRAMES_FLAGS \
+$ENABLE_FLIGHT_RECORDER_FLAGS \
+$ENABLE_TYPE_SPECIALIZATION_FLAGS \
+$TIERED_COMPILATION_THRESOLD_FLAGS \
+$DISABLE_MATH_INTRINSICS_FLAGS \
+$PRINT_ASM_FLAGS \
+-Xbootclasspath/p:$NASHORN_JAR \
+-Xms2G -Xmx2G \
+-XX:TypeProfileLevel=222 \
+-cp $CLASSPATH:../build/test/classes/ \
+jdk.nashorn.tools.Shell $ENABLE_TIME_FLAGS ${@}
+
+
--- a/make/build.xml	Tue Oct 21 14:24:16 2014 +0100
+++ b/make/build.xml	Mon Oct 27 11:16:19 2014 +0100
@@ -408,7 +408,7 @@
     <fileset id="test.nosecurity.classes" dir="${build.test.classes.dir}">
       <include name="**/framework/ScriptTest.class"/>
     </fileset>
-    <testng outputdir="${build.nosecurity.test.results.dir}" classfilesetref="test.nosecurity.classes"
+    <testng outputdir="${build.nosecurity.test.results.dir}/${testResultsSubDir}" classfilesetref="test.nosecurity.classes"
        verbose="${testng.verbose}" haltonfailure="true" useDefaultListeners="false" listeners="${testng.listeners}" workingDir="${basedir}">
       <jvmarg line="${ext.class.path}"/>
       <jvmarg line="${run.test.jvmargs} -Xmx${run.test.xmx} -Dbuild.dir=${build.dir}"/>
@@ -431,7 +431,7 @@
   <target name="-test-security">
     <delete dir="${build.dir}/nashorn_code_cache"/>
     <property name="debug.test.jvmargs" value=""/>
-    <testng outputdir="${build.test.results.dir}" classfilesetref="test.classes"
+    <testng outputdir="${build.test.results.dir}/${testResultsSubDir}" classfilesetref="test.classes"
 	    verbose="${testng.verbose}" haltonfailure="true" useDefaultListeners="false" listeners="${testng.listeners}" workingDir="${basedir}">
       <jvmarg line="${ext.class.path}"/>
       <jvmarg line="${run.test.jvmargs} -Xmx${run.test.xmx} ${run.test.jvmsecurityargs} -Dbuild.dir=${build.dir}"/>
@@ -457,9 +457,11 @@
     <echo message="Running test suite in OPTIMISTIC mode..."/>
     <antcall target="-test-nosecurity" inheritRefs="true">
       <param name="optimistic" value="true"/>
+      <param name="testResultsSubDir" value="optimistic"/>
     </antcall>    
     <antcall target="-test-security" inheritRefs="true">
       <param name="optimistic" value="true"/>
+      <param name="testResultsSubDir" value="optimistic"/>
     </antcall>
   </target>
 
@@ -467,9 +469,11 @@
     <echo message="Running test suite in PESSIMISTIC mode..."/>
     <antcall target="-test-nosecurity" inheritRefs="true">
       <param name="optimistic" value="false"/>
+      <param name="testResultsSubDir" value="pessimistic"/>
     </antcall>    
     <antcall target="-test-security" inheritRefs="true">
       <param name="optimistic" value="false"/>
+      <param name="testResultsSubDir" value="pessimistic"/>
     </antcall>
   </target>
 
--- a/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/api/scripting/NashornScriptEngine.java	Tue Oct 21 14:24:16 2014 +0100
+++ b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/api/scripting/NashornScriptEngine.java	Mon Oct 27 11:16:19 2014 +0100
@@ -229,6 +229,8 @@
     }
 
     private <T> T getInterfaceInner(final Object thiz, final Class<T> clazz) {
+        assert !(thiz instanceof ScriptObject) : "raw ScriptObject not expected here";
+
         if (clazz == null || !clazz.isInterface()) {
             throw new IllegalArgumentException(getMessage("interface.class.expected"));
         }
@@ -254,17 +256,6 @@
             if (! isOfContext(realGlobal, nashornContext)) {
                 throw new IllegalArgumentException(getMessage("script.object.from.another.engine"));
             }
-        } else if (thiz instanceof ScriptObject) {
-            // called from script code.
-            realSelf = (ScriptObject)thiz;
-            realGlobal = Context.getGlobal();
-            if (realGlobal == null) {
-                throw new IllegalArgumentException(getMessage("no.current.nashorn.global"));
-            }
-
-            if (! isOfContext(realGlobal, nashornContext)) {
-                throw new IllegalArgumentException(getMessage("script.object.from.another.engine"));
-            }
         }
 
         if (realSelf == null) {
@@ -368,6 +359,7 @@
 
     private Object invokeImpl(final Object selfObject, final String name, final Object... args) throws ScriptException, NoSuchMethodException {
         name.getClass(); // null check
+        assert !(selfObject instanceof ScriptObject) : "raw ScriptObject not expected here";
 
         Global invokeGlobal = null;
         ScriptObjectMirror selfMirror = null;
@@ -377,20 +369,6 @@
                 throw new IllegalArgumentException(getMessage("script.object.from.another.engine"));
             }
             invokeGlobal = selfMirror.getHomeGlobal();
-        } else if (selfObject instanceof ScriptObject) {
-            // invokeMethod called from script code - in which case we may get 'naked' ScriptObject
-            // Wrap it with oldGlobal to make a ScriptObjectMirror for the same.
-            final Global oldGlobal = Context.getGlobal();
-            invokeGlobal = oldGlobal;
-            if (oldGlobal == null) {
-                throw new IllegalArgumentException(getMessage("no.current.nashorn.global"));
-            }
-
-            if (! isOfContext(oldGlobal, nashornContext)) {
-                throw new IllegalArgumentException(getMessage("script.object.from.another.engine"));
-            }
-
-            selfMirror = (ScriptObjectMirror)ScriptObjectMirror.wrap(selfObject, oldGlobal);
         } else if (selfObject == null) {
             // selfObject is null => global function call
             final Global ctxtGlobal = getNashornGlobalFrom(context);
--- a/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/api/scripting/ScriptUtils.java	Tue Oct 21 14:24:16 2014 +0100
+++ b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/api/scripting/ScriptUtils.java	Mon Oct 27 11:16:19 2014 +0100
@@ -25,8 +25,6 @@
 
 package jdk.nashorn.api.scripting;
 
-import static jdk.nashorn.internal.runtime.ECMAErrors.typeError;
-
 import java.lang.invoke.MethodHandle;
 import jdk.internal.dynalink.beans.StaticClass;
 import jdk.internal.dynalink.linker.LinkerServices;
@@ -75,11 +73,8 @@
      * @param sync the object to synchronize on
      * @return a synchronizing wrapper function
      */
-    public static Object makeSynchronizedFunction(final Object func, final Object sync) {
-        if (func instanceof ScriptFunction) {
-           return ((ScriptFunction)func).makeSynchronizedFunction(sync);
-        }
-        throw typeError("not.a.function", ScriptRuntime.safeToString(func));
+    public static Object makeSynchronizedFunction(final ScriptFunction func, final Object sync) {
+        return func.makeSynchronizedFunction(unwrap(sync));
     }
 
     /**
@@ -88,12 +83,8 @@
      * @param obj object to be wrapped
      * @return wrapped object
      */
-    public static Object wrap(final Object obj) {
-        if (obj instanceof ScriptObject) {
-            return ScriptObjectMirror.wrap(obj, Context.getGlobal());
-        }
-
-        return obj;
+    public static ScriptObjectMirror wrap(final ScriptObject obj) {
+        return (ScriptObjectMirror) ScriptObjectMirror.wrap(obj, Context.getGlobal());
     }
 
     /**
@@ -160,14 +151,15 @@
         }
 
         final LinkerServices linker = Bootstrap.getLinkerServices();
-        final MethodHandle converter = linker.getTypeConverter(obj.getClass(),  clazz);
+        final Object objToConvert = unwrap(obj);
+        final MethodHandle converter = linker.getTypeConverter(objToConvert.getClass(),  clazz);
         if (converter == null) {
             // no supported conversion!
             throw new UnsupportedOperationException("conversion not supported");
         }
 
         try {
-            return converter.invoke(obj);
+            return converter.invoke(objToConvert);
         } catch (final RuntimeException | Error e) {
             throw e;
         } catch (final Throwable t) {
--- a/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/AssignSymbols.java	Tue Oct 21 14:24:16 2014 +0100
+++ b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/AssignSymbols.java	Mon Oct 27 11:16:19 2014 +0100
@@ -511,16 +511,6 @@
 
         thisProperties.push(new HashSet<String>());
 
-        if (functionNode.isDeclared()) {
-            // Can't use lc.getCurrentBlock() as we can have an outermost function in our lexical context that
-            // is not a program - it is a function being compiled on-demand.
-            final Iterator<Block> blocks = lc.getBlocks();
-            if (blocks.hasNext()) {
-                final IdentNode ident = functionNode.getIdent();
-                defineSymbol(blocks.next(), ident.getName(), ident, IS_VAR | (functionNode.isAnonymous()? IS_INTERNAL : 0));
-            }
-        }
-
         // Every function has a body, even the ones skipped on reparse (they have an empty one). We're
         // asserting this as even for those, enterBlock() must be invoked to correctly process symbols that
         // are used in them.
@@ -532,14 +522,34 @@
     @Override
     public boolean enterVarNode(final VarNode varNode) {
         start(varNode);
+        // Normally, a symbol assigned in a var statement is not live for its RHS. Since we also represent function
+        // declarations as VarNodes, they are exception to the rule, as they need to have the symbol visible to the
+        // body of the declared function for self-reference.
+        if (varNode.isFunctionDeclaration()) {
+            defineVarIdent(varNode);
+        }
         return true;
     }
 
     @Override
     public Node leaveVarNode(final VarNode varNode) {
+        if (!varNode.isFunctionDeclaration()) {
+            defineVarIdent(varNode);
+        }
+        return super.leaveVarNode(varNode);
+    }
+
+    private void defineVarIdent(final VarNode varNode) {
         final IdentNode ident = varNode.getName();
-        defineSymbol(lc.getCurrentBlock(), ident.getName(), ident, varNode.getSymbolFlags() | (lc.getCurrentFunction().isProgram() ? IS_SCOPE : 0));
-        return super.leaveVarNode(varNode);
+        final int flags;
+        if (varNode.isAnonymousFunctionDeclaration()) {
+            flags = IS_INTERNAL;
+        } else if (lc.getCurrentFunction().isProgram()) {
+            flags = IS_SCOPE;
+        } else {
+            flags = 0;
+        }
+        defineSymbol(lc.getCurrentBlock(), ident.getName(), ident, varNode.getSymbolFlags() | flags);
     }
 
     private Symbol exceptionSymbol() {
--- a/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/Compiler.java	Tue Oct 21 14:24:16 2014 +0100
+++ b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/Compiler.java	Mon Oct 27 11:16:19 2014 +0100
@@ -410,10 +410,29 @@
             baseName = baseName + installer.getUniqueScriptId();
         }
 
-        final String mangled = NameCodec.encode(baseName);
+        // ASM's bytecode verifier does not allow JVM allowed safe escapes using '\' as escape char.
+        // While ASM accepts such escapes for method names, field names, it enforces Java identifier
+        // for class names. Workaround that ASM bug here by replacing JVM 'dangerous' chars with '_'
+        // rather than safe encoding using '\'.
+        final String mangled = env._verify_code? replaceDangerChars(baseName) : NameCodec.encode(baseName);
         return mangled != null ? mangled : baseName;
     }
 
+    private static final String DANGEROUS_CHARS   = "\\/.;:$[]<>";
+    private static String replaceDangerChars(final String name) {
+        final int len = name.length();
+        final StringBuilder buf = new StringBuilder();
+        for (int i = 0; i < len; i++) {
+            final char ch = name.charAt(i);
+            if (DANGEROUS_CHARS.indexOf(ch) != -1) {
+                buf.append('_');
+            } else {
+                buf.append(ch);
+            }
+        }
+        return buf.toString();
+    }
+
     private String firstCompileUnitName() {
         final StringBuilder sb = new StringBuilder(SCRIPTS_PACKAGE).
                 append('/').
--- a/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/MethodEmitter.java	Tue Oct 21 14:24:16 2014 +0100
+++ b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/MethodEmitter.java	Mon Oct 27 11:16:19 2014 +0100
@@ -98,6 +98,7 @@
 import jdk.nashorn.internal.ir.RuntimeNode;
 import jdk.nashorn.internal.ir.Symbol;
 import jdk.nashorn.internal.ir.TryNode;
+import jdk.nashorn.internal.objects.NativeArray;
 import jdk.nashorn.internal.runtime.ArgumentSetter;
 import jdk.nashorn.internal.runtime.Context;
 import jdk.nashorn.internal.runtime.Debug;
@@ -2125,7 +2126,14 @@
 
         int pos = 0;
         for (int i = argCount - 1; i >= 0; i--) {
-            paramTypes[i] = stack.peek(pos++);
+            Type pt = stack.peek(pos++);
+            // "erase" specific ScriptObject subtype info - except for NativeArray.
+            // NativeArray is used for array/List/Deque conversion for Java calls.
+            if (ScriptObject.class.isAssignableFrom(pt.getTypeClass()) &&
+                !NativeArray.class.isAssignableFrom(pt.getTypeClass())) {
+                pt = Type.SCRIPT_OBJECT;
+            }
+            paramTypes[i] = pt;
         }
         final String descriptor = Type.getMethodDescriptor(returnType, paramTypes);
         for (int i = 0; i < argCount; i++) {
--- a/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/TypeEvaluator.java	Tue Oct 21 14:24:16 2014 +0100
+++ b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/TypeEvaluator.java	Mon Oct 27 11:16:19 2014 +0100
@@ -29,16 +29,22 @@
 import static jdk.nashorn.internal.runtime.Property.NOT_ENUMERABLE;
 import static jdk.nashorn.internal.runtime.Property.NOT_WRITABLE;
 
+import java.lang.invoke.MethodType;
 import jdk.nashorn.internal.codegen.types.Type;
 import jdk.nashorn.internal.ir.AccessNode;
+import jdk.nashorn.internal.ir.CallNode;
 import jdk.nashorn.internal.ir.Expression;
+import jdk.nashorn.internal.ir.FunctionNode;
 import jdk.nashorn.internal.ir.IdentNode;
 import jdk.nashorn.internal.ir.IndexNode;
 import jdk.nashorn.internal.ir.Optimistic;
+import jdk.nashorn.internal.objects.ArrayBufferView;
 import jdk.nashorn.internal.objects.NativeArray;
 import jdk.nashorn.internal.runtime.FindProperty;
 import jdk.nashorn.internal.runtime.JSType;
 import jdk.nashorn.internal.runtime.Property;
+import jdk.nashorn.internal.runtime.RecompilableScriptFunctionData;
+import jdk.nashorn.internal.runtime.ScriptFunction;
 import jdk.nashorn.internal.runtime.ScriptObject;
 import jdk.nashorn.internal.runtime.ScriptRuntime;
 
@@ -47,6 +53,13 @@
  * Used during recompilation.
  */
 final class TypeEvaluator {
+    /**
+     * Type signature for invocation of functions without parameters: we must pass (callee, this) of type
+     * (ScriptFunction, Object) respectively. We also use Object as the return type (we must pass something,
+     * but it'll be ignored; it can't be void, though).
+     */
+    private static final MethodType EMPTY_INVOCATION_TYPE = MethodType.methodType(Object.class, ScriptFunction.class, Object.class);
+
     private final Compiler compiler;
     private final ScriptObject runtimeScope;
 
@@ -190,30 +203,46 @@
                 return null;
             }
             return getPropertyType(runtimeScope, ((IdentNode)expr).getName());
-        }
-
-        if (expr instanceof AccessNode) {
+        } else if (expr instanceof AccessNode) {
             final AccessNode accessNode = (AccessNode)expr;
             final Object base = evaluateSafely(accessNode.getBase());
             if (!(base instanceof ScriptObject)) {
                 return null;
             }
             return getPropertyType((ScriptObject)base, accessNode.getProperty());
-        }
-
-        if (expr instanceof IndexNode) {
+        } else if (expr instanceof IndexNode) {
             final IndexNode indexNode = (IndexNode)expr;
             final Object    base = evaluateSafely(indexNode.getBase());
-            if(!(base instanceof NativeArray)) {
-                // We only know how to deal with NativeArray. TODO: maybe manage buffers too
-                return null;
+            if(base instanceof NativeArray || base instanceof ArrayBufferView) {
+                // NOTE: optimistic array getters throw UnwarrantedOptimismException based on the type of their
+                // underlying array storage, not based on values of individual elements. Thus, a LongArrayData will
+                // throw UOE for every optimistic int linkage attempt, even if the long value being returned in the
+                // first invocation would be representable as int. That way, we can presume that the array's optimistic
+                // type is the most optimistic type for which an element getter has a chance of executing successfully.
+                return ((ScriptObject)base).getArray().getOptimisticType();
             }
-            // NOTE: optimistic array getters throw UnwarrantedOptimismException based on the type of their underlying
-            // array storage, not based on values of individual elements. Thus, a LongArrayData will throw UOE for every
-            // optimistic int linkage attempt, even if the long value being returned in the first invocation would be
-            // representable as int. That way, we can presume that the array's optimistic type is the most optimistic
-            // type for which an element getter has a chance of executing successfully.
-            return ((NativeArray)base).getArray().getOptimisticType();
+        } else if (expr instanceof CallNode) {
+            // Currently, we'll only try to guess the return type of immediately invoked function expressions with no
+            // parameters, that is (function() { ... })(). We could do better, but these are all heuristics and we can
+            // gradually introduce them as needed. An easy one would be to do the same for .call(this) idiom.
+            final CallNode callExpr = (CallNode)expr;
+            final Expression fnExpr = callExpr.getFunction();
+            if (fnExpr instanceof FunctionNode) {
+                final FunctionNode fn = (FunctionNode)fnExpr;
+                if (callExpr.getArgs().isEmpty()) {
+                    final RecompilableScriptFunctionData data = compiler.getScriptFunctionData(fn.getId());
+                    if (data != null) {
+                        final Type returnType = Type.typeFor(data.getReturnType(EMPTY_INVOCATION_TYPE, runtimeScope));
+                        if (returnType == Type.BOOLEAN) {
+                            // We don't have optimistic booleans. In fact, optimistic call sites getting back boolean
+                            // currently deoptimize all the way to Object.
+                            return Type.OBJECT;
+                        }
+                        assert returnType == Type.INT || returnType == Type.LONG || returnType == Type.NUMBER || returnType == Type.OBJECT;
+                        return returnType;
+                    }
+                }
+            }
         }
 
         return null;
--- a/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/Block.java	Tue Oct 21 14:24:16 2014 +0100
+++ b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/Block.java	Mon Oct 27 11:16:19 2014 +0100
@@ -80,11 +80,12 @@
     /**
      * Constructor
      *
-     * @param token      token
-     * @param finish     finish
-     * @param statements statements
+     * @param token      The first token of the block
+     * @param finish     The index of the last character
+     * @param flags      The flags of the block
+     * @param statements All statements in the block
      */
-    public Block(final long token, final int finish, final Statement... statements) {
+    public Block(final long token, final int finish, final int flags, final Statement... statements) {
         super(token, finish);
 
         this.statements = Arrays.asList(statements);
@@ -92,29 +93,52 @@
         this.entryLabel = new Label("block_entry");
         this.breakLabel = new Label("block_break");
         final int len = statements.length;
-        this.flags = len > 0 && statements[len - 1].hasTerminalFlags() ? IS_TERMINAL : 0;
+        final int terminalFlags = len > 0 && statements[len - 1].hasTerminalFlags() ? IS_TERMINAL : 0;
+        this.flags = terminalFlags | flags;
         this.conversion = null;
     }
 
     /**
+     * Constructs a new block
+     *
+     * @param token The first token of the block
+     * @param finish The index of the last character
+     * @param statements All statements in the block
+     */
+    public Block(final long token, final int finish, final Statement...statements){
+        this(token, finish, 0, statements);
+    }
+
+    /**
+     * Constructs a new block
+     *
+     * @param token The first token of the block
+     * @param finish The index of the last character
+     * @param statements All statements in the block
+     */
+    public Block(final long token, final int finish, final List<Statement> statements){
+        this(token, finish, 0, statements);
+    }
+
+    /**
      * Constructor
      *
-     * @param token      token
-     * @param finish     finish
-     * @param statements statements
+     * @param token      The first token of the block
+     * @param finish     The index of the last character
+     * @param flags      The flags of the block
+     * @param statements All statements in the block
      */
-    public Block(final long token, final int finish, final List<Statement> statements) {
-        this(token, finish, statements.toArray(new Statement[statements.size()]));
+    public Block(final long token, final int finish, final int flags, final List<Statement> statements) {
+        this(token, finish, flags, statements.toArray(new Statement[statements.size()]));
     }
 
     private Block(final Block block, final int finish, final List<Statement> statements, final int flags, final Map<String, Symbol> symbols, final LocalVariableConversion conversion) {
-        super(block);
+        super(block, finish);
         this.statements = statements;
         this.flags      = flags;
         this.symbols    = new LinkedHashMap<>(symbols); //todo - symbols have no dependencies on any IR node and can as far as we understand it be shallow copied now
         this.entryLabel = new Label(block.entryLabel);
         this.breakLabel = new Label(block.breakLabel);
-        this.finish     = finish;
         this.conversion = conversion;
     }
 
--- a/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/ForNode.java	Tue Oct 21 14:24:16 2014 +0100
+++ b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/ForNode.java	Mon Oct 27 11:16:19 2014 +0100
@@ -55,19 +55,36 @@
     private final int flags;
 
     /**
+     * Constructs a ForNode
+     *
+     * @param lineNumber The line number of header
+     * @param token      The for token
+     * @param finish     The last character of the for node
+     * @param body       The body of the for node
+     * @param flags      The flags
+     */
+    public ForNode(final int lineNumber, final long token, final int finish, final Block body, final int flags){
+        this(lineNumber, token, finish, body, flags, null, null, null);
+    }
+
+    /**
      * Constructor
      *
-     * @param lineNumber line number
-     * @param token      token
-     * @param finish     finish
-     * @param body       body
-     * @param flags      flags
+     * @param lineNumber The line number of header
+     * @param token      The for token
+     * @param finish     The last character of the for node
+     * @param body       The body of the for node
+     * @param flags      The flags
+     * @param init       The initial expression
+     * @param test       The test expression
+     * @param modify     The modify expression
      */
-    public ForNode(final int lineNumber, final long token, final int finish, final Block body, final int flags) {
-        super(lineNumber, token, finish, body, false);
+    public ForNode(final int lineNumber, final long token, final int finish, final Block body, final int flags, final Expression init, final JoinPredecessorExpression test, final JoinPredecessorExpression modify) {
+        super(lineNumber, token, finish, body, test, false);
         this.flags  = flags;
-        this.init = null;
-        this.modify = null;
+        this.init = init;
+        this.modify = modify;
+
     }
 
     private ForNode(final ForNode forNode, final Expression init, final JoinPredecessorExpression test,
@@ -166,16 +183,6 @@
     public boolean isForIn() {
         return (flags & IS_FOR_IN) != 0;
     }
-
-    /**
-     * Flag this to be a for in construct
-     * @param lc lexical context
-     * @return new for node if changed or existing if not
-     */
-    public ForNode setIsForIn(final LexicalContext lc) {
-        return setFlags(lc, flags | IS_FOR_IN);
-    }
-
     /**
      * Is this a for each construct, known from e.g. Rhino. This will be a for of construct
      * in ECMAScript 6
@@ -186,15 +193,6 @@
     }
 
     /**
-     * Flag this to be a for each construct
-     * @param lc lexical context
-     * @return new for node if changed or existing if not
-     */
-    public ForNode setIsForEach(final LexicalContext lc) {
-        return setFlags(lc, flags | IS_FOR_EACH);
-    }
-
-    /**
      * If this is a for in or for each construct, there is an iterator symbol
      * @return the symbol for the iterator to be used, or null if none exists
      */
@@ -260,13 +258,6 @@
         return Node.replaceInLexicalContext(lc, this, new ForNode(this, init, test, body, modify, flags, controlFlowEscapes, conversion));
     }
 
-    private ForNode setFlags(final LexicalContext lc, final int flags) {
-        if (this.flags == flags) {
-            return this;
-        }
-        return Node.replaceInLexicalContext(lc, this, new ForNode(this, init, test, body, modify, flags, controlFlowEscapes, conversion));
-    }
-
     @Override
     JoinPredecessor setLocalVariableConversionChanged(final LexicalContext lc, final LocalVariableConversion conversion) {
         return Node.replaceInLexicalContext(lc, this, new ForNode(this, init, test, body, modify, flags, controlFlowEscapes, conversion));
--- a/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/FunctionNode.java	Tue Oct 21 14:24:16 2014 +0100
+++ b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/FunctionNode.java	Mon Oct 27 11:16:19 2014 +0100
@@ -31,7 +31,6 @@
 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;
@@ -46,6 +45,7 @@
 import jdk.nashorn.internal.ir.annotations.Ignore;
 import jdk.nashorn.internal.ir.annotations.Immutable;
 import jdk.nashorn.internal.ir.visitor.NodeVisitor;
+import jdk.nashorn.internal.parser.Token;
 import jdk.nashorn.internal.runtime.RecompilableScriptFunctionData;
 import jdk.nashorn.internal.runtime.ScriptFunction;
 import jdk.nashorn.internal.runtime.Source;
@@ -299,12 +299,16 @@
      * @param token      token
      * @param finish     finish
      * @param firstToken first token of the function node (including the function declaration)
+     * @param lastToken  lastToken
      * @param namespace  the namespace
      * @param ident      the identifier
      * @param name       the name of the function
      * @param parameters parameter list
      * @param kind       kind of function as in {@link FunctionNode.Kind}
      * @param flags      initial flags
+     * @param body       body of the function
+     * @param state      The initial state from the parser. Must be one of {@link CompilationState#PARSED} and {@link CompilationState#PARSE_ERROR}
+     * @param endParserState The parser state at the end of the parsing.
      */
     public FunctionNode(
         final Source source,
@@ -312,12 +316,16 @@
         final long token,
         final int finish,
         final long firstToken,
+        final long lastToken,
         final Namespace namespace,
         final IdentNode ident,
         final String name,
         final List<IdentNode> parameters,
         final FunctionNode.Kind kind,
-        final int flags) {
+        final int flags,
+        final Block body,
+        final CompilationState state,
+        final Object endParserState) {
         super(token, finish);
 
         this.source           = source;
@@ -327,15 +335,15 @@
         this.kind             = kind;
         this.parameters       = parameters;
         this.firstToken       = firstToken;
-        this.lastToken        = token;
+        this.lastToken        = lastToken;
         this.namespace        = namespace;
-        this.compilationState = EnumSet.of(CompilationState.INITIALIZED);
+        this.compilationState = EnumSet.of(CompilationState.INITIALIZED, state);
         this.flags            = flags;
         this.compileUnit      = null;
-        this.body             = null;
+        this.body             = body;
         this.thisProperties   = 0;
         this.rootClass        = null;
-        this.endParserState    = null;
+        this.endParserState    = endParserState;
     }
 
     private FunctionNode(
@@ -439,7 +447,7 @@
      * @return the id
      */
     public int getId() {
-        return position();
+        return isProgram() ? -1: Token.descPosition(firstToken);
     }
 
     /**
@@ -903,34 +911,6 @@
     }
 
     /**
-     * Set the last token for this function's code
-     * @param lc lexical context
-     * @param lastToken the last token
-     * @return function node or a new one if state was changed
-     */
-    public FunctionNode setLastToken(final LexicalContext lc, final long lastToken) {
-        if (this.lastToken == lastToken) {
-            return this;
-        }
-        return Node.replaceInLexicalContext(
-                lc,
-                this,
-                new FunctionNode(
-                        this,
-                        lastToken,
-                        endParserState,
-                        flags,
-                        name,
-                        returnType,
-                        compileUnit,
-                        compilationState,
-                        body,
-                        parameters,
-                        thisProperties,
-                        rootClass));
-    }
-
-    /**
      * Returns the end parser state for this function.
      * @return the end parser state for this function.
      */
@@ -939,33 +919,6 @@
     }
 
     /**
-     * Set the end parser state for this function.
-     * @param lc lexical context
-     * @param endParserState the parser state to set
-     * @return function node or a new one if state was changed
-     */
-    public FunctionNode setEndParserState(final LexicalContext lc, final Object endParserState) {
-        if (this.endParserState == endParserState) {
-            return this;
-        }
-        return Node.replaceInLexicalContext(
-                lc,
-                this,
-                new FunctionNode(
-                        this,
-                        lastToken,
-                        endParserState,
-                        flags,
-                        name,
-                        returnType,
-                        compileUnit,
-                        compilationState,
-                        body,
-                        parameters,
-                        thisProperties, rootClass));
-    }
-
-    /**
      * Get the name of this function
      * @return the name
      */
--- a/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/LoopNode.java	Tue Oct 21 14:24:16 2014 +0100
+++ b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/LoopNode.java	Mon Oct 27 11:16:19 2014 +0100
@@ -53,14 +53,15 @@
      * @param token              token
      * @param finish             finish
      * @param body               loop body
+     * @param test               test
      * @param controlFlowEscapes controlFlowEscapes
      */
-    protected LoopNode(final int lineNumber, final long token, final int finish, final Block body, final boolean controlFlowEscapes) {
+    protected LoopNode(final int lineNumber, final long token, final int finish, final Block body, final JoinPredecessorExpression test, final boolean controlFlowEscapes) {
         super(lineNumber, token, finish, new Label("while_break"));
         this.continueLabel = new Label("while_continue");
-        this.test = null;
         this.body = body;
         this.controlFlowEscapes = controlFlowEscapes;
+        this.test = test;
     }
 
     /**
--- a/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/Node.java	Tue Oct 21 14:24:16 2014 +0100
+++ b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/Node.java	Mon Oct 27 11:16:19 2014 +0100
@@ -39,7 +39,7 @@
     protected final int start;
 
     /** End of source range. */
-    protected int finish;
+    protected final int finish;
 
     /** Token descriptor. */
     private final long token;
@@ -81,6 +81,18 @@
     }
 
     /**
+     * Copy constructor that overrides finish
+     *
+     * @param node source node
+     * @param finish Last character
+     */
+    protected Node(final Node node, final int finish) {
+        this.token = node.token;
+        this.start = node.start;
+        this.finish = finish;
+    }
+
+    /**
      * Is this a loop node?
      *
      * @return true if atom
@@ -152,14 +164,6 @@
     }
 
     /**
-     * Set finish position for this node in the source string
-     * @param finish finish
-     */
-    public void setFinish(final int finish) {
-        this.finish = finish;
-    }
-
-    /**
      * Get start position for node
      * @return start position
      */
--- a/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/VarNode.java	Tue Oct 21 14:24:16 2014 +0100
+++ b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/VarNode.java	Mon Oct 27 11:16:19 2014 +0100
@@ -272,4 +272,12 @@
     public boolean isFunctionDeclaration() {
         return init instanceof FunctionNode && ((FunctionNode)init).isDeclared();
     }
+
+    /**
+     * Returns true if this is an anonymous function declaration.
+     * @return true if this is an anonymous function declaration.
+     */
+    public boolean isAnonymousFunctionDeclaration() {
+        return isFunctionDeclaration() && ((FunctionNode)init).isAnonymous();
+    }
 }
--- a/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/WhileNode.java	Tue Oct 21 14:24:16 2014 +0100
+++ b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/WhileNode.java	Mon Oct 27 11:16:19 2014 +0100
@@ -45,9 +45,11 @@
      * @param token      token
      * @param finish     finish
      * @param isDoWhile  is this a do while loop?
+     * @param test       test expression
+     * @param body       body of the while loop
      */
-    public WhileNode(final int lineNumber, final long token, final int finish, final boolean isDoWhile) {
-        super(lineNumber, token, finish, null, false);
+    public WhileNode(final int lineNumber, final long token, final int finish, final boolean isDoWhile, final JoinPredecessorExpression test, final Block body) {
+        super(lineNumber, token, finish, body, test, false);
         this.isDoWhile = isDoWhile;
     }
 
@@ -55,10 +57,10 @@
      * Internal copy constructor
      *
      * @param whileNode while node
-     * @param test      test
-     * @param body      body
+     * @param test      Test expression
+     * @param body      body of the while loop
      * @param controlFlowEscapes control flow escapes?
-     * @param conversion TODO
+     * @param conversion local variable conversion info
      */
     private WhileNode(final WhileNode whileNode, final JoinPredecessorExpression test, final Block body, final boolean controlFlowEscapes, final LocalVariableConversion conversion) {
         super(whileNode, test, body, controlFlowEscapes, conversion);
--- a/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/WithNode.java	Tue Oct 21 14:24:16 2014 +0100
+++ b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/WithNode.java	Mon Oct 27 11:16:19 2014 +0100
@@ -42,14 +42,16 @@
     /**
      * Constructor
      *
-     * @param lineNumber line number
-     * @param token      token
-     * @param finish     finish
+     * @param lineNumber Line number of the header
+     * @param token      First token
+     * @param finish     Character index of the last token
+     * @param expression With expression
+     * @param body       Body of with node
      */
-    public WithNode(final int lineNumber, final long token, final int finish) {
+    public WithNode(final int lineNumber, final long token, final int finish, final Expression expression, final Block body) {
         super(lineNumber, token, finish);
-        this.expression = null;
-        this.body       = null;
+        this.expression = expression;
+        this.body       = body;
     }
 
     private WithNode(final WithNode node, final Expression expression, final Block body) {
--- a/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/ArrayBufferView.java	Tue Oct 21 14:24:16 2014 +0100
+++ b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/ArrayBufferView.java	Mon Oct 27 11:16:19 2014 +0100
@@ -31,7 +31,6 @@
 
 import java.nio.ByteBuffer;
 import java.nio.ByteOrder;
-
 import jdk.internal.dynalink.CallSiteDescriptor;
 import jdk.internal.dynalink.linker.GuardedInvocation;
 import jdk.internal.dynalink.linker.LinkRequest;
@@ -46,7 +45,7 @@
 import jdk.nashorn.internal.runtime.arrays.TypedArrayData;
 
 @ScriptClass("ArrayBufferView")
-abstract class ArrayBufferView extends ScriptObject {
+public abstract class ArrayBufferView extends ScriptObject {
     private final NativeArrayBuffer buffer;
     private final int byteOffset;
 
--- a/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/Global.java	Tue Oct 21 14:24:16 2014 +0100
+++ b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/Global.java	Mon Oct 27 11:16:19 2014 +0100
@@ -561,7 +561,6 @@
      *
      * @param engine ScriptEngine to initialize
      */
-    @SuppressWarnings("hiding")
     public void initBuiltinObjects(final ScriptEngine engine) {
         if (this.builtinObject != null) {
             // already initialized, just return
@@ -1718,7 +1717,6 @@
         return func;
     }
 
-    @SuppressWarnings("hiding")
     private void init(final ScriptEngine engine) {
         assert Context.getGlobal() == this : "this global is not set as current";
 
--- a/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeError.java	Tue Oct 21 14:24:16 2014 +0100
+++ b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeError.java	Mon Oct 27 11:16:19 2014 +0100
@@ -27,7 +27,6 @@
 
 import static jdk.nashorn.internal.lookup.Lookup.MH;
 import static jdk.nashorn.internal.runtime.ScriptRuntime.UNDEFINED;
-
 import java.lang.invoke.MethodHandle;
 import java.lang.invoke.MethodHandles;
 import jdk.nashorn.api.scripting.NashornException;
@@ -131,7 +130,6 @@
 
     // This is called NativeError, NativeTypeError etc. to
     // associate a ECMAException with the ECMA Error object.
-    @SuppressWarnings("unused")
     static void initException(final ScriptObject self) {
         // ECMAException constructor has side effects
         new ECMAException(self, null);
--- a/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeFloat32Array.java	Tue Oct 21 14:24:16 2014 +0100
+++ b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeFloat32Array.java	Mon Oct 27 11:16:19 2014 +0100
@@ -26,6 +26,7 @@
 package jdk.nashorn.internal.objects;
 
 import static jdk.nashorn.internal.codegen.CompilerConstants.specialCall;
+
 import java.lang.invoke.MethodHandle;
 import java.lang.invoke.MethodHandles;
 import java.nio.ByteBuffer;
@@ -141,6 +142,11 @@
         }
 
         @Override
+        public double getDoubleOptimistic(final int index, final int programPoint) {
+            return getElem(index);
+        }
+
+        @Override
         public Object getObject(final int index) {
             return getDouble(index);
         }
--- a/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeFloat64Array.java	Tue Oct 21 14:24:16 2014 +0100
+++ b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeFloat64Array.java	Mon Oct 27 11:16:19 2014 +0100
@@ -26,6 +26,7 @@
 package jdk.nashorn.internal.objects;
 
 import static jdk.nashorn.internal.codegen.CompilerConstants.specialCall;
+
 import java.lang.invoke.MethodHandle;
 import java.lang.invoke.MethodHandles;
 import java.nio.ByteBuffer;
@@ -141,6 +142,11 @@
         }
 
         @Override
+        public double getDoubleOptimistic(final int index, final int programPoint) {
+            return getElem(index);
+        }
+
+        @Override
         public Object getObject(final int index) {
             return getDouble(index);
         }
--- a/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeInt16Array.java	Tue Oct 21 14:24:16 2014 +0100
+++ b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeInt16Array.java	Mon Oct 27 11:16:19 2014 +0100
@@ -26,6 +26,7 @@
 package jdk.nashorn.internal.objects;
 
 import static jdk.nashorn.internal.codegen.CompilerConstants.specialCall;
+
 import java.lang.invoke.MethodHandle;
 import java.lang.invoke.MethodHandles;
 import java.nio.ByteBuffer;
@@ -124,16 +125,31 @@
         }
 
         @Override
+        public int getIntOptimistic(final int index, final int programPoint) {
+            return getElem(index);
+        }
+
+        @Override
         public long getLong(final int index) {
             return getInt(index);
         }
 
         @Override
+        public long getLongOptimistic(final int index, final int programPoint) {
+            return getElem(index);
+        }
+
+        @Override
         public double getDouble(final int index) {
             return getInt(index);
         }
 
         @Override
+        public double getDoubleOptimistic(final int index, final int programPoint) {
+            return getElem(index);
+        }
+
+        @Override
         public Object getObject(final int index) {
             return getInt(index);
         }
--- a/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeInt32Array.java	Tue Oct 21 14:24:16 2014 +0100
+++ b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeInt32Array.java	Mon Oct 27 11:16:19 2014 +0100
@@ -26,6 +26,7 @@
 package jdk.nashorn.internal.objects;
 
 import static jdk.nashorn.internal.codegen.CompilerConstants.specialCall;
+
 import java.lang.invoke.MethodHandle;
 import java.lang.invoke.MethodHandles;
 import java.nio.ByteBuffer;
@@ -122,16 +123,31 @@
         }
 
         @Override
+        public int getIntOptimistic(final int index, final int programPoint) {
+            return getElem(index);
+        }
+
+        @Override
         public long getLong(final int index) {
             return getInt(index);
         }
 
         @Override
+        public long getLongOptimistic(final int index, final int programPoint) {
+            return getElem(index);
+        }
+
+        @Override
         public double getDouble(final int index) {
             return getInt(index);
         }
 
         @Override
+        public double getDoubleOptimistic(final int index, final int programPoint) {
+            return getElem(index);
+        }
+
+        @Override
         public Object getObject(final int index) {
             return getInt(index);
         }
--- a/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeInt8Array.java	Tue Oct 21 14:24:16 2014 +0100
+++ b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeInt8Array.java	Mon Oct 27 11:16:19 2014 +0100
@@ -26,6 +26,7 @@
 package jdk.nashorn.internal.objects;
 
 import static jdk.nashorn.internal.codegen.CompilerConstants.specialCall;
+
 import java.lang.invoke.MethodHandle;
 import java.lang.invoke.MethodHandles;
 import java.nio.ByteBuffer;
@@ -122,16 +123,31 @@
         }
 
         @Override
+        public int getIntOptimistic(final int index, final int programPoint) {
+            return getElem(index);
+        }
+
+        @Override
         public long getLong(final int index) {
             return getInt(index);
         }
 
         @Override
+        public long getLongOptimistic(final int index, final int programPoint) {
+            return getElem(index);
+        }
+
+        @Override
         public double getDouble(final int index) {
             return getInt(index);
         }
 
         @Override
+        public double getDoubleOptimistic(final int index, final int programPoint) {
+            return getElem(index);
+        }
+
+        @Override
         public Object getObject(final int index) {
             return getInt(index);
         }
--- a/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeJava.java	Tue Oct 21 14:24:16 2014 +0100
+++ b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeJava.java	Mon Oct 27 11:16:19 2014 +0100
@@ -27,7 +27,6 @@
 
 import static jdk.nashorn.internal.runtime.ECMAErrors.typeError;
 import static jdk.nashorn.internal.runtime.ScriptRuntime.UNDEFINED;
-
 import java.lang.invoke.MethodHandles;
 import java.lang.reflect.Array;
 import java.util.Collection;
@@ -36,7 +35,6 @@
 import jdk.internal.dynalink.beans.StaticClass;
 import jdk.internal.dynalink.support.TypeUtilities;
 import jdk.nashorn.api.scripting.JSObject;
-import jdk.nashorn.api.scripting.ScriptUtils;
 import jdk.nashorn.internal.objects.annotations.Attribute;
 import jdk.nashorn.internal.objects.annotations.Function;
 import jdk.nashorn.internal.objects.annotations.ScriptClass;
@@ -90,7 +88,11 @@
      */
     @Function(name="synchronized", attributes = Attribute.NOT_ENUMERABLE, where = Where.CONSTRUCTOR)
     public static Object synchronizedFunc(final Object self, final Object func, final Object obj) {
-        return ScriptUtils.makeSynchronizedFunction(func, obj);
+        if (func instanceof ScriptFunction) {
+            return ((ScriptFunction)func).makeSynchronizedFunction(obj);
+        }
+
+        throw typeError("not.a.function", ScriptRuntime.safeToString(func));
     }
 
     /**
--- a/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeJavaImporter.java	Tue Oct 21 14:24:16 2014 +0100
+++ b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeJavaImporter.java	Mon Oct 27 11:16:19 2014 +0100
@@ -25,6 +25,7 @@
 
 package jdk.nashorn.internal.objects;
 
+import static jdk.nashorn.internal.runtime.ECMAErrors.typeError;
 import static jdk.nashorn.internal.runtime.UnwarrantedOptimismException.isValid;
 
 import jdk.internal.dynalink.CallSiteDescriptor;
@@ -36,9 +37,11 @@
 import jdk.nashorn.internal.objects.annotations.Function;
 import jdk.nashorn.internal.objects.annotations.ScriptClass;
 import jdk.nashorn.internal.runtime.Context;
+import jdk.nashorn.internal.runtime.JSType;
 import jdk.nashorn.internal.runtime.NativeJavaPackage;
 import jdk.nashorn.internal.runtime.PropertyMap;
 import jdk.nashorn.internal.runtime.ScriptObject;
+import jdk.nashorn.internal.runtime.ScriptRuntime;
 import jdk.nashorn.internal.runtime.UnwarrantedOptimismException;
 
 /**
@@ -94,33 +97,30 @@
     }
 
     /**
-     * "No such property" call placeholder.
-     *
-     * This can never be called as we override {@link ScriptObject#noSuchProperty}. We do declare it here as it's a signal
-     * to {@link jdk.nashorn.internal.runtime.WithObject} that it's worth trying doing a {@code noSuchProperty} on this object.
+     * "No such property" handler.
      *
      * @param self self reference
      * @param name property name
-     * @return never returns
+     * @return value of the missing property
      */
     @Function(attributes = Attribute.NOT_ENUMERABLE)
     public static Object __noSuchProperty__(final Object self, final Object name) {
-        throw new AssertionError("__noSuchProperty__ placeholder called");
+        if (! (self instanceof NativeJavaImporter)) {
+            throw typeError("not.a.java.importer", ScriptRuntime.safeToString(self));
+        }
+        return ((NativeJavaImporter)self).createProperty(JSType.toString(name));
     }
 
     /**
-     * "No such method call" placeholder
-     *
-     * This can never be called as we override {@link ScriptObject#noSuchMethod}. We do declare it here as it's a signal
-     * to {@link jdk.nashorn.internal.runtime.WithObject} that it's worth trying doing a noSuchProperty on this object.
+     * "No such method call" handler
      *
      * @param self self reference
      * @param args arguments to method
-     * @return never returns
+     * @return never returns always throw TypeError
      */
     @Function(attributes = Attribute.NOT_ENUMERABLE)
     public static Object __noSuchMethod__(final Object self, final Object... args) {
-        throw new AssertionError("__noSuchMethod__ placeholder called");
+       throw typeError("not.a.function", ScriptRuntime.safeToString(args[0]));
     }
 
     @Override
--- a/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeUint16Array.java	Tue Oct 21 14:24:16 2014 +0100
+++ b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeUint16Array.java	Mon Oct 27 11:16:19 2014 +0100
@@ -26,6 +26,7 @@
 package jdk.nashorn.internal.objects;
 
 import static jdk.nashorn.internal.codegen.CompilerConstants.specialCall;
+
 import java.lang.invoke.MethodHandle;
 import java.lang.invoke.MethodHandles;
 import java.nio.ByteBuffer;
@@ -128,16 +129,31 @@
         }
 
         @Override
+        public int getIntOptimistic(final int index, final int programPoint) {
+            return getElem(index);
+        }
+
+        @Override
         public long getLong(final int index) {
             return getInt(index);
         }
 
         @Override
+        public long getLongOptimistic(final int index, final int programPoint) {
+            return getElem(index);
+        }
+
+        @Override
         public double getDouble(final int index) {
             return getInt(index);
         }
 
         @Override
+        public double getDoubleOptimistic(final int index, final int programPoint) {
+            return getElem(index);
+        }
+
+        @Override
         public Object getObject(final int index) {
             return getInt(index);
         }
--- a/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeUint32Array.java	Tue Oct 21 14:24:16 2014 +0100
+++ b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeUint32Array.java	Mon Oct 27 11:16:19 2014 +0100
@@ -26,6 +26,7 @@
 package jdk.nashorn.internal.objects;
 
 import static jdk.nashorn.internal.codegen.CompilerConstants.specialCall;
+
 import java.lang.invoke.MethodHandle;
 import java.lang.invoke.MethodHandles;
 import java.nio.ByteBuffer;
@@ -128,7 +129,7 @@
 
         @Override
         public Class<?> getElementType() {
-            return int.class;
+            return long.class;
         }
 
         @Override
@@ -142,11 +143,21 @@
         }
 
         @Override
+        public long getLongOptimistic(final int index, final int programPoint) {
+            return getElem(index);
+        }
+
+        @Override
         public double getDouble(final int index) {
             return getLong(index);
         }
 
         @Override
+        public double getDoubleOptimistic(final int index, final int programPoint) {
+            return getLong(index);
+        }
+
+        @Override
         public Object getObject(final int index) {
             return getLong(index);
         }
--- a/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeUint8Array.java	Tue Oct 21 14:24:16 2014 +0100
+++ b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeUint8Array.java	Mon Oct 27 11:16:19 2014 +0100
@@ -26,6 +26,7 @@
 package jdk.nashorn.internal.objects;
 
 import static jdk.nashorn.internal.codegen.CompilerConstants.specialCall;
+
 import java.lang.invoke.MethodHandle;
 import java.lang.invoke.MethodHandles;
 import java.nio.ByteBuffer;
@@ -128,16 +129,31 @@
         }
 
         @Override
+        public int getIntOptimistic(final int index, final int programPoint) {
+            return getElem(index);
+        }
+
+        @Override
         public long getLong(final int index) {
             return getInt(index);
         }
 
         @Override
+        public long getLongOptimistic(final int index, final int programPoint) {
+            return getElem(index);
+        }
+
+        @Override
         public double getDouble(final int index) {
             return getInt(index);
         }
 
         @Override
+        public double getDoubleOptimistic(final int index, final int programPoint) {
+            return getElem(index);
+        }
+
+        @Override
         public Object getObject(final int index) {
             return getInt(index);
         }
--- a/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeUint8ClampedArray.java	Tue Oct 21 14:24:16 2014 +0100
+++ b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeUint8ClampedArray.java	Mon Oct 27 11:16:19 2014 +0100
@@ -28,6 +28,7 @@
 import static jdk.nashorn.internal.codegen.CompilerConstants.specialCall;
 import static jdk.nashorn.internal.codegen.CompilerConstants.staticCall;
 import static jdk.nashorn.internal.lookup.Lookup.MH;
+
 import java.lang.invoke.MethodHandle;
 import java.lang.invoke.MethodHandles;
 import java.nio.ByteBuffer;
@@ -158,16 +159,31 @@
         }
 
         @Override
+        public int getIntOptimistic(final int index, final int programPoint) {
+            return getElem(index);
+        }
+
+        @Override
         public long getLong(final int index) {
             return getInt(index);
         }
 
         @Override
+        public long getLongOptimistic(final int index, final int programPoint) {
+            return getElem(index);
+        }
+
+        @Override
         public double getDouble(final int index) {
             return getInt(index);
         }
 
         @Override
+        public double getDoubleOptimistic(final int index, final int programPoint) {
+            return getElem(index);
+        }
+
+        @Override
         public Object getObject(final int index) {
             return getInt(index);
         }
--- a/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/parser/Parser.java	Tue Oct 21 14:24:16 2014 +0100
+++ b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/parser/Parser.java	Mon Oct 27 11:16:19 2014 +0100
@@ -53,7 +53,6 @@
 import static jdk.nashorn.internal.parser.TokenType.SEMICOLON;
 import static jdk.nashorn.internal.parser.TokenType.TERNARY;
 import static jdk.nashorn.internal.parser.TokenType.WHILE;
-
 import java.io.Serializable;
 import java.util.ArrayDeque;
 import java.util.ArrayList;
@@ -71,10 +70,8 @@
 import jdk.nashorn.internal.ir.BaseNode;
 import jdk.nashorn.internal.ir.BinaryNode;
 import jdk.nashorn.internal.ir.Block;
-import jdk.nashorn.internal.ir.BlockLexicalContext;
 import jdk.nashorn.internal.ir.BlockStatement;
 import jdk.nashorn.internal.ir.BreakNode;
-import jdk.nashorn.internal.ir.BreakableNode;
 import jdk.nashorn.internal.ir.CallNode;
 import jdk.nashorn.internal.ir.CaseNode;
 import jdk.nashorn.internal.ir.CatchNode;
@@ -90,9 +87,7 @@
 import jdk.nashorn.internal.ir.IndexNode;
 import jdk.nashorn.internal.ir.JoinPredecessorExpression;
 import jdk.nashorn.internal.ir.LabelNode;
-import jdk.nashorn.internal.ir.LexicalContext;
 import jdk.nashorn.internal.ir.LiteralNode;
-import jdk.nashorn.internal.ir.LoopNode;
 import jdk.nashorn.internal.ir.Node;
 import jdk.nashorn.internal.ir.ObjectNode;
 import jdk.nashorn.internal.ir.PropertyKey;
@@ -138,8 +133,8 @@
 
     private List<Statement> functionDeclarations;
 
-    private final BlockLexicalContext lc = new BlockLexicalContext();
-    private final Deque<Object> defaultNames = new ArrayDeque<>();
+    private final ParserContext lc;
+    private final Deque<Object> defaultNames;
 
     /** Namespace for function names where not explicitly given */
     private final Namespace namespace;
@@ -187,6 +182,8 @@
      */
     public Parser(final ScriptEnvironment env, final Source source, final ErrorManager errors, final boolean strict, final int lineOffset, final DebugLogger log) {
         super(source, errors, strict, lineOffset);
+        this.lc = new ParserContext();
+        this.defaultNames = new ArrayDeque<>();
         this.env = env;
         this.namespace = new Namespace(env.getNamespace());
         this.scripting = env._scripting;
@@ -344,26 +341,35 @@
             final long functionToken = Token.toDesc(FUNCTION, 0, source.getLength());
             // Set up the function to append elements.
 
-            FunctionNode function = newFunctionNode(
-                functionToken,
-                new IdentNode(functionToken, Token.descPosition(functionToken), PROGRAM.symbolName()),
-                new ArrayList<IdentNode>(),
-                FunctionNode.Kind.NORMAL,
-                functionLine);
+            final IdentNode ident = new IdentNode(functionToken, Token.descPosition(functionToken), PROGRAM.symbolName());
+            final ParserContextFunctionNode function = createParserContextFunctionNode(ident, functionToken, FunctionNode.Kind.NORMAL, functionLine, Collections.<IdentNode>emptyList());
+            lc.push(function);
+
+            final ParserContextBlockNode body = newBlock();
 
             functionDeclarations = new ArrayList<>();
             sourceElements(false);
             addFunctionDeclarations(function);
             functionDeclarations = null;
 
+            restoreBlock(body);
+            body.setFlag(Block.NEEDS_SCOPE);
+
+            final Block functionBody = new Block(functionToken, source.getLength() - 1, body.getFlags(), body.getStatements());
+            lc.pop(function);
+
             expect(EOF);
 
-            function.setFinish(source.getLength() - 1);
-            function = restoreFunctionNode(function, token); //commit code
-            function = function.setBody(lc, function.getBody().setNeedsScope(lc));
-
-            printAST(function);
-            return function;
+            final FunctionNode functionNode = createFunctionNode(
+                    function,
+                    functionToken,
+                    ident,
+                    Collections.<IdentNode>emptyList(),
+                    FunctionNode.Kind.NORMAL,
+                    functionLine,
+                    functionBody);
+            printAST(functionNode);
+            return functionNode;
         } catch (final Exception e) {
             handleParseException(e);
             return null;
@@ -444,21 +450,15 @@
      *
      * @return New block.
      */
-    private Block newBlock() {
-        return lc.push(new Block(token, Token.descPosition(token)));
+    private ParserContextBlockNode newBlock() {
+        return lc.push(new ParserContextBlockNode(token));
     }
 
-    /**
-     * Set up a new function block.
-     *
-     * @param ident Name of function.
-     * @return New block.
-     */
-    private FunctionNode newFunctionNode(final long startToken, final IdentNode ident, final List<IdentNode> parameters, final FunctionNode.Kind kind, final int functionLine) {
+    private ParserContextFunctionNode createParserContextFunctionNode(final IdentNode ident, final long functionToken, final FunctionNode.Kind kind, final int functionLine, final List<IdentNode> parameters) {
         // Build function name.
         final StringBuilder sb = new StringBuilder();
 
-        final FunctionNode parentFunction = lc.getCurrentFunction();
+        final ParserContextFunctionNode parentFunction = lc.getCurrentFunction();
         if (parentFunction != null && !parentFunction.isProgram()) {
             sb.append(parentFunction.getName()).append('$');
         }
@@ -477,25 +477,33 @@
             flags |= FunctionNode.IS_PROGRAM;
         }
 
+        final ParserContextFunctionNode functionNode = new ParserContextFunctionNode(functionToken, ident, name, namespace, functionLine, kind, parameters);
+        functionNode.setFlag(flags);
+        return functionNode;
+    }
+
+    private FunctionNode createFunctionNode(final ParserContextFunctionNode function, final long startToken, final IdentNode ident, final List<IdentNode> parameters, final FunctionNode.Kind kind, final int functionLine, final Block body){
+        final CompilationState state = errors.hasErrors() ? CompilationState.PARSE_ERROR : CompilationState.PARSED;
         // Start new block.
         final FunctionNode functionNode =
             new FunctionNode(
                 source,
                 functionLine,
-                token,
-                Token.descPosition(token),
+                body.getToken(),
+                Token.descPosition(body.getToken()),
                 startToken,
+                function.getLastToken(),
                 namespace,
                 ident,
-                name,
+                function.getName(),
                 parameters,
                 kind,
-                flags);
-
-        lc.push(functionNode);
-        // Create new block, and just put it on the context stack, restoreFunctionNode() will associate it with the
-        // FunctionNode.
-        newBlock();
+                function.getFlags(),
+                body,
+                state,
+                function.getEndParserState());
+
+        printAST(functionNode);
 
         return functionNode;
     }
@@ -503,27 +511,17 @@
     /**
      * Restore the current block.
      */
-    private Block restoreBlock(final Block block) {
+    private ParserContextBlockNode restoreBlock(final ParserContextBlockNode block) {
         return lc.pop(block);
     }
 
-
-    private FunctionNode restoreFunctionNode(final FunctionNode functionNode, final long lastToken) {
-        final Block newBody = restoreBlock(lc.getFunctionBody(functionNode));
-
-        return lc.pop(functionNode).
-            setBody(lc, newBody).
-            setLastToken(lc, lastToken).
-            setState(lc, errors.hasErrors() ? CompilationState.PARSE_ERROR : CompilationState.PARSED);
-    }
-
     /**
      * Get the statements in a block.
      * @return Block statements.
      */
     private Block getBlock(final boolean needsBraces) {
-        // Set up new block. Captures LBRACE.
-        Block newBlock = newBlock();
+        final long blockToken = token;
+        final ParserContextBlockNode newBlock = newBlock();
         try {
             // Block opening brace.
             if (needsBraces) {
@@ -533,21 +531,18 @@
             statementList();
 
         } finally {
-            newBlock = restoreBlock(newBlock);
+            restoreBlock(newBlock);
         }
 
-        final int possibleEnd = Token.descPosition(token) + Token.descLength(token);
-
         // Block closing brace.
         if (needsBraces) {
             expect(RBRACE);
         }
 
-        newBlock.setFinish(possibleEnd);
-
-        return newBlock;
+        return new Block(blockToken, finish, newBlock.getFlags(), newBlock.getStatements());
     }
 
+
     /**
      * Get all the statements generated by a single statement.
      * @return Statements.
@@ -557,13 +552,13 @@
             return getBlock(true);
         }
         // Set up new block. Captures first token.
-        Block newBlock = newBlock();
+        final ParserContextBlockNode newBlock = newBlock();
         try {
             statement();
         } finally {
-            newBlock = restoreBlock(newBlock);
+            restoreBlock(newBlock);
         }
-        return newBlock;
+        return new Block(newBlock.getToken(), finish, newBlock.getFlags(), newBlock.getStatements());
     }
 
     /**
@@ -584,7 +579,7 @@
      */
     private void detectSpecialProperty(final IdentNode ident) {
         if (isArguments(ident)) {
-            lc.setFlag(lc.getCurrentFunction(), FunctionNode.USES_ARGUMENTS);
+            lc.getCurrentFunction().setFlag(FunctionNode.USES_ARGUMENTS);
         }
     }
 
@@ -698,18 +693,19 @@
         // Make a pseudo-token for the script holding its start and length.
         final long functionToken = Token.toDesc(FUNCTION, Token.descPosition(Token.withDelimiter(token)), source.getLength());
         final int  functionLine  = line;
-        // Set up the script to append elements.
-
-        FunctionNode script = newFunctionNode(
-            functionToken,
-            new IdentNode(functionToken, Token.descPosition(functionToken), scriptName),
-            new ArrayList<IdentNode>(),
-            FunctionNode.Kind.SCRIPT,
-            functionLine);
-
+
+        final IdentNode ident = new IdentNode(functionToken, Token.descPosition(functionToken), scriptName);
+        final ParserContextFunctionNode script = createParserContextFunctionNode(
+                ident,
+                functionToken,
+                FunctionNode.Kind.SCRIPT,
+                functionLine,
+                Collections.<IdentNode>emptyList());
+        lc.push(script);
+        final ParserContextBlockNode body = newBlock();
         // If ES6 block scope is enabled add a per-script block for top-level LET and CONST declarations.
         final int startLine = start;
-        Block outer = useBlockScope() ? newBlock() : null;
+        final ParserContextBlockNode outer = useBlockScope() ? newBlock() : null;
         functionDeclarations = new ArrayList<>();
 
         try {
@@ -717,20 +713,25 @@
             addFunctionDeclarations(script);
         } finally {
             if (outer != null) {
-                outer = restoreBlock(outer);
-                appendStatement(new BlockStatement(startLine, outer));
+                restoreBlock(outer);
+                appendStatement(new BlockStatement(
+                        startLine,
+                        new Block(
+                                functionToken,
+                                startLine, outer.getFlags(),
+                                outer.getStatements())));
             }
         }
         functionDeclarations = null;
+        restoreBlock(body);
+        body.setFlag(Block.NEEDS_SCOPE);
+        final Block programBody = new Block(functionToken, functionLine, body.getFlags(), body.getStatements());
+        lc.pop(script);
+        script.setLastToken(token);
 
         expect(EOF);
 
-        script.setFinish(source.getLength() - 1);
-
-        script = restoreFunctionNode(script, token); //commit code
-        script = script.setBody(lc, script.getBody().setNeedsScope(lc));
-
-        return script;
+        return createFunctionNode(script, functionToken, ident, Collections.<IdentNode>emptyList(), FunctionNode.Kind.SCRIPT, functionLine, programBody);
     }
 
     /**
@@ -789,7 +790,7 @@
                     // check for directive prologues
                     if (checkDirective) {
                         // skip any debug statement like line number to get actual first line
-                        final Node lastStatement = lc.getLastStatement();
+                        final Statement lastStatement = lc.getLastStatement();
 
                         // get directive prologue, if any
                         final String directive = getDirective(lastStatement);
@@ -809,8 +810,8 @@
                             // handle use strict directive
                             if ("use strict".equals(directive)) {
                                 isStrictMode = true;
-                                final FunctionNode function = lc.getCurrentFunction();
-                                lc.setFlag(lc.getCurrentFunction(), FunctionNode.IS_STRICT);
+                                final ParserContextFunctionNode function = lc.getCurrentFunction();
+                                function.setFlag(FunctionNode.IS_STRICT);
 
                                 // We don't need to check these, if lexical environment is already strict
                                 if (!oldStrictMode && directiveStmts != null) {
@@ -831,8 +832,8 @@
                             } else if (Context.DEBUG) {
                                 final int flag = FunctionNode.getDirectiveFlag(directive);
                                 if (flag != 0) {
-                                    final FunctionNode function = lc.getCurrentFunction();
-                                    lc.setFlag(function, flag);
+                                    final ParserContextFunctionNode function = lc.getCurrentFunction();
+                                    function.setFlag(flag);
                                 }
                             }
                         }
@@ -1114,11 +1115,7 @@
 
         // If is a statement then handle end of line.
         if (isStatement) {
-            final boolean semicolon = type == SEMICOLON;
             endOfLine();
-            if (semicolon) {
-                lc.getCurrentBlock().setFinish(finish);
-            }
         }
 
         return vars;
@@ -1166,11 +1163,6 @@
         }
 
         endOfLine();
-
-        if (expressionStatement != null) {
-            expressionStatement.setFinish(finish);
-            lc.getCurrentBlock().setFinish(finish);
-        }
     }
 
     /**
@@ -1216,13 +1208,23 @@
      * Parse a FOR statement.
      */
     private void forStatement() {
+        final long forToken = token;
+        final int forLine = line;
         // When ES6 for-let is enabled we create a container block to capture the LET.
         final int startLine = start;
-        Block outer = useBlockScope() ? newBlock() : null;
+        final ParserContextBlockNode outer = useBlockScope() ? newBlock() : null;
+
 
         // Create FOR node, capturing FOR token.
-        ForNode forNode = new ForNode(line, token, Token.descPosition(token), null, ForNode.IS_FOR);
+        final ParserContextLoopNode forNode = new ParserContextLoopNode();
         lc.push(forNode);
+        Block body = null;
+        List<VarNode> vars = null;
+        Expression init = null;
+        JoinPredecessorExpression test = null;
+        JoinPredecessorExpression modify = null;
+
+        int flags = 0;
 
         try {
             // FOR tested in caller.
@@ -1231,13 +1233,12 @@
             // Nashorn extension: for each expression.
             // iterate property values rather than property names.
             if (!env._no_syntax_extensions && type == IDENT && "each".equals(getValue())) {
-                forNode = forNode.setIsForEach(lc);
+                flags |= ForNode.IS_FOR_EACH;
                 next();
             }
 
             expect(LPAREN);
 
-            List<VarNode> vars = null;
 
             switch (type) {
             case VAR:
@@ -1258,8 +1259,7 @@
                     break;
                 }
 
-                final Expression expression = expression(unaryExpression(), COMMARIGHT.getPrecedence(), true);
-                forNode = forNode.setInit(lc, expression);
+                init = expression(unaryExpression(), COMMARIGHT.getPrecedence(), true);
                 break;
             }
 
@@ -1268,26 +1268,27 @@
                 // for (init; test; modify)
 
                 // for each (init; test; modify) is invalid
-                if (forNode.isForEach()) {
+                if ((flags & ForNode.IS_FOR_EACH) != 0) {
                     throw error(AbstractParser.message("for.each.without.in"), token);
                 }
 
                 expect(SEMICOLON);
                 if (type != SEMICOLON) {
-                    forNode = forNode.setTest(lc, joinPredecessorExpression());
+                    test = joinPredecessorExpression();
                 }
                 expect(SEMICOLON);
                 if (type != RPAREN) {
-                    forNode = forNode.setModify(lc, joinPredecessorExpression());
+                    modify = joinPredecessorExpression();
                 }
                 break;
 
             case IN:
-                forNode = forNode.setIsForIn(lc).setTest(lc, new JoinPredecessorExpression());
+                flags |= ForNode.IS_FOR_IN;
+                test = new JoinPredecessorExpression();
                 if (vars != null) {
                     // for (var i in obj)
                     if (vars.size() == 1) {
-                        forNode = forNode.setInit(lc, new IdentNode(vars.get(0).getName()));
+                        init = new IdentNode(vars.get(0).getName());
                     } else {
                         // for (var i, j in obj) is invalid
                         throw error(AbstractParser.message("many.vars.in.for.in.loop"), vars.get(1).getToken());
@@ -1295,7 +1296,6 @@
 
                 } else {
                     // for (expr in obj)
-                    final Node init = forNode.getInit();
                     assert init != null : "for..in init expression can not be null here";
 
                     // check if initial expression is a valid L-value
@@ -1316,7 +1316,7 @@
                 next();
 
                 // Get the collection expression.
-                forNode = forNode.setModify(lc, joinPredecessorExpression());
+                modify = joinPredecessorExpression();
                 break;
 
             default:
@@ -1327,38 +1327,28 @@
             expect(RPAREN);
 
             // Set the for body.
-            final Block body = getStatement();
-            forNode = forNode.setBody(lc, body);
-            forNode.setFinish(body.getFinish());
-
-            appendStatement(forNode);
+            body = getStatement();
         } finally {
             lc.pop(forNode);
+            if (vars != null) {
+                for (final VarNode var : vars) {
+                    appendStatement(var);
+                }
+            }
+            if (body != null) {
+                appendStatement(new ForNode(forLine, forToken, body.getFinish(), body, (forNode.getFlags() | flags), init, test, modify));
+            }
             if (outer != null) {
-                outer.setFinish(forNode.getFinish());
-                outer = restoreBlock(outer);
-                appendStatement(new BlockStatement(startLine, outer));
+                restoreBlock(outer);
+                appendStatement(new BlockStatement(startLine, new Block(
+                        outer.getToken(),
+                        body.getFinish(),
+                        outer.getStatements())));
             }
         }
     }
 
     /**
-     * ... IterationStatement :
-     *           ...
-     *           Expression[NoIn]?; Expression? ; Expression?
-     *           var VariableDeclarationList[NoIn]; Expression? ; Expression?
-     *           LeftHandSideExpression in Expression
-     *           var VariableDeclaration[NoIn] in Expression
-     *
-     * See 12.6
-     *
-     * Parse the control section of a FOR statement.  Also used for
-     * comprehensions.
-     * @param forNode Owning FOR.
-     */
-
-
-    /**
      * ...IterationStatement :
      *           ...
      *           while ( Expression ) Statement
@@ -1371,25 +1361,26 @@
     private void whileStatement() {
         // Capture WHILE token.
         final long whileToken = token;
+        final int whileLine = line;
         // WHILE tested in caller.
         next();
 
-        // Construct WHILE node.
-        WhileNode whileNode = new WhileNode(line, whileToken, Token.descPosition(whileToken), false);
+        final ParserContextLoopNode whileNode = new ParserContextLoopNode();
         lc.push(whileNode);
 
+        JoinPredecessorExpression test = null;
+        Block body = null;
+
         try {
             expect(LPAREN);
-            final int whileLine = line;
-            final JoinPredecessorExpression test = joinPredecessorExpression();
+            test = joinPredecessorExpression();
             expect(RPAREN);
-            final Block body = getStatement();
-            appendStatement(whileNode =
-                new WhileNode(whileLine, whileToken, finish, false).
-                    setTest(lc, test).
-                    setBody(lc, body));
+            body = getStatement();
         } finally {
             lc.pop(whileNode);
+            if (body != null){
+              appendStatement(new WhileNode(whileLine, whileToken, body.getFinish(), false, test, body));
+            }
         }
     }
 
@@ -1406,34 +1397,32 @@
     private void doStatement() {
         // Capture DO token.
         final long doToken = token;
+        int doLine = 0;
         // DO tested in the caller.
         next();
 
-        WhileNode doWhileNode = new WhileNode(-1, doToken, Token.descPosition(doToken), true);
+        final ParserContextLoopNode doWhileNode = new ParserContextLoopNode();
         lc.push(doWhileNode);
 
+        Block body = null;
+        JoinPredecessorExpression test = null;
+
         try {
            // Get DO body.
-            final Block body = getStatement();
+            body = getStatement();
 
             expect(WHILE);
             expect(LPAREN);
-            final int doLine = line;
-            final JoinPredecessorExpression test = joinPredecessorExpression();
+            doLine = line;
+            test = joinPredecessorExpression();
             expect(RPAREN);
 
             if (type == SEMICOLON) {
                 endOfLine();
             }
-            doWhileNode.setFinish(finish);
-
-            //line number is last
-            appendStatement(doWhileNode =
-                new WhileNode(doLine, doToken, finish, true).
-                    setBody(lc, body).
-                    setTest(lc, test));
         } finally {
             lc.pop(doWhileNode);
+            appendStatement(new WhileNode(doLine, doToken, finish, true, test, body));
         }
     }
 
@@ -1452,7 +1441,7 @@
         // CONTINUE tested in caller.
         nextOrEOL();
 
-        LabelNode labelNode = null;
+        ParserContextLabelNode labelNode = null;
 
         // SEMICOLON or label.
         switch (type) {
@@ -1474,7 +1463,7 @@
         }
 
         final String labelName = labelNode == null ? null : labelNode.getLabelName();
-        final LoopNode targetNode = lc.getContinueTo(labelName);
+        final ParserContextLoopNode targetNode = lc.getContinueTo(labelName);
 
         if (targetNode == null) {
             throw error(AbstractParser.message("illegal.continue.stmt"), continueToken);
@@ -1500,7 +1489,7 @@
         // BREAK tested in caller.
         nextOrEOL();
 
-        LabelNode labelNode = null;
+        ParserContextLabelNode labelNode = null;
 
         // SEMICOLON or label.
         switch (type) {
@@ -1524,7 +1513,7 @@
         //either an explicit label - then get its node or just a "break" - get first breakable
         //targetNode is what we are breaking out from.
         final String labelName = labelNode == null ? null : labelNode.getLabelName();
-        final BreakableNode targetNode = lc.getBreakable(labelName);
+        final ParserContextBreakableNode targetNode = lc.getBreakable(labelName);
         if (targetNode == null) {
             throw error(AbstractParser.message("illegal.break.stmt"), breakToken);
         }
@@ -1632,20 +1621,17 @@
             throw error(AbstractParser.message("strict.no.with"), withToken);
         }
 
-        // Get WITH expression.
-        WithNode withNode = new WithNode(withLine, withToken, finish);
-
+        Expression expression = null;
+        Block body = null;
         try {
-            lc.push(withNode);
             expect(LPAREN);
-            withNode = withNode.setExpression(lc, expression());
+            expression = expression();
             expect(RPAREN);
-            withNode = withNode.setBody(lc, getStatement());
+            body = getStatement();
         } finally {
-            lc.pop(withNode);
+            appendStatement(new WithNode(withLine, withToken, finish, expression, body));
         }
 
-        appendStatement(withNode);
     }
 
     /**
@@ -1677,19 +1663,22 @@
         next();
 
         // Create and add switch statement.
-        SwitchNode switchNode = new SwitchNode(switchLine, switchToken, Token.descPosition(switchToken), null, new ArrayList<CaseNode>(), null);
+        final ParserContextSwitchNode switchNode= new ParserContextSwitchNode();
         lc.push(switchNode);
 
+        CaseNode defaultCase = null;
+        // Prepare to accumulate cases.
+        final List<CaseNode> cases = new ArrayList<>();
+
+        Expression expression = null;
+
         try {
             expect(LPAREN);
-            switchNode = switchNode.setExpression(lc, expression());
+            expression = expression();
             expect(RPAREN);
 
             expect(LBRACE);
 
-            // Prepare to accumulate cases.
-            final List<CaseNode> cases = new ArrayList<>();
-            CaseNode defaultCase = null;
 
             while (type != RBRACE) {
                 // Prepare for next case.
@@ -1720,7 +1709,6 @@
                 // Get CASE body.
                 final Block statements = getBlock(false);
                 final CaseNode caseNode = new CaseNode(caseToken, finish, caseExpression, statements);
-                statements.setFinish(finish);
 
                 if (caseExpression == null) {
                     defaultCase = caseNode;
@@ -1729,13 +1717,10 @@
                 cases.add(caseNode);
             }
 
-            switchNode = switchNode.setCases(lc, cases, defaultCase);
             next();
-            switchNode.setFinish(finish);
-
-            appendStatement(switchNode);
         } finally {
             lc.pop(switchNode);
+            appendStatement(new SwitchNode(switchLine, switchToken, finish, expression, cases, defaultCase));
         }
     }
 
@@ -1759,15 +1744,17 @@
             throw error(AbstractParser.message("duplicate.label", ident.getName()), labelToken);
         }
 
-        LabelNode labelNode = new LabelNode(line, labelToken, finish, ident.getName(), null);
+        final ParserContextLabelNode labelNode = new ParserContextLabelNode(ident.getName());
+        Block body = null;
         try {
             lc.push(labelNode);
-            labelNode = labelNode.setBody(lc, getStatement());
-            labelNode.setFinish(finish);
-            appendStatement(labelNode);
+            body = getStatement();
         } finally {
-            assert lc.peek() instanceof LabelNode;
+            assert lc.peek() instanceof ParserContextLabelNode;
             lc.pop(labelNode);
+            if (ident != null){
+              appendStatement(new LabelNode(line, labelToken, finish, ident.getName(), body));
+            }
         }
     }
 
@@ -1835,8 +1822,7 @@
 
         // Container block needed to act as target for labeled break statements
         final int startLine = line;
-        Block outer = newBlock();
-
+        final ParserContextBlockNode outer = newBlock();
         // Create try.
 
         try {
@@ -1867,15 +1853,15 @@
 
                 expect(RPAREN);
 
-                Block catchBlock = newBlock();
+                final ParserContextBlockNode catchBlock = newBlock();
                 try {
                     // Get CATCH body.
                     final Block catchBody = getBlock(true);
                     final CatchNode catchNode = new CatchNode(catchLine, catchToken, finish, exception, ifExpression, catchBody, false);
                     appendStatement(catchNode);
                 } finally {
-                    catchBlock = restoreBlock(catchBlock);
-                    catchBlocks.add(catchBlock);
+                    restoreBlock(catchBlock);
+                    catchBlocks.add(new Block(catchBlock.getToken(), finish, catchBlock.getFlags(), catchBlock.getStatements()));
                 }
 
                 // If unconditional catch then should to be the end.
@@ -1897,19 +1883,15 @@
                 throw error(AbstractParser.message("missing.catch.or.finally"), tryToken);
             }
 
-            final TryNode tryNode = new TryNode(tryLine, tryToken, Token.descPosition(tryToken), tryBody, catchBlocks, finallyStatements);
+            final TryNode tryNode = new TryNode(tryLine, tryToken, finish, tryBody, catchBlocks, finallyStatements);
             // Add try.
             assert lc.peek() == outer;
             appendStatement(tryNode);
-
-            tryNode.setFinish(finish);
-            outer.setFinish(finish);
-
         } finally {
-            outer = restoreBlock(outer);
+            restoreBlock(outer);
         }
 
-        appendStatement(new BlockStatement(startLine, outer));
+        appendStatement(new BlockStatement(startLine, new Block(tryToken, finish, outer.getFlags(), outer.getStatements())));
     }
 
     /**
@@ -1927,7 +1909,7 @@
         // DEBUGGER tested in caller.
         next();
         endOfLine();
-        appendStatement(new ExpressionStatement(debuggerLine, debuggerToken, finish, new RuntimeNode(debuggerToken, finish, RuntimeNode.Request.DEBUGGER, new ArrayList<Expression>())));
+        appendStatement(new ExpressionStatement(debuggerLine, debuggerToken, finish, new RuntimeNode(debuggerToken, finish, RuntimeNode.Request.DEBUGGER, Collections.<Expression>emptyList())));
     }
 
     /**
@@ -1954,7 +1936,7 @@
         case THIS:
             final String name = type.getName();
             next();
-            lc.setFlag(lc.getCurrentFunction(), FunctionNode.USES_THIS);
+            lc.getCurrentFunction().setFlag(FunctionNode.USES_THIS);
             return new IdentNode(primaryToken, finish, name);
         case IDENT:
             final IdentNode ident = getIdent();
@@ -2314,9 +2296,24 @@
         final IdentNode getNameNode = createIdentNode(((Node)getIdent).getToken(), finish, NameCodec.encode("get " + getterName));
         expect(LPAREN);
         expect(RPAREN);
-        final FunctionNode functionNode = functionBody(getSetToken, getNameNode, new ArrayList<IdentNode>(), FunctionNode.Kind.GETTER, functionLine);
-
-        return new PropertyFunction(getIdent, functionNode);
+
+        final ParserContextFunctionNode functionNode = createParserContextFunctionNode(getNameNode, getSetToken, FunctionNode.Kind.GETTER, functionLine, Collections.<IdentNode>emptyList());
+        lc.push(functionNode);
+
+        final Block functionBody = functionBody(functionNode);
+
+        lc.pop(functionNode);
+
+        final FunctionNode  function = createFunctionNode(
+                functionNode,
+                getSetToken,
+                getNameNode,
+                Collections.<IdentNode>emptyList(),
+                FunctionNode.Kind.GETTER,
+                functionLine,
+                functionBody);
+
+        return new PropertyFunction(getIdent, function);
     }
 
     private PropertyFunction propertySetterFunction(final long getSetToken, final int functionLine) {
@@ -2338,9 +2335,25 @@
         if (argIdent != null) {
             parameters.add(argIdent);
         }
-        final FunctionNode functionNode = functionBody(getSetToken, setNameNode, parameters, FunctionNode.Kind.SETTER, functionLine);
-
-        return new PropertyFunction(setIdent, functionNode);
+
+
+        final ParserContextFunctionNode functionNode = createParserContextFunctionNode(setNameNode, getSetToken, FunctionNode.Kind.SETTER, functionLine, parameters);
+        lc.push(functionNode);
+
+        final Block functionBody = functionBody(functionNode);
+
+        lc.pop(functionNode);
+
+        final FunctionNode  function = createFunctionNode(
+                functionNode,
+                getSetToken,
+                setNameNode,
+                parameters,
+                FunctionNode.Kind.SETTER,
+                functionLine,
+                functionBody);
+
+        return new PropertyFunction(setIdent, function);
     }
 
     private static class PropertyFunction {
@@ -2655,11 +2668,18 @@
         final List<IdentNode> parameters = formalParameterList();
         expect(RPAREN);
 
-        FunctionNode functionNode = functionBody(functionToken, name, parameters, FunctionNode.Kind.NORMAL, functionLine);
+        final ParserContextFunctionNode functionNode = createParserContextFunctionNode(name, functionToken, FunctionNode.Kind.NORMAL, functionLine, parameters);
+        lc.push(functionNode);
+        Block functionBody = null;
+        try{
+            functionBody = functionBody(functionNode);
+        } finally {
+            lc.pop(functionNode);
+        }
 
         if (isStatement) {
             if (topLevel || useBlockScope()) {
-                functionNode = functionNode.setFlag(lc, FunctionNode.IS_DECLARED);
+                functionNode.setFlag(FunctionNode.IS_DECLARED);
             } else if (isStrictMode) {
                 throw error(JSErrorType.SYNTAX_ERROR, AbstractParser.message("strict.no.func.decl.here"), functionToken);
             } else if (env._function_statement == ScriptEnvironment.FunctionStatementBehavior.ERROR) {
@@ -2668,12 +2688,12 @@
                 warning(JSErrorType.SYNTAX_ERROR, AbstractParser.message("no.func.decl.here.warn"), functionToken);
             }
             if (isArguments(name)) {
-                lc.setFlag(lc.getCurrentFunction(), FunctionNode.DEFINES_ARGUMENTS);
+               lc.getCurrentFunction().setFlag(FunctionNode.DEFINES_ARGUMENTS);
             }
         }
 
         if (isAnonymous) {
-            functionNode = functionNode.setFlag(lc, FunctionNode.IS_ANONYMOUS);
+            functionNode.setFlag(FunctionNode.IS_ANONYMOUS);
         }
 
         final int arity = parameters.size();
@@ -2687,7 +2707,7 @@
                 String parameterName = parameter.getName();
 
                 if (isArguments(parameterName)) {
-                    functionNode = functionNode.setFlag(lc, FunctionNode.DEFINES_ARGUMENTS);
+                    functionNode.setFlag(FunctionNode.DEFINES_ARGUMENTS);
                 }
 
                 if (parametersSet.contains(parameterName)) {
@@ -2705,17 +2725,26 @@
             }
         } else if (arity == 1) {
             if (isArguments(parameters.get(0))) {
-                functionNode = functionNode.setFlag(lc, FunctionNode.DEFINES_ARGUMENTS);
+                functionNode.setFlag(FunctionNode.DEFINES_ARGUMENTS);
             }
         }
 
+        final FunctionNode function = createFunctionNode(
+                functionNode,
+                functionToken,
+                name,
+                parameters,
+                FunctionNode.Kind.NORMAL,
+                functionLine,
+                functionBody);
+
         if (isStatement) {
             int varFlags = VarNode.IS_STATEMENT;
             if (!topLevel && useBlockScope()) {
                 // mark ES6 block functions as lexically scoped
                 varFlags |= VarNode.IS_LET;
             }
-            final VarNode varNode = new VarNode(functionLine, functionToken, finish, name, functionNode, varFlags);
+            final VarNode varNode = new VarNode(functionLine, functionToken, finish, name, function, varFlags);
             if (topLevel) {
                 functionDeclarations.add(varNode);
             } else if (useBlockScope()) {
@@ -2725,7 +2754,7 @@
             }
         }
 
-        return functionNode;
+        return function;
     }
 
     private String getDefaultValidFunctionName(final int functionLine) {
@@ -2832,15 +2861,19 @@
      * Parse function body.
      * @return function node (body.)
      */
-    private FunctionNode functionBody(final long firstToken, final IdentNode ident, final List<IdentNode> parameters, final FunctionNode.Kind kind, final int functionLine) {
-        FunctionNode functionNode = null;
+    private Block functionBody(final ParserContextFunctionNode functionNode) {
         long lastToken = 0L;
+        ParserContextBlockNode body = null;
+        final long bodyToken = token;
+        Block functionBody;
+        int bodyFinish = 0;
+
 
         final boolean parseBody;
         Object endParserState = null;
         try {
             // Create a new function block.
-            functionNode = newFunctionNode(firstToken, ident, parameters, kind, functionLine);
+            body = newBlock();
             assert functionNode != null;
             final int functionId = functionNode.getId();
             parseBody = reparsedFunction == null || functionId <= reparsedFunction.getFunctionNodeId();
@@ -2856,6 +2889,7 @@
                 // just expression as function body
                 final Expression expr = assignmentExpression(true);
                 lastToken = previousToken;
+                functionNode.setLastToken(previousToken);
                 assert lc.getCurrentBlock() == lc.getFunctionBody(functionNode);
                 // EOL uses length field to store the line number
                 final int lastFinish = Token.descPosition(lastToken) + (Token.descType(lastToken) == EOL ? 0 : Token.descLength(lastToken));
@@ -2868,7 +2902,6 @@
                     final ReturnNode returnNode = new ReturnNode(functionNode.getLineNumber(), expr.getToken(), lastFinish, expr);
                     appendStatement(returnNode);
                 }
-                functionNode.setFinish(lastFinish);
             } else {
                 expectDontAdvance(LBRACE);
                 if (parseBody || !skipFunctionBody(functionNode)) {
@@ -2902,25 +2935,25 @@
                         // we'll rather just restart parsing from this well-known, friendly token instead.
                     }
                 }
+                bodyFinish = finish;
+                functionNode.setLastToken(token);
                 expect(RBRACE);
-                functionNode.setFinish(finish);
             }
         } finally {
-            functionNode = restoreFunctionNode(functionNode, lastToken);
+            restoreBlock(body);
         }
 
         // NOTE: we can only do alterations to the function node after restoreFunctionNode.
 
         if (parseBody) {
-            functionNode = functionNode.setEndParserState(lc, endParserState);
-        } else if (functionNode.getBody().getStatementCount() > 0){
+            functionNode.setEndParserState(endParserState);
+        } else if (!body.getStatements().isEmpty()){
             // This is to ensure the body is empty when !parseBody but we couldn't skip parsing it (see
             // skipFunctionBody() for possible reasons). While it is not strictly necessary for correctness to
             // enforce empty bodies in nested functions that were supposed to be skipped, we do assert it as
             // an invariant in few places in the compiler pipeline, so for consistency's sake we'll throw away
             // nested bodies early if we were supposed to skip 'em.
-            functionNode = functionNode.setBody(null, functionNode.getBody().setStatements(null,
-                    Collections.<Statement>emptyList()));
+            body.setStatements(Collections.<Statement>emptyList());
         }
 
         if (reparsedFunction != null) {
@@ -2932,20 +2965,20 @@
             if (data != null) {
                 // Data can be null if when we originally parsed the file, we removed the function declaration
                 // as it was dead code.
-                functionNode = functionNode.setFlags(lc, data.getFunctionFlags());
+                functionNode.setFlag(data.getFunctionFlags());
                 // 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 (functionNode.hasNestedEval()) {
                     assert functionNode.hasScopeBlock();
-                    functionNode = functionNode.setBody(lc, functionNode.getBody().setNeedsScope(null));
+                    body.setFlag(Block.NEEDS_SCOPE);
                 }
             }
         }
-        printAST(functionNode);
-        return functionNode;
+        functionBody = new Block(bodyToken, bodyFinish, body.getFlags(), body.getStatements());
+        return functionBody;
     }
 
-    private boolean skipFunctionBody(final FunctionNode functionNode) {
+    private boolean skipFunctionBody(final ParserContextFunctionNode functionNode) {
         if (reparsedFunction == null) {
             // Not reparsing, so don't skip any function body.
             return false;
@@ -3008,13 +3041,13 @@
         }
     }
 
-    private void addFunctionDeclarations(final FunctionNode functionNode) {
+    private void addFunctionDeclarations(final ParserContextFunctionNode functionNode) {
         VarNode lastDecl = null;
         for (int i = functionDeclarations.size() - 1; i >= 0; i--) {
             Statement decl = functionDeclarations.get(i);
             if (lastDecl == null && decl instanceof VarNode) {
                 decl = lastDecl = ((VarNode)decl).setFlag(VarNode.IS_LAST_FUNCTION_DECLARATION);
-                lc.setFlag(functionNode, FunctionNode.HAS_FUNCTION_DECLARATIONS);
+                functionNode.setFlag(FunctionNode.HAS_FUNCTION_DECLARATIONS);
             }
             prependStatement(decl);
         }
@@ -3359,29 +3392,31 @@
         return "'JavaScript Parsing'";
     }
 
-    private static void markEval(final LexicalContext lc) {
-        final Iterator<FunctionNode> iter = lc.getFunctions();
+    private static void markEval(final ParserContext lc) {
+        final Iterator<ParserContextFunctionNode> iter = lc.getFunctions();
         boolean flaggedCurrentFn = false;
         while (iter.hasNext()) {
-            final FunctionNode fn = iter.next();
+            final ParserContextFunctionNode fn = iter.next();
             if (!flaggedCurrentFn) {
-                lc.setFlag(fn, FunctionNode.HAS_EVAL);
+                fn.setFlag(FunctionNode.HAS_EVAL);
                 flaggedCurrentFn = true;
             } else {
-                lc.setFlag(fn, FunctionNode.HAS_NESTED_EVAL);
+                fn.setFlag(FunctionNode.HAS_NESTED_EVAL);
             }
+            final ParserContextBlockNode body = lc.getFunctionBody(fn);
             // NOTE: it is crucial to mark the body of the outer function as needing scope even when we skip
             // parsing a nested function. functionBody() contains code to compensate for the lack of invoking
             // this method when the parser skips a nested function.
-            lc.setBlockNeedsScope(lc.getFunctionBody(fn));
+            body.setFlag(Block.NEEDS_SCOPE);
+            fn.setFlag(FunctionNode.HAS_SCOPE_BLOCK);
         }
     }
 
     private void prependStatement(final Statement statement) {
-        lc.prependStatement(statement);
+        lc.prependStatementToCurrentNode(statement);
     }
 
     private void appendStatement(final Statement statement) {
-        lc.appendStatement(statement);
+        lc.appendStatementToCurrentNode(statement);
     }
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/parser/ParserContext.java	Mon Oct 27 11:16:19 2014 +0100
@@ -0,0 +1,334 @@
+/*
+ * 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.parser;
+
+import java.util.Iterator;
+import java.util.NoSuchElementException;
+import jdk.nashorn.internal.ir.Statement;
+
+/**
+ * A class that tracks the current lexical context of node visitation as a stack of {@code ParserContextNode} nodes. Has special
+ * methods to retrieve useful subsets of the context.
+ *
+ * This is implemented with a primitive array and a stack pointer, because it really makes a difference
+ * performance wise. None of the collection classes were optimal
+ */
+
+class ParserContext {
+
+    private ParserContextNode[] stack;
+    private int sp;
+
+    private static final int INITIAL_DEPTH = 16;
+
+    /**
+     * Constructs a ParserContext,
+     * initializes the stack
+     */
+    public ParserContext(){
+        this.sp    = 0;
+        this.stack = new ParserContextNode[INITIAL_DEPTH];
+    }
+
+    /**
+     * Pushes a new block on top of the context, making it the innermost open block.
+     * @param node the new node
+     * @return The node that was pushed
+     */
+    public <T extends ParserContextNode> T push(final T node) {
+        assert !contains(node);
+        if (sp == stack.length) {
+            final ParserContextNode[] newStack = new ParserContextNode[sp * 2];
+            System.arraycopy(stack, 0, newStack, 0, sp);
+            stack = newStack;
+        }
+        stack[sp] = node;
+        sp++;
+
+        return node;
+    }
+
+    /**
+     * The topmost node on the stack
+     * @return The topmost node on the stack
+     */
+    public ParserContextNode peek() {
+        return stack[sp - 1];
+    }
+
+    /**
+     * Removes and returns the topmost Node from the stack.
+     * @param node The node expected to be popped, used for sanity check
+     * @return The removed node
+     */
+    public <T extends ParserContextNode> T pop(final T node) {
+        --sp;
+        @SuppressWarnings("unchecked")
+        final T popped = (T)stack[sp];
+        stack[sp] = null;
+        assert node == popped;
+
+        return popped;
+    }
+
+    /**
+     * Tests if a node is on the stack.
+     * @param node  The node to test
+     * @return true if stack contains node, false otherwise
+     */
+    public boolean contains(final ParserContextNode node) {
+        for (int i = 0; i < sp; i++) {
+            if (stack[i] == node) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    /**
+     * Returns the topmost {@link ParserContextBreakableNode} on the stack, null if none on stack
+     * @return Returns the topmost {@link ParserContextBreakableNode} on the stack, null if none on stack
+     */
+    private ParserContextBreakableNode getBreakable() {
+        for (final NodeIterator<ParserContextBreakableNode> iter = new NodeIterator<>(ParserContextBreakableNode.class, getCurrentFunction()); iter.hasNext(); ) {
+            final ParserContextBreakableNode next = iter.next();
+            if (next.isBreakableWithoutLabel()) {
+                return next;
+            }
+        }
+        return null;
+    }
+
+
+
+    /**
+     * Find the breakable node corresponding to this label.
+     * @param labelName name of the label to search for. If null, the closest breakable node will be returned
+     * unconditionally, e.g. a while loop with no label
+     * @return closest breakable node
+     */
+    public ParserContextBreakableNode getBreakable(final String labelName) {
+        if (labelName != null) {
+            final ParserContextLabelNode foundLabel = findLabel(labelName);
+            if (foundLabel != null) {
+                // iterate to the nearest breakable to the foundLabel
+                ParserContextBreakableNode breakable = null;
+                for (final NodeIterator<ParserContextBreakableNode> iter = new NodeIterator<>(ParserContextBreakableNode.class, foundLabel); iter.hasNext(); ) {
+                    breakable = iter.next();
+                }
+                return breakable;
+            }
+            return null;
+        } else {
+            return getBreakable();
+        }
+    }
+
+    /**
+     * Returns the loop node of the current loop, or null if not inside a loop
+     * @return loop noder
+     */
+    public ParserContextLoopNode getCurrentLoop() {
+        final Iterator<ParserContextLoopNode> iter = new NodeIterator<>(ParserContextLoopNode.class, getCurrentFunction());
+        return iter.hasNext() ? iter.next() : null;
+    }
+
+    private ParserContextLoopNode getContinueTo() {
+        return getCurrentLoop();
+    }
+
+    /**
+     * Find the continue target node corresponding to this label.
+     * @param labelName label name to search for. If null the closest loop node will be returned unconditionally, e.g. a
+     * while loop with no label
+     * @return closest continue target node
+     */
+    public ParserContextLoopNode getContinueTo(final String labelName) {
+        if (labelName != null) {
+            final ParserContextLabelNode foundLabel = findLabel(labelName);
+            if (foundLabel != null) {
+                // iterate to the nearest loop to the foundLabel
+                ParserContextLoopNode loop = null;
+                for (final NodeIterator<ParserContextLoopNode> iter = new NodeIterator<>(ParserContextLoopNode.class, foundLabel); iter.hasNext(); ) {
+                    loop = iter.next();
+                }
+                return loop;
+            }
+            return null;
+        }
+        return getContinueTo();
+    }
+
+    /**
+     * Get the function body of a function node on the stack.
+     * This will trigger an assertion if node isn't present
+     * @param functionNode function node
+     * @return body of function node
+     */
+    public ParserContextBlockNode getFunctionBody(final ParserContextFunctionNode functionNode) {
+        for (int i = sp - 1; i >= 0 ; i--) {
+            if (stack[i] == functionNode) {
+                return (ParserContextBlockNode)stack[i + 1];
+            }
+        }
+        throw new AssertionError(functionNode.getName() + " not on context stack");
+    }
+
+    /**
+     * Check the stack for a given label node by name
+     * @param name name of the label
+     * @return LabelNode if found, null otherwise
+     */
+    public ParserContextLabelNode findLabel(final String name) {
+        for (final Iterator<ParserContextLabelNode> iter = new NodeIterator<>(ParserContextLabelNode.class, getCurrentFunction()); iter.hasNext(); ) {
+            final ParserContextLabelNode next = iter.next();
+            if (next.getLabelName().equals(name)) {
+                return next;
+            }
+        }
+        return null;
+    }
+
+    /**
+     * Prepends a statement to the current node.
+     * @param statement The statement to prepend
+     */
+    public void prependStatementToCurrentNode(final Statement statement) {
+        assert statement != null;
+        stack[sp - 1].prependStatement(statement);
+    }
+
+    /**
+     * Appends a statement to the current Node.
+     * @param statement The statement to append
+     */
+    public void appendStatementToCurrentNode(final Statement statement) {
+        assert statement != null;
+        stack[sp - 1].appendStatement(statement);
+    }
+
+    /**
+     * Returns the innermost function in the context.
+     * @return the innermost function in the context.
+     */
+    public ParserContextFunctionNode getCurrentFunction() {
+        for (int i = sp - 1; i >= 0; i--) {
+            if (stack[i] instanceof ParserContextFunctionNode) {
+                return (ParserContextFunctionNode) stack[i];
+            }
+        }
+        return null;
+    }
+
+    /**
+     * Returns an iterator over all blocks in the context, with the top block (innermost lexical context) first.
+     * @return an iterator over all blocks in the context.
+     */
+    public Iterator<ParserContextBlockNode> getBlocks() {
+        return new NodeIterator<>(ParserContextBlockNode.class);
+    }
+
+    /**
+     * Returns the innermost block in the context.
+     * @return the innermost block in the context.
+     */
+    public ParserContextBlockNode getCurrentBlock() {
+        return getBlocks().next();
+    }
+
+    /**
+     * The last statement added to the context
+     * @return The last statement added to the context
+     */
+    public Statement getLastStatement() {
+        if (sp == 0) {
+            return null;
+        }
+        final ParserContextNode top = stack[sp - 1];
+        final int s = top.getStatements().size();
+        return s == 0 ? null : top.getStatements().get(s - 1);
+    }
+
+    /**
+     * Returns an iterator over all functions in the context, with the top (innermost open) function first.
+     * @return an iterator over all functions in the context.
+     */
+    public Iterator<ParserContextFunctionNode> getFunctions() {
+        return new NodeIterator<>(ParserContextFunctionNode.class);
+    }
+
+    private class NodeIterator <T extends ParserContextNode> implements Iterator<T> {
+        private int index;
+        private T next;
+        private final Class<T> clazz;
+        private ParserContextNode until;
+
+        NodeIterator(final Class<T> clazz) {
+            this(clazz, null);
+        }
+
+        NodeIterator(final Class<T> clazz, final ParserContextNode until) {
+            this.index = sp - 1;
+            this.clazz = clazz;
+            this.until = until;
+            this.next  = findNext();
+        }
+
+        @Override
+        public boolean hasNext() {
+            return next != null;
+        }
+
+        @Override
+        public T next() {
+            if (next == null) {
+                throw new NoSuchElementException();
+            }
+            final T lnext = next;
+            next = findNext();
+            return lnext;
+        }
+
+        @SuppressWarnings("unchecked")
+        private T findNext() {
+            for (int i = index; i >= 0; i--) {
+                final Object node = stack[i];
+                if (node == until) {
+                    return null;
+                }
+                if (clazz.isAssignableFrom(node.getClass())) {
+                    index = i - 1;
+                    return (T)node;
+                }
+            }
+            return null;
+        }
+
+        @Override
+        public void remove() {
+            throw new UnsupportedOperationException();
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/parser/ParserContextBaseNode.java	Mon Oct 27 11:16:19 2014 +0100
@@ -0,0 +1,109 @@
+/*
+ * 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.parser;
+
+import java.util.ArrayList;
+import java.util.List;
+import jdk.nashorn.internal.ir.Statement;
+
+/**
+ * Base class for parser context nodes
+ */
+abstract class ParserContextBaseNode implements ParserContextNode {
+    /**
+     * Flags for this node
+     */
+    protected int flags;
+
+    private List<Statement> statements;
+
+    /**
+     * Constructor
+     */
+    public ParserContextBaseNode() {
+        this.statements = new ArrayList<>();
+    }
+
+    /**
+     * @return The flags for this node
+     */
+    @Override
+    public int getFlags() {
+        return flags;
+    }
+
+    /**
+     * Returns a single flag
+     * @param flag
+     * @return A single flag
+     */
+    protected int getFlag(final int flag) {
+        return (flags & flag);
+    }
+
+    /**
+     * @param flag
+     * @return the new flags
+     */
+    @Override
+    public int setFlag(final int flag) {
+        flags |= flag;
+        return flags;
+    }
+
+    /**
+     * @return The list of statements that belongs to this node
+     */
+    @Override
+    public List<Statement> getStatements() {
+        return statements;
+    }
+
+    /**
+     * @param statements
+     */
+    @Override
+    public void setStatements(final List<Statement> statements) {
+        this.statements = statements;
+    }
+
+    /**
+     * Adds a Statement at the end of the Statementlist
+     * @param statement The statement to add
+     */
+    @Override
+    public void appendStatement(final Statement statement) {
+        this.statements.add(statement);
+    }
+
+    /**
+     * Adds a statement at the begining of the statementlist
+     * @param statement The statement to add
+     */
+    @Override
+    public void prependStatement(final Statement statement) {
+        this.statements.add(0, statement);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/parser/ParserContextBlockNode.java	Mon Oct 27 11:16:19 2014 +0100
@@ -0,0 +1,56 @@
+/*
+ * 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.parser;
+
+/**
+ * A ParserContextNode that represents a block that is currently being parsed
+ */
+class ParserContextBlockNode extends ParserContextBaseNode implements ParserContextBreakableNode {
+
+    private final long token;
+
+    /**
+     * Constructs a ParserContextBlockNode
+     *
+     * @param token The first token of the block
+     */
+    public ParserContextBlockNode(final long token) {
+        this.token = token;
+    }
+
+    @Override
+    public boolean isBreakableWithoutLabel() {
+        return false;
+    }
+
+    /**
+     * Get token
+     * @return The first token of the block
+     */
+    public long getToken() {
+        return token;
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/parser/ParserContextBreakableNode.java	Mon Oct 27 11:16:19 2014 +0100
@@ -0,0 +1,40 @@
+/*
+ * 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.parser;
+
+import jdk.nashorn.internal.ir.BreakNode;
+
+/**
+ * An interface that is implemented by ParserContextNodes that can
+ * contain a {@link BreakNode}
+ */
+interface ParserContextBreakableNode extends ParserContextNode {
+
+    /**
+     * Returns true if not i breakable without label, false otherwise
+     * @return Returns true if not i breakable without label, false otherwise
+     */
+    boolean isBreakableWithoutLabel();
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/parser/ParserContextFunctionNode.java	Mon Oct 27 11:16:19 2014 +0100
@@ -0,0 +1,197 @@
+/*
+ * 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.parser;
+
+import java.util.List;
+import jdk.nashorn.internal.codegen.Namespace;
+import jdk.nashorn.internal.ir.FunctionNode;
+import jdk.nashorn.internal.ir.IdentNode;
+
+/**
+ * ParserContextNode that represents a function that is currently being parsed
+ */
+class ParserContextFunctionNode extends ParserContextBaseNode {
+
+    /** Function name */
+    private final String name;
+
+    /** Function identifier node */
+    private final IdentNode ident;
+
+    /** Name space for function */
+    private final Namespace namespace;
+
+    /** Line number for function declaration */
+    private final int line;
+
+    /** Function node kind, see {@link FunctionNode#Kind} */
+    private final FunctionNode.Kind kind;
+
+    /** List of parameter identifiers for function */
+    private final List<IdentNode> parameters;
+
+    /** Token for function start */
+    private final long token;
+
+    /** Last function token */
+    private long lastToken;
+
+    /** Opaque node for parser end state, see {@link Parser} */
+    private Object endParserState;
+
+    /**
+     * @param token The token for the function
+     * @param ident External function name
+     * @param name  Internal name of the function
+     * @param namespace Function's namespace
+     * @param line  The source line of the function
+     * @param kind  Function kind
+     * @param parameters The parameters of the function
+     */
+    public ParserContextFunctionNode(final long token, final IdentNode ident, final String name, final Namespace namespace, final int line, final FunctionNode.Kind kind, final List<IdentNode> parameters) {
+        this.ident      = ident;
+        this.namespace  = namespace;
+        this.line       = line;
+        this.kind       = kind;
+        this.name       = name;
+        this.parameters = parameters;
+        this.token      = token;
+    }
+
+    /**
+     * @return Internal name of the function
+     */
+    public String getName() {
+        return name;
+    }
+
+    /**
+     * @return The external identifier for the function
+     */
+    public IdentNode getIdent() {
+        return ident;
+    }
+
+    /**
+     *
+     * @return true if function is the program function
+     */
+    public boolean isProgram() {
+        return getFlag(FunctionNode.IS_PROGRAM) != 0;
+    }
+
+    /**
+     * @return if function in strict mode
+     */
+    public boolean isStrict() {
+        return getFlag(FunctionNode.IS_STRICT) != 0;
+    }
+
+    /**
+     * @return true if the function has nested evals
+     */
+    public boolean hasNestedEval() {
+        return getFlag(FunctionNode.HAS_NESTED_EVAL) != 0;
+    }
+
+    /**
+     * Returns true if any of the blocks in this function create their own scope.
+     * @return true if any of the blocks in this function create their own scope.
+     */
+    public boolean hasScopeBlock() {
+        return getFlag(FunctionNode.HAS_SCOPE_BLOCK) != 0;
+    }
+
+    /**
+     * Create a unique name in the namespace of this FunctionNode
+     * @param base prefix for name
+     * @return base if no collision exists, otherwise a name prefix with base
+     */
+    public String uniqueName(final String base) {
+        return namespace.uniqueName(base);
+    }
+
+    /**
+     * @return line number of the function
+     */
+    public int getLineNumber() {
+        return line;
+    }
+
+    /**
+     * @return The kind if function
+     */
+    public FunctionNode.Kind getKind() {
+        return kind;
+    }
+
+    /**
+     * Get parameters
+     * @return The parameters of the function
+     */
+    public List<IdentNode> getParameters() {
+        return parameters;
+    }
+
+    /**
+     * Set last token
+     * @param token New last token
+     */
+    public void setLastToken(final long token) {
+        this.lastToken = token;
+
+    }
+
+    /**
+     * @return lastToken Function's last token
+     */
+    public long getLastToken() {
+        return lastToken;
+    }
+
+    /**
+     * Returns the ParserState of when the parsing of this function was ended
+     * @return endParserState The end parser state
+     */
+    public Object getEndParserState() {
+        return endParserState;
+    }
+
+    /**
+     * Sets the ParserState of when the parsing of this function was ended
+     * @param endParserState The end parser state
+     */
+    public void setEndParserState(final Object endParserState) {
+        this.endParserState = endParserState;
+    }
+
+    /**
+     * Returns the if of this function
+     * @return The function id
+     */
+    public int getId() {
+        return isProgram() ? -1 : Token.descPosition(token);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/parser/ParserContextLabelNode.java	Mon Oct 27 11:16:19 2014 +0100
@@ -0,0 +1,52 @@
+/**
+/*
+ * 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.parser;
+
+/**
+ * ParserContextNode that represents a LabelNode
+ */
+class ParserContextLabelNode extends ParserContextBaseNode {
+
+    /** Name for label */
+    private final String name;
+
+    /**
+     * Constructor
+     *
+     * @param name The name of the label
+     */
+    public ParserContextLabelNode(final String name) {
+        this.name = name;
+    }
+
+    /**
+     * Returns the name of the label
+     * @return name of label
+     */
+    public String getLabelName() {
+        return name;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/parser/ParserContextLoopNode.java	Mon Oct 27 11:16:19 2014 +0100
@@ -0,0 +1,37 @@
+/*
+ * 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.parser;
+
+/**
+ * A ParserContextNode that represents a loop that is being parsed
+ */
+class ParserContextLoopNode extends ParserContextBaseNode implements ParserContextBreakableNode {
+
+    @Override
+    public boolean isBreakableWithoutLabel() {
+        return true;
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/parser/ParserContextNode.java	Mon Oct 27 11:16:19 2014 +0100
@@ -0,0 +1,67 @@
+/*
+ * 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.parser;
+
+import java.util.List;
+import jdk.nashorn.internal.ir.Statement;
+
+/**
+ * Used for keeping state when needed in the parser.
+ */
+interface ParserContextNode {
+    /**
+     * @return The flags for this node
+     */
+    public int getFlags();
+
+    /**
+     * @param flag The flag to set
+     * @return All current flags after update
+     */
+    public int setFlag(final int flag);
+
+    /**
+     * @return The list of statements that belongs to this node
+     */
+    public List<Statement> getStatements();
+
+    /**
+     * @param statements The statement list
+     */
+    public void setStatements(final List<Statement> statements);
+
+    /**
+     * Adds a Statement at the end of the Statementlist
+     * @param statement The statement to add
+     */
+    public void appendStatement(final Statement statement);
+
+    /**
+     * Adds a statement at the begining of the statementlist
+     * @param statement The statement to add
+     */
+    public void prependStatement(final Statement statement);
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/parser/ParserContextSwitchNode.java	Mon Oct 27 11:16:19 2014 +0100
@@ -0,0 +1,36 @@
+/*
+ * 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.parser;
+
+/**
+ * A ParserContextNode that represents a SwithcNode that is currently being parsed
+ */
+class ParserContextSwitchNode extends ParserContextBaseNode implements ParserContextBreakableNode {
+
+    @Override
+    public boolean isBreakableWithoutLabel() {
+        return true;
+    }
+}
--- a/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/Context.java	Tue Oct 21 14:24:16 2014 +0100
+++ b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/Context.java	Mon Oct 27 11:16:19 2014 +0100
@@ -483,7 +483,7 @@
 
         final int cacheSize = env._class_cache_size;
         if (cacheSize > 0) {
-            classCache = new ClassCache(cacheSize);
+            classCache = new ClassCache(this, cacheSize);
         }
 
         if (env._persistent_cache) {
@@ -1261,17 +1261,23 @@
      * Cache for compiled script classes.
      */
     @SuppressWarnings("serial")
-    private static class ClassCache extends LinkedHashMap<Source, ClassReference> {
+    @Logger(name="classcache")
+    private static class ClassCache extends LinkedHashMap<Source, ClassReference> implements Loggable {
         private final int size;
         private final ReferenceQueue<Class<?>> queue;
+        private final DebugLogger log;
 
-        ClassCache(final int size) {
+        ClassCache(final Context context, final int size) {
             super(size, 0.75f, true);
             this.size = size;
             this.queue = new ReferenceQueue<>();
+            this.log   = initLogger(context);
         }
 
         void cache(final Source source, final Class<?> clazz) {
+            if (log.isEnabled()) {
+                log.info("Caching ", source, " in class cache");
+            }
             put(source, new ClassReference(clazz, queue, source));
         }
 
@@ -1283,9 +1289,28 @@
         @Override
         public ClassReference get(final Object key) {
             for (ClassReference ref; (ref = (ClassReference)queue.poll()) != null; ) {
-                remove(ref.source);
+                final Source source = ref.source;
+                if (log.isEnabled()) {
+                    log.info("Evicting ", source, " from class cache.");
+                }
+                remove(source);
             }
-            return super.get(key);
+
+            final ClassReference ref = super.get(key);
+            if (ref != null && log.isEnabled()) {
+                log.info("Retrieved class reference for ", ref.source, " from class cache");
+            }
+            return ref;
+        }
+
+        @Override
+        public DebugLogger initLogger(final Context context) {
+            return context.getLogger(getClass());
+        }
+
+        @Override
+        public DebugLogger getLogger() {
+            return log;
         }
 
     }
--- a/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/GlobalConstants.java	Tue Oct 21 14:24:16 2014 +0100
+++ b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/GlobalConstants.java	Mon Oct 27 11:16:19 2014 +0100
@@ -31,7 +31,6 @@
 import static jdk.nashorn.internal.runtime.UnwarrantedOptimismException.INVALID_PROGRAM_POINT;
 import static jdk.nashorn.internal.runtime.linker.NashornCallSiteDescriptor.getProgramPoint;
 import static jdk.nashorn.internal.runtime.logging.DebugLogger.quote;
-
 import java.lang.invoke.MethodHandle;
 import java.lang.invoke.MethodHandles;
 import java.lang.invoke.SwitchPoint;
@@ -328,7 +327,9 @@
         }
 
         if (!acc.mayRetry()) {
-            log.info("*** SET: Giving up on " + quote(name) + " - retry count has exceeded " + DynamicLinker.getLinkedCallSiteLocation());
+            if (log.isEnabled()) {
+                log.fine("*** SET: Giving up on " + quote(name) + " - retry count has exceeded " + DynamicLinker.getLinkedCallSiteLocation());
+            }
             return null;
         }
 
@@ -404,7 +405,9 @@
         }
 
         if (acc.hasBeenInvalidated() || acc.guardFailed()) {
-            log.fine("*** GET: Giving up on " + quote(name) + " - retry count has exceeded");
+            if (log.isEnabled()) {
+                log.info("*** GET: Giving up on " + quote(name) + " - retry count has exceeded " + DynamicLinker.getLinkedCallSiteLocation());
+            }
             return null;
         }
 
--- a/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/RecompilableScriptFunctionData.java	Tue Oct 21 14:24:16 2014 +0100
+++ b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/RecompilableScriptFunctionData.java	Mon Oct 27 11:16:19 2014 +0100
@@ -676,6 +676,22 @@
         return addCode(lookup(fnInit).asType(toType), fnInit.getInvalidatedProgramPoints(), callSiteType, fnInit.getFlags());
     }
 
+    /**
+     * Returns the return type of a function specialization for particular parameter types.<br>
+     * <b>Be aware that the way this is implemented, it forces full materialization (compilation and installation) of
+     * code for that specialization.</b>
+     * @param callSiteType the parameter types at the call site. It must include the mandatory {@code callee} and
+     * {@code this} parameters, so it needs to start with at least {@code ScriptFunction.class} and
+     * {@code Object.class} class. Since the return type of the function is calculated from the code itself, it is
+     * irrelevant and should be set to {@code Object.class}.
+     * @param runtimeScope a current runtime scope. Can be null but when it's present it will be used as a source of
+     * current runtime values that can improve the compiler's type speculations (and thus reduce the need for later
+     * recompilations) if the specialization is not already present and thus needs to be freshly compiled.
+     * @return the return type of the function specialization.
+     */
+    public Class<?> getReturnType(final MethodType callSiteType, final ScriptObject runtimeScope) {
+        return getBest(callSiteType, runtimeScope, CompiledFunction.NO_FUNCTIONS).type().returnType();
+    }
 
     @Override
     synchronized CompiledFunction getBest(final MethodType callSiteType, final ScriptObject runtimeScope, final Collection<CompiledFunction> forbidden) {
--- a/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/WithObject.java	Tue Oct 21 14:24:16 2014 +0100
+++ b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/WithObject.java	Mon Oct 27 11:16:19 2014 +0100
@@ -210,6 +210,19 @@
     }
 
     @Override
+    protected Object invokeNoSuchProperty(final String name, final int programPoint) {
+        FindProperty find = expression.findProperty(NO_SUCH_PROPERTY_NAME, true);
+        if (find != null) {
+            final Object func = find.getObjectValue();
+            if (func instanceof ScriptFunction) {
+                return ScriptRuntime.apply((ScriptFunction)func, expression, name);
+            }
+        }
+
+        return getProto().invokeNoSuchProperty(name, programPoint);
+    }
+
+    @Override
     public void setSplitState(final int state) {
         getNonWithParent().setSplitState(state);
     }
--- a/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/arrays/ContinuousArrayData.java	Tue Oct 21 14:24:16 2014 +0100
+++ b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/arrays/ContinuousArrayData.java	Mon Oct 27 11:16:19 2014 +0100
@@ -30,6 +30,7 @@
 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;
@@ -37,6 +38,7 @@
 import jdk.internal.dynalink.CallSiteDescriptor;
 import jdk.internal.dynalink.linker.GuardedInvocation;
 import jdk.internal.dynalink.linker.LinkRequest;
+import jdk.nashorn.internal.codegen.types.Type;
 import jdk.nashorn.internal.lookup.Lookup;
 import jdk.nashorn.internal.runtime.ScriptObject;
 import jdk.nashorn.internal.runtime.linker.NashornCallSiteDescriptor;
@@ -120,6 +122,11 @@
      */
     public abstract Class<?> getElementType();
 
+    @Override
+    public Type getOptimisticType() {
+        return Type.typeFor(getElementType());
+    }
+
     /**
      * Look up a continuous array element getter
      * @param get          getter, sometimes combined with a has check that throws CCE on failure for relink
--- a/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/arrays/DeletedRangeArrayFilter.java	Tue Oct 21 14:24:16 2014 +0100
+++ b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/arrays/DeletedRangeArrayFilter.java	Mon Oct 27 11:16:19 2014 +0100
@@ -66,9 +66,9 @@
     public Object[] asObjectArray() {
         final Object[] value = super.asObjectArray();
 
-        if (lo <= Integer.MAX_VALUE) {
-            final int intHi = (int)Math.min(hi, Integer.MAX_VALUE);
-            for (int i = (int)lo; i <= intHi; i++) {
+        if (lo < Integer.MAX_VALUE) {
+            final int end = (int)Math.min(hi + 1, Integer.MAX_VALUE);
+            for (int i = (int)lo; i < end; i++) {
                 value[i] = ScriptRuntime.UNDEFINED;
             }
         }
@@ -81,9 +81,9 @@
         final Object value = super.asArrayOfType(componentType);
         final Object undefValue = convertUndefinedValue(componentType);
 
-        if (lo <= Integer.MAX_VALUE) {
-            final int intHi = (int)Math.min(hi, Integer.MAX_VALUE);
-            for (int i = (int)lo; i <= intHi; i++) {
+        if (lo < Integer.MAX_VALUE) {
+            final int end = (int)Math.min(hi + 1, Integer.MAX_VALUE);
+            for (int i = (int)lo; i < end; i++) {
                 Array.set(value, i, undefValue);
             }
         }
--- a/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/arrays/IntArrayData.java	Tue Oct 21 14:24:16 2014 +0100
+++ b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/arrays/IntArrayData.java	Mon Oct 27 11:16:19 2014 +0100
@@ -26,10 +26,10 @@
 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;
-import jdk.nashorn.internal.codegen.types.Type;
 import jdk.nashorn.internal.runtime.JSType;
 import jdk.nashorn.internal.runtime.ScriptRuntime;
 
@@ -73,7 +73,7 @@
 
     @Override
     public Object[] asObjectArray() {
-        return toObjectArray();
+        return toObjectArray(true);
     }
 
     @SuppressWarnings("unused")
@@ -116,9 +116,9 @@
         return super.asArrayOfType(componentType);
     }
 
-    private Object[] toObjectArray() {
+    private Object[] toObjectArray(final boolean trim) {
         assert length <= array.length : "length exceeds internal array size";
-        final Object[] oarray = new Object[array.length];
+        final Object[] oarray = new Object[trim ? (int)length : array.length];
 
         for (int index = 0; index < length; index++) {
             oarray[index] = Integer.valueOf(array[index]);
@@ -158,7 +158,7 @@
     }
 
     private ObjectArrayData convertToObject() {
-        return new ObjectArrayData(toObjectArray(), (int)length);
+        return new ObjectArrayData(toObjectArray(false), (int)length);
     }
 
     @Override
@@ -257,11 +257,6 @@
     }
 
     @Override
-    public Type getOptimisticType() {
-        return Type.INT;
-    }
-
-    @Override
     public int getInt(final int index) {
         return array[index];
     }
--- a/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/arrays/LongArrayData.java	Tue Oct 21 14:24:16 2014 +0100
+++ b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/arrays/LongArrayData.java	Mon Oct 27 11:16:19 2014 +0100
@@ -27,10 +27,10 @@
 
 import static jdk.nashorn.internal.codegen.CompilerConstants.specialCall;
 import static jdk.nashorn.internal.lookup.Lookup.MH;
+
 import java.lang.invoke.MethodHandle;
 import java.lang.invoke.MethodHandles;
 import java.util.Arrays;
-import jdk.nashorn.internal.codegen.types.Type;
 import jdk.nashorn.internal.runtime.JSType;
 import jdk.nashorn.internal.runtime.ScriptRuntime;
 
@@ -67,12 +67,12 @@
 
     @Override
     public Object[] asObjectArray() {
-        return toObjectArray(array, (int)length);
+        return toObjectArray(true);
     }
 
-    private static Object[] toObjectArray(final long[] array, final int length) {
+    private Object[] toObjectArray(final boolean trim) {
         assert length <= array.length : "length exceeds internal array size";
-        final Object[] oarray = new Object[array.length];
+        final Object[] oarray = new Object[trim ? (int)length : array.length];
 
         for (int index = 0; index < length; index++) {
             oarray[index] = Long.valueOf(array[index]);
@@ -89,7 +89,7 @@
         return super.asArrayOfType(componentType);
     }
 
-    private static double[] toDoubleArray(final long[] array, final int length) {
+    private double[] toDoubleArray() {
         assert length <= array.length : "length exceeds internal array size";
         final double[] darray = new double[array.length];
 
@@ -107,9 +107,9 @@
         }
         final int len = (int)length;
         if (type == Double.class) {
-            return new NumberArrayData(LongArrayData.toDoubleArray(array, len), len);
+            return new NumberArrayData(toDoubleArray(), len);
         }
-        return new ObjectArrayData(LongArrayData.toObjectArray(array, len), len);
+        return new ObjectArrayData(toObjectArray(false), len);
     }
 
     @Override
@@ -186,11 +186,6 @@
         return convert(Double.class).set(index, value, strict);
     }
 
-    @Override
-    public Type getOptimisticType() {
-        return Type.LONG;
-    }
-
     private static final MethodHandle HAS_GET_ELEM = specialCall(MethodHandles.lookup(), LongArrayData.class, "getElem", long.class, int.class).methodHandle();
     private static final MethodHandle SET_ELEM     = specialCall(MethodHandles.lookup(), LongArrayData.class, "setElem", void.class, int.class, long.class).methodHandle();
 
--- a/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/arrays/NumberArrayData.java	Tue Oct 21 14:24:16 2014 +0100
+++ b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/arrays/NumberArrayData.java	Mon Oct 27 11:16:19 2014 +0100
@@ -28,10 +28,10 @@
 import static jdk.nashorn.internal.codegen.CompilerConstants.specialCall;
 import static jdk.nashorn.internal.lookup.Lookup.MH;
 import static jdk.nashorn.internal.runtime.ScriptRuntime.UNDEFINED;
+
 import java.lang.invoke.MethodHandle;
 import java.lang.invoke.MethodHandles;
 import java.util.Arrays;
-import jdk.nashorn.internal.codegen.types.Type;
 
 /**
  * Implementation of {@link ArrayData} as soon as a double has been
@@ -66,12 +66,12 @@
 
     @Override
     public Object[] asObjectArray() {
-        return toObjectArray(array, (int)length);
+        return toObjectArray(true);
     }
 
-    private static Object[] toObjectArray(final double[] array, final int length) {
+    private Object[] toObjectArray(final boolean trim) {
         assert length <= array.length : "length exceeds internal array size";
-        final Object[] oarray = new Object[array.length];
+        final Object[] oarray = new Object[trim ? (int)length : array.length];
 
         for (int index = 0; index < length; index++) {
             oarray[index] = Double.valueOf(array[index]);
@@ -91,7 +91,7 @@
     public ArrayData convert(final Class<?> type) {
         if (type != Double.class && type != Integer.class && type != Long.class) {
             final int len = (int)length;
-            return new ObjectArrayData(NumberArrayData.toObjectArray(array, len), len);
+            return new ObjectArrayData(toObjectArray(false), len);
         }
         return this;
     }
@@ -166,11 +166,6 @@
         return this;
     }
 
-    @Override
-    public Type getOptimisticType() {
-        return Type.NUMBER;
-    }
-
     private static final MethodHandle HAS_GET_ELEM = specialCall(MethodHandles.lookup(), NumberArrayData.class, "getElem", double.class, int.class).methodHandle();
     private static final MethodHandle SET_ELEM     = specialCall(MethodHandles.lookup(), NumberArrayData.class, "setElem", void.class, int.class, double.class).methodHandle();
 
--- a/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/arrays/ObjectArrayData.java	Tue Oct 21 14:24:16 2014 +0100
+++ b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/arrays/ObjectArrayData.java	Mon Oct 27 11:16:19 2014 +0100
@@ -26,10 +26,10 @@
 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;
-import jdk.nashorn.internal.codegen.types.Type;
 import jdk.nashorn.internal.runtime.JSType;
 import jdk.nashorn.internal.runtime.ScriptRuntime;
 
@@ -155,15 +155,11 @@
 
     @Override
     public ArrayData setEmpty(final long lo, final long hi) {
-        Arrays.fill(array, (int)Math.max(lo, 0L), (int)Math.min(hi, Integer.MAX_VALUE), ScriptRuntime.EMPTY);
+        // hi parameter is inclusive, but Arrays.fill toIndex parameter is exclusive
+        Arrays.fill(array, (int)Math.max(lo, 0L), (int)Math.min(hi + 1, Integer.MAX_VALUE), ScriptRuntime.EMPTY);
         return this;
     }
 
-    @Override
-    public Type getOptimisticType() {
-        return Type.OBJECT;
-    }
-
     private static final MethodHandle HAS_GET_ELEM = specialCall(MethodHandles.lookup(), ObjectArrayData.class, "getElem", Object.class, int.class).methodHandle();
     private static final MethodHandle SET_ELEM     = specialCall(MethodHandles.lookup(), ObjectArrayData.class, "setElem", void.class, int.class, Object.class).methodHandle();
 
--- a/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/arrays/SparseArrayData.java	Tue Oct 21 14:24:16 2014 +0100
+++ b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/arrays/SparseArrayData.java	Mon Oct 27 11:16:19 2014 +0100
@@ -78,7 +78,7 @@
 
         for (final Map.Entry<Long, Object> entry : sparseMap.entrySet()) {
             final long key = entry.getKey();
-            if (key <= Integer.MAX_VALUE) {
+            if (key < Integer.MAX_VALUE) {
                 objArray[(int)key] = entry.getValue();
             } else {
                 break; // ascending key order
--- a/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/linker/JavaAdapterBytecodeGenerator.java	Tue Oct 21 14:24:16 2014 +0100
+++ b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/linker/JavaAdapterBytecodeGenerator.java	Mon Oct 27 11:16:19 2014 +0100
@@ -152,6 +152,7 @@
     static final String SET_GLOBAL_METHOD_DESCRIPTOR = Type.getMethodDescriptor(Type.VOID_TYPE, OBJECT_TYPE);
     static final String VOID_NOARG_METHOD_DESCRIPTOR = Type.getMethodDescriptor(Type.VOID_TYPE);
 
+    private static final Type SCRIPT_OBJECT_TYPE = Type.getType(ScriptObject.class);
     private static final Type SCRIPT_FUNCTION_TYPE = Type.getType(ScriptFunction.class);
     private static final Type STRING_TYPE = Type.getType(String.class);
     private static final Type METHOD_TYPE_TYPE = Type.getType(MethodType.class);
@@ -536,8 +537,8 @@
         final int argLen = originalArgTypes.length;
         final Type[] newArgTypes = new Type[argLen + 1];
 
-        // Insert ScriptFunction|Object as the last argument to the constructor
-        final Type extraArgumentType = fromFunction ? SCRIPT_FUNCTION_TYPE : OBJECT_TYPE;
+        // Insert ScriptFunction|ScriptObject as the last argument to the constructor
+        final Type extraArgumentType = fromFunction ? SCRIPT_FUNCTION_TYPE : SCRIPT_OBJECT_TYPE;
         newArgTypes[argLen] = extraArgumentType;
         System.arraycopy(originalArgTypes, 0, newArgTypes, 0, argLen);
 
@@ -588,6 +589,34 @@
         // Initialize converters
         generateConverterInit(mv, fromFunction);
         endInitMethod(mv);
+
+        if (! fromFunction) {
+            newArgTypes[argLen] = OBJECT_TYPE;
+            final InstructionAdapter mv2 = new InstructionAdapter(cw.visitMethod(ACC_PUBLIC, INIT,
+                Type.getMethodDescriptor(originalCtorType.getReturnType(), newArgTypes), null, null));
+            generateOverridingConstructorWithObjectParam(mv2, ctor, originalCtorType.getDescriptor());
+        }
+    }
+
+    // Object additional param accepting constructor - generated to handle null and undefined value
+    // for script adapters. This is effectively to throw TypeError on such script adapters. See
+    // JavaAdapterServices.getHandle as well.
+    private void generateOverridingConstructorWithObjectParam(final InstructionAdapter mv, final Constructor<?> ctor, final String ctorDescriptor) {
+        mv.visitCode();
+        mv.visitVarInsn(ALOAD, 0);
+        final Class<?>[] argTypes = ctor.getParameterTypes();
+        int offset = 1; // First arg is at position 1, after this.
+        for (int i = 0; i < argTypes.length; ++i) {
+            final Type argType = Type.getType(argTypes[i]);
+            mv.load(offset, argType);
+            offset += argType.getSize();
+        }
+        mv.invokespecial(superClassName, INIT, ctorDescriptor, false);
+        mv.visitVarInsn(ALOAD, offset);
+        mv.visitInsn(ACONST_NULL);
+        mv.visitInsn(ACONST_NULL);
+        mv.invokestatic(SERVICES_CLASS_TYPE_NAME, "getHandle", GET_HANDLE_OBJECT_DESCRIPTOR, false);
+        endInitMethod(mv);
     }
 
     private static void endInitMethod(final InstructionAdapter mv) {
--- a/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/linker/JavaAdapterClassLoader.java	Tue Oct 21 14:24:16 2014 +0100
+++ b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/linker/JavaAdapterClassLoader.java	Mon Oct 27 11:16:19 2014 +0100
@@ -39,6 +39,7 @@
 import jdk.nashorn.internal.runtime.Context;
 import jdk.nashorn.internal.runtime.JSType;
 import jdk.nashorn.internal.runtime.ScriptFunction;
+import jdk.nashorn.internal.runtime.ScriptObject;
 
 /**
  * This class encapsulates the bytecode of the adapter class and can be used to load it into the JVM as an actual Class.
@@ -51,7 +52,7 @@
     private static final AccessControlContext CREATE_LOADER_ACC_CTXT = ClassAndLoader.createPermAccCtxt("createClassLoader");
     private static final AccessControlContext GET_CONTEXT_ACC_CTXT = ClassAndLoader.createPermAccCtxt(Context.NASHORN_GET_CONTEXT);
     private static final Collection<String> VISIBLE_INTERNAL_CLASS_NAMES = Collections.unmodifiableCollection(new HashSet<>(
-            Arrays.asList(JavaAdapterServices.class.getName(), ScriptFunction.class.getName(), JSType.class.getName())));
+            Arrays.asList(JavaAdapterServices.class.getName(), ScriptObject.class.getName(), ScriptFunction.class.getName(), JSType.class.getName())));
 
     private final String className;
     private final byte[] classBytes;
--- a/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/linker/JavaAdapterServices.java	Tue Oct 21 14:24:16 2014 +0100
+++ b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/linker/JavaAdapterServices.java	Mon Oct 27 11:16:19 2014 +0100
@@ -47,7 +47,6 @@
 import jdk.internal.org.objectweb.asm.Opcodes;
 import jdk.internal.org.objectweb.asm.Type;
 import jdk.internal.org.objectweb.asm.commons.InstructionAdapter;
-import jdk.nashorn.api.scripting.ScriptUtils;
 import jdk.nashorn.internal.runtime.Context;
 import jdk.nashorn.internal.runtime.ScriptFunction;
 import jdk.nashorn.internal.runtime.ScriptObject;
@@ -220,7 +219,7 @@
      * @return the filtered return value.
      */
     public static Object exportReturnValue(final Object obj) {
-        return ScriptUtils.wrap(NashornBeansLinker.exportArgument(obj));
+        return NashornBeansLinker.exportArgument(obj, true);
     }
 
     /**
--- a/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/linker/NashornBeansLinker.java	Tue Oct 21 14:24:16 2014 +0100
+++ b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/linker/NashornBeansLinker.java	Mon Oct 27 11:16:19 2014 +0100
@@ -35,17 +35,28 @@
 import jdk.internal.dynalink.linker.LinkRequest;
 import jdk.internal.dynalink.linker.LinkerServices;
 import jdk.internal.dynalink.support.Lookup;
+import jdk.nashorn.api.scripting.ScriptUtils;
+import jdk.nashorn.internal.objects.NativeArray;
 import jdk.nashorn.internal.runtime.ConsString;
+import jdk.nashorn.internal.runtime.ScriptObject;
+import jdk.nashorn.internal.runtime.options.Options;
 
 /**
  * This linker delegates to a {@code BeansLinker} but passes it a special linker services object that has a modified
  * {@code asType} method that will ensure that we never pass internal engine objects that should not be externally
- * observable (currently only ConsString) to Java APIs, but rather that we flatten it into a String. We can't just add
+ * observable (currently ConsString and ScriptObject) to Java APIs, but rather that we flatten it into a String. We can't just add
  * this functionality as custom converters via {@code GuaardingTypeConverterFactory}, since they are not consulted when
  * the target method handle parameter signature is {@code Object}.
  */
 public class NashornBeansLinker implements GuardingDynamicLinker {
+    // System property to control whether to wrap ScriptObject->ScriptObjectMirror for
+    // Object type arguments of Java method calls, field set and array set.
+    private static final boolean MIRROR_ALWAYS = Options.getBooleanProperty("nashorn.mirror.always", true);
+
     private static final MethodHandle EXPORT_ARGUMENT = new Lookup(MethodHandles.lookup()).findOwnStatic("exportArgument", Object.class, Object.class);
+    private static final MethodHandle EXPORT_NATIVE_ARRAY = new Lookup(MethodHandles.lookup()).findOwnStatic("exportNativeArray", Object.class, NativeArray.class);
+    private static final MethodHandle EXPORT_SCRIPT_OBJECT = new Lookup(MethodHandles.lookup()).findOwnStatic("exportScriptObject", Object.class, ScriptObject.class);
+    private static final MethodHandle IMPORT_RESULT = new Lookup(MethodHandles.lookup()).findOwnStatic("importResult", Object.class, Object.class);
 
     private final BeansLinker beansLinker = new BeansLinker();
 
@@ -67,8 +78,39 @@
         return delegateLinker.getGuardedInvocation(linkRequest, new NashornBeansLinkerServices(linkerServices));
     }
 
-    static Object exportArgument(final Object arg) {
-        return arg instanceof ConsString ? arg.toString() : arg;
+    @SuppressWarnings("unused")
+    private static Object exportArgument(final Object arg) {
+        return exportArgument(arg, MIRROR_ALWAYS);
+    }
+
+    @SuppressWarnings("unused")
+    private static Object exportNativeArray(final NativeArray arg) {
+        return exportArgument(arg, MIRROR_ALWAYS);
+    }
+
+    @SuppressWarnings("unused")
+    private static Object exportScriptObject(final ScriptObject arg) {
+        return exportArgument(arg, MIRROR_ALWAYS);
+    }
+
+    @SuppressWarnings("unused")
+    private static Object exportScriptArray(final NativeArray arg) {
+        return exportArgument(arg, MIRROR_ALWAYS);
+    }
+
+    static Object exportArgument(final Object arg, final boolean mirrorAlways) {
+        if (arg instanceof ConsString) {
+            return arg.toString();
+        } else if (mirrorAlways && arg instanceof ScriptObject) {
+            return ScriptUtils.wrap((ScriptObject)arg);
+        } else {
+            return arg;
+        }
+    }
+
+    @SuppressWarnings("unused")
+    private static Object importResult(final Object arg) {
+        return ScriptUtils.unwrap(arg);
     }
 
     private static class NashornBeansLinkerServices implements LinkerServices {
@@ -80,23 +122,50 @@
 
         @Override
         public MethodHandle asType(final MethodHandle handle, final MethodType fromType) {
-            final MethodHandle typed = linkerServices.asType(handle, fromType);
-
             final MethodType handleType = handle.type();
             final int paramCount = handleType.parameterCount();
             assert fromType.parameterCount() == handleType.parameterCount();
 
+            MethodType newFromType = fromType;
             MethodHandle[] filters = null;
             for(int i = 0; i < paramCount; ++i) {
-                if(shouldConvert(handleType.parameterType(i), fromType.parameterType(i))) {
-                    if(filters == null) {
+                final MethodHandle filter = argConversionFilter(handleType.parameterType(i), fromType.parameterType(i));
+                if (filter != null) {
+                    if (filters == null) {
                         filters = new MethodHandle[paramCount];
                     }
-                    filters[i] = EXPORT_ARGUMENT;
+                    // "erase" specific type with Object type or else we'll get filter mismatch
+                    newFromType = newFromType.changeParameterType(i, Object.class);
+                    filters[i] = filter;
                 }
             }
 
-            return filters != null ? MethodHandles.filterArguments(typed, 0, filters) : typed;
+            final MethodHandle typed = linkerServices.asType(handle, newFromType);
+            MethodHandle result = filters != null ? MethodHandles.filterArguments(typed, 0, filters) : typed;
+            // Filter Object typed return value for possible ScriptObjectMirror. We convert
+            // ScriptObjectMirror as ScriptObject (if it is mirror from current global).
+            if (MIRROR_ALWAYS && areBothObjects(handleType.returnType(), fromType.returnType())) {
+                result = MethodHandles.filterReturnValue(result, IMPORT_RESULT);
+            }
+
+            return result;
+        }
+
+        private static MethodHandle argConversionFilter(final Class<?> handleType, final Class<?> fromType) {
+            if (handleType == Object.class) {
+                if (fromType == Object.class) {
+                    return EXPORT_ARGUMENT;
+                } else if (fromType == NativeArray.class) {
+                    return EXPORT_NATIVE_ARRAY;
+                } else if (fromType == ScriptObject.class) {
+                    return EXPORT_SCRIPT_OBJECT;
+                }
+            }
+            return null;
+        }
+
+        private static boolean areBothObjects(final Class<?> handleType, final Class<?> fromType) {
+            return handleType == Object.class && fromType == Object.class;
         }
 
         @Override
@@ -104,10 +173,6 @@
             return Implementation.asTypeLosslessReturn(this, handle, fromType);
         }
 
-        private static boolean shouldConvert(final Class<?> handleType, final Class<?> fromType) {
-            return handleType == Object.class && fromType == Object.class;
-        }
-
         @Override
         public MethodHandle getTypeConverter(final Class<?> sourceType, final Class<?> targetType) {
             return linkerServices.getTypeConverter(sourceType, targetType);
--- a/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/linker/NashornLinker.java	Tue Oct 21 14:24:16 2014 +0100
+++ b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/linker/NashornLinker.java	Mon Oct 27 11:16:19 2014 +0100
@@ -292,7 +292,7 @@
 
     @SuppressWarnings("unused")
     private static Object createMirror(final Object obj) {
-        return ScriptUtils.wrap(obj);
+        return obj instanceof ScriptObject? ScriptUtils.wrap((ScriptObject)obj) : obj;
     }
 
     private static MethodHandle findOwnMH(final String name, final Class<?> rtype, final Class<?>... types) {
--- a/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/resources/Messages.properties	Tue Oct 21 14:24:16 2014 +0100
+++ b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/resources/Messages.properties	Mon Oct 27 11:16:19 2014 +0100
@@ -73,6 +73,7 @@
 type.error.not.an.object={0} is not an Object
 type.error.not.a.boolean={0} is not a Boolean
 type.error.not.a.date={0} is not a Date
+type.error.not.a.java.importer={0} is not a JavaImporter object
 type.error.not.a.number={0} is not a Number
 type.error.not.a.regexp={0} is not a RegExp
 type.error.not.a.string={0} is not a String
--- a/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/resources/mozilla_compat.js	Tue Oct 21 14:24:16 2014 +0100
+++ b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/resources/mozilla_compat.js	Mon Oct 27 11:16:19 2014 +0100
@@ -105,7 +105,7 @@
         if (arguments.length < 1 || arguments.length > 2 ) {
             throw "sync(function [,object]) parameter count mismatch";
         }
-        return Packages.jdk.nashorn.api.scripting.ScriptUtils.makeSynchronizedFunction(func, syncobj);
+        return Java.synchronized(func, syncobj);
     }
 });
 
@@ -160,7 +160,7 @@
     configurable: true, enumerable: false, writable: true,
     value: function(state) {
         if (! state) {
-            state = java.util.Collections.newSetFromMap(new java.util.IdentityHashMap());
+            state = java.util.Collections.newSetFromMap(new java.util.HashMap());
         }
         if (state.contains(this)) {
             return "{}";
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/script/basic/JDK-8060011.js	Mon Oct 27 11:16:19 2014 +0100
@@ -0,0 +1,58 @@
+/*
+ * 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-8060011: Concatenating an array and converting it to Java gives wrong result
+ *
+ * @test
+ * @run
+ */
+
+
+function compareAsJavaArrays(a1, a2) {
+    var ja1 = Java.to(a1);
+    var ja2 = Java.to(a2);
+    if (ja1.length !== ja2.length) {
+        throw "different length";
+    }
+    for (var i = 0; i < ja1.length; i++) {
+        if (ja1[i] !== ja2[i]) {
+            throw "different element at " + i;
+        }
+    }
+    if (java.util.Arrays.toString(ja1) !== java.util.Arrays.toString(ja2)) {
+        throw "different string representation";
+    }
+}
+
+compareAsJavaArrays([0, 1, 2, 3],
+                    [0].concat([1, 2, 3]));
+compareAsJavaArrays([1000000000, 2000000000, 3000000000, 4000000000],
+                    [1000000000].concat([2000000000, 3000000000, 4000000000]));
+compareAsJavaArrays([0.5, 1.5, 2.5, 3.5],
+                    [0.5].concat([1.5, 2.5, 3.5]));
+compareAsJavaArrays(["0", "1", "2", "3"],
+                    ["0"].concat(["1", "2", "3"]));
+
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/script/basic/JDK-8060101.js	Mon Oct 27 11:16:19 2014 +0100
@@ -0,0 +1,54 @@
+/*
+ * 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-8060101: AssertionError: __noSuchProperty__ placeholder called from NativeJavaImporter
+ *
+ * @test
+ * @run
+ */
+
+var constant = 0.50;
+var ind = 0.0;
+
+// make sure callsites are exercised quite a few times
+// to induce megamorphic callsite for with/JavaImporter
+// combo - which triggered that AssertionError.
+for (var i = 0; i < 50; i++) {
+    var math = new JavaImporter(java.lang.StrictMath);
+    ind += 10.0;
+    with (math) {
+        StrictMath.exp(-constant*ind);
+    }
+}
+
+for (var i = 0; i < 50; i++) {
+    var math = new JavaImporter(java.lang.StrictMath);
+    try {
+        math.Foo();
+    } catch (e) {
+        if (! (e instanceof TypeError)) {
+            throw e;
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/script/basic/JDK-8061113.js	Mon Oct 27 11:16:19 2014 +0100
@@ -0,0 +1,35 @@
+/*
+ * 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-8061113: Boolean used as optimistic call return type
+ *
+ * @test
+ * @run
+ */
+
+function testcase() {
+    var a = {x:0};
+    return (function () {return a.x === 0})();
+}
+print(testcase());
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/script/basic/JDK-8061113.js.EXPECTED	Mon Oct 27 11:16:19 2014 +0100
@@ -0,0 +1,1 @@
+true
--- a/test/script/basic/convert.js	Tue Oct 21 14:24:16 2014 +0100
+++ b/test/script/basic/convert.js	Mon Oct 27 11:16:19 2014 +0100
@@ -42,7 +42,7 @@
 
 // object to Map
 obj = { foo: 333, bar: 'hello'};
-var map = ScriptUtils.convert(obj, java.util.Map.class);
+var map = ScriptUtils.wrap(obj);
 print(map instanceof java.util.Map);
 for (m in map) {
    print(m + " " + map[m]);
--- a/test/script/nosecurity/JDK-8044798.js	Tue Oct 21 14:24:16 2014 +0100
+++ b/test/script/nosecurity/JDK-8044798.js	Mon Oct 27 11:16:19 2014 +0100
@@ -25,6 +25,8 @@
  * JDK-8044798: API for debugging Nashorn
  *
  * @test
+ * @option -Dnashorn.mirror.always=false
+ * @fork
  * @run
  */
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/script/nosecurity/JDK-8060688.js	Mon Oct 27 11:16:19 2014 +0100
@@ -0,0 +1,56 @@
+/*
+ * 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-8060688: Nashorn: Generated script class name fails --verify-code for names with special chars
+ *
+ * @test
+ * @run
+ */
+
+var NashornEngineFactory = Java.type("jdk.nashorn.api.scripting.NashornScriptEngineFactory");
+var ScriptEngine = Java.type("javax.script.ScriptEngine");
+var ScriptContext = Java.type("javax.script.ScriptContext");
+
+var factory = new NashornEngineFactory();
+
+var e = factory.getScriptEngine("--verify-code");
+
+function evalAndCheck(code) {
+    try {
+        e.eval(code);
+    } catch (exp) {
+        exp.printStackTrace();
+    }
+}
+
+// check default name
+evalAndCheck("var a = 3");
+// check few names with special chars
+var scontext = e.context;
+scontext.setAttribute(ScriptEngine.FILENAME, "<myscript>", ScriptContext.ENGINE_SCOPE);
+evalAndCheck("var h = 'hello'");
+scontext.setAttribute(ScriptEngine.FILENAME, "[myscript]", ScriptContext.ENGINE_SCOPE);
+evalAndCheck("var foo = 'world'");
+scontext.setAttribute(ScriptEngine.FILENAME, ";/\\$.", ScriptContext.ENGINE_SCOPE);
+evalAndCheck("var foo = 'helloworld'");
--- a/test/src/jdk/nashorn/api/scripting/ScriptEngineSecurityTest.java	Tue Oct 21 14:24:16 2014 +0100
+++ b/test/src/jdk/nashorn/api/scripting/ScriptEngineSecurityTest.java	Mon Oct 27 11:16:19 2014 +0100
@@ -168,42 +168,6 @@
         }
     }
 
-    @Test
-    /**
-     * Check that script can't implement sensitive package interfaces.
-     */
-    public void checkSensitiveInterfaceImplTest() throws ScriptException {
-        if (System.getSecurityManager() == null) {
-            // pass vacuously
-            return;
-        }
-
-        final ScriptEngineManager m = new ScriptEngineManager();
-        final ScriptEngine e = m.getEngineByName("nashorn");
-        final Object[] holder = new Object[1];
-        e.put("holder", holder);
-        // put an empty script object into array
-        e.eval("holder[0] = {}");
-        // holder[0] is an object of some subclass of ScriptObject
-        final Class<?> ScriptObjectClass = holder[0].getClass().getSuperclass();
-        final Class<?> PropertyAccessClass = ScriptObjectClass.getInterfaces()[0];
-        // implementation methods for PropertyAccess class
-        e.eval("function set() {}; function get() {}; function getInt(){} " +
-               "function getDouble(){}; function getLong() {}; " +
-               "this.delete = function () {}; function has() {}; " +
-               "function hasOwnProperty() {}");
-
-        // get implementation of a restricted package interface
-        try {
-            log(Objects.toString(((Invocable)e).getInterface((Class<?>)PropertyAccessClass)));
-            fail("should have thrown SecurityException");
-        } catch (final Exception exp) {
-            if (! (exp instanceof SecurityException)) {
-                fail("SecurityException expected, got " + exp);
-            }
-        }
-    }
-
     // @bug 8032948: Nashorn linkages awry
     public static class FakeProxy extends Proxy {
         public FakeProxy(final InvocationHandler ih) {
--- a/test/src/jdk/nashorn/api/scripting/ScriptEngineTest.java	Tue Oct 21 14:24:16 2014 +0100
+++ b/test/src/jdk/nashorn/api/scripting/ScriptEngineTest.java	Mon Oct 27 11:16:19 2014 +0100
@@ -38,6 +38,7 @@
 import java.util.concurrent.Callable;
 import javax.script.Compilable;
 import javax.script.CompiledScript;
+import javax.script.Invocable;
 import javax.script.ScriptContext;
 import javax.script.ScriptEngine;
 import javax.script.ScriptEngineFactory;
@@ -629,6 +630,40 @@
         assertEquals(enumerable, Boolean.FALSE);
     }
 
+    public static class Context {
+        private Object myobj;
+
+        public void set(Object o) {
+            myobj = o;
+        }
+
+        public Object get() {
+            return myobj;
+        }
+    }
+
+    // @bug 8050977: Java8 Javascript Nashorn exception:
+    // no current Global instance for nashorn
+    @Test
+    public void currentGlobalMissingTest() throws Exception {
+        final ScriptEngineManager manager = new ScriptEngineManager();
+        final ScriptEngine e = manager.getEngineByName("nashorn");
+
+        final Context ctx = new Context();
+        e.put("ctx", ctx);
+        e.eval("var obj = { foo: function(str) { return str.toUpperCase() } }");
+        e.eval("ctx.set(obj)");
+        final Invocable inv = (Invocable)e;
+        assertEquals("HELLO", inv.invokeMethod(ctx.get(), "foo", "hello"));
+        // try object literal
+        e.eval("ctx.set({ bar: function(str) { return str.toLowerCase() } })");
+        assertEquals("hello", inv.invokeMethod(ctx.get(), "bar", "HELLO"));
+        // try array literal
+        e.eval("var arr = [ 'hello', 'world' ]");
+        e.eval("ctx.set(arr)");
+        assertEquals("helloworld", inv.invokeMethod(ctx.get(), "join", ""));
+    }
+
     private static void checkProperty(final ScriptEngine e, final String name)
         throws ScriptException {
         final String value = System.getProperty(name);
--- a/test/src/jdk/nashorn/internal/codegen/CompilerTest.java	Tue Oct 21 14:24:16 2014 +0100
+++ b/test/src/jdk/nashorn/internal/codegen/CompilerTest.java	Mon Oct 27 11:16:19 2014 +0100
@@ -72,6 +72,7 @@
         options.set("print.parse", true);
         options.set("scripting", true);
         options.set("const.as.var", true);
+        options.set("verify.code", true);
 
         final ErrorManager errors = new ErrorManager() {
             @Override
--- a/test/src/jdk/nashorn/internal/runtime/TrustedScriptEngineTest.java	Tue Oct 21 14:24:16 2014 +0100
+++ b/test/src/jdk/nashorn/internal/runtime/TrustedScriptEngineTest.java	Mon Oct 27 11:16:19 2014 +0100
@@ -325,4 +325,29 @@
         );
         assertEquals(ret, 10, "Parsed and executed OK");
     }
+
+    @Test
+    public void evalDefaultFileNameTest() throws ScriptException {
+        final NashornScriptEngineFactory fac = new NashornScriptEngineFactory();
+        final ScriptEngine engine = fac.getScriptEngine(new String[] { "--verify-code=true" });
+        // default FILENAME being "<eval>" make sure generated code bytecode verifies.
+        engine.eval("var a = 3;");
+    }
+
+    @Test
+    public void evalFileNameWithSpecialCharsTest() throws ScriptException {
+        final NashornScriptEngineFactory fac = new NashornScriptEngineFactory();
+        final ScriptEngine engine = fac.getScriptEngine(new String[] { "--verify-code=true" });
+        final ScriptContext ctxt = new SimpleScriptContext();
+        // use file name with "dangerous" chars.
+        ctxt.setAttribute(ScriptEngine.FILENAME, "<myscript>", ScriptContext.ENGINE_SCOPE);
+        engine.eval("var a = 3;");
+        ctxt.setAttribute(ScriptEngine.FILENAME, "[myscript]", ScriptContext.ENGINE_SCOPE);
+        engine.eval("var h = 'hello';");
+        ctxt.setAttribute(ScriptEngine.FILENAME, ";/\\$.", ScriptContext.ENGINE_SCOPE);
+        engine.eval("var foo = 'world';");
+        // name used by jjs shell tool for the interactive mode
+        ctxt.setAttribute(ScriptEngine.FILENAME, "<shell>", ScriptContext.ENGINE_SCOPE);
+        engine.eval("var foo = 'world';");
+    }
 }