8035836: Array performance improvements
authorlagergren
Mon, 03 Mar 2014 11:24:44 +0100
changeset 24720 75f8388b79df
parent 24719 f726e9d67629
child 24721 81f70e23cd3b
8035836: Array performance improvements Summary: Implement typed arrays with native byte buffers and do fast linking for all continuous arrays Reviewed-by: attila, jlaskey, sundar, hannesw
nashorn/bin/runnormal.sh
nashorn/bin/runnormaldual.sh
nashorn/bin/runopt.sh
nashorn/bin/runoptdual.sh
nashorn/bin/runoptdualcatch.sh
nashorn/bin/verbose_octane.bat
nashorn/bin/verbose_octane.sh
nashorn/buildtools/nasgen/src/jdk/nashorn/internal/tools/nasgen/MemberInfo.java
nashorn/make/build-benchmark.xml
nashorn/src/jdk/internal/dynalink/ChainedCallSite.java
nashorn/src/jdk/internal/dynalink/DynamicLinker.java
nashorn/src/jdk/internal/dynalink/linker/GuardedInvocation.java
nashorn/src/jdk/internal/dynalink/linker/GuardedTypeConversion.java
nashorn/src/jdk/internal/dynalink/linker/LinkRequest.java
nashorn/src/jdk/internal/dynalink/support/LinkRequestImpl.java
nashorn/src/jdk/internal/dynalink/support/RuntimeContextLinkRequestImpl.java
nashorn/src/jdk/internal/dynalink/support/TypeConverterFactory.java
nashorn/src/jdk/nashorn/internal/codegen/CodeGenerator.java
nashorn/src/jdk/nashorn/internal/codegen/CompilationEnvironment.java
nashorn/src/jdk/nashorn/internal/codegen/Compiler.java
nashorn/src/jdk/nashorn/internal/codegen/CompilerConstants.java
nashorn/src/jdk/nashorn/internal/codegen/Label.java
nashorn/src/jdk/nashorn/internal/codegen/MapCreator.java
nashorn/src/jdk/nashorn/internal/codegen/Namespace.java
nashorn/src/jdk/nashorn/internal/codegen/ObjectClassGenerator.java
nashorn/src/jdk/nashorn/internal/ir/AccessNode.java
nashorn/src/jdk/nashorn/internal/ir/FunctionNode.java
nashorn/src/jdk/nashorn/internal/ir/IdentNode.java
nashorn/src/jdk/nashorn/internal/ir/IndexNode.java
nashorn/src/jdk/nashorn/internal/lookup/Lookup.java
nashorn/src/jdk/nashorn/internal/lookup/MethodHandleFactory.java
nashorn/src/jdk/nashorn/internal/lookup/MethodHandleFunctionality.java
nashorn/src/jdk/nashorn/internal/objects/ArrayBufferView.java
nashorn/src/jdk/nashorn/internal/objects/Global.java
nashorn/src/jdk/nashorn/internal/objects/NativeArray.java
nashorn/src/jdk/nashorn/internal/objects/NativeArrayBuffer.java
nashorn/src/jdk/nashorn/internal/objects/NativeDebug.java
nashorn/src/jdk/nashorn/internal/objects/NativeError.java
nashorn/src/jdk/nashorn/internal/objects/NativeFloat32Array.java
nashorn/src/jdk/nashorn/internal/objects/NativeFloat64Array.java
nashorn/src/jdk/nashorn/internal/objects/NativeInt16Array.java
nashorn/src/jdk/nashorn/internal/objects/NativeInt32Array.java
nashorn/src/jdk/nashorn/internal/objects/NativeInt8Array.java
nashorn/src/jdk/nashorn/internal/objects/NativeMath.java
nashorn/src/jdk/nashorn/internal/objects/NativeNumber.java
nashorn/src/jdk/nashorn/internal/objects/NativeObject.java
nashorn/src/jdk/nashorn/internal/objects/NativeRegExp.java
nashorn/src/jdk/nashorn/internal/objects/NativeString.java
nashorn/src/jdk/nashorn/internal/objects/NativeUint16Array.java
nashorn/src/jdk/nashorn/internal/objects/NativeUint32Array.java
nashorn/src/jdk/nashorn/internal/objects/NativeUint8Array.java
nashorn/src/jdk/nashorn/internal/objects/NativeUint8ClampedArray.java
nashorn/src/jdk/nashorn/internal/runtime/AccessorProperty.java
nashorn/src/jdk/nashorn/internal/runtime/GlobalFunctions.java
nashorn/src/jdk/nashorn/internal/runtime/NativeJavaPackage.java
nashorn/src/jdk/nashorn/internal/runtime/Property.java
nashorn/src/jdk/nashorn/internal/runtime/PropertyHashMap.java
nashorn/src/jdk/nashorn/internal/runtime/RecompilableScriptFunctionData.java
nashorn/src/jdk/nashorn/internal/runtime/ScriptFunction.java
nashorn/src/jdk/nashorn/internal/runtime/ScriptFunctionData.java
nashorn/src/jdk/nashorn/internal/runtime/ScriptLoader.java
nashorn/src/jdk/nashorn/internal/runtime/ScriptObject.java
nashorn/src/jdk/nashorn/internal/runtime/SetMethodCreator.java
nashorn/src/jdk/nashorn/internal/runtime/SpillProperty.java
nashorn/src/jdk/nashorn/internal/runtime/WithObject.java
nashorn/src/jdk/nashorn/internal/runtime/arrays/ArrayData.java
nashorn/src/jdk/nashorn/internal/runtime/arrays/ContinuousArray.java
nashorn/src/jdk/nashorn/internal/runtime/arrays/ContinuousArrayData.java
nashorn/src/jdk/nashorn/internal/runtime/arrays/IntArrayData.java
nashorn/src/jdk/nashorn/internal/runtime/arrays/LongArrayData.java
nashorn/src/jdk/nashorn/internal/runtime/arrays/NumberArrayData.java
nashorn/src/jdk/nashorn/internal/runtime/arrays/ObjectArrayData.java
nashorn/src/jdk/nashorn/internal/runtime/arrays/TypedArrayData.java
nashorn/src/jdk/nashorn/internal/runtime/linker/JavaAdapterFactory.java
nashorn/src/jdk/nashorn/internal/runtime/linker/LinkerCallSite.java
nashorn/src/jdk/nashorn/internal/runtime/linker/NashornGuards.java
nashorn/src/jdk/nashorn/internal/runtime/linker/NashornLinker.java
nashorn/src/jdk/nashorn/internal/runtime/resources/Messages.properties
nashorn/test/examples/string-micro.js
nashorn/test/script/basic/JDK-8020357.js
nashorn/test/script/basic/NASHORN-377.js
nashorn/test/script/basic/typedarrays.js
--- a/nashorn/bin/runnormal.sh	Wed Feb 26 13:17:57 2014 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,3 +0,0 @@
-#!/bin/sh
-FILENAME="./pessimistic_$(date|sed "s/ /_/g"|sed "s/:/_/g").jfr"
-$JAVA_HOME/bin/java -ea -Xms2G -Xmx2G -XX:+UnlockCommercialFeatures -XX:+FlightRecorder -XX:FlightRecorderOptions=defaultrecording=true,disk=true,dumponexit=true,dumponexitpath=$FILENAME,stackdepth=128 -Djava.ext.dirs=dist jdk.nashorn.tools.Shell ${@}
--- a/nashorn/bin/runnormaldual.sh	Wed Feb 26 13:17:57 2014 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,3 +0,0 @@
-#!/bin/sh
-FILENAME="./optimistic_dual_$(date|sed "s/ /_/g"|sed "s/:/_/g").jfr"
-$JAVA_HOME/bin/java -ea -Dnashorn.fields.dual -Xms2G -Xmx2G -XX:+UnlockCommercialFeatures -XX:+FlightRecorder -XX:FlightRecorderOptions=defaultrecording=true,disk=true,dumponexit=true,dumponexitpath=$FILENAME,stackdepth=128 -XX:TypeProfileLevel=222 -XX:+UnlockExperimentalVMOptions -XX:+UseTypeSpeculation -XX:+UseMathExactIntrinsics ${@}
--- a/nashorn/bin/runopt.sh	Wed Feb 26 13:17:57 2014 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,3 +0,0 @@
-#!/bin/sh
-FILENAME="./optimistic_$(date|sed "s/ /_/g"|sed "s/:/_/g").jfr"
-$JAVA_HOME/bin/java -ea -Dnashorn.optimistic -Dnashorn.fastrewrite -Xms2G -Xmx2G -XX:+UnlockCommercialFeatures -XX:+FlightRecorder -XX:FlightRecorderOptions=defaultrecording=true,disk=true,dumponexit=true,dumponexitpath=$FILENAME,stackdepth=128 -XX:TypeProfileLevel=222 -XX:+UnlockExperimentalVMOptions -XX:+UseTypeSpeculation -XX:-UseMathExactIntrinsics -Xbootclasspath/p:dist/nashorn.jar jdk.nashorn.tools.Shell ${@} 
--- a/nashorn/bin/runoptdual.sh	Wed Feb 26 13:17:57 2014 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,3 +0,0 @@
-#!/bin/sh
-FILENAME="./optimistic_dual_$(date|sed "s/ /_/g"|sed "s/:/_/g").jfr"
-$JAVA_HOME/bin/java -ea -Dnashorn.fields.dual -Dnashorn.optimistic -Xms2G -Xmx2G -XX:+UnlockCommercialFeatures -XX:+FlightRecorder -XX:FlightRecorderOptions=defaultrecording=true,disk=true,dumponexit=true,dumponexitpath=$FILENAME,stackdepth=128 -XX:TypeProfileLevel=222 -XX:+UnlockExperimentalVMOptions -XX:+UseTypeSpeculation -XX:-UseMathExactIntrinsics ${@}
--- a/nashorn/bin/runoptdualcatch.sh	Wed Feb 26 13:17:57 2014 +0100
+++ b/nashorn/bin/runoptdualcatch.sh	Mon Mar 03 11:24:44 2014 +0100
@@ -2,15 +2,18 @@
 
 #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"
 
-FILENAME="./optimistic_dual_catch$(date|sed "s/ /_/g"|sed "s/:/_/g").jfr"
+FILENAME="./optimistic_dual_catch_$(date|sed "s/ /_/g"|sed "s/:/_/g").jfr"
+
+DIR=/Users/marcus/src/tip/
+FAST_CATCH_COMBINATOR=$DIR/bin/fastCatchCombinator.jar
+NASHORN_JAR=$DIR/dist/nashorn.jar
 
 $JAVA_HOME/bin/java \
+$FLAGS \
 -ea \
 -esa \
-$FLAGS \
--Dnashorn.fastrewrite \
 -Dnashorn.optimistic \
--Xbootclasspath/p:/Users/marcus/src/tip/dist/nashorn.jar \
+-Xbootclasspath/p:$FAST_CATCH_COMBINATOR:$NASHORN_JAR \
 -Xms2G -Xmx2G \
 -XX:+UnlockCommercialFeatures \
 -XX:+FlightRecorder \
@@ -23,3 +26,8 @@
 -cp $CLASSPATH:../build/test/classes/ \
 jdk.nashorn.tools.Shell ${@}
 
+#-XX:+UnlockDiagnosticVMOptions \
+#-XX:+ShowHiddenFrames \
+#-XX:+PrintOptoAssembly \
+#-XX:-TieredCompilation \
+#-XX:CICompilerCount=1 \
--- a/nashorn/bin/verbose_octane.bat	Wed Feb 26 13:17:57 2014 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,59 +0,0 @@
-rem
-rem Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved.
-rem DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
-rem 
-rem This code is free software; you can redistribute it and/or modify it
-rem under the terms of the GNU General Public License version 2 only, as
-rem published by the Free Software Foundation.
-rem 
-rem This code is distributed in the hope that it will be useful, but WITHOUT
-rem ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
-rem FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
-rem version 2 for more details (a copy is included in the LICENSE file that
-rem accompanied this code).
-rem 
-rem You should have received a copy of the GNU General Public License version
-rem 2 along with this work; if not, write to the Free Software Foundation,
-rem Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
-rem 
-rem Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
-rem or visit www.oracle.com if you need additional information or have any
-rem questions.
-rem
-@echo off
-
-if "%JAVA_HOME%" neq "" (
-  call :run "%JAVA_HOME%/bin/java"
-) else (
-  call :run java
-)
-goto :EOF
-
-:run
-setlocal
-set NASHORN_JAR=dist/nashorn.jar
-set JVM_FLAGS=-Xms2G -Xmx2G -XX:-TieredCompilation -server -esa -ea -jar %NASHORN_JAR%
-set JVM_FLAGS7=-Xbootclasspath/p:%NASHORN_JAR% %JVM_FLAGS%
-set OCTANE_ARGS=--verbose --iterations 7
-
-%1 -fullversion 2>&1 | findstr /L /C:"version ""1.7"
-if %errorlevel% equ 0 (
-  set CMD=%1 %JVM_FLAGS7%
-) else (
-  %1 -fullversion
-  set CMD=%1 %JVM_FLAGS%
-)
-
-%CMD% test/script/basic/run-octane.js -- test/script/external/octane/box2d.js %OCTANE_ARGS%
-%CMD% test/script/basic/run-octane.js -- test/script/external/octane/code-load.js %OCTANE_ARGS%
-%CMD% test/script/basic/run-octane.js -- test/script/external/octane/crypto.js %OCTANE_ARGS%
-%CMD% test/script/basic/run-octane.js -- test/script/external/octane/deltablue.js %OCTANE_ARGS%
-%CMD% test/script/basic/run-octane.js -- test/script/external/octane/gbemu.js %OCTANE_ARGS%
-%CMD% test/script/basic/run-octane.js -- test/script/external/octane/navier-stokes.js %OCTANE_ARGS%
-%CMD% test/script/basic/run-octane.js -- test/script/external/octane/pdfjs.js %OCTANE_ARGS%
-%CMD% test/script/basic/run-octane.js -- test/script/external/octane/raytrace.js %OCTANE_ARGS%
-%CMD% test/script/basic/run-octane.js -- test/script/external/octane/regexp.js %OCTANE_ARGS%
-%CMD% test/script/basic/run-octane.js -- test/script/external/octane/richards.js %OCTANE_ARGS%
-%CMD% test/script/basic/run-octane.js -- test/script/external/octane/splay.js %OCTANE_ARGS%
-endlocal
-goto :EOF
--- a/nashorn/bin/verbose_octane.sh	Wed Feb 26 13:17:57 2014 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,58 +0,0 @@
-#!/bin/bash
-# Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved.
-# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
-# 
-# This code is free software; you can redistribute it and/or modify it
-# under the terms of the GNU General Public License version 2 only, as
-# published by the Free Software Foundation.
-# 
-# This code is distributed in the hope that it will be useful, but WITHOUT
-# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
-# FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
-# version 2 for more details (a copy is included in the LICENSE file that
-# accompanied this code).
-# 
-# You should have received a copy of the GNU General Public License version
-# 2 along with this work; if not, write to the Free Software Foundation,
-# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
-# 
-# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
-# or visit www.oracle.com if you need additional information or have any
-# questions.
-#
-
-ITERS=$1
-if [ -z $ITERS ]; then 
-    ITERS=7
-fi
-NASHORN_JAR=dist/nashorn.jar
-JVM_FLAGS="-Djava.ext.dirs=`dirname $0`/../dist:$JAVA_HOME/jre/lib/ext -XX:+UnlockDiagnosticVMOptions -Dnashorn.unstable.relink.threshold=8 -Xms2G -Xmx2G -XX:+TieredCompilation -server -jar ${NASHORN_JAR}"
-JVM_FLAGS7="-Xbootclasspath/p:${NASHORN_JAR} ${JVM_FLAGS}"
-OCTANE_ARGS="--verbose --iterations ${ITERS}"
-
-BENCHMARKS=( "box2d.js" "code-load.js" "crypto.js" "deltablue.js" "earley-boyer.js" "gbemu.js" "navier-stokes.js" "pdfjs.js" "raytrace.js" "regexp.js" "richards.js" "splay.js" )
-# TODO mandreel.js has metaspace issues
-
-if [ ! -z $JAVA7_HOME ]; then	
-    echo "running ${ITERS} iterations with java7 using JAVA_HOME=${JAVA7_HOME}..."
-    for BENCHMARK in "${BENCHMARKS[@]}"
-    do 
-	CMD="${JAVA7_HOME}/bin/java ${JVM_FLAGS} test/script/basic/run-octane.js -- test/script/external/octane/${BENCHMARK} ${OCTANE_ARGS}"
-	$CMD
-    done
-else
-    echo "no JAVA7_HOME set. skipping java7"
-fi
-
-if [ ! -z $JAVA8_HOME ]; then
-    echo "running ${ITERS} iterations with java8 using JAVA_HOME=${JAVA8_HOME}..."   
-    for BENCHMARK in "${BENCHMARKS[@]}"
-    do 
-	CMD="${JAVA8_HOME}/bin/java ${JVM_FLAGS} test/script/basic/run-octane.js -- test/script/external/octane/${BENCHMARK} ${OCTANE_ARGS}"
-	$CMD
-    done
-else 
-    echo "no JAVA8_HOME set."
-fi
-
-echo "Done"
--- a/nashorn/buildtools/nasgen/src/jdk/nashorn/internal/tools/nasgen/MemberInfo.java	Wed Feb 26 13:17:57 2014 +0100
+++ b/nashorn/buildtools/nasgen/src/jdk/nashorn/internal/tools/nasgen/MemberInfo.java	Mon Mar 03 11:24:44 2014 +0100
@@ -248,17 +248,17 @@
         if (kind == Kind.CONSTRUCTOR) {
             final Type returnType = Type.getReturnType(javaDesc);
             if (! returnType.toString().equals(OBJECT_DESC)) {
-                error("return value should be of Object type, found" + returnType);
+                error("return value should be of Object type, found " + returnType);
             }
             final Type[] argTypes = Type.getArgumentTypes(javaDesc);
             if (argTypes.length < 2) {
                 error("constructor methods should have at least 2 args");
             }
             if (! argTypes[0].equals(Type.BOOLEAN_TYPE)) {
-                error("first argument should be of boolean type, found" + argTypes[0]);
+                error("first argument should be of boolean type, found " + argTypes[0]);
             }
             if (! argTypes[1].toString().equals(OBJECT_DESC)) {
-                error("second argument should be of Object type, found" + argTypes[0]);
+                error("second argument should be of Object type, found " + argTypes[0]);
             }
 
             if (argTypes.length > 2) {
@@ -284,7 +284,7 @@
                 error("function methods should have at least 1 arg");
             }
             if (! argTypes[0].toString().equals(OBJECT_DESC)) {
-                error("first argument should be of Object type, found" + argTypes[0]);
+                error("first argument should be of Object type, found " + argTypes[0]);
             }
 
             if (argTypes.length > 1) {
--- a/nashorn/make/build-benchmark.xml	Wed Feb 26 13:17:57 2014 +0100
+++ b/nashorn/make/build-benchmark.xml	Mon Mar 03 11:24:44 2014 +0100
@@ -400,6 +400,8 @@
           fork="true"
           dir=".">
       <jvmarg line="${run.test.jvmargs.octane} -Xms${run.test.xms} -Xmx${run.test.xmx}"/>
+      <arg value="-opt"/>
+      <arg value="9"/>
       <arg value="${octane-test-sys-prop.test.js.framework}"/>
       <arg value="${octane-tests}"/>
       <arg value="--runtime"/>
--- a/nashorn/src/jdk/internal/dynalink/ChainedCallSite.java	Wed Feb 26 13:17:57 2014 +0100
+++ b/nashorn/src/jdk/internal/dynalink/ChainedCallSite.java	Mon Mar 03 11:24:44 2014 +0100
@@ -88,6 +88,7 @@
 import java.util.Iterator;
 import java.util.LinkedList;
 import java.util.concurrent.atomic.AtomicReference;
+
 import jdk.internal.dynalink.linker.GuardedInvocation;
 import jdk.internal.dynalink.support.AbstractRelinkableCallSite;
 import jdk.internal.dynalink.support.Lookup;
@@ -103,8 +104,27 @@
  * handle is always at the start of the chain.
  */
 public class ChainedCallSite extends AbstractRelinkableCallSite {
-    private static final MethodHandle PRUNE = Lookup.findOwnSpecial(MethodHandles.lookup(), "prune", MethodHandle.class,
-            MethodHandle.class);
+    private static final MethodHandle PRUNE_CATCHES =
+            MethodHandles.insertArguments(
+                    Lookup.findOwnSpecial(
+                            MethodHandles.lookup(),
+                            "prune",
+                            MethodHandle.class,
+                            MethodHandle.class,
+                            boolean.class),
+                    2,
+                    true);
+
+    private static final MethodHandle PRUNE_SWITCHPOINTS =
+            MethodHandles.insertArguments(
+                    Lookup.findOwnSpecial(
+                            MethodHandles.lookup(),
+                            "prune",
+                            MethodHandle.class,
+                            MethodHandle.class,
+                            boolean.class),
+                    2,
+                    false);
 
     private final AtomicReference<LinkedList<GuardedInvocation>> invocations = new AtomicReference<>();
 
@@ -127,23 +147,25 @@
 
     @Override
     public void relink(GuardedInvocation guardedInvocation, MethodHandle fallback) {
-        relinkInternal(guardedInvocation, fallback, false);
+        relinkInternal(guardedInvocation, fallback, false, false);
     }
 
     @Override
     public void resetAndRelink(GuardedInvocation guardedInvocation, MethodHandle fallback) {
-        relinkInternal(guardedInvocation, fallback, true);
+        relinkInternal(guardedInvocation, fallback, true, false);
     }
 
-    private MethodHandle relinkInternal(GuardedInvocation invocation, MethodHandle relink, boolean reset) {
+    private MethodHandle relinkInternal(GuardedInvocation invocation, MethodHandle relink, boolean reset, boolean removeCatches) {
         final LinkedList<GuardedInvocation> currentInvocations = invocations.get();
         @SuppressWarnings({ "unchecked", "rawtypes" })
         final LinkedList<GuardedInvocation> newInvocations =
             currentInvocations == null || reset ? new LinkedList<>() : (LinkedList)currentInvocations.clone();
 
-        // First, prune the chain of invalidated switchpoints.
+        // First, prune the chain of invalidated switchpoints, we always do this
+        // We also remove any catches if the remove catches flag is set
         for(Iterator<GuardedInvocation> it = newInvocations.iterator(); it.hasNext();) {
-            if(it.next().hasBeenInvalidated()) {
+            final GuardedInvocation inv = it.next();
+            if(inv.hasBeenInvalidated() || (removeCatches && inv.getException() != null)) {
                 it.remove();
             }
         }
@@ -160,12 +182,13 @@
 
         // prune-and-invoke is used as the fallback for invalidated switchpoints. If a switchpoint gets invalidated, we
         // rebuild the chain and get rid of all invalidated switchpoints instead of letting them linger.
-        final MethodHandle pruneAndInvoke = makePruneAndInvokeMethod(relink);
+        final MethodHandle pruneAndInvokeSwitchPoints = makePruneAndInvokeMethod(relink, getPruneSwitchpoints());
+        final MethodHandle pruneAndInvokeCatches      = makePruneAndInvokeMethod(relink, getPruneCatches());
 
         // Fold the new chain
         MethodHandle target = relink;
         for(GuardedInvocation inv: newInvocations) {
-            target = inv.compose(pruneAndInvoke, target);
+            target = inv.compose(target, pruneAndInvokeSwitchPoints, pruneAndInvokeCatches);
         }
 
         // If nobody else updated the call site while we were rebuilding the chain, set the target to our chain. In case
@@ -178,14 +201,30 @@
     }
 
     /**
+     * Get the switchpoint pruning function for a chained call site
+     * @return function that removes invalidated switchpoints tied to callsite guard chain and relinks
+     */
+    protected MethodHandle getPruneSwitchpoints() {
+        return PRUNE_SWITCHPOINTS;
+    }
+
+    /**
+     * Get the catch pruning function for a chained call site
+     * @return function that removes all catches tied to callsite guard chain and relinks
+     */
+    protected MethodHandle getPruneCatches() {
+        return PRUNE_CATCHES;
+    }
+
+    /**
      * Creates a method that rebuilds our call chain, pruning it of any invalidated switchpoints, and then invokes that
      * chain.
      * @param relink the ultimate fallback for the chain (the {@code DynamicLinker}'s relink).
      * @return a method handle for prune-and-invoke
      */
-    private MethodHandle makePruneAndInvokeMethod(MethodHandle relink) {
+    private MethodHandle makePruneAndInvokeMethod(MethodHandle relink, MethodHandle prune) {
         // Bind prune to (this, relink)
-        final MethodHandle boundPrune = MethodHandles.insertArguments(PRUNE, 0, this, relink);
+        final MethodHandle boundPrune = MethodHandles.insertArguments(prune, 0, this, relink);
         // Make it ignore all incoming arguments
         final MethodHandle ignoreArgsPrune = MethodHandles.dropArguments(boundPrune, 0, type().parameterList());
         // Invoke prune, then invoke the call site target with original arguments
@@ -193,7 +232,7 @@
     }
 
     @SuppressWarnings("unused")
-    private MethodHandle prune(MethodHandle relink) {
-        return relinkInternal(null, relink, false);
+    private MethodHandle prune(MethodHandle relink, final boolean catches) {
+        return relinkInternal(null, relink, false, catches);
     }
 }
--- a/nashorn/src/jdk/internal/dynalink/DynamicLinker.java	Wed Feb 26 13:17:57 2014 +0100
+++ b/nashorn/src/jdk/internal/dynalink/DynamicLinker.java	Mon Mar 03 11:24:44 2014 +0100
@@ -227,8 +227,8 @@
         final boolean callSiteUnstable = unstableDetectionEnabled && relinkCount >= unstableRelinkThreshold;
         final LinkRequest linkRequest =
                 runtimeContextArgCount == 0 ?
-                        new LinkRequestImpl(callSiteDescriptor, callSite, callSiteUnstable, arguments) :
-                        new RuntimeContextLinkRequestImpl(callSiteDescriptor, callSite, callSiteUnstable, arguments, runtimeContextArgCount);
+                        new LinkRequestImpl(callSiteDescriptor, callSite, relinkCount, callSiteUnstable, arguments) :
+                        new RuntimeContextLinkRequestImpl(callSiteDescriptor, callSite, relinkCount, callSiteUnstable, arguments, runtimeContextArgCount);
 
         GuardedInvocation guardedInvocation = linkerServices.getGuardedInvocation(linkRequest);
 
--- a/nashorn/src/jdk/internal/dynalink/linker/GuardedInvocation.java	Wed Feb 26 13:17:57 2014 +0100
+++ b/nashorn/src/jdk/internal/dynalink/linker/GuardedInvocation.java	Mon Mar 03 11:24:44 2014 +0100
@@ -89,6 +89,7 @@
 import java.lang.invoke.SwitchPoint;
 import java.lang.invoke.WrongMethodTypeException;
 import java.util.List;
+
 import jdk.internal.dynalink.CallSiteDescriptor;
 import jdk.internal.dynalink.support.CatchExceptionCombinator;
 import jdk.internal.dynalink.support.Guards;
@@ -344,21 +345,44 @@
      * @return a composite method handle.
      */
     public MethodHandle compose(MethodHandle fallback) {
-        return compose(fallback, fallback);
+        return compose(fallback, fallback, fallback);
     }
 
     /**
      * Composes the invocation, switchpoint, and the guard into a composite method handle that knows how to fall back.
      * @param switchpointFallback the fallback method handle in case switchpoint is invalidated.
      * @param guardFallback the fallback method handle in case guard returns false.
+     * @param catchFallback the fallback method in case the exception handler triggers
      * @return a composite method handle.
      */
-    public MethodHandle compose(MethodHandle switchpointFallback, MethodHandle guardFallback) {
+    public MethodHandle compose(MethodHandle guardFallback, MethodHandle switchpointFallback, MethodHandle catchFallback) {
         final MethodHandle guarded =
-                guard == null ? invocation : MethodHandles.guardWithTest(guard, invocation, guardFallback);
-        final MethodHandle catchGuarded = exception == null ? guarded : catchException(guarded, exception,
-                MethodHandles.dropArguments(guardFallback, 0, exception));
-        return switchPoint == null ? catchGuarded : switchPoint.guardWithTest(catchGuarded, switchpointFallback);
+                guard == null ?
+                        invocation :
+                        MethodHandles.guardWithTest(
+                                guard,
+                                invocation,
+                                guardFallback);
+
+        final MethodHandle catchGuarded =
+                exception == null ?
+                        guarded :
+                        catchException(
+                                guarded,
+                                exception,
+                                MethodHandles.dropArguments(
+                                    catchFallback,
+                                    0,
+                                    exception));
+
+        final MethodHandle spGuarded =
+                switchPoint == null ?
+                        catchGuarded :
+                        switchPoint.guardWithTest(
+                                catchGuarded,
+                                switchpointFallback);
+
+        return spGuarded;
     }
 
     private static MethodHandle catchException(final MethodHandle target, final Class<? extends Throwable> exType, final MethodHandle handler) {
@@ -367,6 +391,7 @@
         }
         return MethodHandles.catchException(target, exType, handler);
     }
+
     private static void assertType(MethodHandle mh, MethodType type) {
         if(!mh.type().equals(type)) {
             throw new WrongMethodTypeException("Expected type: " + type + " actual type: " + mh.type());
--- a/nashorn/src/jdk/internal/dynalink/linker/GuardedTypeConversion.java	Wed Feb 26 13:17:57 2014 +0100
+++ b/nashorn/src/jdk/internal/dynalink/linker/GuardedTypeConversion.java	Mon Mar 03 11:24:44 2014 +0100
@@ -83,19 +83,35 @@
 
 package jdk.internal.dynalink.linker;
 
+/**
+ * Guarded type conversion
+ */
 public class GuardedTypeConversion {
     private final GuardedInvocation conversionInvocation;
     private final boolean cacheable;
 
+    /**
+     * Constructor
+     * @param conversionInvocation guarded invocation for this type conversion
+     * @param cacheable is this invocation cacheable
+     */
     public GuardedTypeConversion(final GuardedInvocation conversionInvocation, final boolean cacheable) {
         this.conversionInvocation = conversionInvocation;
         this.cacheable = cacheable;
     }
 
+    /**
+     * Get the invocation
+     * @return invocation
+     */
     public GuardedInvocation getConversionInvocation() {
         return conversionInvocation;
     }
 
+    /**
+     * Check if invocation is cacheable
+     * @return true if cachable, false otherwise
+     */
     public boolean isCacheable() {
         return cacheable;
     }
--- a/nashorn/src/jdk/internal/dynalink/linker/LinkRequest.java	Wed Feb 26 13:17:57 2014 +0100
+++ b/nashorn/src/jdk/internal/dynalink/linker/LinkRequest.java	Mon Mar 03 11:24:44 2014 +0100
@@ -127,6 +127,17 @@
     public Object getReceiver();
 
     /**
+     * Returns the number of times this callsite has been linked/relinked. This can be useful if you want to
+     * change e.g. exception based relinking to guard based relinking. It's probably not a good idea to keep,
+     * for example, expensive exception throwing relinkage based on failed type checks/ClassCastException in
+     * a nested callsite tree where the exception is thrown repeatedly for the common case. There it would be
+     * much more performant to use exact type guards instead.
+     *
+     * @return link count for call site
+     */
+    public int getLinkCount();
+
+    /**
      * Returns true if the call site is considered unstable, that is, it has been relinked more times than was
      * specified in {@link DynamicLinkerFactory#setUnstableRelinkThreshold(int)}. Linkers should use this as a
      * hint to prefer producing linkage that is more stable (its guard fails less frequently), even if that assumption
--- a/nashorn/src/jdk/internal/dynalink/support/LinkRequestImpl.java	Wed Feb 26 13:17:57 2014 +0100
+++ b/nashorn/src/jdk/internal/dynalink/support/LinkRequestImpl.java	Mon Mar 03 11:24:44 2014 +0100
@@ -98,18 +98,21 @@
     private final Object callSiteToken;
     private final Object[] arguments;
     private final boolean callSiteUnstable;
+    private final int linkCount;
 
     /**
      * Creates a new link request.
      *
      * @param callSiteDescriptor the descriptor for the call site being linked
      * @param callSiteToken the opaque token for the call site being linked.
+     * @param linkCount how many times this callsite has been linked/relinked
      * @param callSiteUnstable true if the call site being linked is considered unstable
      * @param arguments the arguments for the invocation
      */
-    public LinkRequestImpl(CallSiteDescriptor callSiteDescriptor, Object callSiteToken, boolean callSiteUnstable, Object... arguments) {
+    public LinkRequestImpl(CallSiteDescriptor callSiteDescriptor, Object callSiteToken, int linkCount, boolean callSiteUnstable, Object... arguments) {
         this.callSiteDescriptor = callSiteDescriptor;
         this.callSiteToken = callSiteToken;
+        this.linkCount = linkCount;
         this.callSiteUnstable = callSiteUnstable;
         this.arguments = arguments;
     }
@@ -140,12 +143,17 @@
     }
 
     @Override
+    public int getLinkCount() {
+        return linkCount;
+    }
+
+    @Override
     public LinkRequest withoutRuntimeContext() {
         return this;
     }
 
     @Override
     public LinkRequest replaceArguments(CallSiteDescriptor newCallSiteDescriptor, Object[] newArguments) {
-        return new LinkRequestImpl(newCallSiteDescriptor, callSiteToken, callSiteUnstable, newArguments);
+        return new LinkRequestImpl(newCallSiteDescriptor, callSiteToken, linkCount, callSiteUnstable, newArguments);
     }
 }
--- a/nashorn/src/jdk/internal/dynalink/support/RuntimeContextLinkRequestImpl.java	Wed Feb 26 13:17:57 2014 +0100
+++ b/nashorn/src/jdk/internal/dynalink/support/RuntimeContextLinkRequestImpl.java	Mon Mar 03 11:24:44 2014 +0100
@@ -103,14 +103,15 @@
      * @param callSiteDescriptor the descriptor for the call site being linked
      * @param callSiteToken the opaque token for the call site being linked.
      * @param arguments the arguments for the invocation
+     * @param linkCount number of times callsite has been linked/relinked
      * @param callSiteUnstable true if the call site being linked is considered unstable
      * @param runtimeContextArgCount the number of the leading arguments on the stack that represent the language
      * runtime specific context arguments.
      * @throws IllegalArgumentException if runtimeContextArgCount is less than 1.
      */
     public RuntimeContextLinkRequestImpl(CallSiteDescriptor callSiteDescriptor, Object callSiteToken,
-            boolean callSiteUnstable, Object[] arguments, int runtimeContextArgCount) {
-        super(callSiteDescriptor, callSiteToken, callSiteUnstable, arguments);
+            int linkCount, boolean callSiteUnstable, Object[] arguments, int runtimeContextArgCount) {
+        super(callSiteDescriptor, callSiteToken, linkCount, callSiteUnstable, arguments);
         if(runtimeContextArgCount < 1) {
             throw new IllegalArgumentException("runtimeContextArgCount < 1");
         }
@@ -122,14 +123,14 @@
         if(contextStrippedRequest == null) {
             contextStrippedRequest =
                     new LinkRequestImpl(CallSiteDescriptorFactory.dropParameterTypes(getCallSiteDescriptor(), 1,
-                            runtimeContextArgCount + 1), getCallSiteToken(), isCallSiteUnstable(), getTruncatedArguments());
+                            runtimeContextArgCount + 1), getCallSiteToken(), getLinkCount(), isCallSiteUnstable(), getTruncatedArguments());
         }
         return contextStrippedRequest;
     }
 
     @Override
     public LinkRequest replaceArguments(CallSiteDescriptor callSiteDescriptor, Object[] arguments) {
-        return new RuntimeContextLinkRequestImpl(callSiteDescriptor, getCallSiteToken(), isCallSiteUnstable(), arguments,
+        return new RuntimeContextLinkRequestImpl(callSiteDescriptor, getCallSiteToken(), getLinkCount(), isCallSiteUnstable(), arguments,
                 runtimeContextArgCount);
     }
 
--- a/nashorn/src/jdk/internal/dynalink/support/TypeConverterFactory.java	Wed Feb 26 13:17:57 2014 +0100
+++ b/nashorn/src/jdk/internal/dynalink/support/TypeConverterFactory.java	Mon Mar 03 11:24:44 2014 +0100
@@ -91,6 +91,7 @@
 import java.security.PrivilegedAction;
 import java.util.LinkedList;
 import java.util.List;
+
 import jdk.internal.dynalink.linker.ConversionComparator;
 import jdk.internal.dynalink.linker.ConversionComparator.Comparison;
 import jdk.internal.dynalink.linker.GuardedInvocation;
@@ -372,6 +373,7 @@
 
     /*private*/ static final MethodHandle IDENTITY_CONVERSION = MethodHandles.identity(Object.class);
 
+    @SuppressWarnings("serial")
     private static class NotCacheableConverter extends RuntimeException {
         final MethodHandle converter;
 
--- a/nashorn/src/jdk/nashorn/internal/codegen/CodeGenerator.java	Wed Feb 26 13:17:57 2014 +0100
+++ b/nashorn/src/jdk/nashorn/internal/codegen/CodeGenerator.java	Mon Mar 03 11:24:44 2014 +0100
@@ -394,7 +394,7 @@
                 }
                 previousWasBlock = true;
             } else {
-                if ((node instanceof WithNode && previousWasBlock) || (node instanceof FunctionNode && CodeGeneratorLexicalContext.isFunctionDynamicScope((FunctionNode)node))) {
+                if (node instanceof WithNode && previousWasBlock || node instanceof FunctionNode && CodeGeneratorLexicalContext.isFunctionDynamicScope((FunctionNode)node)) {
                     // If we hit a scope that can have symbols introduced into it at run time before finding the defining
                     // block, the symbol can't be fast scoped. A WithNode only counts if we've immediately seen a block
                     // before - its block. Otherwise, we are currently processing the WithNode's expression, and that's
@@ -963,7 +963,7 @@
                     if (callNode.isEval()) {
                         evalCall(node, flags);
                     } else if (useCount <= SharedScopeCall.FAST_SCOPE_CALL_THRESHOLD
-                            || (!isFastScope(symbol) && useCount <= SharedScopeCall.SLOW_SCOPE_CALL_THRESHOLD)
+                            || !isFastScope(symbol) && useCount <= SharedScopeCall.SLOW_SCOPE_CALL_THRESHOLD
                             || CodeGenerator.this.lc.inDynamicScope()
                             || isOptimisticOrRestOf()) {
                         scopeCall(node, flags);
@@ -1186,7 +1186,7 @@
      * @return flags without optimism
      */
     static int nonOptimisticFlags(int flags) {
-        return flags & ~(CALLSITE_OPTIMISTIC | (-1 << CALLSITE_PROGRAM_POINT_SHIFT));
+        return flags & ~(CALLSITE_OPTIMISTIC | -1 << CALLSITE_PROGRAM_POINT_SHIFT);
     }
 
     @Override
@@ -1398,7 +1398,7 @@
                         //this symbol will be put fielded, we can't initialize it as undefined with a known type
                         @Override
                         public Class<?> getValueType() {
-                            return (OBJECT_FIELDS_ONLY || value == null || value.getSymbolType().isBoolean()) ? Object.class : value.getSymbolType().getTypeClass();
+                            return OBJECT_FIELDS_ONLY || value == null || value.getSymbolType().isBoolean() ? Object.class : value.getSymbolType().getTypeClass();
                             //return OBJECT_FIELDS_ONLY ? Object.class : symbol.getSymbolType().getTypeClass();
                         }
                     });
@@ -1482,7 +1482,7 @@
         }
 
         // Nested functions are not visited when we either recompile or lazily compile, only the outermost function is.
-        if (compileOutermostOnly() && (lc.getOutermostFunction() != functionNode)) {
+        if (compileOutermostOnly() && lc.getOutermostFunction() != functionNode) {
             // In case we are not generating code for the function, we must create or retrieve the function object and
             // load it on the stack here.
             newFunctionObject(functionNode, false);
@@ -1790,7 +1790,7 @@
         } else if (value instanceof String) {
             final String string = (String)value;
 
-            if (string.length() > (MethodEmitter.LARGE_STRING_THRESHOLD / 3)) { // 3 == max bytes per encoded char
+            if (string.length() > MethodEmitter.LARGE_STRING_THRESHOLD / 3) { // 3 == max bytes per encoded char
                 loadConstant(string);
             } else {
                 method.load(string);
@@ -1907,7 +1907,7 @@
             tuples.add(new MapTuple<Expression>(key, symbol, value) {
                 @Override
                 public Class<?> getValueType() {
-                    return (OBJECT_FIELDS_ONLY || value == null || value.getType().isBoolean()) ? Object.class : value.getType().getTypeClass();
+                    return OBJECT_FIELDS_ONLY || value == null || value.getType().isBoolean() ? Object.class : value.getType().getTypeClass();
                 }
             });
         }
@@ -2397,7 +2397,7 @@
                     final Label   entry = caseNode.getEntry();
 
                     // Take first duplicate.
-                    if (!(tree.containsKey(value))) {
+                    if (!tree.containsKey(value)) {
                         tree.put(value, entry);
                     }
                 }
@@ -2435,7 +2435,7 @@
             }
 
             // If reasonable size and not too sparse (80%), use table otherwise use lookup.
-            if (range > 0 && range < 4096 && range <= (size * 5 / 4)) {
+            if (range > 0 && range < 4096 && range <= size * 5 / 4) {
                 final Label[] table = new Label[range];
                 Arrays.fill(table, defaultLabel);
                 for (int i = 0; i < size; i++) {
@@ -2650,7 +2650,7 @@
 
         if (needsScope) {
             load(init);
-            int flags = CALLSITE_SCOPE | getCallSiteFlags();
+            final int flags = CALLSITE_SCOPE | getCallSiteFlags();
             if (isFastScope(identSymbol)) {
                 storeFastScopeVar(identSymbol, flags);
             } else {
@@ -2984,7 +2984,7 @@
         new Store<BinaryNode>(binaryNode, lhs) {
             @Override
             protected void evaluate() {
-                if ((lhs instanceof IdentNode) && !lhs.getSymbol().isScope()) {
+                if (lhs instanceof IdentNode && !lhs.getSymbol().isScope()) {
                     load(rhs, lhsType);
                 } else {
                     load(rhs);
@@ -4064,10 +4064,9 @@
             // There are at least as many as are declared by the current blocks.
             int usedSlots = lc.getUsedSlotCount();
             // Look at every load on the stack, and bump the number of used slots up by the temporaries seen there.
-            for(int i = 0; i < localLoadsOnStack.length; ++i) {
-                final int slot = localLoadsOnStack[i];
+            for (final int slot : localLoadsOnStack) {
                 if(slot != Label.Stack.NON_LOAD) {
-                    int afterSlot = slot + localVariableTypes.get(slot).getSlots();
+                    final int afterSlot = slot + localVariableTypes.get(slot).getSlots();
                     if(afterSlot > usedSlots) {
                         usedSlots = afterSlot;
                     }
@@ -4085,8 +4084,8 @@
     }
 
     private static boolean everyLocalLoadIsValid(final int[] loads, int localCount) {
-        for(int i = 0; i < loads.length; ++i) {
-            if(loads[i] < 0 || loads[i] >= localCount) {
+        for (final int load : loads) {
+            if(load < 0 || load >= localCount) {
                 return false;
             }
         }
@@ -4106,8 +4105,8 @@
     }
 
     private static boolean everyStackValueIsLocalLoad(final int[] loads) {
-        for(int i = 0; i < loads.length; ++i) {
-            if(loads[i] == Label.Stack.NON_LOAD) {
+        for (final int load : loads) {
+            if(load == Label.Stack.NON_LOAD) {
                 return false;
             }
         }
@@ -4330,7 +4329,7 @@
 
         @Override
         public String toString() {
-            StringBuilder b = new StringBuilder(64).append("[HandlerSpec ").append(lvarSpec);
+            final StringBuilder b = new StringBuilder(64).append("[HandlerSpec ").append(lvarSpec);
             if(catchTarget) {
                 b.append(", catchTarget");
             }
--- a/nashorn/src/jdk/nashorn/internal/codegen/CompilationEnvironment.java	Wed Feb 26 13:17:57 2014 +0100
+++ b/nashorn/src/jdk/nashorn/internal/codegen/CompilationEnvironment.java	Mon Mar 03 11:24:44 2014 +0100
@@ -338,6 +338,7 @@
      * @return most optimistic type in current environment
      */
     Type getOptimisticType(final Optimistic node) {
+
         assert useOptimisticTypes();
         final Type invalidType = invalidatedProgramPoints.get(node.getProgramPoint());
         if (invalidType != null) {
--- a/nashorn/src/jdk/nashorn/internal/codegen/Compiler.java	Wed Feb 26 13:17:57 2014 +0100
+++ b/nashorn/src/jdk/nashorn/internal/codegen/Compiler.java	Mon Mar 03 11:24:44 2014 +0100
@@ -136,11 +136,10 @@
             compilationEnv.setIsStrict(true);
         }
 
-        final StringBuilder sb = new StringBuilder();
-        sb.append(functionNode.uniqueName(className)).
-                append('$').
-                append(safeSourceName(functionNode.getSource()));
-        this.scriptName = sb.toString();
+        final String name       = className + '$' + safeSourceName(functionNode.getSource());
+        final String uniqueName = functionNode.uniqueName(name);
+
+        this.scriptName = uniqueName;
     }
 
     private Compiler(final CompilationEnvironment compilationEnv, final ScriptEnvironment scriptEnv, final CodeInstaller<ScriptEnvironment> installer) {
@@ -437,11 +436,11 @@
         }
 
         baseName = baseName.replace('.', '_').replace('-', '_');
-        if (! scriptEnv._loader_per_compile) {
+        if (!scriptEnv._loader_per_compile) {
             baseName = baseName + installer.getUniqueScriptId();
         }
+
         final String mangled = NameCodec.encode(baseName);
-
         return mangled != null ? mangled : baseName;
     }
 
--- a/nashorn/src/jdk/nashorn/internal/codegen/CompilerConstants.java	Wed Feb 26 13:17:57 2014 +0100
+++ b/nashorn/src/jdk/nashorn/internal/codegen/CompilerConstants.java	Mon Mar 03 11:24:44 2014 +0100
@@ -553,6 +553,48 @@
     }
 
     /**
+     * Create a special call, given an explicit lookup, looking up the method handle for it at the same time
+     *
+     * @param lookup    the lookup
+     * @param thisClass this class
+     * @param clazz     the class
+     * @param name      the name of the method
+     * @param rtype     the return type
+     * @param ptypes    the parameter types
+     *
+     * @return the call object representing the virtual call
+     */
+    public static Call specialCall0(final MethodHandles.Lookup lookup, final Class<?> thisClass, final Class<?> clazz, final String name, final Class<?> rtype, final Class<?>... ptypes) {
+        return new Call(MH.findSpecial(lookup, clazz, name, MH.type(rtype, ptypes), thisClass), className(clazz), name, methodDescriptor(rtype, ptypes)) {
+            @Override
+            public MethodEmitter invoke(final MethodEmitter method) {
+                return method.invokespecial(className, name, descriptor);
+            }
+        };
+    }
+
+    /**
+     * Create a special call, given an explicit lookup, looking up the method handle for it at the same time.
+     * clazz is used as this class
+     *
+     * @param lookup    the lookup
+     * @param clazz     the class
+     * @param name      the name of the method
+     * @param rtype     the return type
+     * @param ptypes    the parameter types
+     *
+     * @return the call object representing the virtual call
+     */
+    public static Call specialCall(final MethodHandles.Lookup lookup, final Class<?> clazz, final String name, final Class<?> rtype, final Class<?>... ptypes) {
+        return new Call(MH.findSpecial(lookup, clazz, name, MH.type(rtype, ptypes), clazz), className(clazz), name, methodDescriptor(rtype, ptypes)) {
+            @Override
+            public MethodEmitter invoke(final MethodEmitter method) {
+                return method.invokespecial(className, name, descriptor);
+            }
+        };
+    }
+
+    /**
      * Returns true if the passed string looks like a method name of an internally generated Nashorn method. Basically,
      * if it starts with a colon character {@code :} but is not the name of the program method {@code :program}.
      * Program function is not considered internal as we want it to show up in exception stack traces.
--- a/nashorn/src/jdk/nashorn/internal/codegen/Label.java	Wed Feb 26 13:17:57 2014 +0100
+++ b/nashorn/src/jdk/nashorn/internal/codegen/Label.java	Mon Mar 03 11:24:44 2014 +0100
@@ -40,9 +40,9 @@
     static final class Stack {
         static final int NON_LOAD = -1;
 
-        Type[] data = new Type[8];
+        Type[] data       = new Type[8];
         int[]  localLoads = new int[8];
-        int sp = 0;
+        int    sp;
 
         Stack() {
         }
--- a/nashorn/src/jdk/nashorn/internal/codegen/MapCreator.java	Wed Feb 26 13:17:57 2014 +0100
+++ b/nashorn/src/jdk/nashorn/internal/codegen/MapCreator.java	Mon Mar 03 11:24:44 2014 +0100
@@ -77,8 +77,16 @@
             final String   key         = tuple.key;
             final Symbol   symbol      = tuple.symbol;
             final Class<?> initialType = tuple.getValueType();
+
             if (symbol != null && !isValidArrayIndex(getArrayIndex(key))) {
-                properties.add(new AccessorProperty(key, getPropertyFlags(symbol, hasArguments), structure, symbol.getFieldIndex(), initialType));
+                final int      flags    = getPropertyFlags(symbol, hasArguments);
+                final Property property = new AccessorProperty(
+                        key,
+                        flags,
+                        structure,
+                        symbol.getFieldIndex(),
+                        initialType);
+                properties.add(property);
             }
         }
 
@@ -94,8 +102,14 @@
             final String key    = tuple.key;
             final Symbol symbol = tuple.symbol;
 
+            //TODO initial type is object here no matter what. Is that right?
             if (symbol != null && !isValidArrayIndex(getArrayIndex(key))) {
-                properties.add(new SpillProperty(key, getPropertyFlags(symbol, hasArguments), spillIndex++));
+                final int flags = getPropertyFlags(symbol, hasArguments);
+                properties.add(
+                        new SpillProperty(
+                                key,
+                                flags,
+                                spillIndex++));
             }
         }
 
@@ -110,11 +124,11 @@
      *
      * @return flags to use for fields
      */
-    protected int getPropertyFlags(final Symbol symbol, final boolean hasArguments) {
+    static int getPropertyFlags(final Symbol symbol, final boolean hasArguments) {
         int flags = 0;
 
         if (symbol.isParam()) {
-            flags |= Property.IS_ALWAYS_OBJECT | Property.IS_PARAMETER;
+            flags |= Property.IS_PARAMETER;
         }
 
         if (hasArguments) {
--- a/nashorn/src/jdk/nashorn/internal/codegen/Namespace.java	Wed Feb 26 13:17:57 2014 +0100
+++ b/nashorn/src/jdk/nashorn/internal/codegen/Namespace.java	Mon Mar 03 11:24:44 2014 +0100
@@ -80,7 +80,6 @@
             if (counter != null) {
                 final int count = counter + 1;
                 namespaceDirectory.put(base, count);
-
                 return base + '-' + count;
             }
         }
--- a/nashorn/src/jdk/nashorn/internal/codegen/ObjectClassGenerator.java	Wed Feb 26 13:17:57 2014 +0100
+++ b/nashorn/src/jdk/nashorn/internal/codegen/ObjectClassGenerator.java	Mon Mar 03 11:24:44 2014 +0100
@@ -215,7 +215,7 @@
      * @param clazz the JavaScript scope class.
      * @return the number of fields in the scope class.
      */
-    public static int getFieldCount(Class<?> clazz) {
+    public static int getFieldCount(final Class<?> clazz) {
         final String name = clazz.getSimpleName();
         final String prefix = JS_OBJECT_PREFIX.symbolName();
         if (prefix.equals(name)) {
@@ -247,13 +247,16 @@
      * @param fieldNames fields to initialize to undefined, where applicable
      */
     private static void initializeToUndefined(final MethodEmitter init, final String className, final List<String> fieldNames) {
+        if (!OBJECT_FIELDS_ONLY) {
+            // no need to initialize anything to undefined in the dual field world
+            // - then we have a constant getter for undefined for any unknown type
+            return;
+        }
+
         if (fieldNames.isEmpty()) {
             return;
         }
 
-        // always initialize fields to undefined, even with --dual-fields. Then it's ok to
-        // remember things like "widest set type" in properties, and if it's object, don't
-        // add any special "return undefined" getters, saving an invalidation
         init.load(Type.OBJECT, JAVA_THIS.slot());
         init.loadUndefined(Type.OBJECT);
 
@@ -565,7 +568,7 @@
         final boolean isPrimitiveStorage = forType != null && forType.isPrimitive();
 
         //which is the primordial getter
-        final MethodHandle getter = OBJECT_FIELDS_ONLY ? objectGetter : (isPrimitiveStorage ? primitiveGetter : objectGetter);
+        final MethodHandle getter = OBJECT_FIELDS_ONLY ? objectGetter : isPrimitiveStorage ? primitiveGetter : objectGetter;
 
         if (forType == null) {
             if (isOptimistic) {
--- a/nashorn/src/jdk/nashorn/internal/ir/AccessNode.java	Wed Feb 26 13:17:57 2014 +0100
+++ b/nashorn/src/jdk/nashorn/internal/ir/AccessNode.java	Mon Mar 03 11:24:44 2014 +0100
@@ -25,9 +25,6 @@
 
 package jdk.nashorn.internal.ir;
 
-import static jdk.nashorn.internal.codegen.ObjectClassGenerator.DEBUG_FIELDS;
-
-import jdk.nashorn.internal.codegen.ObjectClassGenerator;
 import jdk.nashorn.internal.codegen.types.Type;
 import jdk.nashorn.internal.ir.annotations.Immutable;
 import jdk.nashorn.internal.ir.visitor.NodeVisitor;
@@ -120,9 +117,6 @@
         if (this.optimisticType == optimisticType) {
             return this;
         }
-        if (DEBUG_FIELDS && getSymbol() != null && !Type.areEquivalent(getSymbol().getSymbolType(), optimisticType)) {
-            ObjectClassGenerator.LOG.info(getClass().getName(), " ", this, " => ", optimisticType, " instead of ", getType());
-        }
         return new AccessNode(this, base, property, isFunction(), optimisticType, isOptimistic, programPoint);
     }
 
--- a/nashorn/src/jdk/nashorn/internal/ir/FunctionNode.java	Wed Feb 26 13:17:57 2014 +0100
+++ b/nashorn/src/jdk/nashorn/internal/ir/FunctionNode.java	Mon Mar 03 11:24:44 2014 +0100
@@ -436,7 +436,6 @@
         return namespace.uniqueName(base);
     }
 
-
     @Override
     public void toString(final StringBuilder sb) {
         sb.append('[').
--- a/nashorn/src/jdk/nashorn/internal/ir/IdentNode.java	Wed Feb 26 13:17:57 2014 +0100
+++ b/nashorn/src/jdk/nashorn/internal/ir/IdentNode.java	Mon Mar 03 11:24:44 2014 +0100
@@ -147,7 +147,7 @@
      * @return true if this is a property name
      */
     public boolean isPropertyName() {
-        return (flags & PROPERTY_NAME) != 0;
+        return (flags & PROPERTY_NAME) == PROPERTY_NAME;
     }
 
     /**
@@ -166,7 +166,7 @@
      * @return true if this is a future strict name
      */
     public boolean isFutureStrictName() {
-        return (flags & FUTURESTRICT_NAME) != 0;
+        return (flags & FUTURESTRICT_NAME) == FUTURESTRICT_NAME;
     }
 
     /**
@@ -185,7 +185,7 @@
      * @return true if IdentNode is initialized on creation
      */
     public boolean isInitializedHere() {
-        return (flags & INITIALIZED_HERE) != 0;
+        return (flags & INITIALIZED_HERE) == INITIALIZED_HERE;
     }
 
     /**
@@ -211,7 +211,7 @@
 
     @Override
     public boolean isFunction() {
-        return (flags & FUNCTION) != 0;
+        return (flags & FUNCTION) == FUNCTION;
     }
 
     @Override
@@ -219,7 +219,7 @@
         if (this.optimisticType == callSiteType) {
             return this;
         }
-        if (DEBUG_FIELDS && getSymbol() != null && !Type.areEquivalent(getSymbol().getSymbolType(), callSiteType)) {
+        if (DEBUG_FIELDS && ObjectClassGenerator.shouldInstrument(getName()) && getSymbol() != null && !Type.areEquivalent(getSymbol().getSymbolType(), callSiteType)) {
             ObjectClassGenerator.LOG.info(getClass().getName(), " ", this, " => ", callSiteType, " instead of ", getType());
         }
         return new IdentNode(this, name, callSiteType, flags, programPoint);
--- a/nashorn/src/jdk/nashorn/internal/ir/IndexNode.java	Wed Feb 26 13:17:57 2014 +0100
+++ b/nashorn/src/jdk/nashorn/internal/ir/IndexNode.java	Mon Mar 03 11:24:44 2014 +0100
@@ -25,9 +25,6 @@
 
 package jdk.nashorn.internal.ir;
 
-import static jdk.nashorn.internal.codegen.ObjectClassGenerator.DEBUG_FIELDS;
-
-import jdk.nashorn.internal.codegen.ObjectClassGenerator;
 import jdk.nashorn.internal.codegen.types.Type;
 import jdk.nashorn.internal.ir.annotations.Immutable;
 import jdk.nashorn.internal.ir.visitor.NodeVisitor;
@@ -120,9 +117,6 @@
         if (this.optimisticType == optimisticType) {
             return this;
         }
-        if (DEBUG_FIELDS && getSymbol() != null && !Type.areEquivalent(getSymbol().getSymbolType(), optimisticType)) {
-            ObjectClassGenerator.LOG.info(getClass().getName(), " ", this, " => ", optimisticType, " instead of ", getType());
-        }
         return new IndexNode(this, base, index, isFunction(), optimisticType, isOptimistic, programPoint);
     }
 
--- a/nashorn/src/jdk/nashorn/internal/lookup/Lookup.java	Wed Feb 26 13:17:57 2014 +0100
+++ b/nashorn/src/jdk/nashorn/internal/lookup/Lookup.java	Mon Mar 03 11:24:44 2014 +0100
@@ -129,6 +129,50 @@
     }
 
     /**
+     * This method filters primitive argument types using JavaScript semantics. For example,
+     * an (int) cast of a double in Java land is not the same thing as invoking toInt32 on it.
+     * If you are returning values to JavaScript that have to be of a specific type, this is
+     * the correct return value filter to use, as the explicitCastArguments just uses the
+     * Java boxing equivalents
+     *
+     * @param mh   method handle for which to filter argument value
+     * @param n    argument index
+     * @param from old argument type, the new one is given by the sent method handle
+     * @return method handle for appropriate argument type conversion
+     */
+    public static MethodHandle filterArgumentType(final MethodHandle mh, final int n, final Class<?> from) {
+        final Class<?> to = mh.type().parameterType(n);
+
+        if (from == int.class) {
+            //fallthru
+        } else if (from == long.class) {
+            //fallthru
+        } else if (from == double.class) {
+            if (to == int.class) {
+                return MH.filterArguments(mh, n, JSType.TO_INT32_D.methodHandle());
+            } else if (to == long.class) {
+                return MH.filterArguments(mh, n, JSType.TO_UINT32_D.methodHandle());
+            }
+            //fallthru
+        } else if (!from.isPrimitive()) {
+            if (to == int.class) {
+                return MH.filterArguments(mh, n, JSType.TO_INT32.methodHandle());
+            } else if (to == long.class) {
+                return MH.filterArguments(mh, n, JSType.TO_UINT32.methodHandle());
+            } else if (to == double.class) {
+                return MH.filterArguments(mh, n, JSType.TO_NUMBER.methodHandle());
+            } else if (!to.isPrimitive()) {
+                return mh;
+            }
+
+            assert false : "unsupported Lookup.filterReturnType type " + from + " -> " + to;
+        }
+
+        //use a standard cast - we don't need to check JavaScript special cases
+        return MH.explicitCastArguments(mh, mh.type().changeParameterType(2, to));
+    }
+
+    /**
      * This method filters primitive return types using JavaScript semantics. For example,
      * an (int) cast of a double in Java land is not the same thing as invoking toInt32 on it.
      * If you are returning values to JavaScript that have to be of a specific type, this is
--- a/nashorn/src/jdk/nashorn/internal/lookup/MethodHandleFactory.java	Wed Feb 26 13:17:57 2014 +0100
+++ b/nashorn/src/jdk/nashorn/internal/lookup/MethodHandleFactory.java	Mon Mar 03 11:24:44 2014 +0100
@@ -142,7 +142,7 @@
         final String str = "\treturn" +
                 (VOID_TAG.equals(value) ?
                     ";" :
-                    (" " + stripName(value) + "; // [type=" + (value == null ? "null" : stripName(value.getClass()) + ']')));
+                    " " + stripName(value) + "; // [type=" + (value == null ? "null" : stripName(value.getClass()) + ']'));
         logger.log(TRACE_LEVEL, str);
         logger.log(TRACE_LEVEL, Debug.firstJSFrame());
         return value;
@@ -214,7 +214,7 @@
 
         if (arg instanceof ScriptObject) {
             return arg.toString() +
-                " (map=" + Debug.id((((ScriptObject)arg).getMap())) +
+                " (map=" + Debug.id(((ScriptObject)arg).getMap()) +
                 ")";
         }
 
@@ -430,6 +430,15 @@
         }
 
         @Override
+        public MethodHandle findSpecial(final MethodHandles.Lookup explicitLookup, final Class<?> clazz, final String name, final MethodType type, final Class<?> thisClass) {
+            try {
+                return explicitLookup.findSpecial(clazz, name, type, thisClass);
+            } catch (final NoSuchMethodException | IllegalAccessException e) {
+                throw new LookupException(e);
+            }
+        }
+
+        @Override
         public MethodHandle findVirtual(final MethodHandles.Lookup explicitLookup, final Class<?> clazz, final String name, final MethodType type) {
             try {
                 return explicitLookup.findVirtual(clazz, name, type);
--- a/nashorn/src/jdk/nashorn/internal/lookup/MethodHandleFunctionality.java	Wed Feb 26 13:17:57 2014 +0100
+++ b/nashorn/src/jdk/nashorn/internal/lookup/MethodHandleFunctionality.java	Mon Mar 03 11:24:44 2014 +0100
@@ -297,6 +297,19 @@
     public MethodHandle findVirtual(MethodHandles.Lookup explicitLookup, Class<?> clazz, String name, MethodType type);
 
     /**
+     * Wrapper for {@link java.lang.invoke.MethodHandles.Lookup#findSpecial(Class, String, MethodType, Class)}
+     *
+     * @param explicitLookup explicit lookup to be used
+     * @param clazz          class to look in
+     * @param name           name of method
+     * @param type           method type
+     * @param thisClass      thisClass
+     *
+     * @return method handle for virtual method
+     */
+    public MethodHandle findSpecial(MethodHandles.Lookup explicitLookup, Class<?> clazz, String name, MethodType type, final Class<?> thisClass);
+
+    /**
      * Wrapper for SwitchPoint creation. Just like {@code new SwitchPoint()} but potentially
      * tracked
      *
--- a/nashorn/src/jdk/nashorn/internal/objects/ArrayBufferView.java	Wed Feb 26 13:17:57 2014 +0100
+++ b/nashorn/src/jdk/nashorn/internal/objects/ArrayBufferView.java	Mon Mar 03 11:24:44 2014 +0100
@@ -26,8 +26,15 @@
 package jdk.nashorn.internal.objects;
 
 import static jdk.nashorn.internal.runtime.ECMAErrors.rangeError;
+import static jdk.nashorn.internal.runtime.ECMAErrors.typeError;
 import static jdk.nashorn.internal.runtime.UnwarrantedOptimismException.INVALID_PROGRAM_POINT;
 
+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;
 import jdk.nashorn.internal.objects.annotations.Attribute;
 import jdk.nashorn.internal.objects.annotations.Getter;
 import jdk.nashorn.internal.objects.annotations.ScriptClass;
@@ -36,9 +43,12 @@
 import jdk.nashorn.internal.runtime.ScriptObject;
 import jdk.nashorn.internal.runtime.ScriptRuntime;
 import jdk.nashorn.internal.runtime.arrays.ArrayData;
+import jdk.nashorn.internal.runtime.arrays.TypedArrayData;
 
 @ScriptClass("ArrayBufferView")
 abstract class ArrayBufferView extends ScriptObject {
+    private final NativeArrayBuffer buffer;
+    private final int byteOffset;
 
     // initialized by nasgen
     private static PropertyMap $nasgenmap$;
@@ -49,24 +59,34 @@
 
     private ArrayBufferView(final NativeArrayBuffer buffer, final int byteOffset, final int elementLength, final Global global) {
         super(global.getArrayBufferViewMap());
-        checkConstructorArgs(buffer, byteOffset, elementLength);
-        this.setProto(getPrototype(global));
-        this.setArray(factory().createArrayData(buffer, byteOffset, elementLength));
+
+        final int bytesPerElement = bytesPerElement();
+
+        checkConstructorArgs(buffer.getByteLength(), bytesPerElement, byteOffset, elementLength);
+        setProto(getPrototype(global));
+
+        this.buffer     = buffer;
+        this.byteOffset = byteOffset;
+
+        assert byteOffset % bytesPerElement == 0;
+        final int start = byteOffset / bytesPerElement;
+        final ByteBuffer newNioBuffer = buffer.getNioBuffer().duplicate().order(ByteOrder.nativeOrder());
+        final ArrayData  data         = factory().createArrayData(newNioBuffer, start, start + elementLength);
+
+        setArray(data);
     }
 
-    ArrayBufferView(final NativeArrayBuffer buffer, final int byteOffset, final int elementLength) {
+    protected ArrayBufferView(final NativeArrayBuffer buffer, final int byteOffset, final int elementLength) {
         this(buffer, byteOffset, elementLength, Global.instance());
     }
 
-    private void checkConstructorArgs(final NativeArrayBuffer buffer, final int byteOffset, final int elementLength) {
+    private static void checkConstructorArgs(final int byteLength, final int bytesPerElement, final int byteOffset, final int elementLength) {
         if (byteOffset < 0 || elementLength < 0) {
-            throw new RuntimeException("byteOffset or length must not be negative");
-        }
-        if (byteOffset + elementLength * bytesPerElement() > buffer.getByteLength()) {
-            throw new RuntimeException("byteOffset + byteLength out of range");
-        }
-        if (byteOffset % bytesPerElement() != 0) {
-            throw new RuntimeException("byteOffset must be a multiple of the element size");
+            throw new RuntimeException("byteOffset or length must not be negative, byteOffset=" + byteOffset + ", elementLength=" + elementLength + ", bytesPerElement=" + bytesPerElement);
+        } else if (byteOffset + elementLength * bytesPerElement > byteLength) {
+            throw new RuntimeException("byteOffset + byteLength out of range, byteOffset=" + byteOffset + ", elementLength=" + elementLength + ", bytesPerElement=" + bytesPerElement);
+        } else if (byteOffset % bytesPerElement != 0) {
+            throw new RuntimeException("byteOffset must be a multiple of the element size, byteOffset=" + byteOffset + " bytesPerElement=" + bytesPerElement);
         }
     }
 
@@ -76,22 +96,22 @@
 
     @Getter(attributes = Attribute.NOT_ENUMERABLE | Attribute.NOT_WRITABLE | Attribute.NOT_CONFIGURABLE)
     public static Object buffer(final Object self) {
-        return ((ArrayDataImpl)((ArrayBufferView)self).getArray()).buffer;
+        return ((ArrayBufferView)self).buffer;
     }
 
     @Getter(attributes = Attribute.NOT_ENUMERABLE | Attribute.NOT_WRITABLE | Attribute.NOT_CONFIGURABLE)
     public static Object byteOffset(final Object self) {
-        return ((ArrayDataImpl)((ArrayBufferView)self).getArray()).byteOffset;
+        return ((ArrayBufferView)self).byteOffset;
     }
 
     @Getter(attributes = Attribute.NOT_ENUMERABLE | Attribute.NOT_WRITABLE | Attribute.NOT_CONFIGURABLE)
-    public static Object byteLength(final Object self) {
+    public static int byteLength(final Object self) {
         final ArrayBufferView view = (ArrayBufferView)self;
-        return ((ArrayDataImpl)view.getArray()).elementLength * view.bytesPerElement();
+        return ((TypedArrayData<?>)view.getArray()).getElementLength() * view.bytesPerElement();
     }
 
     @Getter(attributes = Attribute.NOT_ENUMERABLE | Attribute.NOT_WRITABLE | Attribute.NOT_CONFIGURABLE)
-    public static Object length(final Object self) {
+    public static int length(final Object self) {
         return ((ArrayBufferView)self).elementLength();
     }
 
@@ -101,182 +121,7 @@
     }
 
     private int elementLength() {
-        return ((ArrayDataImpl)getArray()).elementLength;
-    }
-
-    protected static abstract class ArrayDataImpl extends ArrayData {
-        protected final NativeArrayBuffer buffer;
-        protected final int byteOffset;
-        private final int elementLength;
-
-        protected ArrayDataImpl(final NativeArrayBuffer buffer, final int byteOffset, final int elementLength) {
-            super(elementLength);
-            this.buffer = buffer;
-            this.byteOffset = byteOffset;
-            this.elementLength = elementLength;
-        }
-
-        @Override
-        public ArrayData copy() {
-            throw new UnsupportedOperationException();   // Not used for ArrayBuffers
-        }
-
-        @Override
-        public Object[] asObjectArray() {
-            final Object[] array = new Object[elementLength];
-            for (int i = 0; i < elementLength; i++) {
-                array[i] = getObjectImpl(i);
-            }
-            return array;
-        }
-
-        @Override
-        public ArrayData ensure(final long safeIndex) {
-            return this;
-        }
-
-        @Override
-        public void setLength(final long length) {
-            //empty?
-            //TODO is this right?
-        }
-
-        @Override
-        public ArrayData shrink(final long newLength) {
-            return this;
-        }
-
-        @Override
-        public ArrayData set(final int index, final Object value, final boolean strict) {
-            if (has(index)) {
-                setImpl(index, value);
-            }
-            return this;
-        }
-
-        @Override
-        public ArrayData set(final int index, final int value, final boolean strict) {
-            if (has(index)) {
-                setImpl(index, value);
-            }
-            return this;
-        }
-
-        @Override
-        public ArrayData set(final int index, final long value, final boolean strict) {
-            if (has(index)) {
-                setImpl(index, value);
-            }
-            return this;
-        }
-
-        @Override
-        public ArrayData set(final int index, final double value, final boolean strict) {
-            if (has(index)) {
-                setImpl(index, value);
-            }
-            return this;
-        }
-
-        @Override
-        public int getInt(final int index) {
-            return getIntImpl(index);
-        }
-
-        @Override
-        public long getLong(final int index) {
-            return getLongImpl(index);
-        }
-
-        @Override
-        public double getDouble(final int index) {
-            return getDoubleImpl(index);
-        }
-
-        @Override
-        public Object getObject(final int index) {
-            return getObjectImpl(index);
-        }
-
-        @Override
-        public boolean has(final int index) {
-            return index >= 0 && index < elementLength;
-        }
-
-        @Override
-        public boolean canDelete(final int index, final boolean strict) {
-            return false;
-        }
-
-        @Override
-        public boolean canDelete(final long fromIndex, final long toIndex, final boolean strict) {
-            return false;
-        }
-
-        @Override
-        public ArrayData delete(final int index) {
-            return this;
-        }
-
-        @Override
-        public ArrayData delete(final long fromIndex, final long toIndex) {
-            return this;
-        }
-
-        @Override
-        protected ArrayData convert(final Class<?> type) {
-            return this;
-        }
-
-        @Override
-        public void shiftLeft(final int by) {
-            throw new UnsupportedOperationException();
-        }
-
-        @Override
-        public ArrayData shiftRight(final int by) {
-            throw new UnsupportedOperationException();
-        }
-
-        @Override
-        public Object pop() {
-            throw new UnsupportedOperationException();
-        }
-
-        @Override
-        public ArrayData slice(final long from, final long to) {
-            throw new UnsupportedOperationException();
-        }
-
-        protected abstract int getIntImpl(int key);
-
-        protected long getLongImpl(final int key) {
-            return getIntImpl(key);
-        }
-
-        protected double getDoubleImpl(final int key) {
-            return getIntImpl(key);
-        }
-
-        protected Object getObjectImpl(final int key) {
-            return getIntImpl(key);
-        }
-
-        protected abstract void setImpl(int key, int value);
-
-        protected void setImpl(final int key, final long value) {
-            setImpl(key, (int)value);
-        }
-
-        protected void setImpl(final int key, final double value) {
-            setImpl(key, JSType.toInt32(value));
-        }
-
-        protected void setImpl(final int key, final Object value) {
-            setImpl(key, JSType.toInt32(value));
-        }
-
-        protected abstract int byteIndex(int index);
+        return ((TypedArrayData<?>)getArray()).getElementLength();
     }
 
     protected static abstract class Factory {
@@ -284,12 +129,12 @@
         final int maxElementLength;
 
         public Factory(final int bytesPerElement) {
-            this.bytesPerElement = bytesPerElement;
+            this.bytesPerElement  = bytesPerElement;
             this.maxElementLength = Integer.MAX_VALUE / bytesPerElement;
         }
 
         public final ArrayBufferView construct(final int elementLength) {
-            if(elementLength > maxElementLength) {
+            if (elementLength > maxElementLength) {
                 throw rangeError("inappropriate.array.buffer.length", JSType.toString(elementLength));
             }
             return construct(new NativeArrayBuffer(elementLength * bytesPerElement), 0, elementLength);
@@ -297,25 +142,39 @@
 
         public abstract ArrayBufferView construct(NativeArrayBuffer buffer, int byteOffset, int elementLength);
 
-        public abstract ArrayData createArrayData(NativeArrayBuffer buffer, int byteOffset, int elementLength);
+        public abstract TypedArrayData<?> createArrayData(ByteBuffer nb, int start, int end);
+
+        public abstract String getClassName();
     }
 
     protected abstract Factory factory();
 
     protected abstract ScriptObject getPrototype(final Global global);
 
+    @Override
+    public final String getClassName() {
+        return factory().getClassName();
+    }
+
     protected boolean isFloatArray() {
         return false;
     }
 
-    protected static ArrayBufferView constructorImpl(final Object[] args, final Factory factory) {
-        final Object arg0 = args.length != 0 ? args[0] : 0;
-        final ArrayBufferView dst;
-        final int length;
+    protected static ArrayBufferView constructorImpl(final boolean newObj, final Object[] args, final Factory factory) {
+        final Object          arg0 = args.length != 0 ? args[0] : 0;
+        final ArrayBufferView dest;
+        final int             length;
+
+        if (!newObj) {
+            throw typeError("constructor.requires.new", factory.getClassName());
+        }
+
+
         if (arg0 instanceof NativeArrayBuffer) {
             // Constructor(ArrayBuffer buffer, optional unsigned long byteOffset, optional unsigned long length)
-            final NativeArrayBuffer buffer = (NativeArrayBuffer) arg0;
-            final int byteOffset = args.length > 1 ? JSType.toInt32(args[1]) : 0;
+            final NativeArrayBuffer buffer     = (NativeArrayBuffer)arg0;
+            final int               byteOffset = args.length > 1 ? JSType.toInt32(args[1]) : 0;
+
             if (args.length > 2) {
                 length = JSType.toInt32(args[2]);
             } else {
@@ -324,15 +183,16 @@
                 }
                 length = (buffer.getByteLength() - byteOffset) / factory.bytesPerElement;
             }
+
             return factory.construct(buffer, byteOffset, length);
         } else if (arg0 instanceof ArrayBufferView) {
             // Constructor(TypedArray array)
             length = ((ArrayBufferView)arg0).elementLength();
-            dst = factory.construct(length);
+            dest   = factory.construct(length);
         } else if (arg0 instanceof NativeArray) {
             // Constructor(type[] array)
             length = lengthToInt(((NativeArray) arg0).getArray().length());
-            dst = factory.construct(length);
+            dest   = factory.construct(length);
         } else {
             // Constructor(unsigned long length). Treating infinity as 0 is a special case for ArrayBufferView.
             final double dlen = JSType.toNumber(arg0);
@@ -340,8 +200,9 @@
             return factory.construct(length);
         }
 
-        copyElements(dst, length, (ScriptObject)arg0, 0);
-        return dst;
+        copyElements(dest, length, (ScriptObject)arg0, 0);
+
+        return dest;
     }
 
     protected static Object setImpl(final Object self, final Object array, final Object offset0) {
@@ -357,7 +218,7 @@
             throw new RuntimeException("argument is not of array type");
         }
 
-        final ScriptObject source = (ScriptObject) array;
+        final ScriptObject source = (ScriptObject)array;
         final int offset = JSType.toInt32(offset0); // default=0
 
         if (dest.elementLength() < length + offset || offset < 0) {
@@ -385,15 +246,39 @@
         if (length > Integer.MAX_VALUE || length < 0) {
             throw rangeError("inappropriate.array.buffer.length", JSType.toString(length));
         }
-        return (int) (length & Integer.MAX_VALUE);
+        return (int)(length & Integer.MAX_VALUE);
     }
 
     protected static Object subarrayImpl(final Object self, final Object begin0, final Object end0) {
-        final ArrayBufferView arrayView = ((ArrayBufferView)self);
-        final int elementLength = arrayView.elementLength();
-        final int begin = NativeArrayBuffer.adjustIndex(JSType.toInt32(begin0), elementLength);
-        final int end = NativeArrayBuffer.adjustIndex(end0 != ScriptRuntime.UNDEFINED ? JSType.toInt32(end0) : elementLength, elementLength);
-        final ArrayDataImpl arrayData = (ArrayDataImpl)arrayView.getArray();
-        return arrayView.factory().construct(arrayData.buffer, arrayData.byteIndex(begin), Math.max(end - begin, 0));
+        final ArrayBufferView arrayView       = ((ArrayBufferView)self);
+        final int             byteOffset      = arrayView.byteOffset;
+        final int             bytesPerElement = arrayView.bytesPerElement();
+        final int             elementLength   = arrayView.elementLength();
+        final int             begin           = NativeArrayBuffer.adjustIndex(JSType.toInt32(begin0), elementLength);
+        final int             end             = NativeArrayBuffer.adjustIndex(end0 != ScriptRuntime.UNDEFINED ? JSType.toInt32(end0) : elementLength, elementLength);
+        final int             length          = Math.max(end - begin, 0);
+
+        assert byteOffset % bytesPerElement == 0;
+
+        //second is byteoffset
+        return arrayView.factory().construct(arrayView.buffer, begin * bytesPerElement + byteOffset, length);
+    }
+
+    @Override
+    protected GuardedInvocation findGetIndexMethod(final CallSiteDescriptor desc, final LinkRequest request) {
+        final GuardedInvocation inv = getArray().findFastGetIndexMethod(getArray().getClass(), desc, request);
+        if (inv != null) {
+            return inv;
+        }
+        return super.findGetIndexMethod(desc, request);
+    }
+
+    @Override
+    protected GuardedInvocation findSetIndexMethod(final CallSiteDescriptor desc, final LinkRequest request) {
+        final GuardedInvocation inv = getArray().findFastSetIndexMethod(getArray().getClass(), desc, request);
+        if (inv != null) {
+            return inv;
+        }
+        return super.findSetIndexMethod(desc, request);
     }
 }
--- a/nashorn/src/jdk/nashorn/internal/objects/Global.java	Wed Feb 26 13:17:57 2014 +0100
+++ b/nashorn/src/jdk/nashorn/internal/objects/Global.java	Mon Mar 03 11:24:44 2014 +0100
@@ -38,7 +38,6 @@
 import java.lang.reflect.Field;
 import java.util.Arrays;
 import java.util.LinkedHashMap;
-import java.util.List;
 import java.util.Map;
 import java.util.concurrent.Callable;
 import java.util.concurrent.ConcurrentHashMap;
@@ -472,7 +471,7 @@
      * @return the global singleton
      */
     public static Global instance() {
-        ScriptObject global = Context.getGlobal();
+        final ScriptObject global = Context.getGlobal();
         if (! (global instanceof Global)) {
             throw new IllegalStateException("no current global instance");
         }
@@ -705,7 +704,7 @@
         private final int size;
         private final ReferenceQueue<Class<?>> queue;
 
-        ClassCache(int size) {
+        ClassCache(final int size) {
             super(size, 0.75f, true);
             this.size = size;
             this.queue = new ReferenceQueue<>();
@@ -721,7 +720,7 @@
         }
 
         @Override
-        public ClassReference get(Object key) {
+        public ClassReference get(final Object key) {
             for (ClassReference ref; (ref = (ClassReference)queue.poll()) != null; ) {
                 remove(ref.source);
             }
@@ -743,7 +742,7 @@
     @Override
     public Class<?> findCachedClass(final Source source) {
         assert classCache != null : "Class cache used without being initialized";
-        ClassReference ref = classCache.get(source);
+        final ClassReference ref = classCache.get(source);
         return ref != null ? ref.get() : null;
     }
 
@@ -815,7 +814,7 @@
             return str;
         }
         final Global global = Global.instance();
-        final ScriptObject scope = (self instanceof ScriptObject) ? (ScriptObject)self : global;
+        final ScriptObject scope = self instanceof ScriptObject ? (ScriptObject)self : global;
 
         return global.getContext().eval(scope, str.toString(), callThis, location, Boolean.TRUE.equals(strict));
     }
@@ -856,7 +855,7 @@
      */
     public static Object load(final Object self, final Object source) throws IOException {
         final Global global = Global.instance();
-        final ScriptObject scope = (self instanceof ScriptObject) ? (ScriptObject)self : global;
+        final ScriptObject scope = self instanceof ScriptObject ? (ScriptObject)self : global;
         return global.getContext().load(scope, source);
     }
 
@@ -1610,11 +1609,13 @@
      * not the case
      *
      * @param obj and object to check
+     * @return the script object
      */
-    public static void checkObject(final Object obj) {
+    public static ScriptObject checkObject(final Object obj) {
         if (!(obj instanceof ScriptObject)) {
             throw typeError("not.an.object", ScriptRuntime.safeToString(obj));
         }
+        return (ScriptObject)obj;
     }
 
     /**
@@ -1665,7 +1666,8 @@
         // initialize global function properties
         this.eval = this.builtinEval = ScriptFunctionImpl.makeFunction("eval", EVAL);
 
-        this.parseInt           = ScriptFunctionImpl.makeFunction("parseInt",   GlobalFunctions.PARSEINT);
+        this.parseInt           = ScriptFunctionImpl.makeFunction("parseInt",   GlobalFunctions.PARSEINT,
+                new MethodHandle[] { GlobalFunctions.PARSEINT_OI, GlobalFunctions.PARSEINT_O });
         this.parseFloat         = ScriptFunctionImpl.makeFunction("parseFloat", GlobalFunctions.PARSEFLOAT);
         this.isNaN              = ScriptFunctionImpl.makeFunction("isNaN",      GlobalFunctions.IS_NAN);
         this.isFinite           = ScriptFunctionImpl.makeFunction("isFinite",   GlobalFunctions.IS_FINITE);
@@ -1751,13 +1753,12 @@
         copyBuiltins();
 
         // expose script (command line) arguments as "arguments" property of global
-        final List<String> arguments = env.getArguments();
-        final Object argsObj = wrapAsObject(arguments.toArray());
-        final int flags = jdk.nashorn.internal.runtime.Property.IS_ALWAYS_OBJECT | Attribute.NOT_ENUMERABLE;
-        addOwnProperty("arguments", flags, argsObj);
+        final Object argumentsObject = wrapAsObject(env.getArguments().toArray());
+        final int    argumentsFlags  = Attribute.NOT_ENUMERABLE;
+        addOwnProperty("arguments", argumentsFlags, argumentsObject);
         if (env._scripting) {
             // synonym for "arguments" in scripting mode
-            addOwnProperty("$ARG", flags, argsObj);
+            addOwnProperty("$ARG", argumentsFlags, argumentsObject);
         }
     }
 
@@ -1857,7 +1858,7 @@
     }
 
     private static void copyOptions(final ScriptObject options, final ScriptEnvironment scriptEnv) {
-        for (Field f : scriptEnv.getClass().getFields()) {
+        for (final Field f : scriptEnv.getClass().getFields()) {
             try {
                 options.set(f.getName(), f.get(scriptEnv), false);
             } catch (final IllegalArgumentException | IllegalAccessException exp) {
--- a/nashorn/src/jdk/nashorn/internal/objects/NativeArray.java	Wed Feb 26 13:17:57 2014 +0100
+++ b/nashorn/src/jdk/nashorn/internal/objects/NativeArray.java	Mon Mar 03 11:24:44 2014 +0100
@@ -29,12 +29,10 @@
 import static jdk.nashorn.internal.runtime.ECMAErrors.typeError;
 import static jdk.nashorn.internal.runtime.PropertyDescriptor.VALUE;
 import static jdk.nashorn.internal.runtime.PropertyDescriptor.WRITABLE;
-import static jdk.nashorn.internal.runtime.UnwarrantedOptimismException.INVALID_PROGRAM_POINT;
 import static jdk.nashorn.internal.runtime.arrays.ArrayLikeIterator.arrayLikeIterator;
 import static jdk.nashorn.internal.runtime.arrays.ArrayLikeIterator.reverseArrayLikeIterator;
 
 import java.lang.invoke.MethodHandle;
-import java.lang.invoke.MethodType;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collections;
@@ -42,11 +40,11 @@
 import java.util.Iterator;
 import java.util.List;
 import java.util.concurrent.Callable;
+
 import jdk.internal.dynalink.CallSiteDescriptor;
 import jdk.internal.dynalink.linker.GuardedInvocation;
 import jdk.internal.dynalink.linker.LinkRequest;
 import jdk.nashorn.api.scripting.JSObject;
-import static jdk.nashorn.internal.lookup.Lookup.MH;
 import jdk.nashorn.internal.objects.annotations.Attribute;
 import jdk.nashorn.internal.objects.annotations.Constructor;
 import jdk.nashorn.internal.objects.annotations.Function;
@@ -54,8 +52,10 @@
 import jdk.nashorn.internal.objects.annotations.ScriptClass;
 import jdk.nashorn.internal.objects.annotations.Setter;
 import jdk.nashorn.internal.objects.annotations.SpecializedConstructor;
+import jdk.nashorn.internal.objects.annotations.SpecializedFunction;
 import jdk.nashorn.internal.objects.annotations.Where;
 import jdk.nashorn.internal.runtime.Context;
+import jdk.nashorn.internal.runtime.Debug;
 import jdk.nashorn.internal.runtime.JSType;
 import jdk.nashorn.internal.runtime.PropertyDescriptor;
 import jdk.nashorn.internal.runtime.PropertyMap;
@@ -66,11 +66,9 @@
 import jdk.nashorn.internal.runtime.arrays.ArrayData;
 import jdk.nashorn.internal.runtime.arrays.ArrayIndex;
 import jdk.nashorn.internal.runtime.arrays.ArrayLikeIterator;
-import jdk.nashorn.internal.runtime.arrays.ContinuousArray;
 import jdk.nashorn.internal.runtime.arrays.IteratorAction;
 import jdk.nashorn.internal.runtime.linker.Bootstrap;
 import jdk.nashorn.internal.runtime.linker.InvokeByName;
-import jdk.nashorn.internal.runtime.linker.NashornCallSiteDescriptor;
 
 /**
  * Runtime representation of a JavaScript array. NativeArray only holds numeric
@@ -97,7 +95,7 @@
 
     NativeArray(final long length) {
         // TODO assert valid index in long before casting
-        this(ArrayData.allocate((int) length));
+        this(ArrayData.allocate((int)length));
     }
 
     NativeArray(final int[] array) {
@@ -142,65 +140,30 @@
     }
 
     @Override
-    protected GuardedInvocation findGetIndexMethod(final CallSiteDescriptor desc, final LinkRequest request) {
-        final ArrayData  data       = getArray();
-        final MethodType callType   = desc.getMethodType();
-        final Class<?>   indexType  = callType.parameterType(1);
-        final Class<?>   returnType = callType.returnType();
-
-        if (data instanceof ContinuousArray && indexType == int.class) {
-            final Object[]   args       = request.getArguments();
-            final int        index      = (int)args[args.length - 1];
+    protected GuardedInvocation findGetMethod(final CallSiteDescriptor desc, final LinkRequest request, final String operator) {
+        final GuardedInvocation inv = getArray().findFastGetMethod(getArray().getClass(), desc, request, operator);
+        if (inv != null) {
+            return inv;
+        }
+        return super.findGetMethod(desc, request, operator);
+    }
 
-            if (data.has(index)) {
-                final MethodHandle getArray     = ScriptObject.GET_ARRAY.methodHandle();
-                final int          programPoint = NashornCallSiteDescriptor.isOptimistic(desc) ? NashornCallSiteDescriptor.getProgramPoint(desc) : INVALID_PROGRAM_POINT;
-                MethodHandle       getElement   = ((ContinuousArray)data).getElementGetter(returnType, programPoint);
-                if (getElement != null) {
-                    getElement = MH.filterArguments(getElement, 0, MH.asType(getArray, getArray.type().changeReturnType(ContinuousArray.class)));
-                    //System.err.println("Relink fast GET "+ desc+ " "+  DynamicLinker.getLinkedCallSiteLocation());
-                    return new GuardedInvocation(getElement, null, null, ClassCastException.class);
-                }
-            }
+    @Override
+    protected GuardedInvocation findGetIndexMethod(final CallSiteDescriptor desc, final LinkRequest request) {
+        final GuardedInvocation inv = getArray().findFastGetIndexMethod(getArray().getClass(), desc, request);
+        if (inv != null) {
+            return inv;
         }
-        //System.err.println("Relink slow GET "+ desc+ " "+  DynamicLinker.getLinkedCallSiteLocation());
-
         return super.findGetIndexMethod(desc, request);
     }
 
     @Override
-    protected GuardedInvocation findSetIndexMethod(final CallSiteDescriptor desc, final LinkRequest request) { // array, index, value
-
-        final ArrayData  data        = getArray();
-        final MethodType callType    = desc.getMethodType();
-        final Class<?>   indexType   = callType.parameterType(1);
-        final Class<?>   elementType = callType.parameterType(2);
-
-        if (data instanceof ContinuousArray && indexType == int.class) {
-            final ContinuousArray cdata = (ContinuousArray)data;
-            final Object[]        args  = request.getArguments();
-            final int             index = (int)args[args.length - 2];
-
-            if (data.has(index)) {
-                MethodHandle hasGuard = cdata.getSetGuard();
-                hasGuard = MH.asType(hasGuard, hasGuard.type().changeParameterType(0, ContinuousArray.class));
-
-                MethodHandle setElement = cdata.getElementSetter(elementType); //Z(continuousarraydata, int, int), return true if successful
-                if (setElement != null) {
-                    //else we are dealing with a wider type than supported by this callsite
-                    MethodHandle getArray = ScriptObject.GET_ARRAY.methodHandle();
-                    getArray   = MH.asType(getArray, getArray.type().changeReturnType(ContinuousArray.class));
-                    setElement = MH.filterArguments(setElement, 0, getArray);
-                    hasGuard   = MH.filterArguments(hasGuard, 0, getArray);
-                    //if this is the first invocation we have to execute the setter ourselves, we know it will work
-
-                    //System.err.println("Relink fast SET "+ desc + " "+  DynamicLinker.getLinkedCallSiteLocation());
-                    return new GuardedInvocation(setElement, hasGuard, null, ClassCastException.class); //CCE if not a scriptObject anymore
-                }
-            }
+    protected GuardedInvocation findSetIndexMethod(final CallSiteDescriptor desc, final LinkRequest request) {
+        final GuardedInvocation inv = getArray().findFastSetIndexMethod(getArray().getClass(), desc, request);
+        if (inv != null) {
+            return inv;
         }
 
-        //System.err.println("Relink slow SET "+ desc + " "+  DynamicLinker.getLinkedCallSiteLocation());
         return super.findSetIndexMethod(desc, request);
     }
 
@@ -856,13 +819,10 @@
         try {
             final ScriptObject sobj   = (ScriptObject)self;
 
-            if (bulkable(sobj)) {
-                if (sobj.getArray().length() + args.length <= JSType.MAX_UINT) {
-                    final ArrayData newData = sobj.getArray().push(true, args);
-                    sobj.setArray(newData);
-                    return newData.length();
-                }
-                //fallthru
+            if (bulkable(sobj) && sobj.getArray().length() + args.length <= JSType.MAX_UINT) {
+                final ArrayData newData = sobj.getArray().push(true, args);
+                sobj.setArray(newData);
+                return newData.length();
             }
 
             long len = JSType.toUint32(sobj.getLength());
@@ -878,6 +838,88 @@
     }
 
     /**
+     * ECMA 15.4.4.7 Array.prototype.push (args...) specialized for single int argument
+     *
+     * @param self self reference
+     * @param arg argument to push
+     * @return array after pushes
+     */
+/*    @SpecializedFunction
+    public static long push(final Object self, final int arg) {
+        try {
+            final ScriptObject sobj = (ScriptObject)self;
+            final ArrayData arrayData = sobj.getArray();
+            final long length = arrayData.length();
+
+            if (bulkable(sobj) && length + 1 <= JSType.MAX_UINT) {
+                sobj.setArray(arrayData.ensure(length).set(ArrayIndex.getArrayIndex(length), arg, true));
+                return length + 1;
+            }
+
+            long len = JSType.toUint32(sobj.getLength());
+            sobj.set(len++, arg, true);
+            sobj.set("length", len, true);
+            return len;
+        } catch (final ClassCastException | NullPointerException e) {
+            throw typeError("not.an.object", ScriptRuntime.safeToString(self));
+        }
+    }
+*/
+    /**
+     * ECMA 15.4.4.7 Array.prototype.push (args...) specialized for single number argument
+     *
+     * @param self self reference
+     * @param arg argument to push
+     * @return array after pushes
+     */
+ /*   @SpecializedFunction
+    public static long push(final Object self, final double arg) {
+        try {
+            final ScriptObject sobj = (ScriptObject)self;        final ArrayData arrayData = sobj.getArray();
+            final long length = arrayData.length();
+
+            if (bulkable(sobj) && length + 1 <= JSType.MAX_UINT) {
+                sobj.setArray(arrayData.ensure(length).set(ArrayIndex.getArrayIndex(length), arg, true));
+                return length + 1;
+            }
+
+            long len = JSType.toUint32(sobj.getLength());
+            sobj.set(len++, arg, true);
+            sobj.set("length", len, true);
+            return len;
+        } catch (final ClassCastException | NullPointerException e) {
+            throw typeError("not.an.object", ScriptRuntime.safeToString(self));
+        }
+    }
+*/
+    /**
+     * ECMA 15.4.4.7 Array.prototype.push (args...) specialized for single object argument
+     *
+     * @param self self reference
+     * @param arg argument to push
+     * @return array after pushes
+     */
+    @SpecializedFunction
+    public static long push(final Object self, final Object arg) {
+        try {
+            final ScriptObject sobj = (ScriptObject)self;
+            final ArrayData arrayData = sobj.getArray();
+            final long length = arrayData.length();
+            if (bulkable(sobj) && length < JSType.MAX_UINT) {
+                sobj.setArray(arrayData.push(true, arg)); //ensure(length).set(ArrayIndex.getArrayIndex(length), arg, true));
+                return length + 1;
+            }
+
+            long len = JSType.toUint32(sobj.getLength());
+            sobj.set(len++, arg, true);
+            sobj.set("length", len, true);
+            return len;
+        } catch (final ClassCastException | NullPointerException e) {
+            throw typeError("not.an.object", ScriptRuntime.safeToString(self));
+        }
+    }
+
+    /**
      * ECMA 15.4.4.8 Array.prototype.reverse ()
      *
      * @param self self reference
@@ -1086,7 +1128,7 @@
                 }
 
                 sobj.setArray(array);
-           }
+            }
 
             return sobj;
         } catch (final ClassCastException | NullPointerException e) {
@@ -1243,7 +1285,7 @@
             }
 
             for (int j = 0; j < items.length; j++) {
-                 sobj.set(j, items[j], true);
+                sobj.set(j, items[j], true);
             }
         }
 
@@ -1520,4 +1562,9 @@
 
         return false;
     }
+
+    @Override
+    public String toString() {
+        return "NativeArray@" + Debug.id(this) + '@' + getArray().getClass().getSimpleName();
+    }
 }
--- a/nashorn/src/jdk/nashorn/internal/objects/NativeArrayBuffer.java	Wed Feb 26 13:17:57 2014 +0100
+++ b/nashorn/src/jdk/nashorn/internal/objects/NativeArrayBuffer.java	Mon Mar 03 11:24:44 2014 +0100
@@ -25,20 +25,28 @@
 
 package jdk.nashorn.internal.objects;
 
-import java.util.Arrays;
+import static jdk.nashorn.internal.runtime.ECMAErrors.typeError;
+
+import java.nio.ByteBuffer;
+
 import jdk.nashorn.internal.objects.annotations.Attribute;
 import jdk.nashorn.internal.objects.annotations.Constructor;
 import jdk.nashorn.internal.objects.annotations.Function;
 import jdk.nashorn.internal.objects.annotations.Getter;
 import jdk.nashorn.internal.objects.annotations.ScriptClass;
+import jdk.nashorn.internal.objects.annotations.SpecializedFunction;
 import jdk.nashorn.internal.runtime.JSType;
 import jdk.nashorn.internal.runtime.PropertyMap;
 import jdk.nashorn.internal.runtime.ScriptObject;
 import jdk.nashorn.internal.runtime.ScriptRuntime;
 
+/**
+ * NativeArrayBuffer - ArrayBuffer as described in the JS typed
+ * array spec
+ */
 @ScriptClass("ArrayBuffer")
-final class NativeArrayBuffer extends ScriptObject {
-    private final byte[] buffer;
+public final class NativeArrayBuffer extends ScriptObject {
+    private final ByteBuffer nb;
 
     // initialized by nasgen
     private static PropertyMap $nasgenmap$;
@@ -47,8 +55,19 @@
         return $nasgenmap$;
     }
 
+    /**
+     * Constructor
+     * @param newObj is this a new call
+     * @param self   self
+     * @param args   arguments
+     * @return new native array buffer
+     */
     @Constructor(arity = 1)
     public static Object constructor(final boolean newObj, final Object self, final Object... args) {
+        if (!newObj) {
+            throw typeError("constructor.requires.new", "ArrayBuffer");
+        }
+
         if (args.length == 0) {
             throw new RuntimeException("missing length argument");
         }
@@ -56,21 +75,56 @@
         return new NativeArrayBuffer(JSType.toInt32(args[0]));
     }
 
-    protected NativeArrayBuffer(final byte[] byteArray, final Global global) {
+    /**
+     * Constructor
+     * @param nb native byte buffer to wrap
+     * @param global global instance
+     */
+    protected NativeArrayBuffer(final ByteBuffer nb, final Global global) {
         super(global.getArrayBufferPrototype(), global.getArrayBufferMap());
-        this.buffer = byteArray;
+        this.nb = nb;
+    }
+
+    /**
+     * Constructor
+     * @param nb native byte buffer to wrap
+     */
+    protected NativeArrayBuffer(final ByteBuffer nb) {
+        this(nb, Global.instance());
     }
 
-    protected NativeArrayBuffer(final byte[] byteArray) {
-        this(byteArray, Global.instance());
+    /**
+     * Constructor
+     * @param byteLength byteLength for buffer
+     */
+    protected NativeArrayBuffer(final int byteLength) {
+        this(ByteBuffer.allocateDirect(byteLength));
     }
 
-    protected NativeArrayBuffer(final int byteLength) {
-        this(new byte[byteLength]);
+    /**
+     * Clone constructor
+     * Used only for slice
+     * @param other original buffer
+     * @param begin begin byte index
+     * @param end   end byte index
+     */
+    protected NativeArrayBuffer(final NativeArrayBuffer other, final int begin, final int end) {
+        this(cloneBuffer(other.getNioBuffer(), begin, end));
     }
 
-    protected NativeArrayBuffer(final NativeArrayBuffer other, final int begin, final int end) {
-        this(Arrays.copyOfRange(other.buffer, begin, end));
+    private static ByteBuffer cloneBuffer(ByteBuffer original, final int begin, final int end) {
+        final ByteBuffer clone = ByteBuffer.allocateDirect(original.capacity());
+        original.rewind();//copy from the beginning
+        clone.put(original);
+        original.rewind();
+        clone.flip();
+        clone.position(begin);
+        clone.limit(end);
+        return clone.slice();
+    }
+
+    ByteBuffer getNioBuffer() {
+        return nb;
     }
 
     @Override
@@ -78,19 +132,55 @@
         return "ArrayBuffer";
     }
 
+    /**
+     * Byte length for native array buffer
+     * @param self native array buffer
+     * @return byte length
+     */
     @Getter(attributes = Attribute.NOT_ENUMERABLE | Attribute.NOT_WRITABLE | Attribute.NOT_CONFIGURABLE)
-    public static Object byteLength(final Object self) {
-        return ((NativeArrayBuffer)self).buffer.length;
+    public static int byteLength(final Object self) {
+        return ((NativeArrayBuffer)self).getByteLength();
     }
 
+    /**
+     * Slice function
+     * @param self   native array buffer
+     * @param begin0 start byte index
+     * @param end0   end byte index
+     * @return new array buffer, sliced
+     */
     @Function(attributes = Attribute.NOT_ENUMERABLE)
     public static Object slice(final Object self, final Object begin0, final Object end0) {
         final NativeArrayBuffer arrayBuffer = (NativeArrayBuffer)self;
-        int begin = JSType.toInt32(begin0);
-        int end = end0 != ScriptRuntime.UNDEFINED ? JSType.toInt32(end0) : arrayBuffer.getByteLength();
-        begin = adjustIndex(begin, arrayBuffer.getByteLength());
-        end = adjustIndex(end, arrayBuffer.getByteLength());
-        return new NativeArrayBuffer((NativeArrayBuffer) self, begin, Math.max(end, begin));
+        final int               byteLength  = arrayBuffer.getByteLength();
+        final int               begin       = adjustIndex(JSType.toInt32(begin0), byteLength);
+        final int               end         = adjustIndex(end0 != ScriptRuntime.UNDEFINED ? JSType.toInt32(end0) : byteLength, byteLength);
+        return new NativeArrayBuffer(arrayBuffer, begin, Math.max(end, begin));
+    }
+
+    /**
+     * Specialized slice function
+     * @param self   native array buffer
+     * @param begin  start byte index
+     * @param end    end byte index
+     * @return new array buffer, sliced
+     */
+    @SpecializedFunction
+    public static Object slice(final Object self, final int begin, final int end) {
+        final NativeArrayBuffer arrayBuffer = (NativeArrayBuffer)self;
+        final int byteLength  = arrayBuffer.getByteLength();
+        return new NativeArrayBuffer(arrayBuffer, adjustIndex(begin, byteLength), Math.max(adjustIndex(end, byteLength), begin));
+    }
+
+    /**
+     * Specialized slice function
+     * @param self   native array buffer
+     * @param begin  start byte index
+     * @return new array buffer, sliced
+     */
+    @SpecializedFunction
+    public static Object slice(final Object self, final int begin) {
+        return slice(self, begin, ((NativeArrayBuffer)self).getByteLength());
     }
 
     /**
@@ -103,10 +193,7 @@
      * @return valid index index in the range [0, length).
      */
     static int adjustIndex(final int index, final int length) {
-        if (index < 0) {
-            return clamp(index + length, length);
-        }
-        return clamp(index, length);
+        return index < 0 ? clamp(index + length, length) : clamp(index, length);
     }
 
     /**
@@ -121,11 +208,7 @@
         return index;
     }
 
-    public byte[] getByteArray() {
-        return buffer;
-    }
-
-    public int getByteLength() {
-        return buffer.length;
+    int getByteLength() {
+        return nb.limit();
     }
 }
--- a/nashorn/src/jdk/nashorn/internal/objects/NativeDebug.java	Wed Feb 26 13:17:57 2014 +0100
+++ b/nashorn/src/jdk/nashorn/internal/objects/NativeDebug.java	Mon Mar 03 11:24:44 2014 +0100
@@ -108,6 +108,7 @@
     /**
      * Returns true if if the two objects are both property maps, and they have identical properties in the same order,
      * but allows the properties to differ in their types.
+     * @param self self
      * @param m1 first property map
      * @param m2 second property map
      * @return true if they have identical properties in same order, with possibly different types.
@@ -119,6 +120,7 @@
 
     /**
      * Returns a diagnostic string representing the difference of two property maps.
+     * @param self self
      * @param m1 first property map
      * @param m2 second property map
      * @return a diagnostic string representing the difference of two property maps.
@@ -128,7 +130,6 @@
         return PropertyMap.diff((PropertyMap)m1, (PropertyMap)m2);
     }
 
-
     /**
      * Object util - getClass
      *
--- a/nashorn/src/jdk/nashorn/internal/objects/NativeError.java	Wed Feb 26 13:17:57 2014 +0100
+++ b/nashorn/src/jdk/nashorn/internal/objects/NativeError.java	Mon Mar 03 11:24:44 2014 +0100
@@ -151,8 +151,7 @@
      */
     @Function(attributes = Attribute.NOT_ENUMERABLE, where = Where.CONSTRUCTOR)
     public static Object captureStackTrace(final Object self, final Object errorObj) {
-        Global.checkObject(errorObj);
-        final ScriptObject sobj = (ScriptObject)errorObj;
+        final ScriptObject sobj = Global.checkObject(errorObj);
         initException(sobj);
         sobj.delete(STACK, false);
         if (! sobj.has("stack")) {
@@ -188,8 +187,7 @@
      */
     @Function(attributes = Attribute.NOT_ENUMERABLE)
     public static Object printStackTrace(final Object self) {
-        Global.checkObject(self);
-        return ECMAException.printStackTrace((ScriptObject)self);
+        return ECMAException.printStackTrace(Global.checkObject(self));
     }
 
     /**
@@ -203,8 +201,7 @@
      */
     @Function(attributes = Attribute.NOT_ENUMERABLE)
     public static Object getStackTrace(final Object self) {
-        Global.checkObject(self);
-        final ScriptObject sobj = (ScriptObject)self;
+        final ScriptObject sobj = Global.checkObject(self);
         final Object exception = ECMAException.getException(sobj);
         Object[] res;
         if (exception instanceof Throwable) {
@@ -224,8 +221,7 @@
      * @return line number from which error was thrown
      */
     public static Object getLineNumber(final Object self) {
-        Global.checkObject(self);
-        final ScriptObject sobj = (ScriptObject)self;
+        final ScriptObject sobj = Global.checkObject(self);
         return sobj.has(LINENUMBER) ? sobj.get(LINENUMBER) : ECMAException.getLineNumber(sobj);
     }
 
@@ -238,8 +234,7 @@
      * @return value that was set
      */
     public static Object setLineNumber(final Object self, final Object value) {
-        Global.checkObject(self);
-        final ScriptObject sobj = (ScriptObject)self;
+        final ScriptObject sobj = Global.checkObject(self);
         if (sobj.hasOwnProperty(LINENUMBER)) {
             sobj.put(LINENUMBER, value, false);
         } else {
@@ -256,8 +251,7 @@
      * @return column number from which error was thrown
      */
     public static Object getColumnNumber(final Object self) {
-        Global.checkObject(self);
-        final ScriptObject sobj = (ScriptObject)self;
+        final ScriptObject sobj = Global.checkObject(self);
         return sobj.has(COLUMNNUMBER) ? sobj.get(COLUMNNUMBER) : ECMAException.getColumnNumber((ScriptObject)self);
     }
 
@@ -270,8 +264,7 @@
      * @return value that was set
      */
     public static Object setColumnNumber(final Object self, final Object value) {
-        Global.checkObject(self);
-        final ScriptObject sobj = (ScriptObject)self;
+        final ScriptObject sobj = Global.checkObject(self);
         if (sobj.hasOwnProperty(COLUMNNUMBER)) {
             sobj.put(COLUMNNUMBER, value, false);
         } else {
@@ -288,8 +281,7 @@
      * @return file name from which error was thrown
      */
     public static Object getFileName(final Object self) {
-        Global.checkObject(self);
-        final ScriptObject sobj = (ScriptObject)self;
+        final ScriptObject sobj = Global.checkObject(self);
         return sobj.has(FILENAME) ? sobj.get(FILENAME) : ECMAException.getFileName((ScriptObject)self);
     }
 
@@ -302,8 +294,7 @@
      * @return value that was set
      */
     public static Object setFileName(final Object self, final Object value) {
-        Global.checkObject(self);
-        final ScriptObject sobj = (ScriptObject)self;
+        final ScriptObject sobj = Global.checkObject(self);
         if (sobj.hasOwnProperty(FILENAME)) {
             sobj.put(FILENAME, value, false);
         } else {
@@ -322,8 +313,7 @@
      * @return      value of "stack" property
      */
     public static Object getStack(final Object self) {
-        Global.checkObject(self);
-        final ScriptObject sobj = (ScriptObject)self;
+        final ScriptObject sobj = Global.checkObject(self);
         if (sobj.has(STACK)) {
             return sobj.get(STACK);
         }
@@ -348,8 +338,7 @@
      * @return value that was set
      */
     public static Object setStack(final Object self, final Object value) {
-        Global.checkObject(self);
-        final ScriptObject sobj = (ScriptObject)self;
+        final ScriptObject sobj = Global.checkObject(self);
         sobj.set(STACK, value, false);
         return value;
     }
@@ -364,9 +353,7 @@
     @Function(attributes = Attribute.NOT_ENUMERABLE)
     public static Object toString(final Object self) {
         // Step 1 and 2 : check if 'self' is object it not throw TypeError
-        Global.checkObject(self);
-
-        final ScriptObject sobj = (ScriptObject)self;
+        final ScriptObject sobj = Global.checkObject(self);
 
         // Step 3 & 4 : get "name" and convert to String.
         // But if message is undefined make it "Error".
--- a/nashorn/src/jdk/nashorn/internal/objects/NativeFloat32Array.java	Wed Feb 26 13:17:57 2014 +0100
+++ b/nashorn/src/jdk/nashorn/internal/objects/NativeFloat32Array.java	Mon Mar 03 11:24:44 2014 +0100
@@ -25,6 +25,13 @@
 
 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;
+import java.nio.FloatBuffer;
+
 import jdk.nashorn.internal.objects.annotations.Attribute;
 import jdk.nashorn.internal.objects.annotations.Constructor;
 import jdk.nashorn.internal.objects.annotations.Function;
@@ -35,6 +42,7 @@
 import jdk.nashorn.internal.runtime.PropertyMap;
 import jdk.nashorn.internal.runtime.ScriptObject;
 import jdk.nashorn.internal.runtime.arrays.ArrayData;
+import jdk.nashorn.internal.runtime.arrays.TypedArrayData;
 
 /**
  * Float32 array for the TypedArray extension
@@ -56,73 +64,103 @@
         public ArrayBufferView construct(final NativeArrayBuffer buffer, final int byteOffset, final int length) {
             return new NativeFloat32Array(buffer, byteOffset, length);
         }
+
         @Override
-        public ArrayData createArrayData(final NativeArrayBuffer buffer, final int byteOffset, final int length) {
-            return new Float32ArrayData(buffer, byteOffset, length);
-        }
-    };
-
-    private static final class Float32ArrayData extends ArrayDataImpl {
-        private Float32ArrayData(final NativeArrayBuffer buffer, final int byteOffset, final int elementLength) {
-            super(buffer, byteOffset, elementLength);
+        public Float32ArrayData createArrayData(final ByteBuffer nb, final int start, final int end) {
+            return new Float32ArrayData(nb.asFloatBuffer(), start, end);
         }
 
         @Override
-        protected int byteIndex(final int index) {
-            return index * BYTES_PER_ELEMENT + byteOffset;
+        public String getClassName() {
+            return "Float32Array";
+        }
+    };
+
+    private static final class Float32ArrayData extends TypedArrayData<FloatBuffer> {
+
+        private static final MethodHandle GET_ELEM = specialCall(MethodHandles.lookup(), Float32ArrayData.class, "getElem", double.class, int.class).methodHandle();
+        private static final MethodHandle SET_ELEM = specialCall(MethodHandles.lookup(), Float32ArrayData.class, "setElem", void.class, int.class, double.class).methodHandle();
+
+        private Float32ArrayData(final FloatBuffer nb, final int start, final int end) {
+            super(((FloatBuffer)nb.position(start).limit(end)).slice(), end - start);
         }
 
         @Override
-        protected double getDoubleImpl(final int index) {
-            final int byteIndex = byteIndex(index);
-            final byte[] byteArray = buffer.getByteArray();
-            final int bits = byteArray[byteIndex  ]       & 0x0000_00ff |
-                             byteArray[byteIndex+1] <<  8 & 0x0000_ff00 |
-                             byteArray[byteIndex+2] << 16 & 0x00ff_0000 |
-                             byteArray[byteIndex+3] << 24 & 0xff00_0000 ;
-            return Float.intBitsToFloat(bits);
-        }
-
-        @Override
-        protected int getIntImpl(final int index) {
-            return (int)getDoubleImpl(index);
+        protected MethodHandle getGetElem() {
+            return GET_ELEM;
         }
 
         @Override
-        protected long getLongImpl(final int key) {
-            return (long)getDoubleImpl(key);
+        protected MethodHandle getSetElem() {
+            return SET_ELEM;
+        }
+
+        private double getElem(final int index) {
+            try {
+                return nb.get(index);
+            } catch (final IndexOutOfBoundsException e) {
+                throw new ClassCastException(); //force relink - this works for unoptimistic too
+            }
+        }
+
+        private void setElem(final int index, final double elem) {
+            try {
+                nb.put(index, (float)elem);
+            } catch (final IndexOutOfBoundsException e) {
+                //swallow valid array indexes. it's ok.
+                if (index < 0) {
+                    throw new ClassCastException();
+                }
+            }
         }
 
         @Override
-        protected Object getObjectImpl(final int key) {
-            return getDoubleImpl(key);
+        public MethodHandle getElementGetter(final Class<?> returnType, final int programPoint) {
+            if (returnType == int.class || returnType == long.class) {
+                return null;
+            }
+            return getContinuousElementGetter(getClass(), GET_ELEM, returnType, programPoint);
         }
 
         @Override
-        protected void setImpl(final int index, final double value) {
-            final int bits = Float.floatToRawIntBits((float)value);
-            final int byteIndex = byteIndex(index);
-            @SuppressWarnings("MismatchedReadAndWriteOfArray")
-            final byte[] byteArray = buffer.getByteArray();
-            byteArray[byteIndex  ] = (byte)(bits        & 0xff);
-            byteArray[byteIndex+1] = (byte)(bits >>>  8 & 0xff);
-            byteArray[byteIndex+2] = (byte)(bits >>> 16 & 0xff);
-            byteArray[byteIndex+3] = (byte)(bits >>> 24 & 0xff);
+        public int getInt(int index) {
+            return (int)getDouble(index);
+        }
+
+        @Override
+        public long getLong(int index) {
+            return (long)getDouble(index);
+        }
+
+        @Override
+        public double getDouble(int index) {
+            return getElem(index);
         }
 
         @Override
-        protected void setImpl(final int key, final int value) {
-            setImpl(key, (double)value);
+        public Object getObject(int index) {
+            return getDouble(index);
+        }
+
+        @Override
+        public ArrayData set(int index, Object value, boolean strict) {
+            return set(index, JSType.toNumber(value), strict);
         }
 
         @Override
-        protected void setImpl(final int key, final long value) {
-            setImpl(key, (double)value);
+        public ArrayData set(int index, int value, boolean strict) {
+            return set(index, (double)value, strict);
         }
 
         @Override
-        protected void setImpl(final int key, final Object value) {
-            setImpl(key, JSType.toNumber(value));
+        public ArrayData set(int index, long value, boolean strict) {
+            return set(index, (double)value, strict);
+        }
+
+        @Override
+        public ArrayData set(int index, double value, boolean strict) {
+            setElem(index, value);
+            return this;
         }
     }
 
@@ -137,7 +175,7 @@
      */
     @Constructor(arity = 1)
     public static Object constructor(final boolean newObj, final Object self, final Object... args) {
-        return constructorImpl(args, FACTORY);
+        return constructorImpl(newObj, args, FACTORY);
     }
 
     NativeFloat32Array(final NativeArrayBuffer buffer, final int byteOffset, final int length) {
@@ -145,11 +183,6 @@
     }
 
     @Override
-    public String getClassName() {
-        return "Float32Array";
-    }
-
-    @Override
     protected Factory factory() {
         return FACTORY;
     }
--- a/nashorn/src/jdk/nashorn/internal/objects/NativeFloat64Array.java	Wed Feb 26 13:17:57 2014 +0100
+++ b/nashorn/src/jdk/nashorn/internal/objects/NativeFloat64Array.java	Mon Mar 03 11:24:44 2014 +0100
@@ -25,6 +25,13 @@
 
 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;
+import java.nio.DoubleBuffer;
+
 import jdk.nashorn.internal.objects.annotations.Attribute;
 import jdk.nashorn.internal.objects.annotations.Constructor;
 import jdk.nashorn.internal.objects.annotations.Function;
@@ -35,6 +42,7 @@
 import jdk.nashorn.internal.runtime.PropertyMap;
 import jdk.nashorn.internal.runtime.ScriptObject;
 import jdk.nashorn.internal.runtime.arrays.ArrayData;
+import jdk.nashorn.internal.runtime.arrays.TypedArrayData;
 
 /**
  * Float64 array for the TypedArray extension
@@ -56,83 +64,103 @@
         public ArrayBufferView construct(final NativeArrayBuffer buffer, final int byteOffset, final int length) {
             return new NativeFloat64Array(buffer, byteOffset, length);
         }
-        @Override
-        public ArrayData createArrayData(final NativeArrayBuffer buffer, final int byteOffset, final int length) {
-            return new Float64ArrayData(buffer, byteOffset, length);
-        }
-    };
-
-    private static final class Float64ArrayData extends ArrayDataImpl {
-        private Float64ArrayData(final NativeArrayBuffer buffer,
-                final int byteOffset, final int elementLength) {
-            super(buffer, byteOffset, elementLength);
-        }
 
         @Override
-        protected int byteIndex(final int index) {
-            return index * BYTES_PER_ELEMENT + byteOffset;
+        public Float64ArrayData createArrayData(final ByteBuffer nb, final int start, final int length) {
+            return new Float64ArrayData(nb.asDoubleBuffer(), start, length);
         }
 
         @Override
-        protected double getDoubleImpl(final int index) {
-            final int byteIndex = byteIndex(index);
-            final byte[] byteArray = buffer.getByteArray();
-            final long bits;
-            bits =       byteArray[byteIndex  ]       & 0x0000_0000_0000_00ffL |
-                   (long)byteArray[byteIndex+1] <<  8 & 0x0000_0000_0000_ff00L |
-                   (long)byteArray[byteIndex+2] << 16 & 0x0000_0000_00ff_0000L |
-                   (long)byteArray[byteIndex+3] << 24 & 0x0000_0000_ff00_0000L |
-                   (long)byteArray[byteIndex+4] << 32 & 0x0000_00ff_0000_0000L |
-                   (long)byteArray[byteIndex+5] << 40 & 0x0000_ff00_0000_0000L |
-                   (long)byteArray[byteIndex+6] << 48 & 0x00ff_0000_0000_0000L |
-                   (long)byteArray[byteIndex+7] << 56 & 0xff00_0000_0000_0000L ;
-            return Double.longBitsToDouble(bits);
+        public String getClassName() {
+            return "Float64Array";
+        }
+    };
+
+    private static final class Float64ArrayData extends TypedArrayData<DoubleBuffer> {
+
+        private static final MethodHandle GET_ELEM = specialCall(MethodHandles.lookup(), Float64ArrayData.class, "getElem", double.class, int.class).methodHandle();
+        private static final MethodHandle SET_ELEM = specialCall(MethodHandles.lookup(), Float64ArrayData.class, "setElem", void.class, int.class, double.class).methodHandle();
+
+        private Float64ArrayData(final DoubleBuffer nb, final int start, final int end) {
+            super(((DoubleBuffer)nb.position(start).limit(end)).slice(), end - start);
         }
 
         @Override
-        protected int getIntImpl(final int index) {
-            return (int)getDoubleImpl(index);
+        protected MethodHandle getGetElem() {
+            return GET_ELEM;
         }
 
         @Override
-        protected long getLongImpl(final int key) {
-            return (long)getDoubleImpl(key);
+        protected MethodHandle getSetElem() {
+            return SET_ELEM;
+        }
+
+        private double getElem(final int index) {
+            try {
+                return nb.get(index);
+            } catch (final IndexOutOfBoundsException e) {
+                throw new ClassCastException(); //force relink - this works for unoptimistic too
+            }
+        }
+
+        private void setElem(final int index, final double elem) {
+            try {
+                nb.put(index, elem);
+            } catch (final IndexOutOfBoundsException e) {
+                //swallow valid array indexes. it's ok.
+                if (index < 0) {
+                    throw new ClassCastException();
+                }
+             }
         }
 
         @Override
-        protected Object getObjectImpl(final int key) {
-            return getDoubleImpl(key);
+        public MethodHandle getElementGetter(final Class<?> returnType, final int programPoint) {
+            if (returnType == int.class || returnType == long.class) {
+                return null;
+            }
+            return getContinuousElementGetter(getClass(), GET_ELEM, returnType, programPoint);
         }
 
         @Override
-        protected void setImpl(final int index, final double value) {
-            final long bits = Double.doubleToRawLongBits(value);
-            final int byteIndex = byteIndex(index);
-            @SuppressWarnings("MismatchedReadAndWriteOfArray")
-            final byte[] byteArray = buffer.getByteArray();
-            byteArray[byteIndex  ] = (byte)(bits        & 0xff);
-            byteArray[byteIndex+1] = (byte)(bits >>>  8 & 0xff);
-            byteArray[byteIndex+2] = (byte)(bits >>> 16 & 0xff);
-            byteArray[byteIndex+3] = (byte)(bits >>> 24 & 0xff);
-            byteArray[byteIndex+4] = (byte)(bits >>> 32 & 0xff);
-            byteArray[byteIndex+5] = (byte)(bits >>> 40 & 0xff);
-            byteArray[byteIndex+6] = (byte)(bits >>> 48 & 0xff);
-            byteArray[byteIndex+7] = (byte)(bits >>> 56 & 0xff);
+        public int getInt(final int index) {
+            return (int)getDouble(index);
+        }
+
+        @Override
+        public long getLong(final int index) {
+            return (long)getDouble(index);
+        }
+
+        @Override
+        public double getDouble(final int index) {
+            return getElem(index);
         }
 
         @Override
-        protected void setImpl(final int key, final int value) {
-            setImpl(key, (double)value);
+        public Object getObject(final int index) {
+            return getDouble(index);
+        }
+
+        @Override
+        public ArrayData set(final int index, final Object value, final boolean strict) {
+            return set(index, JSType.toNumber(value), strict);
         }
 
         @Override
-        protected void setImpl(final int key, final long value) {
-            setImpl(key, (double)value);
+        public ArrayData set(final int index, final int value, final boolean strict) {
+            return set(index, (double)value, strict);
         }
 
         @Override
-        protected void setImpl(final int key, final Object value) {
-            setImpl(key, JSType.toNumber(value));
+        public ArrayData set(final int index, final long value, final boolean strict) {
+            return set(index, (double)value, strict);
+        }
+
+        @Override
+        public ArrayData set(final int index, final double value, final boolean strict) {
+            setElem(index, value);
+            return this;
         }
     }
 
@@ -147,7 +175,7 @@
      */
     @Constructor(arity = 1)
     public static Object constructor(final boolean newObj, final Object self, final Object... args) {
-        return constructorImpl(args, FACTORY);
+        return constructorImpl(newObj, args, FACTORY);
     }
 
     NativeFloat64Array(final NativeArrayBuffer buffer, final int byteOffset, final int length) {
@@ -155,11 +183,6 @@
     }
 
     @Override
-    public String getClassName() {
-        return "Float64Array";
-    }
-
-    @Override
     protected Factory factory() {
         return FACTORY;
     }
--- a/nashorn/src/jdk/nashorn/internal/objects/NativeInt16Array.java	Wed Feb 26 13:17:57 2014 +0100
+++ b/nashorn/src/jdk/nashorn/internal/objects/NativeInt16Array.java	Mon Mar 03 11:24:44 2014 +0100
@@ -25,15 +25,24 @@
 
 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;
+import java.nio.ShortBuffer;
+
 import jdk.nashorn.internal.objects.annotations.Attribute;
 import jdk.nashorn.internal.objects.annotations.Constructor;
 import jdk.nashorn.internal.objects.annotations.Function;
 import jdk.nashorn.internal.objects.annotations.Property;
 import jdk.nashorn.internal.objects.annotations.ScriptClass;
 import jdk.nashorn.internal.objects.annotations.Where;
+import jdk.nashorn.internal.runtime.JSType;
 import jdk.nashorn.internal.runtime.PropertyMap;
 import jdk.nashorn.internal.runtime.ScriptObject;
 import jdk.nashorn.internal.runtime.arrays.ArrayData;
+import jdk.nashorn.internal.runtime.arrays.TypedArrayData;
 
 /**
  * Int16 array for the TypedArray extension
@@ -56,37 +65,95 @@
         public ArrayBufferView construct(final NativeArrayBuffer buffer, final int byteOffset, final int length) {
             return new NativeInt16Array(buffer, byteOffset, length);
         }
+
         @Override
-        public ArrayData createArrayData(final NativeArrayBuffer buffer, final int byteOffset, final int length) {
-            return new Int16ArrayData(buffer, byteOffset, length);
+        public Int16ArrayData createArrayData(final ByteBuffer nb, final int start, final int end) {
+            return new Int16ArrayData(nb.asShortBuffer(), start, end);
+        }
+
+        @Override
+        public String getClassName() {
+            return "Int16Array";
         }
     };
 
-    private static final class Int16ArrayData extends ArrayDataImpl {
-        private Int16ArrayData(final NativeArrayBuffer buffer, final int byteOffset, final int elementLength) {
-            super(buffer, byteOffset, elementLength);
+    private static final class Int16ArrayData extends TypedArrayData<ShortBuffer> {
+
+        private static final MethodHandle GET_ELEM = specialCall(MethodHandles.lookup(), Int16ArrayData.class, "getElem", int.class, int.class).methodHandle();
+        private static final MethodHandle SET_ELEM = specialCall(MethodHandles.lookup(), Int16ArrayData.class, "setElem", void.class, int.class, int.class).methodHandle();
+
+        private Int16ArrayData(final ShortBuffer nb, final int start, final int end) {
+            super(((ShortBuffer)nb.position(start).limit(end)).slice(), end - start);
+        }
+
+        @Override
+        protected MethodHandle getGetElem() {
+            return GET_ELEM;
         }
 
         @Override
-        protected int byteIndex(final int index) {
-            return index * BYTES_PER_ELEMENT + byteOffset;
+        protected MethodHandle getSetElem() {
+            return SET_ELEM;
+        }
+
+        private int getElem(final int index) {
+            try {
+                return nb.get(index);
+            } catch (final IndexOutOfBoundsException e) {
+                throw new ClassCastException(); //force relink - this works for unoptimistic too
+            }
+        }
+
+        private void setElem(final int index, final int elem) {
+            try {
+                nb.put(index, (short)elem);
+            } catch (final IndexOutOfBoundsException e) {
+                //swallow valid array indexes. it's ok.
+                if (index < 0) {
+                    throw new ClassCastException();
+                }
+            }
+        }
+
+        @Override
+        public int getInt(int index) {
+            return getElem(index);
         }
 
         @Override
-        protected int getIntImpl(final int index) {
-            final int byteIndex = byteIndex(index);
-            final byte[] byteArray = buffer.getByteArray();
-            return byteArray[byteIndex  ]       & (short)0x00ff |
-                   byteArray[byteIndex+1] <<  8 & (short)0xff00 ;
+        public long getLong(int index) {
+            return getInt(index);
+        }
+
+        @Override
+        public double getDouble(int index) {
+            return getInt(index);
+        }
+
+        @Override
+        public Object getObject(int index) {
+            return getInt(index);
         }
 
         @Override
-        protected void setImpl(final int index, final int value) {
-            final int byteIndex = byteIndex(index);
-            @SuppressWarnings("MismatchedReadAndWriteOfArray")
-            final byte[] byteArray = buffer.getByteArray();
-            byteArray[byteIndex  ] = (byte)(value       & 0xff);
-            byteArray[byteIndex+1] = (byte)(value >>> 8 & 0xff);
+        public ArrayData set(int index, Object value, boolean strict) {
+            return set(index, JSType.toInt32(value), strict);
+        }
+
+        @Override
+        public ArrayData set(int index, int value, boolean strict) {
+            setElem(index, value);
+            return this;
+        }
+
+        @Override
+        public ArrayData set(int index, long value, boolean strict) {
+            return set(index, (int)value, strict);
+        }
+
+        @Override
+        public ArrayData set(int index, double value, boolean strict) {
+            return set(index, (int)value, strict);
         }
     }
 
@@ -101,7 +168,7 @@
      */
     @Constructor(arity = 1)
     public static Object constructor(final boolean newObj, final Object self, final Object... args) {
-        return constructorImpl(args, FACTORY);
+        return constructorImpl(newObj, args, FACTORY);
     }
 
     NativeInt16Array(final NativeArrayBuffer buffer, final int byteOffset, final int byteLength) {
@@ -109,11 +176,6 @@
     }
 
     @Override
-    public String getClassName() {
-        return "Int16Array";
-    }
-
-    @Override
     protected Factory factory() {
         return FACTORY;
     }
--- a/nashorn/src/jdk/nashorn/internal/objects/NativeInt32Array.java	Wed Feb 26 13:17:57 2014 +0100
+++ b/nashorn/src/jdk/nashorn/internal/objects/NativeInt32Array.java	Mon Mar 03 11:24:44 2014 +0100
@@ -25,15 +25,24 @@
 
 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;
+import java.nio.IntBuffer;
+
 import jdk.nashorn.internal.objects.annotations.Attribute;
 import jdk.nashorn.internal.objects.annotations.Constructor;
 import jdk.nashorn.internal.objects.annotations.Function;
 import jdk.nashorn.internal.objects.annotations.Property;
 import jdk.nashorn.internal.objects.annotations.ScriptClass;
 import jdk.nashorn.internal.objects.annotations.Where;
+import jdk.nashorn.internal.runtime.JSType;
 import jdk.nashorn.internal.runtime.PropertyMap;
 import jdk.nashorn.internal.runtime.ScriptObject;
 import jdk.nashorn.internal.runtime.arrays.ArrayData;
+import jdk.nashorn.internal.runtime.arrays.TypedArrayData;
 
 /**
  * Int32 array for the TypedArray extension
@@ -55,41 +64,94 @@
         public ArrayBufferView construct(final NativeArrayBuffer buffer, final int byteOffset, final int length) {
             return new NativeInt32Array(buffer, byteOffset, length);
         }
+
         @Override
-        public ArrayData createArrayData(final NativeArrayBuffer buffer, final int byteOffset, final int length) {
-            return new Int32ArrayData(buffer, byteOffset, length);
+        public Int32ArrayData createArrayData(final ByteBuffer nb, final int start, final int length) {
+            return new Int32ArrayData(nb.asIntBuffer(), start, length);
+        }
+
+        @Override
+        public String getClassName() {
+            return "Int32Array";
         }
     };
 
-    private static final class Int32ArrayData extends ArrayDataImpl {
-        private Int32ArrayData(final NativeArrayBuffer buffer, final int byteOffset, final int elementLength) {
-            super(buffer, byteOffset, elementLength);
+    private static final class Int32ArrayData extends TypedArrayData<IntBuffer> {
+
+        private static final MethodHandle GET_ELEM = specialCall(MethodHandles.lookup(), Int32ArrayData.class, "getElem", int.class, int.class).methodHandle();
+        private static final MethodHandle SET_ELEM = specialCall(MethodHandles.lookup(), Int32ArrayData.class, "setElem", void.class, int.class, int.class).methodHandle();
+
+        private Int32ArrayData(final IntBuffer nb, final int start, final int end) {
+            super(((IntBuffer)nb.position(start).limit(end)).slice(), end - start);
         }
 
         @Override
-        protected int byteIndex(final int index) {
-            return index * BYTES_PER_ELEMENT + byteOffset;
+        protected MethodHandle getGetElem() {
+            return GET_ELEM;
         }
 
         @Override
-        protected int getIntImpl(final int index) {
-            final int byteIndex = byteIndex(index);
-            final byte[] byteArray = buffer.getByteArray();
-            return byteArray[byteIndex  ]       & 0x0000_00ff |
-                   byteArray[byteIndex+1] <<  8 & 0x0000_ff00 |
-                   byteArray[byteIndex+2] << 16 & 0x00ff_0000 |
-                   byteArray[byteIndex+3] << 24 & 0xff00_0000 ;
+        protected MethodHandle getSetElem() {
+            return SET_ELEM;
+        }
+
+        private int getElem(final int index) {
+            try {
+                return nb.get(index);
+            } catch (final IndexOutOfBoundsException e) {
+                throw new ClassCastException(); //force relink - this works for unoptimistic too
+            }
+        }
+
+        private void setElem(final int index, final int elem) {
+            try {
+                nb.put(index, elem);
+               } catch (final IndexOutOfBoundsException e) {
+                   if (index < 0) {
+                      throw new ClassCastException();
+                 }
+            }
+        }
+
+        @Override
+        public int getInt(int index) {
+            return getElem(index);
         }
 
         @Override
-        protected void setImpl(final int index, final int value) {
-            final int byteIndex = byteIndex(index);
-            @SuppressWarnings("MismatchedReadAndWriteOfArray")
-            final byte[] byteArray = buffer.getByteArray();
-            byteArray[byteIndex  ] = (byte)(value        & 0xff);
-            byteArray[byteIndex+1] = (byte)(value >>>  8 & 0xff);
-            byteArray[byteIndex+2] = (byte)(value >>> 16 & 0xff);
-            byteArray[byteIndex+3] = (byte)(value >>> 24 & 0xff);
+        public long getLong(int index) {
+            return getInt(index);
+        }
+
+        @Override
+        public double getDouble(int index) {
+            return getInt(index);
+        }
+
+        @Override
+        public Object getObject(int index) {
+            return getInt(index);
+        }
+
+        @Override
+        public ArrayData set(int index, Object value, boolean strict) {
+            return set(index, JSType.toInt32(value), strict);
+        }
+
+        @Override
+        public ArrayData set(int index, int value, boolean strict) {
+            setElem(index, value);
+            return this;
+        }
+
+        @Override
+        public ArrayData set(int index, long value, boolean strict) {
+            return set(index, (int)value, strict);
+        }
+
+        @Override
+        public ArrayData set(int index, double value, boolean strict) {
+            return set(index, (int)value, strict);
         }
     }
 
@@ -104,7 +166,7 @@
      */
     @Constructor(arity = 1)
     public static Object constructor(final boolean newObj, final Object self, final Object... args) {
-        return constructorImpl(args, FACTORY);
+        return constructorImpl(newObj, args, FACTORY);
     }
 
     NativeInt32Array(final NativeArrayBuffer buffer, final int byteOffset, final int length) {
@@ -112,11 +174,6 @@
     }
 
     @Override
-    public String getClassName() {
-        return "Int32Array";
-    }
-
-    @Override
     protected Factory factory() {
         return FACTORY;
     }
--- a/nashorn/src/jdk/nashorn/internal/objects/NativeInt8Array.java	Wed Feb 26 13:17:57 2014 +0100
+++ b/nashorn/src/jdk/nashorn/internal/objects/NativeInt8Array.java	Mon Mar 03 11:24:44 2014 +0100
@@ -25,15 +25,23 @@
 
 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;
+
 import jdk.nashorn.internal.objects.annotations.Attribute;
 import jdk.nashorn.internal.objects.annotations.Constructor;
 import jdk.nashorn.internal.objects.annotations.Function;
 import jdk.nashorn.internal.objects.annotations.Property;
 import jdk.nashorn.internal.objects.annotations.ScriptClass;
 import jdk.nashorn.internal.objects.annotations.Where;
+import jdk.nashorn.internal.runtime.JSType;
 import jdk.nashorn.internal.runtime.PropertyMap;
 import jdk.nashorn.internal.runtime.ScriptObject;
 import jdk.nashorn.internal.runtime.arrays.ArrayData;
+import jdk.nashorn.internal.runtime.arrays.TypedArrayData;
 
 /**
  * Int8Array for the TypedArray extension
@@ -57,32 +65,97 @@
         }
 
         @Override
-        public ArrayData createArrayData(final NativeArrayBuffer buffer, final int byteOffset, final int length) {
-            return new Int8ArrayData(buffer, byteOffset, length);
+        public Int8ArrayData createArrayData(final ByteBuffer nb, final int start, final int end) {
+            return new Int8ArrayData(nb, start, end);
+        }
+
+        @Override
+        public String getClassName() {
+            return "Int8Array";
         }
     };
 
-    private static final class Int8ArrayData extends ArrayDataImpl {
-        private Int8ArrayData(final NativeArrayBuffer buffer, final int byteOffset, final int elementLength) {
-            super(buffer, byteOffset, elementLength);
+    private static final class Int8ArrayData extends TypedArrayData<ByteBuffer> {
+
+        private static final MethodHandle GET_ELEM = specialCall(MethodHandles.lookup(), Int8ArrayData.class, "getElem", int.class, int.class).methodHandle();
+        private static final MethodHandle SET_ELEM = specialCall(MethodHandles.lookup(), Int8ArrayData.class, "setElem", void.class, int.class, int.class).methodHandle();
+
+        private Int8ArrayData(final ByteBuffer nb, final int start, final int end) {
+            super(((ByteBuffer)nb.position(start).limit(end)).slice(), end - start);
+        }
+
+        @Override
+        protected MethodHandle getGetElem() {
+            return GET_ELEM;
         }
 
         @Override
-        protected int byteIndex(final int index) {
-            return index * BYTES_PER_ELEMENT + byteOffset;
+        protected MethodHandle getSetElem() {
+            return SET_ELEM;
+        }
+
+        private int getElem(final int index) {
+            try {
+                return nb.get(index);
+            } catch (final IndexOutOfBoundsException e) {
+                throw new ClassCastException(); //force relink - this works for unoptimistic too
+            }
+        }
+
+        private void setElem(final int index, final int elem) {
+            try {
+                nb.put(index, (byte)elem);
+            } catch (final IndexOutOfBoundsException e) {
+                //swallow valid array indexes. it's ok.
+                if (index < 0) {
+                    throw new ClassCastException();
+                }
+            }
+        }
+
+        @Override
+        public int getInt(int index) {
+            return getElem(index);
         }
 
         @Override
-        protected int getIntImpl(final int index) {
-            return buffer.getByteArray()[byteIndex(index)];
+        public long getLong(int index) {
+            return getInt(index);
+        }
+
+        @Override
+        public double getDouble(int index) {
+            return getInt(index);
+        }
+
+        @Override
+        public Object getObject(int index) {
+            return getInt(index);
         }
 
         @Override
-        protected void setImpl(final int index, final int value) {
-            buffer.getByteArray()[byteIndex(index)] = (byte)value;
+        public ArrayData set(int index, Object value, boolean strict) {
+            return set(index, JSType.toInt32(value), strict);
+        }
+
+        @Override
+        public ArrayData set(int index, int value, boolean strict) {
+            setElem(index, value);
+            return this;
+        }
+
+        @Override
+        public ArrayData set(int index, long value, boolean strict) {
+            return set(index, (int)value, strict);
+        }
+
+        @Override
+        public ArrayData set(int index, double value, boolean strict) {
+            return set(index, (int)value, strict);
         }
     }
 
+
     /**
      * Constructor
      *
@@ -94,7 +167,7 @@
      */
     @Constructor(arity = 1)
     public static Object constructor(final boolean newObj, final Object self, final Object... args) {
-        return constructorImpl(args, FACTORY);
+        return constructorImpl(newObj, args, FACTORY);
     }
 
     NativeInt8Array(final NativeArrayBuffer buffer, final int byteOffset, final int length) {
@@ -102,11 +175,6 @@
     }
 
     @Override
-    public String getClassName() {
-        return "Int8Array";
-    }
-
-    @Override
     protected Factory factory() {
         return FACTORY;
     }
--- a/nashorn/src/jdk/nashorn/internal/objects/NativeMath.java	Wed Feb 26 13:17:57 2014 +0100
+++ b/nashorn/src/jdk/nashorn/internal/objects/NativeMath.java	Mon Mar 03 11:24:44 2014 +0100
@@ -489,6 +489,20 @@
     }
 
     /**
+     * ECMA 15.8.2.11 max(x) - specialized version for two Object args
+     *
+     * @param self  self reference
+     * @param x     first argument
+     * @param y     second argument
+     *
+     * @return largest value of x and y
+     */
+    @SpecializedFunction
+    public static double max(final Object self, final Object x, final Object y) {
+        return Math.max(JSType.toNumber(x), JSType.toNumber(y));
+    }
+
+    /**
      * ECMA 15.8.2.12 min(x)
      *
      * @param self  self reference
@@ -567,6 +581,20 @@
     }
 
     /**
+     * ECMA 15.8.2.12 min(x) - specialized version for two Object args
+     *
+     * @param self  self reference
+     * @param x     first argument
+     * @param y     second argument
+     *
+     * @return smallest value of x and y
+     */
+    @SpecializedFunction
+    public static double min(final Object self, final Object x, final Object y) {
+        return Math.min(JSType.toNumber(x), JSType.toNumber(y));
+    }
+
+    /**
      * ECMA 15.8.2.13 pow(x,y)
      *
      * @param self  self reference
--- a/nashorn/src/jdk/nashorn/internal/objects/NativeNumber.java	Wed Feb 26 13:17:57 2014 +0100
+++ b/nashorn/src/jdk/nashorn/internal/objects/NativeNumber.java	Mon Mar 03 11:24:44 2014 +0100
@@ -41,6 +41,7 @@
 import jdk.nashorn.internal.objects.annotations.Function;
 import jdk.nashorn.internal.objects.annotations.Property;
 import jdk.nashorn.internal.objects.annotations.ScriptClass;
+import jdk.nashorn.internal.objects.annotations.SpecializedFunction;
 import jdk.nashorn.internal.objects.annotations.Where;
 import jdk.nashorn.internal.runtime.JSType;
 import jdk.nashorn.internal.runtime.PropertyMap;
@@ -156,8 +157,20 @@
      */
     @Function(attributes = Attribute.NOT_ENUMERABLE)
     public static Object toFixed(final Object self, final Object fractionDigits) {
-        final int f = JSType.toInteger(fractionDigits);
-        if (f < 0 || f > 20) {
+        return toFixed(self, JSType.toInteger(fractionDigits));
+    }
+
+    /**
+     * ECMA 15.7.4.5 Number.prototype.toFixed (fractionDigits) specialized for int fractionDigits
+     *
+     * @param self           self reference
+     * @param fractionDigits how many digits should be after the decimal point, 0 if undefined
+     *
+     * @return number in decimal fixed point notation
+     */
+    @SpecializedFunction
+    public static Object toFixed(final Object self, final int fractionDigits) {
+        if (fractionDigits < 0 || fractionDigits > 20) {
             throw rangeError("invalid.fraction.digits", "toFixed");
         }
 
@@ -171,8 +184,8 @@
         }
 
         final NumberFormat format = NumberFormat.getNumberInstance(Locale.US);
-        format.setMinimumFractionDigits(f);
-        format.setMaximumFractionDigits(f);
+        format.setMinimumFractionDigits(fractionDigits);
+        format.setMaximumFractionDigits(fractionDigits);
         format.setGroupingUsed(false);
 
         return format.format(x);
@@ -210,7 +223,7 @@
      * ECMA 15.7.4.7 Number.prototype.toPrecision (precision)
      *
      * @param self      self reference
-     * @param precision use {@code precision - 1} digits after the significand's decimal point or call {@link NativeDate#toString} if undefined
+     * @param precision use {@code precision - 1} digits after the significand's decimal point or call {@link JSType#toString} if undefined
      *
      * @return number in decimal exponentiation notation or decimal fixed notation depending on {@code precision}
      */
@@ -220,8 +233,23 @@
         if (precision == UNDEFINED) {
             return JSType.toString(x);
         }
+        return (toPrecision(x, JSType.toInteger(precision)));
+    }
 
-        final int p = JSType.toInteger(precision);
+    /**
+     * ECMA 15.7.4.7 Number.prototype.toPrecision (precision) specialized f
+     *
+     * @param self      self reference
+     * @param precision use {@code precision - 1} digits after the significand's decimal point.
+     *
+     * @return number in decimal exponentiation notation or decimal fixed notation depending on {@code precision}
+     */
+    @SpecializedFunction
+    public static Object toPrecision(Object self, final int precision) {
+        return toPrecision(getNumberValue(self), precision);
+    }
+
+    private static Object toPrecision(final double x, final int p) {
         if (Double.isNaN(x)) {
             return "NaN";
         } else if (Double.isInfinite(x)) {
--- a/nashorn/src/jdk/nashorn/internal/objects/NativeObject.java	Wed Feb 26 13:17:57 2014 +0100
+++ b/nashorn/src/jdk/nashorn/internal/objects/NativeObject.java	Mon Mar 03 11:24:44 2014 +0100
@@ -250,8 +250,7 @@
      */
     @Function(attributes = Attribute.NOT_ENUMERABLE, where = Where.CONSTRUCTOR)
     public static Object defineProperty(final Object self, final Object obj, final Object prop, final Object attr) {
-        Global.checkObject(obj);
-        ((ScriptObject)obj).defineOwnProperty(JSType.toString(prop), attr, true);
+        Global.checkObject(obj).defineOwnProperty(JSType.toString(prop), attr, true);
         return obj;
     }
 
@@ -265,9 +264,7 @@
      */
     @Function(attributes = Attribute.NOT_ENUMERABLE, where = Where.CONSTRUCTOR)
     public static Object defineProperties(final Object self, final Object obj, final Object props) {
-        Global.checkObject(obj);
-
-        final ScriptObject sobj     = (ScriptObject)obj;
+        final ScriptObject sobj     = Global.checkObject(obj);
         final Object       propsObj = Global.toObject(props);
 
         if (propsObj instanceof ScriptObject) {
@@ -425,7 +422,7 @@
 
         // Object(null), Object(undefined), Object() are same as "new Object()"
 
-        if (newObj || (type == JSType.NULL || type == JSType.UNDEFINED)) {
+        if (newObj || type == JSType.NULL || type == JSType.UNDEFINED) {
             switch (type) {
             case BOOLEAN:
             case NUMBER:
@@ -513,7 +510,7 @@
         final Object key = JSType.toPrimitive(v, String.class);
         final Object obj = Global.toObject(self);
 
-        return (obj instanceof ScriptObject) && ((ScriptObject)obj).hasOwnProperty(key);
+        return obj instanceof ScriptObject && ((ScriptObject)obj).hasOwnProperty(key);
     }
 
     /**
@@ -627,12 +624,10 @@
     @Function(attributes = Attribute.NOT_ENUMERABLE, where = Where.CONSTRUCTOR)
     public static Object bindProperties(final Object self, final Object target, final Object source) {
         // target object has to be a ScriptObject
-        Global.checkObject(target);
+        final ScriptObject targetObj = Global.checkObject(target);
         // check null or undefined source object
         Global.checkObjectCoercible(source);
 
-        final ScriptObject targetObj = (ScriptObject)target;
-
         if (source instanceof ScriptObject) {
             final ScriptObject sourceObj  = (ScriptObject)source;
 
@@ -753,7 +748,7 @@
                     Bootstrap.bindDynamicMethod(methodGetter.invoke(source), source)), 0, Object.class);
         } catch(RuntimeException|Error e) {
             throw e;
-        } catch(Throwable t) {
+        } catch(final Throwable t) {
             throw new RuntimeException(t);
         }
     }
@@ -766,7 +761,7 @@
             assert passesGuard(source, inv.getGuard());
         } catch(RuntimeException|Error e) {
             throw e;
-        } catch(Throwable t) {
+        } catch(final Throwable t) {
             throw new RuntimeException(t);
         }
         assert inv.getSwitchPoint() == null; // Linkers in Dynalink's beans package don't use switchpoints.
@@ -780,6 +775,6 @@
 
     private static LinkRequest createLinkRequest(String operation, MethodType methodType, Object source) {
         return new LinkRequestImpl(CallSiteDescriptorFactory.create(MethodHandles.publicLookup(), operation,
-                methodType), null, false, source);
+                methodType), null, 0, false, source);
     }
 }
--- a/nashorn/src/jdk/nashorn/internal/objects/NativeRegExp.java	Wed Feb 26 13:17:57 2014 +0100
+++ b/nashorn/src/jdk/nashorn/internal/objects/NativeRegExp.java	Mon Mar 03 11:24:44 2014 +0100
@@ -602,7 +602,7 @@
         for (int i = 0, lastGroupStart = matcher.start(); i <= groupCount; i++) {
             final int groupStart = matcher.start(i);
             if (lastGroupStart > groupStart
-                    || (groupsInNegativeLookahead != null && groupsInNegativeLookahead.isSet(i))) {
+                    || groupsInNegativeLookahead != null && groupsInNegativeLookahead.isSet(i)) {
                 // (1) ECMA 15.10.2.5 NOTE 3: need to clear Atom's captures each time Atom is repeated.
                 // (2) ECMA 15.10.2.8 NOTE 3: Backreferences to captures in (?!Disjunction) from elsewhere
                 // in the pattern always return undefined because the negative lookahead must fail.
@@ -750,8 +750,8 @@
                     cursor++;
                     if (cursor < replacement.length() && firstDigit < matcher.groupCount()) {
                         final int secondDigit = replacement.charAt(cursor) - '0';
-                        if ((secondDigit >= 0) && (secondDigit <= 9)) {
-                            final int newRefNum = (firstDigit * 10) + secondDigit;
+                        if (secondDigit >= 0 && secondDigit <= 9) {
+                            final int newRefNum = firstDigit * 10 + secondDigit;
                             if (newRefNum <= matcher.groupCount() && newRefNum > 0) {
                                 // $nn ($01-$99)
                                 refNum = newRefNum;
@@ -922,7 +922,6 @@
     }
 
     private static NativeRegExp checkRegExp(final Object self) {
-        Global.checkObjectCoercible(self);
         if (self instanceof NativeRegExp) {
             return (NativeRegExp)self;
         } else if (self != null && self == Global.instance().getRegExpPrototype()) {
--- a/nashorn/src/jdk/nashorn/internal/objects/NativeString.java	Wed Feb 26 13:17:57 2014 +0100
+++ b/nashorn/src/jdk/nashorn/internal/objects/NativeString.java	Mon Mar 03 11:24:44 2014 +0100
@@ -443,22 +443,8 @@
     public static Object fromCharCode(final Object self, final Object value) {
         if (value instanceof Integer) {
             return fromCharCode(self, (int)value);
-        } else if (value instanceof String) {
-            return "" + (char)JSType.toUint16(value);
         }
-        return fromCharCode(self, new Object[] { value });
-    }
-
-    /**
-     * fromCharCode specialization
-     *
-     * @param self  self reference
-     * @param value one argument to be interpreted as char
-     * @return string with one charcode
-     */
-    @SpecializedFunction
-    public static Object fromCharCode(final Object self, final String value) {
-        return fromCharCode(self, new Object[] { value });
+        return Character.toString((char)JSType.toUint16(value));
     }
 
     /**
@@ -469,18 +455,46 @@
      */
     @SpecializedFunction
     public static Object fromCharCode(final Object self, final int value) {
-        return "" + (char)(value & 0xffff);
+        return Character.toString((char)(value & 0xffff));
+    }
+
+    /**
+     * ECMA 15.5.3.2 - specialization for two chars of int type
+     * @param self  self reference
+     * @param ch1 first char
+     * @param ch2 second char
+     * @return string with one charcode
+     */
+    @SpecializedFunction
+    public static Object fromCharCode(final Object self, final int ch1, final int ch2) {
+        return Character.toString((char)(ch1 & 0xffff)) + Character.toString((char)(ch2 & 0xffff));
     }
 
     /**
-     * ECMA 15.5.3.2 - specialization for one char of long type
+     * ECMA 15.5.3.2 - specialization for three chars of int type
      * @param self  self reference
-     * @param value one argument to be interpreted as char
+     * @param ch1 first char
+     * @param ch2 second char
+     * @param ch3 third char
      * @return string with one charcode
      */
     @SpecializedFunction
-    public static Object fromCharCode(final Object self, final long value) {
-        return "" + (char)((int)value & 0xffff);
+    public static Object fromCharCode(final Object self, final int ch1, final int ch2, final int ch3) {
+        return Character.toString((char)(ch1 & 0xffff)) + Character.toString((char)(ch2 & 0xffff)) + Character.toString((char)(ch3 & 0xffff));
+    }
+
+    /**
+     * ECMA 15.5.3.2 - specialization for four chars of int type
+     * @param self  self reference
+     * @param ch1 first char
+     * @param ch2 second char
+     * @param ch3 third char
+     * @param ch4 fourth char
+     * @return string with one charcode
+     */
+    @SpecializedFunction
+    public static Object fromCharCode(final Object self, final int ch1, final int ch2, final int ch3, final int ch4) {
+        return Character.toString((char)(ch1 & 0xffff)) + Character.toString((char)(ch2 & 0xffff)) + Character.toString((char)(ch3 & 0xffff)) + Character.toString((char)(ch4 & 0xffff));
     }
 
     /**
@@ -491,7 +505,7 @@
      */
     @SpecializedFunction
     public static Object fromCharCode(final Object self, final double value) {
-        return "" + (char)JSType.toUint16(value);
+        return Character.toString((char)JSType.toUint16(value));
     }
 
     /**
@@ -548,7 +562,7 @@
     }
 
     private static String charAtImpl(final String str, final int pos) {
-        return (pos < 0 || pos >= str.length()) ? "" : String.valueOf(str.charAt(pos));
+        return pos < 0 || pos >= str.length() ? "" : String.valueOf(str.charAt(pos));
     }
 
     /**
@@ -585,7 +599,7 @@
     }
 
     private static double charCodeAtImpl(final String str, final int pos) {
-        return (pos < 0 || pos >= str.length()) ? Double.NaN :  str.charAt(pos);
+        return pos < 0 || pos >= str.length() ? Double.NaN : str.charAt(pos);
     }
 
     /**
@@ -820,7 +834,7 @@
     @SpecializedFunction
     public static Object slice(final Object self, final int start) {
         final String str = checkObjectToString(self);
-        final int from = (start < 0) ? Math.max(str.length() + start, 0) : Math.min(start, str.length());
+        final int from = start < 0 ? Math.max(str.length() + start, 0) : Math.min(start, str.length());
 
         return str.substring(from);
     }
@@ -851,8 +865,8 @@
         final String str = checkObjectToString(self);
         final int len    = str.length();
 
-        final int from = (start < 0) ? Math.max(len + start, 0) : Math.min(start, len);
-        final int to   = (end < 0)   ? Math.max(len + end, 0)   : Math.min(end, len);
+        final int from = start < 0 ? Math.max(len + start, 0) : Math.min(start, len);
+        final int to   = end < 0   ? Math.max(len + end, 0)   : Math.min(end, len);
 
         return str.substring(Math.min(from, to), to);
     }
@@ -881,7 +895,7 @@
     @Function(attributes = Attribute.NOT_ENUMERABLE)
     public static Object split(final Object self, final Object separator, final Object limit) {
         final String str = checkObjectToString(self);
-        final long lim = (limit == UNDEFINED) ? JSType.MAX_UINT : JSType.toUint32(limit);
+        final long lim = limit == UNDEFINED ? JSType.MAX_UINT : JSType.toUint32(limit);
 
         if (separator == UNDEFINED) {
             return lim == 0 ? new NativeArray() : new NativeArray(new Object[]{str});
@@ -912,7 +926,7 @@
         int n = 0;
 
         while (pos < strLength && n < limit) {
-            int found = str.indexOf(separator, pos);
+            final int found = str.indexOf(separator, pos);
             if (found == -1) {
                 break;
             }
@@ -945,7 +959,7 @@
             intStart = Math.max(intStart + strLength, 0);
         }
 
-        final int intLen = Math.min(Math.max((length == UNDEFINED) ? Integer.MAX_VALUE : JSType.toInteger(length), 0), strLength - intStart);
+        final int intLen = Math.min(Math.max(length == UNDEFINED ? Integer.MAX_VALUE : JSType.toInteger(length), 0), strLength - intStart);
 
         return intLen <= 0 ? "" : str.substring(intStart, intStart + intLen);
     }
@@ -1011,8 +1025,8 @@
     public static String substring(final Object self, final int start, final int end) {
         final String str = checkObjectToString(self);
         final int len = str.length();
-        final int validStart = start < 0 ? 0 : (start > len ? len : start);
-        final int validEnd   = end < 0 ? 0 : (end > len ? len : end);
+        final int validStart = start < 0 ? 0 : start > len ? len : start;
+        final int validEnd   = end < 0 ? 0 : end > len ? len : end;
 
         if (validStart < validEnd) {
             return str.substring(validStart, validEnd);
@@ -1105,7 +1119,7 @@
 
         final String str = checkObjectToString(self);
         int start = 0;
-        int end   = str.length() - 1;
+        final int end   = str.length() - 1;
 
         while (start <= end && ScriptRuntime.isJSWhitespace(str.charAt(start))) {
             start++;
@@ -1123,7 +1137,7 @@
     public static Object trimRight(final Object self) {
 
         final String str = checkObjectToString(self);
-        int start = 0;
+        final int start = 0;
         int end   = str.length() - 1;
 
         while (end >= start && ScriptRuntime.isJSWhitespace(str.charAt(end))) {
@@ -1150,7 +1164,7 @@
      */
     @Constructor(arity = 1)
     public static Object constructor(final boolean newObj, final Object self, final Object... args) {
-        final CharSequence str = (args.length > 0) ? JSType.toCharSequence(args[0]) : "";
+        final CharSequence str = args.length > 0 ? JSType.toCharSequence(args[0]) : "";
         return newObj ? newObj(self, str) : str.toString();
     }
 
--- a/nashorn/src/jdk/nashorn/internal/objects/NativeUint16Array.java	Wed Feb 26 13:17:57 2014 +0100
+++ b/nashorn/src/jdk/nashorn/internal/objects/NativeUint16Array.java	Mon Mar 03 11:24:44 2014 +0100
@@ -25,15 +25,24 @@
 
 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;
+import java.nio.CharBuffer;
+
 import jdk.nashorn.internal.objects.annotations.Attribute;
 import jdk.nashorn.internal.objects.annotations.Constructor;
 import jdk.nashorn.internal.objects.annotations.Function;
 import jdk.nashorn.internal.objects.annotations.Property;
 import jdk.nashorn.internal.objects.annotations.ScriptClass;
 import jdk.nashorn.internal.objects.annotations.Where;
+import jdk.nashorn.internal.runtime.JSType;
 import jdk.nashorn.internal.runtime.PropertyMap;
 import jdk.nashorn.internal.runtime.ScriptObject;
 import jdk.nashorn.internal.runtime.arrays.ArrayData;
+import jdk.nashorn.internal.runtime.arrays.TypedArrayData;
 
 /**
  * Uint16 array for TypedArray extension
@@ -55,37 +64,100 @@
         public ArrayBufferView construct(final NativeArrayBuffer buffer, final int byteOffset, final int length) {
             return new NativeUint16Array(buffer, byteOffset, length);
         }
+
         @Override
-        public ArrayData createArrayData(final NativeArrayBuffer buffer, final int byteOffset, final int length) {
-            return new Uint16ArrayData(buffer, byteOffset, length);
+        public Uint16ArrayData createArrayData(final ByteBuffer nb, final int start, final int end) {
+            return new Uint16ArrayData(nb.asCharBuffer(), start, end);
+        }
+
+        @Override
+        public String getClassName() {
+            return "Uint16Array";
         }
     };
 
-    private static final class Uint16ArrayData extends ArrayDataImpl {
-        private Uint16ArrayData(final NativeArrayBuffer buffer, final int byteOffset, final int elementLength) {
-            super(buffer, byteOffset, elementLength);
+    private static final class Uint16ArrayData extends TypedArrayData<CharBuffer> {
+
+        private static final MethodHandle GET_ELEM = specialCall(MethodHandles.lookup(), Uint16ArrayData.class, "getElem", int.class, int.class).methodHandle();
+        private static final MethodHandle SET_ELEM = specialCall(MethodHandles.lookup(), Uint16ArrayData.class, "setElem", void.class, int.class, int.class).methodHandle();
+
+        private Uint16ArrayData(final CharBuffer nb, final int start, final int end) {
+            super(((CharBuffer)nb.position(start).limit(end)).slice(), end - start);
+        }
+
+        @Override
+        protected MethodHandle getGetElem() {
+            return GET_ELEM;
         }
 
         @Override
-        protected int byteIndex(final int index) {
-            return index * BYTES_PER_ELEMENT + byteOffset;
+        protected MethodHandle getSetElem() {
+            return SET_ELEM;
+        }
+
+        private int getElem(final int index) {
+            try {
+                return nb.get(index);
+            } catch (final IndexOutOfBoundsException e) {
+                throw new ClassCastException(); //force relink - this works for unoptimistic too
+            }
+        }
+
+        private void setElem(final int index, final int elem) {
+            try {
+                nb.put(index, (char)elem);
+            } catch (final IndexOutOfBoundsException e) {
+                //swallow valid array indexes. it's ok.
+                if (index < 0) {
+                    throw new ClassCastException();
+                }
+            }
+        }
+
+        @Override
+        public boolean isUnsigned() {
+            return true;
+        }
+
+        @Override
+        public int getInt(int index) {
+            return getElem(index);
         }
 
         @Override
-        protected int getIntImpl(final int index) {
-            final int byteIndex = byteIndex(index);
-            final byte[] byteArray = buffer.getByteArray();
-            return byteArray[byteIndex  ]       & 0x0000_00ff |
-                   byteArray[byteIndex+1] <<  8 & 0x0000_ff00 ;
+        public long getLong(int index) {
+            return getInt(index);
+        }
+
+        @Override
+        public double getDouble(int index) {
+            return getInt(index);
+        }
+
+        @Override
+        public Object getObject(int index) {
+            return getInt(index);
         }
 
         @Override
-        protected void setImpl(final int index, final int value) {
-            final int byteIndex = byteIndex(index);
-            @SuppressWarnings("MismatchedReadAndWriteOfArray")
-            final byte[] byteArray = buffer.getByteArray();
-            byteArray[byteIndex  ] = (byte)(value       & 0xff);
-            byteArray[byteIndex+1] = (byte)(value >>> 8 & 0xff);
+        public ArrayData set(int index, Object value, boolean strict) {
+            return set(index, JSType.toInt32(value), strict);
+        }
+
+        @Override
+        public ArrayData set(int index, int value, boolean strict) {
+            setElem(index, value);
+            return this;
+        }
+
+        @Override
+        public ArrayData set(int index, long value, boolean strict) {
+            return set(index, (int)value, strict);
+        }
+
+        @Override
+        public ArrayData set(int index, double value, boolean strict) {
+            return set(index, (int)value, strict);
         }
     }
 
@@ -100,7 +172,7 @@
      */
     @Constructor(arity = 1)
     public static Object constructor(final boolean newObj, final Object self, final Object... args) {
-        return constructorImpl(args, FACTORY);
+        return constructorImpl(newObj, args, FACTORY);
     }
 
     NativeUint16Array(final NativeArrayBuffer buffer, final int byteOffset, final int length) {
@@ -108,11 +180,6 @@
     }
 
     @Override
-    public String getClassName() {
-        return "Uint16Array";
-    }
-
-    @Override
     protected Factory factory() {
         return FACTORY;
     }
--- a/nashorn/src/jdk/nashorn/internal/objects/NativeUint32Array.java	Wed Feb 26 13:17:57 2014 +0100
+++ b/nashorn/src/jdk/nashorn/internal/objects/NativeUint32Array.java	Mon Mar 03 11:24:44 2014 +0100
@@ -25,6 +25,14 @@
 
 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;
+import java.nio.ByteOrder;
+import java.nio.IntBuffer;
+
 import jdk.nashorn.internal.objects.annotations.Attribute;
 import jdk.nashorn.internal.objects.annotations.Constructor;
 import jdk.nashorn.internal.objects.annotations.Function;
@@ -35,6 +43,7 @@
 import jdk.nashorn.internal.runtime.PropertyMap;
 import jdk.nashorn.internal.runtime.ScriptObject;
 import jdk.nashorn.internal.runtime.arrays.ArrayData;
+import jdk.nashorn.internal.runtime.arrays.TypedArrayData;
 
 /**
  * Uint32 array for TypedArray extension
@@ -56,55 +65,108 @@
         public ArrayBufferView construct(final NativeArrayBuffer buffer, final int byteBegin, final int length) {
             return new NativeUint32Array(buffer, byteBegin, length);
         }
+
         @Override
-        public ArrayData createArrayData(final NativeArrayBuffer buffer, final int byteOffset, final int length) {
-            return new Uint32ArrayData(buffer, byteOffset, length);
+        public Uint32ArrayData createArrayData(final ByteBuffer nb, final int start, final int end) {
+            return new Uint32ArrayData(nb.order(ByteOrder.nativeOrder()).asIntBuffer(), start, end);
+        }
+
+        @Override
+        public String getClassName() {
+            return "Uint32Array";
         }
     };
 
-    private static final class Uint32ArrayData extends ArrayDataImpl {
-        private Uint32ArrayData(final NativeArrayBuffer buffer, final int byteOffset, final int elementLength) {
-            super(buffer, byteOffset, elementLength);
+    private static final class Uint32ArrayData extends TypedArrayData<IntBuffer> {
+
+        private static final MethodHandle GET_ELEM = specialCall(MethodHandles.lookup(), Uint32ArrayData.class, "getElem", long.class, int.class).methodHandle();
+        private static final MethodHandle SET_ELEM = specialCall(MethodHandles.lookup(), Uint32ArrayData.class, "setElem", void.class, int.class, int.class).methodHandle();
+
+        private Uint32ArrayData(final IntBuffer nb, final int start, final int end) {
+            super(((IntBuffer)nb.position(start).limit(end)).slice(), end - start);
         }
 
         @Override
-        protected int byteIndex(final int index) {
-            return index * BYTES_PER_ELEMENT + byteOffset;
+        protected MethodHandle getGetElem() {
+            return GET_ELEM;
+        }
+
+        @Override
+        protected MethodHandle getSetElem() {
+            return SET_ELEM;
         }
 
         @Override
-        protected int getIntImpl(final int index) {
-            final int byteIndex = byteIndex(index);
-            final byte[] byteArray = buffer.getByteArray();
-            return byteArray[byteIndex  ]       & 0x0000_00ff |
-                   byteArray[byteIndex+1] <<  8 & 0x0000_ff00 |
-                   byteArray[byteIndex+2] << 16 & 0x00ff_0000 |
-                   byteArray[byteIndex+3] << 24 & 0xff00_0000 ;
+        public MethodHandle getElementGetter(final Class<?> returnType, final int programPoint) {
+            if (returnType == int.class) {
+                return null;
+            }
+            return getContinuousElementGetter(getClass(), GET_ELEM, returnType, programPoint);
+        }
+
+        private long getElem(final int index) {
+            try {
+                return nb.get(index) & JSType.MAX_UINT;
+            } catch (final IndexOutOfBoundsException e) {
+                throw new ClassCastException(); //force relink - this works for unoptimistic too
+            }
+        }
+
+        private void setElem(final int index, final int elem) {
+            try {
+                nb.put(index, elem);
+            } catch (final IndexOutOfBoundsException e) {
+                //swallow valid array indexes. it's ok.
+                if (index < 0) {
+                    throw new ClassCastException();
+                }
+            }
         }
 
         @Override
-        protected long getLongImpl(final int key) {
-            return getIntImpl(key) & JSType.MAX_UINT;
+        public boolean isUnsigned() {
+            return true;
         }
 
         @Override
-        protected double getDoubleImpl(final int key) {
-            return getIntImpl(key) & JSType.MAX_UINT;
+        public int getInt(int index) {
+            return (int)getLong(index);
+        }
+
+        @Override
+        public long getLong(int index) {
+            return getElem(index);
+        }
+
+        @Override
+        public double getDouble(int index) {
+            return getLong(index);
         }
 
         @Override
-        protected Object getObjectImpl(final int key) {
-            return getIntImpl(key) & JSType.MAX_UINT;
+        public Object getObject(int index) {
+            return getLong(index);
+        }
+
+        @Override
+        public ArrayData set(int index, Object value, boolean strict) {
+            return set(index, JSType.toInt32(value), strict);
         }
 
         @Override
-        protected void setImpl(final int index, final int value) {
-            final int byteIndex = byteIndex(index);
-            final byte[] byteArray = buffer.getByteArray();
-            byteArray[byteIndex  ] = (byte)(value        & 0xff);
-            byteArray[byteIndex+1] = (byte)(value >>>  8 & 0xff);
-            byteArray[byteIndex+2] = (byte)(value >>> 16 & 0xff);
-            byteArray[byteIndex+3] = (byte)(value >>> 24 & 0xff);
+        public ArrayData set(int index, int value, boolean strict) {
+            setElem(index, value);
+            return this;
+        }
+
+        @Override
+        public ArrayData set(int index, long value, boolean strict) {
+            return set(index, (int)value, strict);
+        }
+
+        @Override
+        public ArrayData set(int index, double value, boolean strict) {
+            return set(index, (int)value, strict);
         }
     }
 
@@ -119,7 +181,7 @@
      */
     @Constructor(arity = 1)
     public static Object constructor(final boolean newObj, final Object self, final Object... args) {
-        return constructorImpl(args, FACTORY);
+        return constructorImpl(newObj, args, FACTORY);
     }
 
     NativeUint32Array(final NativeArrayBuffer buffer, final int byteOffset, final int length) {
@@ -127,11 +189,6 @@
     }
 
     @Override
-    public String getClassName() {
-        return "Uint32Array";
-    }
-
-    @Override
     protected Factory factory() {
         return FACTORY;
     }
--- a/nashorn/src/jdk/nashorn/internal/objects/NativeUint8Array.java	Wed Feb 26 13:17:57 2014 +0100
+++ b/nashorn/src/jdk/nashorn/internal/objects/NativeUint8Array.java	Mon Mar 03 11:24:44 2014 +0100
@@ -25,21 +25,30 @@
 
 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;
+
 import jdk.nashorn.internal.objects.annotations.Attribute;
 import jdk.nashorn.internal.objects.annotations.Constructor;
 import jdk.nashorn.internal.objects.annotations.Function;
 import jdk.nashorn.internal.objects.annotations.Property;
 import jdk.nashorn.internal.objects.annotations.ScriptClass;
 import jdk.nashorn.internal.objects.annotations.Where;
+import jdk.nashorn.internal.runtime.JSType;
 import jdk.nashorn.internal.runtime.PropertyMap;
 import jdk.nashorn.internal.runtime.ScriptObject;
 import jdk.nashorn.internal.runtime.arrays.ArrayData;
+import jdk.nashorn.internal.runtime.arrays.TypedArrayData;
 
 /**
  * Uint8 array for TypedArray extension
  */
 @ScriptClass("Uint8Array")
 public final class NativeUint8Array extends ArrayBufferView {
+
     /**
      * The size in bytes of each element in the array.
      */
@@ -55,31 +64,102 @@
         public ArrayBufferView construct(final NativeArrayBuffer buffer, final int byteOffset, final int length) {
             return new NativeUint8Array(buffer, byteOffset, length);
         }
+
         @Override
-        public ArrayData createArrayData(final NativeArrayBuffer buffer, final int byteOffset, final int length) {
-            return new Uint8ArrayData(buffer, byteOffset, length);
+        public Uint8ArrayData createArrayData(final ByteBuffer nb, final int start, final int end) {
+            return new Uint8ArrayData(nb, start, end);
+        }
+
+        @Override
+        public String getClassName() {
+            return "Uint8Array";
         }
     };
 
-    private static final class Uint8ArrayData extends ArrayDataImpl {
-        private Uint8ArrayData(final NativeArrayBuffer buffer, final int byteOffset, final int elementLength) {
-            super(buffer, byteOffset, elementLength);
+    private static final class Uint8ArrayData extends TypedArrayData<ByteBuffer> {
+
+        private static final MethodHandle GET_ELEM = specialCall(MethodHandles.lookup(), Uint8ArrayData.class, "getElem", int.class, int.class).methodHandle();
+        private static final MethodHandle SET_ELEM = specialCall(MethodHandles.lookup(), Uint8ArrayData.class, "setElem", void.class, int.class, int.class).methodHandle();
+
+        private Uint8ArrayData(final ByteBuffer nb, final int start, final int end) {
+            super(((ByteBuffer)nb.position(start).limit(end)).slice(), end - start);
+        }
+
+        @Override
+        protected MethodHandle getGetElem() {
+            return GET_ELEM;
         }
 
         @Override
-        protected int byteIndex(final int index) {
-            return index * BYTES_PER_ELEMENT + byteOffset;
+        protected MethodHandle getSetElem() {
+            return SET_ELEM;
+        }
+
+        private int getElem(final int index) {
+            try {
+                return nb.get(index) & 0xff;
+            } catch (final IndexOutOfBoundsException e) {
+                throw new ClassCastException(); //force relink - this works for unoptimistic too
+            }
+        }
+
+        private void setElem(final int index, final int elem) {
+            try {
+                nb.put(index, (byte)elem);
+            } catch (final IndexOutOfBoundsException e) {
+                //swallow valid array indexes. it's ok.
+                if (index < 0) {
+                    throw new ClassCastException();
+                }
+            }
+        }
+
+        @Override
+        public boolean isUnsigned() {
+            return true;
+        }
+
+        @Override
+        public int getInt(int index) {
+            return getElem(index);
         }
 
         @Override
-        protected int getIntImpl(final int index) {
-            return buffer.getByteArray()[byteIndex(index)] & 0xff;
+        public long getLong(int index) {
+            return getInt(index);
+        }
+
+        @Override
+        public double getDouble(int index) {
+            return getInt(index);
+        }
+
+        @Override
+        public Object getObject(int index) {
+            return getInt(index);
         }
 
         @Override
-        protected void setImpl(final int index, final int value) {
-            buffer.getByteArray()[byteIndex(index)] = (byte)value;
+        public ArrayData set(int index, Object value, boolean strict) {
+            return set(index, JSType.toInt32(value), strict);
+        }
+
+        @Override
+        public ArrayData set(int index, int value, boolean strict) {
+            setElem(index, value);
+            return this;
         }
+
+        @Override
+        public ArrayData set(int index, long value, boolean strict) {
+            return set(index, (int)value, strict);
+        }
+
+        @Override
+        public ArrayData set(int index, double value, boolean strict) {
+            return set(index, (int)value, strict);
+        }
+
     }
 
     /**
@@ -93,16 +173,11 @@
      */
     @Constructor(arity = 1)
     public static Object constructor(final boolean newObj, final Object self, final Object... args) {
-        return constructorImpl(args, FACTORY);
+        return constructorImpl(newObj, args, FACTORY);
     }
 
-    NativeUint8Array(final NativeArrayBuffer buffer, final int byteOffset, final int length) {
-        super(buffer, byteOffset, length);
-    }
-
-    @Override
-    public String getClassName() {
-        return "Uint8Array";
+    NativeUint8Array(NativeArrayBuffer buffer, int byteOffset, int elementLength) {
+        super(buffer, byteOffset, elementLength);
     }
 
     @Override
--- a/nashorn/src/jdk/nashorn/internal/objects/NativeUint8ClampedArray.java	Wed Feb 26 13:17:57 2014 +0100
+++ b/nashorn/src/jdk/nashorn/internal/objects/NativeUint8ClampedArray.java	Mon Mar 03 11:24:44 2014 +0100
@@ -25,6 +25,14 @@
 
 package jdk.nashorn.internal.objects;
 
+import static jdk.nashorn.internal.codegen.CompilerConstants.staticCall;
+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.nio.ByteBuffer;
+
 import jdk.nashorn.internal.objects.annotations.Attribute;
 import jdk.nashorn.internal.objects.annotations.Constructor;
 import jdk.nashorn.internal.objects.annotations.Function;
@@ -35,6 +43,7 @@
 import jdk.nashorn.internal.runtime.PropertyMap;
 import jdk.nashorn.internal.runtime.ScriptObject;
 import jdk.nashorn.internal.runtime.arrays.ArrayData;
+import jdk.nashorn.internal.runtime.arrays.TypedArrayData;
 
 /**
  * Uint8 clamped array for TypedArray extension
@@ -56,47 +65,127 @@
         public ArrayBufferView construct(final NativeArrayBuffer buffer, final int byteOffset, final int length) {
             return new NativeUint8ClampedArray(buffer, byteOffset, length);
         }
+
         @Override
-        public ArrayData createArrayData(final NativeArrayBuffer buffer, final int byteOffset, final int length) {
-            return new Uint8ClampedArrayData(buffer, byteOffset, length);
+        public Uint8ClampedArrayData createArrayData(final ByteBuffer nb, final int start, final int end) {
+            return new Uint8ClampedArrayData(nb, start, end);
+        }
+
+        @Override
+        public String getClassName() {
+            return "Uint8ClampedArray";
         }
     };
 
-    private static final class Uint8ClampedArrayData extends ArrayDataImpl {
-        private Uint8ClampedArrayData(final NativeArrayBuffer buffer, final int byteOffset, final int elementLength) {
-            super(buffer, byteOffset, elementLength);
+    private static final class Uint8ClampedArrayData extends TypedArrayData<ByteBuffer> {
+
+        private static final MethodHandle GET_ELEM = specialCall(MethodHandles.lookup(), Uint8ClampedArrayData.class, "getElem", int.class, int.class).methodHandle();
+        private static final MethodHandle SET_ELEM = specialCall(MethodHandles.lookup(), Uint8ClampedArrayData.class, "setElem", void.class, int.class, int.class).methodHandle();
+        private static final MethodHandle RINT     = staticCall(MethodHandles.lookup(), Uint8ClampedArrayData.class, "rint", double.class, double.class).methodHandle();
+
+        private Uint8ClampedArrayData(final ByteBuffer nb, final int start, final int end) {
+            super(((ByteBuffer)nb.position(start).limit(end)).slice(), end - start);
         }
 
         @Override
-        protected int byteIndex(final int index) {
-            return index * BYTES_PER_ELEMENT + byteOffset;
+        protected MethodHandle getGetElem() {
+            return GET_ELEM;
+        }
+
+        @Override
+        protected MethodHandle getSetElem() {
+            return SET_ELEM;
+        }
+
+        private int getElem(final int index) {
+            try {
+                return nb.get(index) & 0xff;
+            } catch (final IndexOutOfBoundsException e) {
+                throw new ClassCastException(); //force relink - this works for unoptimistic too
+            }
         }
 
         @Override
-        protected int getIntImpl(final int index) {
-            return buffer.getByteArray()[byteIndex(index)] & 0xff;
+        public MethodHandle getElementSetter(final Class<?> elementType) {
+            final MethodHandle setter = super.getElementSetter(elementType); //getContinuousElementSetter(getClass(), setElem(), elementType);
+            if (setter != null && elementType == double.class) {
+                return MH.filterArguments(setter, 2, RINT);
+            }
+            return setter;
+        }
+
+        private void setElem(final int index, final int elem) {
+            try {
+                final byte clamped;
+                if ((elem & 0xffff_ff00) == 0) {
+                    clamped = (byte)elem;
+                } else {
+                    clamped = elem < 0 ? 0 : (byte)0xff;
+                }
+                nb.put(index, clamped);
+            } catch (final IndexOutOfBoundsException e) {
+                //swallow valid array indexes. it's ok.
+                if (index < 0) {
+                    throw new ClassCastException();
+                }
+            }
+        }
+
+        @Override
+        public boolean isClamped() {
+            return true;
+        }
+
+        @Override
+        public boolean isUnsigned() {
+            return true;
         }
 
         @Override
-        protected void setImpl(final int index, final int value) {
-            final byte clamped;
-            if ((value & 0xffff_ff00) == 0) {
-                clamped = (byte) value;
-            } else {
-                clamped = value < 0 ? 0 : (byte)0xff;
-            }
-            buffer.getByteArray()[byteIndex(index)] = clamped;
+        public int getInt(int index) {
+            return getElem(index);
+        }
+
+        @Override
+        public long getLong(int index) {
+            return getInt(index);
+        }
+
+        @Override
+        public double getDouble(int index) {
+            return getInt(index);
+        }
+
+        @Override
+        public Object getObject(int index) {
+            return getInt(index);
         }
 
         @Override
-        protected void setImpl(final int key, final double value) {
-            setImpl(key, (int)Math.rint(value));
+        public ArrayData set(int index, Object value, boolean strict) {
+            return set(index, JSType.toNumber(value), strict);
+        }
+
+        @Override
+        public ArrayData set(int index, int value, boolean strict) {
+            setElem(index, value);
+            return this;
         }
 
         @Override
-        protected void setImpl(final int key, final Object value) {
-            setImpl(key, JSType.toNumber(value));
+        public ArrayData set(int index, long value, boolean strict) {
+            return set(index, (int)value, strict);
         }
+
+        @Override
+        public ArrayData set(int index, double value, boolean strict) {
+            return set(index, rint(value), strict);
+        }
+
+        private static double rint(double rint) {
+            return (int)Math.rint(rint);
+        }
+
     }
 
     /**
@@ -110,7 +199,7 @@
      */
     @Constructor(arity = 1)
     public static Object constructor(final boolean newObj, final Object self, final Object... args) {
-        return constructorImpl(args, FACTORY);
+        return constructorImpl(newObj, args, FACTORY);
     }
 
     NativeUint8ClampedArray(final NativeArrayBuffer buffer, final int byteOffset, final int length) {
@@ -118,11 +207,6 @@
     }
 
     @Override
-    public String getClassName() {
-        return "Uint8ClampedArray";
-    }
-
-    @Override
     protected Factory factory() {
         return FACTORY;
     }
--- a/nashorn/src/jdk/nashorn/internal/runtime/AccessorProperty.java	Wed Feb 26 13:17:57 2014 +0100
+++ b/nashorn/src/jdk/nashorn/internal/runtime/AccessorProperty.java	Mon Mar 03 11:24:44 2014 +0100
@@ -184,13 +184,21 @@
      * @param primitiveGetter
      * @param primitiveSetter
      */
-    protected AccessorProperty(final String key, final int flags, final int slot, final MethodHandle primitiveGetter, final MethodHandle primitiveSetter, final MethodHandle objectGetter, final MethodHandle objectSetter) {
+    protected AccessorProperty(
+            final String key,
+            final int flags,
+            final int slot,
+            final MethodHandle primitiveGetter,
+            final MethodHandle primitiveSetter,
+            final MethodHandle objectGetter,
+            final MethodHandle objectSetter) {
         super(key, flags, slot);
         assert getClass() != AccessorProperty.class;
         this.primitiveGetter = primitiveGetter;
         this.primitiveSetter = primitiveSetter;
         this.objectGetter    = objectGetter;
         this.objectSetter    = objectSetter;
+//        setCurrentType(OBJECT_FIELDS_ONLY ? Object.class : initialType);
         initializeType();
     }
 
@@ -357,13 +365,15 @@
      */
     protected final void initializeType() {
         Class<?> initialType = null;
-        if (OBJECT_FIELDS_ONLY || isAlwaysObject()) {
+        if (OBJECT_FIELDS_ONLY) {
             initialType = Object.class;
         } else {
             if (!canBeUndefined()) { //todo if !canBeUndefined it means that we have an exact initialType
                 initialType = int.class;
             }
-            info(getKey(), canBeUndefined() ? " can be undefined" : " is always defined");
+            if (shouldInstrument(getKey())) {
+                info(getKey(), canBeUndefined() ? " can be undefined" : " is always defined");
+            }
         }
         setCurrentType(initialType);
     }
--- a/nashorn/src/jdk/nashorn/internal/runtime/GlobalFunctions.java	Wed Feb 26 13:17:57 2014 +0100
+++ b/nashorn/src/jdk/nashorn/internal/runtime/GlobalFunctions.java	Mon Mar 03 11:24:44 2014 +0100
@@ -25,7 +25,6 @@
 
 package jdk.nashorn.internal.runtime;
 
-import static jdk.nashorn.internal.runtime.JSType.digit;
 import static jdk.nashorn.internal.lookup.Lookup.MH;
 
 import java.lang.invoke.MethodHandle;
@@ -38,7 +37,13 @@
 public final class GlobalFunctions {
 
     /** Methodhandle to implementation of ECMA 15.1.2.2, parseInt */
-    public static final MethodHandle PARSEINT = findOwnMH("parseInt",   double.class, Object.class, Object.class, Object.class);
+    public static final MethodHandle PARSEINT = findOwnMH("parseInt", double.class, Object.class, Object.class, Object.class);
+
+    /** Methodhandle (specialized) to implementation of ECMA 15.1.2.2, parseInt */
+    public static final MethodHandle PARSEINT_OI = findOwnMH("parseInt", double.class, Object.class, Object.class, int.class);
+
+    /** Methodhandle (specialized) to implementation of ECMA 15.1.2.2, parseInt */
+    public static final MethodHandle PARSEINT_O = findOwnMH("parseInt", double.class, Object.class, Object.class);
 
     /** Methodhandle to implementation of ECMA 15.1.2.3, parseFloat */
     public static final MethodHandle PARSEFLOAT = findOwnMH("parseFloat", double.class, Object.class, Object.class);
@@ -78,19 +83,44 @@
     /**
      * ECMA 15.1.2.2 parseInt implementation
      *
-     * TODO: specialize
+     * @param self   self reference
+     * @param string string to parse
+     * @param rad    radix
+     *
+     * @return numeric type representing string contents as an int
+     */
+    public static double parseInt(final Object self, final Object string, final Object rad) {
+        return parseIntInternal(JSType.trimLeft(JSType.toString(string)), JSType.toInt32(rad));
+    }
+
+    /**
+     * ECMA 15.1.2.2 parseInt implementation specialized for int radix
      *
      * @param self   self reference
      * @param string string to parse
      * @param rad    radix
      *
-     * @return numeric type representing string contents as an int (TODO: specialize for int case)
+     * @return numeric type representing string contents as an int
      */
-    //TODO specialize
-    public static double parseInt(final Object self, final Object string, final Object rad) {
-        final String str    = JSType.trimLeft(JSType.toString(string));
-        final int    length = str.length();
-        int          radix  = JSType.toInt32(rad);
+    public static double parseInt(final Object self, final Object string, final int rad) {
+        return parseIntInternal(JSType.trimLeft(JSType.toString(string)), rad);
+    }
+
+    /**
+     * ECMA 15.1.2.2 parseInt implementation specialized for no radix argument
+     *
+     * @param self   self reference
+     * @param string string to parse
+     *
+     * @return numeric type representing string contents as an int
+     */
+    public static double parseInt(final Object self, final Object string) {
+        return parseIntInternal(JSType.trimLeft(JSType.toString(string)), 0);
+    }
+
+    private static double parseIntInternal(final String str, final int rad) {
+        final int length = str.length();
+        int radix = rad;
 
         // empty string is not valid
         if (length == 0) {
@@ -142,7 +172,7 @@
         // we should see atleast one valid digit
         boolean entered = false;
         while (idx < length) {
-            digit = digit(str.charAt(idx++), radix, true);
+            digit = fastDigit(str.charAt(idx++), radix);
             if (digit < 0) {
                 break;
             }
@@ -456,6 +486,20 @@
         return ScriptRuntime.UNDEFINED;
     }
 
+    private static int fastDigit(int ch, int radix) {
+        int n = -1;
+        if (ch >= '0' && ch <= '9') {
+            n = ch - '0';
+        } else if (radix > 10) {
+            if (ch >= 'a' && ch <= 'z') {
+                n = ch - 'a' + 10;
+            } else if (ch >= 'A' && ch <= 'Z') {
+                n = ch - 'A' + 10;
+            }
+        }
+        return n < radix ? n : -1;
+    }
+
     private static MethodHandle findOwnMH(final String name, final Class<?> rtype, final Class<?>... types) {
         return MH.findStatic(MethodHandles.lookup(), GlobalFunctions.class, name, MH.type(rtype, types));
     }
--- a/nashorn/src/jdk/nashorn/internal/runtime/NativeJavaPackage.java	Wed Feb 26 13:17:57 2014 +0100
+++ b/nashorn/src/jdk/nashorn/internal/runtime/NativeJavaPackage.java	Mon Mar 03 11:24:44 2014 +0100
@@ -205,8 +205,8 @@
     }
 
     @Override
-    protected Object invokeNoSuchProperty(final String name, final int programPoint) {
-        final Object retval = createProperty(name);
+    protected Object invokeNoSuchProperty(final String key, final int programPoint) {
+        final Object retval = createProperty(key);
         if (isValid(programPoint)) {
             throw new UnwarrantedOptimismException(retval, programPoint);
         }
--- a/nashorn/src/jdk/nashorn/internal/runtime/Property.java	Wed Feb 26 13:17:57 2014 +0100
+++ b/nashorn/src/jdk/nashorn/internal/runtime/Property.java	Mon Mar 03 11:24:44 2014 +0100
@@ -32,7 +32,6 @@
 import java.lang.invoke.MethodHandle;
 import java.util.Objects;
 import jdk.nashorn.internal.codegen.ObjectClassGenerator;
-import jdk.nashorn.internal.codegen.types.Type;
 
 /**
  * This is the abstract superclass representing a JavaScript Property.
@@ -64,7 +63,7 @@
     /** ECMA 8.6.1 - Is this property not configurable? */
     public static final int NOT_CONFIGURABLE = 1 << 2;
 
-    private static final int MODIFY_MASK     = (NOT_WRITABLE | NOT_ENUMERABLE | NOT_CONFIGURABLE);
+    private static final int MODIFY_MASK     = NOT_WRITABLE | NOT_ENUMERABLE | NOT_CONFIGURABLE;
 
     /** Is this a function parameter? */
     public static final int IS_PARAMETER     = 1 << 3;
@@ -72,14 +71,11 @@
     /** Is parameter accessed thru arguments? */
     public static final int HAS_ARGUMENTS    = 1 << 4;
 
-    /** Is this property always represented as an Object? See {@link ObjectClassGenerator} and dual fields flag. */
-    public static final int IS_ALWAYS_OBJECT = 1 << 5;
-
     /** Can this property be undefined? */
-    public static final int CAN_BE_UNDEFINED = 1 << 6;
+    public static final int CAN_BE_UNDEFINED = 1 << 5;
 
     /** Is this a function declaration property ? */
-    public static final int IS_FUNCTION_DECLARATION = 1 << 7;
+    public static final int IS_FUNCTION_DECLARATION = 1 << 6;
 
     /**
      * Is this is a primitive field given to us by Nasgen, i.e.
@@ -87,7 +83,7 @@
      * is narrower than object, e.g. Math.PI which is declared
      * as a double
      */
-    public static final int IS_NASGEN_PRIMITIVE = 1 << 8;
+    public static final int IS_NASGEN_PRIMITIVE = 1 << 7;
 
     /** Property key. */
     private final String key;
@@ -290,6 +286,16 @@
     }
 
     /**
+     * Check if a flag is set for a property
+     * @param property property
+     * @param flag     flag to check
+     * @return true if flag is set
+     */
+    public static boolean checkFlag(final Property property, final int flag) {
+        return (property.getFlags() & flag) == flag;
+    }
+
+    /**
      * Get the flags for this property
      * @return property flags
      */
@@ -609,17 +615,6 @@
     }
 
     /**
-     * Check whether this Property is ever used as anything but an Object. If this is used only
-     * as an object, dual fields mode need not even try to represent it as a primitive at any
-     * callsite, saving map rewrites for performance.
-     *
-     * @return true if representation should always be an object field
-     */
-    public boolean isAlwaysObject() {
-        return (flags & IS_ALWAYS_OBJECT) == IS_ALWAYS_OBJECT;
-    }
-
-    /**
      * Check whether this property can be primitive. This is a conservative
      * analysis result, so {@code true} might mean that it can still be
      * defined, but it will never say that a property can not be undefined
--- a/nashorn/src/jdk/nashorn/internal/runtime/PropertyHashMap.java	Wed Feb 26 13:17:57 2014 +0100
+++ b/nashorn/src/jdk/nashorn/internal/runtime/PropertyHashMap.java	Mon Mar 03 11:24:44 2014 +0100
@@ -303,7 +303,7 @@
      * @return The bin index.
      */
     private static int binIndex(final Element[] bins, final String key) {
-        return  key.hashCode() & (bins.length - 1);
+        return  key.hashCode() & bins.length - 1;
     }
 
     /**
@@ -315,7 +315,7 @@
      */
     private static int binsNeeded(final int n) {
         // 50% padding
-        return 1 << (32 - Integer.numberOfLeadingZeros((n + (n >>> 1)) | (INITIAL_BINS - 1)));
+        return 1 << 32 - Integer.numberOfLeadingZeros(n + (n >>> 1) | INITIAL_BINS - 1);
     }
 
     /**
@@ -442,15 +442,11 @@
         if (bins != null) {
             final int binIndex = binIndex(bins, key);
             Element bin = bins[binIndex];
-    //        System.err.println("oldBin = " + bin);
             bin = replaceInList(bin, key, property);
-    //        System.err.println("newBin = " + bin);
             bins[binIndex] = bin;
         }
         Element newList = list;
-        //System.err.println("oldList = " + newList);
         newList = replaceInList(newList, key, property);
-        //System.err.println("newList = " + newList);
         return new PropertyHashMap(size, bins, newList);
     }
 
--- a/nashorn/src/jdk/nashorn/internal/runtime/RecompilableScriptFunctionData.java	Wed Feb 26 13:17:57 2014 +0100
+++ b/nashorn/src/jdk/nashorn/internal/runtime/RecompilableScriptFunctionData.java	Mon Mar 03 11:24:44 2014 +0100
@@ -118,6 +118,7 @@
      * @param allocatorClassName name of our allocator class, will be looked up dynamically if used as a constructor
      * @param allocatorMap       allocator map to seed instances with, when constructing
      * @param nestedFunctions    nested function map
+     * @param sourceURL          source URL
      */
     public RecompilableScriptFunctionData(
         final FunctionNode functionNode,
--- a/nashorn/src/jdk/nashorn/internal/runtime/ScriptFunction.java	Wed Feb 26 13:17:57 2014 +0100
+++ b/nashorn/src/jdk/nashorn/internal/runtime/ScriptFunction.java	Mon Mar 03 11:24:44 2014 +0100
@@ -469,6 +469,7 @@
         final MethodType type = desc.getMethodType();
         assert desc.getMethodType().returnType() == Object.class && !NashornCallSiteDescriptor.isOptimistic(desc);
         final GuardedInvocation bestCtorInv = data.getBestConstructor(type);
+        //TODO - ClassCastException
         return new GuardedInvocation(pairArguments(bestCtorInv.getInvocation(), type), getFunctionGuard(this), bestCtorInv.getSwitchPoint());
     }
 
--- a/nashorn/src/jdk/nashorn/internal/runtime/ScriptFunctionData.java	Wed Feb 26 13:17:57 2014 +0100
+++ b/nashorn/src/jdk/nashorn/internal/runtime/ScriptFunctionData.java	Mon Mar 03 11:24:44 2014 +0100
@@ -37,6 +37,7 @@
 import java.util.Collections;
 import java.util.Map;
 import java.util.WeakHashMap;
+
 import jdk.internal.dynalink.linker.GuardedInvocation;
 import jdk.nashorn.internal.runtime.linker.JavaAdapterFactory;
 import jdk.nashorn.internal.runtime.linker.LinkerCallSite;
@@ -234,7 +235,6 @@
 
     private MethodHandle createGenericInvoker() {
         return makeGenericMethod(getGeneric().createComposableInvoker());
-// TODO hannes        return code.generic().getInvoker();
     }
 
     final MethodHandle getGenericConstructor() {
@@ -298,7 +298,7 @@
         final CompiledFunction bindTarget = new CompiledFunction(getGenericInvoker(), getGenericConstructor());
         boundList.add(bind(bindTarget, fn, self, allArgs));
 
-        ScriptFunctionData boundData = new FinalScriptFunctionData(name, Math.max(0, getArity() - length), boundList, isStrict(), isBuiltin(), isConstructor(), isVariableArity());
+        final ScriptFunctionData boundData = new FinalScriptFunctionData(name, Math.max(0, getArity() - length), boundList, isStrict(), isBuiltin(), isConstructor(), isVariableArity());
         return boundData;
     }
 
@@ -381,7 +381,7 @@
         } else {
             // If target is already bound, insert additional bound arguments after "this" argument, at position 1.
             final int argInsertPos = isTargetBound ? 1 : 0;
-            final Object[] boundArgs = new Object[Math.min(originalInvoker.type().parameterCount() - argInsertPos, args.length + (isTargetBound ? 0 : (needsCallee  ? 2 : 1)))];
+            final Object[] boundArgs = new Object[Math.min(originalInvoker.type().parameterCount() - argInsertPos, args.length + (isTargetBound ? 0 : needsCallee  ? 2 : 1))];
             int next = 0;
             if (!isTargetBound) {
                 if (needsCallee) {
@@ -463,7 +463,7 @@
      */
     private static MethodHandle makeGenericMethod(final MethodHandle mh) {
         final MethodType type = mh.type();
-        MethodType newType = makeGenericType(type);
+        final MethodType newType = makeGenericType(type);
         return type.equals(newType) ? mh : mh.asType(newType);
     }
 
@@ -681,7 +681,7 @@
         }
 
         final Class<?> param0 = type.parameterType(0);
-        return param0 == ScriptFunction.class || (param0 == boolean.class && length > 1 && type.parameterType(1) == ScriptFunction.class);
+        return param0 == ScriptFunction.class || param0 == boolean.class && length > 1 && type.parameterType(1) == ScriptFunction.class;
     }
 
     /**
--- a/nashorn/src/jdk/nashorn/internal/runtime/ScriptLoader.java	Wed Feb 26 13:17:57 2014 +0100
+++ b/nashorn/src/jdk/nashorn/internal/runtime/ScriptLoader.java	Mon Mar 03 11:24:44 2014 +0100
@@ -26,7 +26,6 @@
 package jdk.nashorn.internal.runtime;
 
 import java.security.CodeSource;
-import java.security.ProtectionDomain;
 
 /**
  * Responsible for loading script generated classes.
--- a/nashorn/src/jdk/nashorn/internal/runtime/ScriptObject.java	Wed Feb 26 13:17:57 2014 +0100
+++ b/nashorn/src/jdk/nashorn/internal/runtime/ScriptObject.java	Mon Mar 03 11:24:44 2014 +0100
@@ -45,6 +45,7 @@
 import static jdk.nashorn.internal.runtime.UnwarrantedOptimismException.isValid;
 import static jdk.nashorn.internal.runtime.arrays.ArrayIndex.getArrayIndex;
 import static jdk.nashorn.internal.runtime.arrays.ArrayIndex.isValidArrayIndex;
+import static jdk.nashorn.internal.runtime.linker.NashornGuards.explicitInstanceOfCheck;
 
 import java.lang.invoke.MethodHandle;
 import java.lang.invoke.MethodHandles;
@@ -60,6 +61,7 @@
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
+
 import jdk.internal.dynalink.CallSiteDescriptor;
 import jdk.internal.dynalink.linker.GuardedInvocation;
 import jdk.internal.dynalink.linker.LinkRequest;
@@ -105,19 +107,19 @@
     static final String NO_SUCH_PROPERTY_NAME = "__noSuchProperty__";
 
     /** Per ScriptObject flag - is this a scope object? */
-    public static final int IS_SCOPE       = 0b0000_0001;
+    public static final int IS_SCOPE       = 1 << 0;
 
     /** Per ScriptObject flag - is this an array object? */
-    public static final int IS_ARRAY       = 0b0000_0010;
+    public static final int IS_ARRAY       = 1 << 1;
 
     /** Per ScriptObject flag - is this an arguments object? */
-    public static final int IS_ARGUMENTS   = 0b0000_0100;
+    public static final int IS_ARGUMENTS   = 1 << 2;
 
     /** Is this a prototype PropertyMap? */
-    public static final int IS_PROTOTYPE   = 0b0000_1000;
+    public static final int IS_PROTOTYPE   = 1 << 3;
 
     /** Is length property not-writable? */
-    public static final int IS_LENGTH_NOT_WRITABLE = 0b0001_0000;
+    public static final int IS_LENGTH_NOT_WRITABLE = 1 << 4;
 
     /**
      * Spill growth rate - by how many elements does {@link ScriptObject#primitiveSpill} and
@@ -252,7 +254,7 @@
     }
 
     private static int alignUp(final int size, final int alignment) {
-        return (((size) + ((alignment) - 1)) & ~((alignment) - 1));
+        return size + alignment - 1 & ~(alignment - 1);
     }
 
     /**
@@ -448,10 +450,10 @@
 
             if (property instanceof UserAccessorProperty) {
                 return global.newAccessorDescriptor(
-                    (get != null) ?
+                    get != null ?
                         get :
                         UNDEFINED,
-                    (set != null) ?
+                    set != null ?
                         set :
                         UNDEFINED,
                     configurable,
@@ -921,7 +923,7 @@
         final int slot = spillLength;
         ensureSpillSize(spillLength); //arguments=slot0, caller=slot0
         objectSpill[slot] = new UserAccessorProperty.Accessors(getter, setter);
-        PropertyMap oldMap = getMap();
+        final PropertyMap oldMap = getMap();
         Property    newProperty;
         PropertyMap newMap;
         do {
@@ -1374,16 +1376,16 @@
      */
     public ScriptObject preventExtensions() {
         PropertyMap oldMap = getMap();
-
-        while (true) {
-            final PropertyMap newMap = getMap().preventExtensions();
-
-            if (!compareAndSetMap(oldMap, newMap)) {
-                oldMap = getMap();
-            } else {
-                return this;
-            }
+        while (!compareAndSetMap(oldMap,  getMap().preventExtensions())) {
+            oldMap = getMap();
         }
+
+        //invalidate any fast array setters
+        final ArrayData array = getArray();
+        if (array != null) {
+            array.invalidateSetters();
+        }
+        return this;
     }
 
     /**
@@ -1394,7 +1396,7 @@
      * @return true if array
      */
     public static boolean isArray(final Object obj) {
-        return (obj instanceof ScriptObject) && ((ScriptObject)obj).isArray();
+        return obj instanceof ScriptObject && ((ScriptObject)obj).isArray();
     }
 
     /**
@@ -1857,17 +1859,26 @@
      * @return GuardedInvocation to be invoked at call site.
      */
     protected GuardedInvocation findGetMethod(final CallSiteDescriptor desc, final LinkRequest request, final String operator) {
-        final String name = desc.getNameToken(CallSiteDescriptor.NAME_OPERAND);
+        final boolean explicitInstanceOfCheck = explicitInstanceOfCheck(desc, request);
+        final String  name = desc.getNameToken(CallSiteDescriptor.NAME_OPERAND);
+
         if (request.isCallSiteUnstable() || hasWithScope()) {
             return findMegaMorphicGetMethod(desc, name, "getMethod".equals(operator));
         }
 
         final FindProperty find = findProperty(name, true);
-        MethodHandle methodHandle;
+        MethodHandle mh;
 
         if (find == null) {
             if (PROTO_PROPERTY_NAME.equals(name)) {
-                return new GuardedInvocation(GETPROTO, null, null, ClassCastException.class);
+                return new GuardedInvocation(
+                        GETPROTO,
+                        explicitInstanceOfCheck ?
+                                NashornGuards.getScriptObjectGuard() :
+                                null,
+                        null,
+                        explicitInstanceOfCheck ?
+                                null : ClassCastException.class);
             }
 
             switch (operator) {
@@ -1876,42 +1887,57 @@
             case "getMethod":
                 return noSuchMethod(desc, request);
             case "getElem":
-                return createEmptyGetter(desc, name);
+                return createEmptyGetter(desc, explicitInstanceOfCheck, name);
             default:
-                throw new AssertionError(); // never invoked with any other operation
+                throw new AssertionError(operator); // never invoked with any other operation
             }
        }
 
         final Class<?> returnType = desc.getMethodType().returnType();
-        final Property property = find.getProperty();
+        final Property property   = find.getProperty();
 
         final int programPoint = NashornCallSiteDescriptor.isOptimistic(desc) ?
                 NashornCallSiteDescriptor.getProgramPoint(desc) :
                 UnwarrantedOptimismException.INVALID_PROGRAM_POINT;
-        methodHandle = find.getGetter(returnType, programPoint);
-
+
+        mh = find.getGetter(returnType, programPoint);
+        //we never need a guard if noGuard is set
         final boolean noGuard = OBJECT_FIELDS_ONLY && NashornCallSiteDescriptor.isFastScope(desc) && !property.canChangeType();
         // getMap() is fine as we have the prototype switchpoint depending on where the property was found
-        final MethodHandle guard = noGuard ? null : NashornGuards.getMapGuard(getMap());
-
-        if (methodHandle != null) {
-            assert methodHandle.type().returnType().equals(returnType) : "returntype mismatch for getter " + methodHandle.type().returnType() + " != " + returnType;
-            if (find.isSelf()) {
-                return new GuardedInvocation(methodHandle, guard, null, noGuard ? null : ClassCastException.class);
-            }
-
-            if (!property.hasGetterFunction(find.getOwner())) {
-                // If not a scope bind to actual prototype as changing prototype will change the property map.
-                // For scopes we install a filter that replaces the self object with the prototype owning the property.
-                methodHandle = isScope() ?
-                        addProtoFilter(methodHandle, find.getProtoChainLength()) :
-                        bindTo(methodHandle, find.getOwner());
-            }
-            return new GuardedInvocation(methodHandle, guard, noGuard ? null : getMap().getProtoGetSwitchPoint(proto, name), noGuard ? null : ClassCastException.class);
+        final MethodHandle guard;
+        final Class<? extends Throwable> exception;
+        if (noGuard) {
+            guard     = null;
+            exception = null;
+        } else {
+            guard     = NashornGuards.getMapGuard(map, explicitInstanceOfCheck);
+            exception = explicitInstanceOfCheck ? null : ClassCastException.class;
         }
 
-        assert !NashornCallSiteDescriptor.isFastScope(desc);
-        return new GuardedInvocation(Lookup.emptyGetter(returnType), guard, getMap().getProtoGetSwitchPoint(proto, name), ClassCastException.class);
+        assert noGuard == (guard == null);
+
+        if (mh == null) {
+            mh = Lookup.emptyGetter(returnType);
+        } else {
+            assert mh.type().returnType().equals(returnType) : "returntype mismatch for getter " + mh.type().returnType() + " != " + returnType;
+             if (find.isSelf()) {
+                return new GuardedInvocation(mh, guard, null, exception);
+             }
+
+             if (!property.hasGetterFunction(find.getOwner())) {
+                 // If not a scope bind to actual prototype as changing prototype will change the property map.
+                 // For scopes we install a filter that replaces the self object with the prototype owning the property.
+                mh = isScope() ? addProtoFilter(mh,    find.getProtoChainLength()) : bindTo(mh, find.getOwner());
+             }
+         }
+
+        assert OBJECT_FIELDS_ONLY || guard != null : "we always need a map guard here";
+
+        return new GuardedInvocation(
+                mh,
+                guard,
+                getMap().getProtoGetSwitchPoint(proto, name),
+                exception);
     }
 
     private static GuardedInvocation findMegaMorphicGetMethod(final CallSiteDescriptor desc, final String name, final boolean isMethod) {
@@ -1939,10 +1965,11 @@
      * @return GuardedInvocation to be invoked at call site.
      */
     protected GuardedInvocation findGetIndexMethod(final CallSiteDescriptor desc, final LinkRequest request) {
-        final MethodType callType    = desc.getMethodType();
-        final Class<?>   returnType  = callType.returnType();
-        final Class<?>   returnClass = returnType.isPrimitive() ? returnType : Object.class;
-        final Class<?>   keyClass    = callType.parameterType(1);
+        final MethodType callType                = desc.getMethodType();
+        final Class<?>   returnType              = callType.returnType();
+        final Class<?>   returnClass             = returnType.isPrimitive() ? returnType : Object.class;
+        final Class<?>   keyClass                = callType.parameterType(1);
+        final boolean    explicitInstanceOfCheck = explicitInstanceOfCheck(desc, request);
 
         final String name;
         if (returnClass.isPrimitive()) {
@@ -1954,7 +1981,7 @@
         }
 
         final MethodHandle mh = findGetIndexMethodHandle(returnClass, name, keyClass, desc);
-        return new GuardedInvocation(mh, null, null, ClassCastException.class);
+        return new GuardedInvocation(mh, NashornGuards.getScriptObjectGuard(explicitInstanceOfCheck), null, explicitInstanceOfCheck ? null : ClassCastException.class);
     }
 
     /**
@@ -1965,7 +1992,7 @@
      * @param desc           call site descriptor
      * @return method handle for getter
      */
-    protected MethodHandle findGetIndexMethodHandle(final Class<?> returnType, String name, final Class<?> elementType, final CallSiteDescriptor desc) {
+    protected MethodHandle findGetIndexMethodHandle(final Class<?> returnType, final String name, final Class<?> elementType, final CallSiteDescriptor desc) {
         if (!returnType.isPrimitive()) {
             return findOwnMH_V(getClass(), name, returnType, elementType);
         }
@@ -1987,12 +2014,14 @@
      * @return GuardedInvocation to be invoked at call site.
      */
     protected GuardedInvocation findSetMethod(final CallSiteDescriptor desc, final LinkRequest request) {
-        final String name = desc.getNameToken(CallSiteDescriptor.NAME_OPERAND);
+        final String  name = desc.getNameToken(CallSiteDescriptor.NAME_OPERAND);
         if (request.isCallSiteUnstable() || hasWithScope()) {
             return findMegaMorphicSetMethod(desc, name);
         }
 
-        final boolean scope = isScope();
+        final boolean scope                   = isScope();
+           final boolean explicitInstanceOfCheck = explicitInstanceOfCheck(desc, request);
+
         /*
          * If doing property set on a scope object, we should stop proto search on the first
          * non-scope object. Without this, for example, when assigning "toString" on global scope,
@@ -2006,7 +2035,7 @@
         if (!scope && find != null && find.isInherited() && !(find.getProperty() instanceof UserAccessorProperty)) {
             // We should still check if inherited data property is not writable
             if (isExtensible() && !find.getProperty().isWritable()) {
-                return createEmptySetMethod(desc, "property.not.writable", false);
+                return createEmptySetMethod(desc, explicitInstanceOfCheck, "property.not.writable", false);
             }
             // Otherwise, forget the found property
             find = null;
@@ -2015,27 +2044,35 @@
         if (find != null) {
             if (!find.getProperty().isWritable()) {
                 // Existing, non-writable property
-                return createEmptySetMethod(desc, "property.not.writable", true);
+                return createEmptySetMethod(desc, explicitInstanceOfCheck, "property.not.writable", true);
             }
         } else {
             if (PROTO_PROPERTY_NAME.equals(name)) {
-                return new GuardedInvocation(SETPROTOCHECK, null, null, ClassCastException.class);
-            } else if (! isExtensible()) {
-                return createEmptySetMethod(desc, "object.non.extensible", false);
+                return new GuardedInvocation(
+                        SETPROTOCHECK,
+                        NashornGuards.getScriptObjectGuard(explicitInstanceOfCheck),
+                        null,
+                        explicitInstanceOfCheck ? null : ClassCastException.class);
+            } else if (!isExtensible()) {
+                return createEmptySetMethod(desc, explicitInstanceOfCheck, "object.non.extensible", false);
             }
         }
 
-        return new SetMethodCreator(this, find, desc).createGuardedInvocation();
+        return new SetMethodCreator(this, find, desc, explicitInstanceOfCheck).createGuardedInvocation();
     }
 
-    private GuardedInvocation createEmptySetMethod(final CallSiteDescriptor desc, String strictErrorMessage, boolean canBeFastScope) {
-        final String name = desc.getNameToken(CallSiteDescriptor.NAME_OPERAND);
-        if (NashornCallSiteDescriptor.isStrict(desc)) {
-               throw typeError(strictErrorMessage, name, ScriptRuntime.safeToString((this)));
-           }
-           assert canBeFastScope || !NashornCallSiteDescriptor.isFastScope(desc);
-           final PropertyMap myMap = getMap();
-           return new GuardedInvocation(Lookup.EMPTY_SETTER, NashornGuards.getMapGuard(myMap), myMap.getProtoGetSwitchPoint(proto, name), ClassCastException.class);
+    private GuardedInvocation createEmptySetMethod(final CallSiteDescriptor desc, final boolean explicitInstanceOfCheck, final String strictErrorMessage, final boolean canBeFastScope) {
+        final String  name = desc.getNameToken(CallSiteDescriptor.NAME_OPERAND);
+         if (NashornCallSiteDescriptor.isStrict(desc)) {
+           throw typeError(strictErrorMessage, name, ScriptRuntime.safeToString(this));
+        }
+        assert canBeFastScope || !NashornCallSiteDescriptor.isFastScope(desc);
+        final PropertyMap myMap = getMap();
+        return new GuardedInvocation(
+                Lookup.EMPTY_SETTER,
+                NashornGuards.getMapGuard(myMap, explicitInstanceOfCheck),
+                myMap.getProtoGetSwitchPoint(proto, name),
+                explicitInstanceOfCheck ? null : ClassCastException.class);
     }
 
     @SuppressWarnings("unused")
@@ -2052,8 +2089,9 @@
     }
 
     private GuardedInvocation findMegaMorphicSetMethod(final CallSiteDescriptor desc, final String name) {
-        final MethodType type = desc.getMethodType().insertParameterTypes(1, Object.class);
-        final GuardedInvocation inv = findSetIndexMethod(getClass(), type, NashornCallSiteDescriptor.isStrict(desc));
+        final MethodType        type = desc.getMethodType().insertParameterTypes(1, Object.class);
+        //never bother with ClassCastExceptionGuard for megamorphic callsites
+        final GuardedInvocation inv  = findSetIndexMethod(getClass(), false, type, NashornCallSiteDescriptor.isStrict(desc));
         return inv.replaceMethods(MH.insertArguments(inv.getInvocation(), 1, name), inv.getGuard());
     }
 
@@ -2067,7 +2105,7 @@
      * @return GuardedInvocation to be invoked at call site.
      */
     protected GuardedInvocation findSetIndexMethod(final CallSiteDescriptor desc, final LinkRequest request) { // array, index, value
-        return findSetIndexMethod(getClass(), desc.getMethodType(), NashornCallSiteDescriptor.isStrict(desc));
+        return findSetIndexMethod(getClass(), explicitInstanceOfCheck(desc, request), desc.getMethodType(), NashornCallSiteDescriptor.isStrict(desc));
     }
 
     /**
@@ -2078,15 +2116,15 @@
      *
      * @return GuardedInvocation to be invoked at call site.
      */
-    private static GuardedInvocation findSetIndexMethod(final Class<? extends ScriptObject> clazz, final MethodType callType, final boolean isStrict) {
+    private static GuardedInvocation findSetIndexMethod(final Class<? extends ScriptObject> clazz, final boolean explicitInstanceOfCheck, final MethodType callType, final boolean isStrict) {
         assert callType.parameterCount() == 3;
-        final Class<?>   keyClass   = callType.parameterType(1);
-        final Class<?>   valueClass = callType.parameterType(2);
+        final Class<?> keyClass   = callType.parameterType(1);
+        final Class<?> valueClass = callType.parameterType(2);
 
         MethodHandle methodHandle = findOwnMH_V(clazz, "set", void.class, keyClass, valueClass, boolean.class);
         methodHandle = MH.insertArguments(methodHandle, 3, isStrict);
 
-        return new GuardedInvocation(methodHandle, null, null, ClassCastException.class);
+        return new GuardedInvocation(methodHandle, NashornGuards.getScriptObjectGuard(explicitInstanceOfCheck), null, explicitInstanceOfCheck ? null : ClassCastException.class);
     }
 
     /**
@@ -2104,17 +2142,26 @@
             return noSuchProperty(desc, request);
         }
 
+        final boolean explicitInstanceOfCheck = explicitInstanceOfCheck(desc, request);
+
         final Object value = getObjectValue(find);
-        if (! (value instanceof ScriptFunction)) {
-            return createEmptyGetter(desc, name);
+        if (!(value instanceof ScriptFunction)) {
+            return createEmptyGetter(desc, explicitInstanceOfCheck, name);
         }
 
         final ScriptFunction func = (ScriptFunction)value;
-        final Object thiz = scopeCall && func.isStrict() ? ScriptRuntime.UNDEFINED : this;
+        final Object         thiz = scopeCall && func.isStrict() ? ScriptRuntime.UNDEFINED : this;
         // TODO: It'd be awesome if we could bind "name" without binding "this".
-        return new GuardedInvocation(MH.dropArguments(MH.constant(ScriptFunction.class,
-                func.makeBoundFunction(thiz, new Object[] { name })), 0, Object.class),
-                NashornGuards.getMapGuard(getMap()), null, ClassCastException.class);
+        return new GuardedInvocation(
+                MH.dropArguments(
+                        MH.constant(
+                                ScriptFunction.class,
+                                func.makeBoundFunction(thiz, new Object[] { name })),
+                        0,
+                        Object.class),
+                NashornGuards.getMapGuard(getMap(), explicitInstanceOfCheck),
+                null,
+                explicitInstanceOfCheck ? null : ClassCastException.class);
     }
 
     /**
@@ -2125,9 +2172,9 @@
      */
     @SuppressWarnings("null")
     public GuardedInvocation noSuchProperty(final CallSiteDescriptor desc, final LinkRequest request) {
-        final String name = desc.getNameToken(CallSiteDescriptor.NAME_OPERAND);
-        final FindProperty find = findProperty(NO_SUCH_PROPERTY_NAME, true);
-        final boolean scopeAccess = isScope() && NashornCallSiteDescriptor.isScope(desc);
+        final String       name        = desc.getNameToken(CallSiteDescriptor.NAME_OPERAND);
+        final FindProperty find        = findProperty(NO_SUCH_PROPERTY_NAME, true);
+        final boolean      scopeAccess = isScope() && NashornCallSiteDescriptor.isScope(desc);
 
         if (find != null) {
             final Object   value        = getObjectValue(find);
@@ -2145,9 +2192,15 @@
                 }
                 return new GuardedInvocation(
                         methodHandle,
-                        getKnownFunctionPropertyGuard(getMap(), find.getGetter(Object.class, INVALID_PROGRAM_POINT), find.getOwner(), func),
+                        //TODO this always does a scriptobject check
+                        getKnownFunctionPropertyGuard(
+                                getMap(),
+                                find.getGetter(Object.class, INVALID_PROGRAM_POINT),
+                                find.getOwner(),
+                                func),
                         find.isInherited() ? getMap().getProtoGetSwitchPoint(proto, NO_SUCH_PROPERTY_NAME) : null,
-                        ClassCastException.class);
+                        //TODO this doesn't need a ClassCastException as guard always checks script object
+                        null);
             }
         }
 
@@ -2155,12 +2208,13 @@
             throw referenceError("not.defined", name);
         }
 
-        return createEmptyGetter(desc, name);
+        return createEmptyGetter(desc, explicitInstanceOfCheck(desc, request), name);
     }
 
     /**
      * Invoke fall back if a property is not found.
      * @param name Name of property.
+     * @param programPoint program point
      * @return Result from call.
      */
     protected Object invokeNoSuchProperty(final String name, final int programPoint) {
@@ -2204,11 +2258,19 @@
         return ((ScriptFunction)value).makeBoundFunction(this, new Object[] {name});
     }
 
-    private GuardedInvocation createEmptyGetter(final CallSiteDescriptor desc, final String name) {
-        if(NashornCallSiteDescriptor.isOptimistic(desc)) {
+    private GuardedInvocation createEmptyGetter(final CallSiteDescriptor desc, final boolean explicitInstanceOfCheck, final String name) {
+        if (NashornCallSiteDescriptor.isOptimistic(desc)) {
             throw new UnwarrantedOptimismException(UNDEFINED, NashornCallSiteDescriptor.getProgramPoint(desc), Type.OBJECT);
         }
-        return new GuardedInvocation(Lookup.emptyGetter(desc.getMethodType().returnType()), NashornGuards.getMapGuard(getMap()), getMap().getProtoGetSwitchPoint(proto, name), ClassCastException.class);
+
+        return new GuardedInvocation(
+                Lookup.emptyGetter(
+                        desc.getMethodType().returnType()),
+                        NashornGuards.getMapGuard(getMap(), explicitInstanceOfCheck),
+                        getMap().getProtoGetSwitchPoint(proto, name),
+                        explicitInstanceOfCheck ?
+                                null :
+                                ClassCastException.class);
     }
 
     private abstract static class ScriptObjectIterator <T extends Object> implements Iterator<T> {
@@ -2284,8 +2346,8 @@
      */
     private Property addSpillProperty(final String key, final int propertyFlags, final Object value, final boolean hasInitialValue) {
         final PropertyMap propertyMap = getMap();
-        final int fieldCount = propertyMap.getFieldCount();
-        final int fieldMax = propertyMap.getFieldMaximum();
+        final int         fieldCount  = propertyMap.getFieldCount();
+        final int         fieldMax    = propertyMap.getFieldMaximum();
 
         Property property;
         if (fieldCount < fieldMax) {
@@ -2354,8 +2416,8 @@
         final int callCount      = callType.parameterCount();
 
         final boolean isCalleeVarArg = parameterCount > 0 && methodType.parameterType(parameterCount - 1).isArray();
-        final boolean isCallerVarArg = callerVarArg != null ? callerVarArg.booleanValue() : (callCount > 0 &&
-                callType.parameterType(callCount - 1).isArray());
+        final boolean isCallerVarArg = callerVarArg != null ? callerVarArg.booleanValue() : callCount > 0 &&
+                callType.parameterType(callCount - 1).isArray();
 
         if (isCalleeVarArg) {
             return isCallerVarArg ?
@@ -2443,8 +2505,8 @@
 
        if (newLength > arrayLength) {
            setArray(getArray().ensure(newLength - 1));
-            if (getArray().canDelete(arrayLength, (newLength - 1), false)) {
-               setArray(getArray().delete(arrayLength, (newLength - 1)));
+            if (getArray().canDelete(arrayLength, newLength - 1, false)) {
+               setArray(getArray().delete(arrayLength, newLength - 1));
            }
            return;
        }
@@ -2869,8 +2931,8 @@
     private void doesNotHaveEnsureDelete(final long longIndex, final long oldLength, final boolean strict) {
         if (longIndex > oldLength) {
             ArrayData array = getArray();
-            if (array.canDelete(oldLength, (longIndex - 1), strict)) {
-                array = array.delete(oldLength, (longIndex - 1));
+            if (array.canDelete(oldLength, longIndex - 1, strict)) {
+                array = array.delete(oldLength, longIndex - 1);
             }
             setArray(array);
         }
@@ -3306,7 +3368,7 @@
     }
 
     private boolean hasOwnArrayProperty(final int index) {
-        return getArray().has(index) || (getMap().containsArrayKeys() && hasProperty(ArrayIndex.toKey(index), false));
+        return getArray().has(index) || getMap().containsArrayKeys() && hasProperty(ArrayIndex.toKey(index), false);
     }
 
     @Override
--- a/nashorn/src/jdk/nashorn/internal/runtime/SetMethodCreator.java	Wed Feb 26 13:17:57 2014 +0100
+++ b/nashorn/src/jdk/nashorn/internal/runtime/SetMethodCreator.java	Mon Mar 03 11:24:44 2014 +0100
@@ -36,7 +36,6 @@
 import jdk.nashorn.internal.runtime.linker.NashornCallSiteDescriptor;
 import jdk.nashorn.internal.runtime.linker.NashornGuards;
 
-
 /**
  * Instances of this class are quite ephemeral; they only exist for the duration of an invocation of
  * {@link ScriptObject#findSetMethod(CallSiteDescriptor, jdk.internal.dynalink.linker.LinkRequest)} and
@@ -49,6 +48,7 @@
     private final FindProperty       find;
     private final CallSiteDescriptor desc;
     private final Class<?>           type;
+    private final boolean            explicitInstanceOfCheck;
 
     /**
      * Creates a new property setter method creator.
@@ -57,12 +57,13 @@
      * want to create a setter for. Can be null if the property does not yet exist on the object.
      * @param desc the descriptor of the call site that triggered the property setter lookup
      */
-    SetMethodCreator(final ScriptObject sobj, final FindProperty find, final CallSiteDescriptor desc) {
+    SetMethodCreator(final ScriptObject sobj, final FindProperty find, final CallSiteDescriptor desc, final boolean explicitInstanceOfCheck) {
         this.sobj = sobj;
         this.map  = sobj.getMap();
         this.find = find;
         this.desc = desc;
         this.type = desc.getMethodType().parameterType(1);
+        this.explicitInstanceOfCheck = explicitInstanceOfCheck;
 
     }
 
@@ -118,7 +119,7 @@
         }
 
         private MethodHandle getGuard() {
-            return needsNoGuard() ? null : NashornGuards.getMapGuard(getMap());
+            return needsNoGuard() ? null : NashornGuards.getMapGuard(getMap(), explicitInstanceOfCheck);
         }
 
         private boolean needsNoGuard() {
--- a/nashorn/src/jdk/nashorn/internal/runtime/SpillProperty.java	Wed Feb 26 13:17:57 2014 +0100
+++ b/nashorn/src/jdk/nashorn/internal/runtime/SpillProperty.java	Mon Mar 03 11:24:44 2014 +0100
@@ -27,6 +27,7 @@
 
 import java.lang.invoke.MethodHandle;
 import java.lang.invoke.MethodHandles;
+
 import static jdk.nashorn.internal.codegen.ObjectClassGenerator.OBJECT_FIELDS_ONLY;
 import static jdk.nashorn.internal.lookup.Lookup.MH;
 
@@ -156,6 +157,7 @@
      * @param flags  the property flags
      * @param slot   spill slot
      */
+    @SuppressWarnings("unused")
     public SpillProperty(final String key, final int flags, final int slot) {
         super(key, flags, slot, primitiveGetter(slot), primitiveSetter(slot), objectGetter(slot), objectSetter(slot));
         assert !OBJECT_FIELDS_ONLY || getCurrentType() == Object.class;
--- a/nashorn/src/jdk/nashorn/internal/runtime/WithObject.java	Wed Feb 26 13:17:57 2014 +0100
+++ b/nashorn/src/jdk/nashorn/internal/runtime/WithObject.java	Mon Mar 03 11:24:44 2014 +0100
@@ -31,6 +31,7 @@
 import java.lang.invoke.MethodHandles;
 import java.lang.invoke.MethodType;
 import java.lang.invoke.SwitchPoint;
+
 import jdk.internal.dynalink.CallSiteDescriptor;
 import jdk.internal.dynalink.linker.GuardedInvocation;
 import jdk.internal.dynalink.linker.LinkRequest;
@@ -66,7 +67,6 @@
         this.expression = expression;
     }
 
-
     /**
      * Delete a property based on a key.
      * @param key Any valid JavaScript value.
@@ -99,7 +99,7 @@
 
         final boolean isNamedOperation;
         final String name;
-        if(desc.getNameTokenCount() > 2) {
+        if (desc.getNameTokenCount() > 2) {
             isNamedOperation = true;
             name = desc.getNameToken(CallSiteDescriptor.NAME_OPERAND);
         } else {
@@ -114,7 +114,6 @@
 
         if (find != null) {
             link = self.lookup(desc, request);
-
             if (link != null) {
                 return fixExpressionCallSite(ndesc, link);
             }
@@ -239,21 +238,33 @@
     private static GuardedInvocation fixExpressionCallSite(final NashornCallSiteDescriptor desc, final GuardedInvocation link) {
         // If it's not a getMethod, just add an expression filter that converts WithObject in "this" position to its
         // expression.
-        if(!"getMethod".equals(desc.getFirstOperator())) {
+        if (!"getMethod".equals(desc.getFirstOperator())) {
             return fixReceiverType(link, WITHEXPRESSIONFILTER).filterArguments(0, WITHEXPRESSIONFILTER);
         }
 
-        final MethodHandle linkInvocation = link.getInvocation();
-        final MethodType linkType = linkInvocation.type();
-        final boolean linkReturnsFunction = ScriptFunction.class.isAssignableFrom(linkType.returnType());
+        final MethodHandle linkInvocation      = link.getInvocation();
+        final MethodType   linkType            = linkInvocation.type();
+        final boolean      linkReturnsFunction = ScriptFunction.class.isAssignableFrom(linkType.returnType());
 
         return link.replaceMethods(
                 // Make sure getMethod will bind the script functions it receives to WithObject.expression
-                MH.foldArguments(linkReturnsFunction ? BIND_TO_EXPRESSION_FN : BIND_TO_EXPRESSION_OBJ,
-                        filterReceiver(linkInvocation.asType(linkType.changeReturnType(
-                                linkReturnsFunction ? ScriptFunction.class : Object.class).changeParameterType(0, ScriptObject.class)), WITHEXPRESSIONFILTER)),
-                // No clever things for the guard -- it is still identically filtered.
-                filterGuardReceiver(link, WITHEXPRESSIONFILTER));
+                MH.foldArguments(
+                        linkReturnsFunction ?
+                                BIND_TO_EXPRESSION_FN :
+                                BIND_TO_EXPRESSION_OBJ,
+                        filterReceiver(
+                                linkInvocation.asType(
+                                        linkType.changeReturnType(
+                                                linkReturnsFunction ?
+                                                        ScriptFunction.class :
+                                                        Object.class).
+                                                            changeParameterType(
+                                                                    0,
+                                                                    ScriptObject.class)),
+                                        WITHEXPRESSIONFILTER)),
+                         filterGuardReceiver(link, WITHEXPRESSIONFILTER));
+     // No clever things for the guard -- it is still identically filtered.
+
     }
 
     private GuardedInvocation fixScopeCallSite(final GuardedInvocation link, final String name) {
@@ -271,10 +282,20 @@
 
     private static MethodHandle filterGuardReceiver(final GuardedInvocation link, final MethodHandle receiverFilter) {
         final MethodHandle test = link.getGuard();
-        return test == null ? null : filterReceiver(test, receiverFilter);
+        if (test == null) {
+            return null;
+        }
+
+        final Class<?> receiverType = test.type().parameterType(0);
+        final MethodHandle filter = MH.asType(receiverFilter,
+                receiverFilter.type().changeParameterType(0, receiverType).
+                changeReturnType(receiverType));
+
+        return filterReceiver(test, filter);
     }
 
     private static MethodHandle filterReceiver(final MethodHandle mh, final MethodHandle receiverFilter) {
+        //With expression filter == receiverFilter, i.e. receiver is cast to withobject and its expression returned
         return MH.filterArguments(mh, 0, receiverFilter);
     }
 
--- a/nashorn/src/jdk/nashorn/internal/runtime/arrays/ArrayData.java	Wed Feb 26 13:17:57 2014 +0100
+++ b/nashorn/src/jdk/nashorn/internal/runtime/arrays/ArrayData.java	Mon Mar 03 11:24:44 2014 +0100
@@ -26,16 +26,16 @@
 package jdk.nashorn.internal.runtime.arrays;
 
 import static jdk.nashorn.internal.codegen.CompilerConstants.staticCall;
-import static jdk.nashorn.internal.lookup.Lookup.MH;
-import static jdk.nashorn.internal.runtime.JSType.getAccessorTypeIndex;
-import static jdk.nashorn.internal.runtime.UnwarrantedOptimismException.isValid;
-
 import java.lang.invoke.MethodHandle;
 import java.lang.invoke.MethodHandles;
+
+import jdk.internal.dynalink.CallSiteDescriptor;
+import jdk.internal.dynalink.linker.GuardedInvocation;
+import jdk.internal.dynalink.linker.LinkRequest;
+
 import java.nio.ByteBuffer;
 import jdk.nashorn.internal.codegen.CompilerConstants;
 import jdk.nashorn.internal.codegen.types.Type;
-import jdk.nashorn.internal.lookup.Lookup;
 import jdk.nashorn.internal.runtime.GlobalObject;
 import jdk.nashorn.internal.runtime.JSType;
 import jdk.nashorn.internal.runtime.PropertyDescriptor;
@@ -66,7 +66,7 @@
     }*/
 
     /** Minimum chunk size for underlying arrays */
-    protected static final int CHUNK_SIZE = 16;
+    protected static final int CHUNK_SIZE = 32;
 
     /** Mask for getting a chunk */
     protected static final int CHUNK_MASK = CHUNK_SIZE - 1;
@@ -88,31 +88,6 @@
     protected static final CompilerConstants.Call THROW_UNWARRANTED = staticCall(MethodHandles.lookup(), ArrayData.class, "throwUnwarranted", void.class, ArrayData.class, int.class, int.class);
 
     /**
-     * Unwarranted thrower
-     *
-     * @param data         array data
-     * @param programPoint program point
-     * @param index        array index
-     */
-    protected static void throwUnwarranted(final ArrayData data, final int programPoint, final int index) {
-        throw new UnwarrantedOptimismException(data.getObject(index), programPoint);
-    }
-
-    /**
-     * Version of has that throws a class cast exception if element does not exist
-     * used for relinking
-     *
-     * @param index index to check - currently only int indexes
-     * @return index
-     */
-    protected int throwHas(final int index) {
-        if (!has(index)) {
-            throw new ClassCastException();
-        }
-        return index;
-    }
-
-    /**
      * Constructor
      * @param length Virtual length of the array.
      */
@@ -129,40 +104,34 @@
     }
 
     /**
-     * Return element getter for a {@link ContinuousArray}
-     * @param getHas       has getter
-     * @param returnType   return type
+     * Unwarranted thrower
+     *
+     * @param data         array data
      * @param programPoint program point
-     * @return method handle for element setter
+     * @param index        array index
      */
-    protected final static MethodHandle getContinuousElementGetter(final MethodHandle getHas, final Class<?> returnType, final int programPoint) {
-        final boolean isOptimistic = isValid(programPoint);
-        final int fti = getAccessorTypeIndex(getHas.type().returnType());
-        final int ti  = getAccessorTypeIndex(returnType);
-        MethodHandle mh = getHas;
+    protected static void throwUnwarranted(final ArrayData data, final int programPoint, final int index) {
+        throw new UnwarrantedOptimismException(data.getObject(index), programPoint);
+    }
 
-        if (isOptimistic) {
-            if (ti < fti) {
-                mh = MH.insertArguments(ArrayData.THROW_UNWARRANTED.methodHandle(), 1, programPoint);
-            }
-        }
-        mh = MH.asType(mh, mh.type().changeReturnType(returnType).changeParameterType(0, ContinuousArray.class));
-
-        if (!isOptimistic) {
-            //for example a & array[17];
-            return Lookup.filterReturnType(mh, returnType);
-        }
-        return mh;
+    private static int alignUp(final int size) {
+        return size + CHUNK_SIZE - 1 & ~(CHUNK_SIZE - 1);
     }
 
     /**
-     * Return element setter for a {@link ContinuousArray}
-     * @param setHas       set has guard
-     * @param elementType  element type
-     * @return method handle for element setter
+     * Generic invalidation hook for script object to have call sites to this array indexing
+     * relinked, e.g. when a native array is marked as non extensible
      */
-    protected final static MethodHandle getContinuousElementSetter(final MethodHandle setHas, final Class<?> elementType) {
-        return MH.asType(setHas, setHas.type().changeParameterType(2, elementType).changeParameterType(0, ContinuousArray.class));
+    public void invalidateGetters() {
+        //subclass responsibility
+    }
+
+    /**
+     * Generic invalidation hook for script object to have call sites to this array indexing
+     * relinked, e.g. when a native array is marked as non extensible
+     */
+    public void invalidateSetters() {
+        //subclass responsibility
     }
 
     /**
@@ -598,6 +567,50 @@
     }
 
     /**
+     * Push an array of items to the end of the array
+     *
+     * @param strict are we in strict mode
+     * @param item   the item
+     * @return new array data (or same)
+     */
+    public ArrayData push(final boolean strict, final Object item) {
+        return push(strict, new Object[] { item });
+    }
+
+    /**
+     * Push an array of items to the end of the array
+     *
+     * @param strict are we in strict mode
+     * @param item   the item
+     * @return new array data (or same)
+     */
+    public ArrayData push(final boolean strict, final double item) {
+        return push(strict, item);
+    }
+
+    /**
+     * Push an array of items to the end of the array
+     *
+     * @param strict are we in strict mode
+     * @param item   the item
+     * @return new array data (or same)
+     */
+    public ArrayData push(final boolean strict, final long item) {
+        return push(strict, item);
+    }
+
+    /**
+     * Push an array of items to the end of the array
+     *
+     * @param strict are we in strict mode
+     * @param item   the item
+     * @return new array data (or same)
+     */
+    public ArrayData push(final boolean strict, final int item) {
+        return push(strict, item);
+    }
+
+    /**
      * Pop an element from the end of the array
      *
      * @return the popped element
@@ -662,16 +675,7 @@
      * @return next size to allocate for internal array
      */
     protected static int nextSize(final int size) {
-        if (size == 0) {
-            return CHUNK_SIZE;
-        }
-
-        int i = size;
-        while ((i & CHUNK_MASK) != 0) {
-            i++;
-        }
-
-        return i << 1;
+        return alignUp(size + 1) * 2;
     }
 
     /**
@@ -696,4 +700,41 @@
         }
     }
 
+    /**
+     * Find a fast property getter if one exists
+     *
+     * @param clazz    array data class
+     * @param desc     callsite descriptor
+     * @param request  link request
+     * @param operator operator
+     * @return fast property getter if one is found
+     */
+    public GuardedInvocation findFastGetMethod(final Class<? extends ArrayData> clazz, final CallSiteDescriptor desc, final LinkRequest request, final String operator) {
+        return null;
+    }
+
+    /**
+     * Find a fast element getter if one exists
+     *
+     * @param clazz   array data class
+     * @param desc    callsite descriptor
+     * @param request link request
+     * @return fast index getter if one is found
+     */
+    public GuardedInvocation findFastGetIndexMethod(final Class<? extends ArrayData> clazz, final CallSiteDescriptor desc, final LinkRequest request) { // array, index, value
+        return null;
+    }
+
+    /**
+     * Find a fast element setter if one exists
+     *
+     * @param clazz   array data class
+     * @param desc    callsite descriptor
+     * @param request link request
+     * @return fast index getter if one is found
+     */
+    public GuardedInvocation findFastSetIndexMethod(final Class<? extends ArrayData> clazz, final CallSiteDescriptor desc, final LinkRequest request) { // array, index, value
+        return null;
+    }
+
 }
--- a/nashorn/src/jdk/nashorn/internal/runtime/arrays/ContinuousArray.java	Wed Feb 26 13:17:57 2014 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,58 +0,0 @@
-/*
- * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.  Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-package jdk.nashorn.internal.runtime.arrays;
-
-import java.lang.invoke.MethodHandle;
-
-/**
- * Interface implemented by all arrays that are directly accessible as underlying
- * native arrays
- */
-public interface ContinuousArray {
-
-    /**
-     * Return the guard used for the setter, usually some kind of {@link ArrayData#has}
-     * @return guard handle for setters
-     */
-    public MethodHandle getSetGuard();
-
-    /**
-     * Return element getter for a certain type at a certain program point
-     * @param returnType   return type
-     * @param programPoint program point
-     * @return element getter or null if not supported (used to implement slow linkage instead
-     *   as fast isn't possible)
-     */
-    public MethodHandle getElementGetter(final Class<?> returnType, final int programPoint);
-
-    /**
-     * Return element getter for a certain type at a certain program point
-     * @param elementType element type
-     * @return element setter or null if not supported (used to implement slow linkage instead
-     *   as fast isn't possible)
-     */
-    public MethodHandle getElementSetter(final Class<?> elementType);
-}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/src/jdk/nashorn/internal/runtime/arrays/ContinuousArrayData.java	Mon Mar 03 11:24:44 2014 +0100
@@ -0,0 +1,284 @@
+/*
+ * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.nashorn.internal.runtime.arrays;
+
+import static jdk.nashorn.internal.codegen.CompilerConstants.staticCall;
+import static jdk.nashorn.internal.lookup.Lookup.MH;
+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;
+import java.lang.invoke.SwitchPoint;
+
+import jdk.internal.dynalink.CallSiteDescriptor;
+import jdk.internal.dynalink.DynamicLinker;
+import jdk.internal.dynalink.linker.GuardedInvocation;
+import jdk.internal.dynalink.linker.LinkRequest;
+import jdk.nashorn.internal.lookup.Lookup;
+import jdk.nashorn.internal.runtime.DebugLogger;
+import jdk.nashorn.internal.runtime.ScriptObject;
+import jdk.nashorn.internal.runtime.linker.NashornCallSiteDescriptor;
+
+/**
+ * Interface implemented by all arrays that are directly accessible as underlying
+ * native arrays
+ */
+public abstract class ContinuousArrayData extends ArrayData {
+
+    /** Logger for array accessor linkage */
+    protected static DebugLogger LOG = new DebugLogger("arrays");
+
+    private SwitchPoint sp;
+
+    /**
+     * Constructor
+     * @param length length (elementLength)
+     */
+    protected ContinuousArrayData(final long length) {
+        super(length);
+    }
+
+    private SwitchPoint ensureSwitchPointExists() {
+        if (sp == null){
+            sp = new SwitchPoint();
+        }
+        return sp;
+    }
+
+    @Override
+    public void invalidateSetters() {
+        SwitchPoint.invalidateAll(new SwitchPoint[] { ensureSwitchPointExists() });
+    }
+
+    /**
+     * Check if we can put one more element at the end of this continous
+     * array without reallocating, or if we are overwriting an already
+     * allocated element
+     *
+     * @param index
+     * @return true if we don't need to do any array reallocation to fit an element at index
+     */
+    public final boolean hasRoomFor(final int index) {
+        return has(index) || (index == length() && ensure(index) == this);
+    }
+
+    /**
+     * Return element getter for a certain type at a certain program point
+     * @param returnType   return type
+     * @param programPoint program point
+     * @return element getter or null if not supported (used to implement slow linkage instead
+     *   as fast isn't possible)
+     */
+    public abstract MethodHandle getElementGetter(final Class<?> returnType, final int programPoint);
+
+    /**
+     * Return element getter for a certain type at a certain program point
+     * @param elementType element type
+     * @return element setter or null if not supported (used to implement slow linkage instead
+     *   as fast isn't possible)
+     */
+    public abstract MethodHandle getElementSetter(final Class<?> elementType);
+
+    /**
+     * Version of has that throws a class cast exception if element does not exist
+     * used for relinking
+     *
+     * @param index index to check - currently only int indexes
+     * @return index
+     */
+    protected int throwHas(final int index) {
+        if (!has(index)) {
+            throw new ClassCastException();
+        }
+        return index;
+    }
+
+    /**
+     * Look up a continuous array element getter
+     * @param get          getter, sometimes combined with a has check that throws CCE on failure for relink
+     * @param returnType   return type
+     * @param programPoint program point
+     * @return array getter
+     */
+    protected final MethodHandle getContinuousElementGetter(final MethodHandle get, final Class<?> returnType, final int programPoint) {
+        return getContinuousElementGetter(getClass(), get, returnType, programPoint);
+    }
+
+    /**
+     * Look up a continuous array element setter
+     * @param set          setter, sometimes combined with a has check that throws CCE on failure for relink
+     * @param returnType   return type
+     * @return array setter
+     */
+    protected final MethodHandle getContinuousElementSetter(final MethodHandle set, final Class<?> returnType) {
+        return getContinuousElementSetter(getClass(), set, returnType);
+    }
+
+    /**
+     * Return element getter for a {@link ContinuousArrayData}
+     * @param clazz        clazz for exact type guard
+     * @param getHas       has getter
+     * @param returnType   return type
+     * @param programPoint program point
+     * @return method handle for element setter
+     */
+    protected MethodHandle getContinuousElementGetter(final Class<? extends ContinuousArrayData> clazz, final MethodHandle getHas, final Class<?> returnType, final int programPoint) {
+        final boolean isOptimistic = isValid(programPoint);
+        final int     fti          = getAccessorTypeIndex(getHas.type().returnType());
+        final int     ti           = getAccessorTypeIndex(returnType);
+        MethodHandle  mh           = getHas;
+
+        if (isOptimistic) {
+            if (ti < fti) {
+                mh = MH.insertArguments(ArrayData.THROW_UNWARRANTED.methodHandle(), 1, programPoint);
+            }
+        }
+        mh = MH.asType(mh, mh.type().changeReturnType(returnType).changeParameterType(0, clazz));
+
+        if (!isOptimistic) {
+            //for example a & array[17];
+            return Lookup.filterReturnType(mh, returnType);
+        }
+        return mh;
+    }
+
+    /**
+     * Return element setter for a {@link ContinuousArrayData}
+     * @param clazz        clazz for exact type guard
+     * @param setHas       set has guard
+     * @param elementType  element type
+     * @return method handle for element setter
+     */
+    protected MethodHandle getContinuousElementSetter(final Class<? extends ContinuousArrayData> clazz, final MethodHandle setHas, final Class<?> elementType) {
+        return MH.asType(setHas, setHas.type().changeParameterType(2, elementType).changeParameterType(0, clazz));
+    }
+
+    @Override
+    public GuardedInvocation findFastGetMethod(final Class<? extends ArrayData> clazz, final CallSiteDescriptor desc, final LinkRequest request, final String operator) {
+        return null;
+    }
+
+    /** Fast access guard - it is impractical for JIT performance reasons to use only CCE asType as guard :-(, also we need
+      the null case explicitly, which is the one that CCE doesn't handle */
+    protected static final MethodHandle FAST_ACCESS_GUARD =
+            MH.dropArguments(
+                    staticCall(
+                            MethodHandles.lookup(),
+                            ContinuousArrayData.class,
+                            "guard",
+                            boolean.class,
+                            Class.class,
+                            ScriptObject.class).methodHandle(),
+                    2,
+                    int.class);
+
+    @SuppressWarnings("unused")
+    private static final boolean guard(final Class<? extends ContinuousArrayData> clazz, final ScriptObject sobj) {
+        if (sobj != null && sobj.getArray().getClass() == clazz) {
+            return true;
+        }
+        return false;
+    }
+
+    /**
+     * Return a fast linked array getter, or null if we have to dispatch to super class
+     * @param desc     descriptor
+     * @param request  link request
+     * @return invocation or null if needs to be sent to slow relink
+     */
+    @Override
+    public GuardedInvocation findFastGetIndexMethod(final Class<? extends ArrayData> clazz, final CallSiteDescriptor desc, final LinkRequest request) {
+        final MethodType callType   = desc.getMethodType();
+        final Class<?>   indexType  = callType.parameterType(1);
+        final Class<?>   returnType = callType.returnType();
+
+        if (ContinuousArrayData.class.isAssignableFrom(clazz) && indexType == int.class) {
+            final Object[] args  = request.getArguments();
+            final int      index = (int)args[args.length - 1];
+
+            if (has(index)) {
+                final MethodHandle getArray     = ScriptObject.GET_ARRAY.methodHandle();
+                final int          programPoint = NashornCallSiteDescriptor.isOptimistic(desc) ? NashornCallSiteDescriptor.getProgramPoint(desc) : INVALID_PROGRAM_POINT;
+                MethodHandle       getElement   = getElementGetter(returnType, programPoint);
+                if (getElement != null) {
+                    getElement = MH.filterArguments(getElement, 0, MH.asType(getArray, getArray.type().changeReturnType(clazz)));
+                    final MethodHandle guard = MH.insertArguments(FAST_ACCESS_GUARD, 0, clazz);
+                    return new GuardedInvocation(getElement, guard, null, ClassCastException.class);
+                }
+            }
+        }
+
+        if (LOG.isEnabled()) {
+            LOG.info(getClass().getSimpleName() + ": Missed fast GETTER " + clazz.getSimpleName() + " " + desc + " " + " line:" + DynamicLinker.getLinkedCallSiteLocation().getLineNumber());
+        }
+
+        return null;
+    }
+
+    /**
+     * Return a fast linked array setter, or null if we have to dispatch to super class
+     * @param desc     descriptor
+     * @param request  link request
+     * @return invocation or null if needs to be sent to slow relink
+     */
+    @Override
+    public GuardedInvocation findFastSetIndexMethod(final Class<? extends ArrayData> clazz, final CallSiteDescriptor desc, final LinkRequest request) { // array, index, value
+        final MethodType callType    = desc.getMethodType();
+        final Class<?>   indexType   = callType.parameterType(1);
+        final Class<?>   elementType = callType.parameterType(2);
+
+        if (ContinuousArrayData.class.isAssignableFrom(clazz) && indexType == int.class) {
+            final Object[]        args  = request.getArguments();
+            final int             index = (int)args[args.length - 2];
+
+            //sp may be invalidated by e.g. preventExtensions before the first setter is linked
+            //then it is already created. otherwise, create it here to guard against future
+            //invalidations
+            ensureSwitchPointExists();
+
+            if (!sp.hasBeenInvalidated() && hasRoomFor(index)) {
+                MethodHandle setElement = getElementSetter(elementType); //Z(continuousarraydata, int, int), return true if successful
+                if (setElement != null) {
+                    //else we are dealing with a wider type than supported by this callsite
+                    MethodHandle getArray = ScriptObject.GET_ARRAY.methodHandle();
+                    getArray   = MH.asType(getArray, getArray.type().changeReturnType(getClass()));
+                    setElement = MH.filterArguments(setElement, 0, getArray);
+                    final MethodHandle guard = MH.insertArguments(FAST_ACCESS_GUARD, 0, clazz);
+                    return new GuardedInvocation(setElement, guard, sp, ClassCastException.class); //CCE if not a scriptObject anymore
+                }
+            }
+        }
+
+        if (LOG.isEnabled()) {
+            LOG.info(getClass().getSimpleName() + ": Missed fast SETTER " + clazz.getSimpleName() + " " + desc + " " + " line:" + DynamicLinker.getLinkedCallSiteLocation().getLineNumber());
+        }
+
+        return null;
+    }
+}
--- a/nashorn/src/jdk/nashorn/internal/runtime/arrays/IntArrayData.java	Wed Feb 26 13:17:57 2014 +0100
+++ b/nashorn/src/jdk/nashorn/internal/runtime/arrays/IntArrayData.java	Mon Mar 03 11:24:44 2014 +0100
@@ -25,7 +25,7 @@
 
 package jdk.nashorn.internal.runtime.arrays;
 
-import static jdk.nashorn.internal.codegen.CompilerConstants.virtualCall;
+import static jdk.nashorn.internal.codegen.CompilerConstants.specialCall;
 
 import java.lang.invoke.MethodHandle;
 import java.lang.invoke.MethodHandles;
@@ -39,7 +39,7 @@
  * Implementation of {@link ArrayData} as soon as an int has been
  * written to the array. This is the default data for new arrays
  */
-final class IntArrayData extends ArrayData implements ContinuousArray {
+final class IntArrayData extends ContinuousArrayData {
     /**
      * The wrapped array
      */
@@ -65,14 +65,8 @@
         this.array = array;
     }
 
-    private static final MethodHandle HAS_GET_ELEM = virtualCall(MethodHandles.lookup(), IntArrayData.class, UNSAFE == null ? "getElem" : "getElemUnsafe", int.class, int.class).methodHandle();
-    private static final MethodHandle SET_ELEM     = virtualCall(MethodHandles.lookup(), IntArrayData.class, UNSAFE == null ? "setElem" : "setElemUnsafe", void.class, int.class, int.class).methodHandle();
-    private static final MethodHandle HAS          = virtualCall(MethodHandles.lookup(), IntArrayData.class, "has", boolean.class, int.class).methodHandle();
-
-    @Override
-    public final MethodHandle getSetGuard() {
-        return HAS;
-    }
+    private static final MethodHandle HAS_GET_ELEM = specialCall(MethodHandles.lookup(), IntArrayData.class, UNSAFE == null ? "getElem" : "getElemUnsafe", int.class, int.class).methodHandle();
+    private static final MethodHandle SET_ELEM     = specialCall(MethodHandles.lookup(), IntArrayData.class, UNSAFE == null ? "setElem" : "setElemUnsafe", void.class, int.class, int.class).methodHandle();
 
     private final static long UNSAFE_BASE  = UNSAFE == null ? 0L : UNSAFE.arrayBaseOffset(int[].class);
     private final static long UNSAFE_SCALE = UNSAFE == null ? 0L : UNSAFE.arrayIndexScale(int[].class);
@@ -95,12 +89,20 @@
 
     @SuppressWarnings("unused")
     private void setElemUnsafe(final int index, final int elem) {
-        UNSAFE.putInt(array, UNSAFE_BASE + UNSAFE_SCALE * index, elem);
+        if (hasRoomFor(index)) {
+            UNSAFE.putInt(array, UNSAFE_BASE + UNSAFE_SCALE * index, elem);
+            return;
+        }
+        throw new ClassCastException();
     }
 
     @SuppressWarnings("unused")
     private void setElem(final int index, final int elem) {
-        array[index] = elem;
+        if (hasRoomFor(index)) {
+            array[index] = elem;
+            return;
+        }
+        throw new ClassCastException();
     }
 
     @Override
@@ -198,22 +200,15 @@
 
     @Override
     public ArrayData ensure(final long safeIndex) {
-        if (safeIndex >= SparseArrayData.MAX_DENSE_LENGTH && safeIndex >= array.length) {
+        if (safeIndex >= SparseArrayData.MAX_DENSE_LENGTH) {
             return new SparseArrayData(this, safeIndex + 1);
         }
-
-        int newLength = array.length;
-
-        while (newLength <= safeIndex) {
-            newLength = ArrayData.nextSize(newLength);
-        }
-
-        if (array.length <= safeIndex) {
+        final int alen = array.length;
+        if (safeIndex >= alen) {
+            final int newLength = ArrayData.nextSize((int)safeIndex);
             array = Arrays.copyOf(array, newLength);
         }
-
         setLength(safeIndex + 1);
-
         return this;
     }
 
@@ -337,20 +332,31 @@
 
     @Override
     public ArrayData slice(final long from, final long to) {
-        final long start     = from < 0 ? (from + length()) : from;
+        final long start     = from < 0 ? from + length() : from;
         final long newLength = to - start;
 
         return new IntArrayData(Arrays.copyOfRange(array, (int)from, (int)to), (int)newLength);
     }
 
     @Override
+    public final ArrayData push(final boolean strict, final int item) {
+        final long      length = length();
+        final ArrayData newData = ensure(length);
+        if (newData == this) {
+            array[(int)length] = item;
+            return this;
+        }
+        return newData.set((int)length, item, strict);
+    }
+
+    @Override
     public ArrayData fastSplice(final int start, final int removed, final int added) throws UnsupportedOperationException {
         final long oldLength = length();
         final long newLength = oldLength - removed + added;
         if (newLength > SparseArrayData.MAX_DENSE_LENGTH && newLength > array.length) {
             throw new UnsupportedOperationException();
         }
-        final ArrayData returnValue = (removed == 0) ?
+        final ArrayData returnValue = removed == 0 ?
                 EMPTY_ARRAY : new IntArrayData(Arrays.copyOfRange(array, start, start + removed), removed);
 
         if (newLength != oldLength) {
--- a/nashorn/src/jdk/nashorn/internal/runtime/arrays/LongArrayData.java	Wed Feb 26 13:17:57 2014 +0100
+++ b/nashorn/src/jdk/nashorn/internal/runtime/arrays/LongArrayData.java	Mon Mar 03 11:24:44 2014 +0100
@@ -26,7 +26,7 @@
 package jdk.nashorn.internal.runtime.arrays;
 
 import static jdk.nashorn.internal.lookup.Lookup.MH;
-import static jdk.nashorn.internal.codegen.CompilerConstants.virtualCall;
+import static jdk.nashorn.internal.codegen.CompilerConstants.specialCall;
 
 import java.lang.invoke.MethodHandle;
 import java.lang.invoke.MethodHandles;
@@ -40,7 +40,7 @@
  * Implementation of {@link ArrayData} as soon as a long has been
  * written to the array
  */
-final class LongArrayData extends ArrayData implements ContinuousArray {
+final class LongArrayData extends ContinuousArrayData {
     /**
      * The wrapped array
      */
@@ -128,22 +128,15 @@
 
     @Override
     public ArrayData ensure(final long safeIndex) {
-        if (safeIndex >= SparseArrayData.MAX_DENSE_LENGTH && safeIndex >= array.length) {
+        if (safeIndex >= SparseArrayData.MAX_DENSE_LENGTH) {
             return new SparseArrayData(this, safeIndex + 1);
         }
-
-        int newLength = array.length;
-
-        while (newLength <= safeIndex) {
-            newLength = ArrayData.nextSize(newLength);
-        }
-
-        if (array.length <= safeIndex) {
+        final int alen = array.length;
+        if (safeIndex >= alen) {
+            final int newLength = ArrayData.nextSize((int)safeIndex);
             array = Arrays.copyOf(array, newLength);
         }
-
         setLength(safeIndex + 1);
-
         return this;
     }
 
@@ -195,18 +188,12 @@
         return Type.LONG;
     }
 
-    private static final MethodHandle HAS_GET_ELEM = virtualCall(MethodHandles.lookup(), LongArrayData.class, UNSAFE == null ? "getElem" : "getElemUnsafe", long.class, int.class).methodHandle();
-    private static final MethodHandle SET_ELEM     = virtualCall(MethodHandles.lookup(), LongArrayData.class, UNSAFE == null ? "setElem" : "setElemUnsafe", void.class, int.class, long.class).methodHandle();
-    private static final MethodHandle HAS          = virtualCall(MethodHandles.lookup(), LongArrayData.class, "has", boolean.class, int.class).methodHandle();
+    private static final MethodHandle HAS_GET_ELEM = specialCall(MethodHandles.lookup(), LongArrayData.class, UNSAFE == null ? "getElem" : "getElemUnsafe", long.class, int.class).methodHandle();
+    private static final MethodHandle SET_ELEM     = specialCall(MethodHandles.lookup(), LongArrayData.class, UNSAFE == null ? "setElem" : "setElemUnsafe", void.class, int.class, long.class).methodHandle();
 
     private final static long UNSAFE_BASE  = UNSAFE == null ? 0L : UNSAFE.arrayBaseOffset(long[].class);
     private final static long UNSAFE_SCALE = UNSAFE == null ? 0L : UNSAFE.arrayIndexScale(long[].class);
 
-    @Override
-    public final MethodHandle getSetGuard() {
-        return HAS;
-    }
-
     @SuppressWarnings("unused")
     private long getElemUnsafe(final int index) {
         if (has(index)) {
@@ -225,12 +212,20 @@
 
     @SuppressWarnings("unused")
     private void setElemUnsafe(final int index, final long elem) {
-        UNSAFE.putLong(array, UNSAFE_BASE + UNSAFE_SCALE * index, elem);
+        if (hasRoomFor(index)) {
+            UNSAFE.putLong(array, UNSAFE_BASE + UNSAFE_SCALE * index, elem);
+            return;
+        }
+        throw new ClassCastException();
     }
 
     @SuppressWarnings("unused")
     private void setElem(final int index, final long elem) {
-        array[index] = elem;
+        if (hasRoomFor(index)) {
+            array[index] = elem;
+            return;
+        }
+        throw new ClassCastException();
     }
 
     @Override
@@ -243,7 +238,7 @@
 
     @Override
     public MethodHandle getElementSetter(final Class<?> elementType) {
-        return (elementType == int.class || elementType == long.class) ? getContinuousElementSetter(MH.asType(SET_ELEM, SET_ELEM.type().changeParameterType(2, elementType)), elementType) : null;
+        return elementType == int.class || elementType == long.class ? getContinuousElementSetter(MH.asType(SET_ELEM, SET_ELEM.type().changeParameterType(2, elementType)), elementType) : null;
     }
 
     @Override
@@ -307,19 +302,30 @@
 
     @Override
     public ArrayData slice(final long from, final long to) {
-        final long start     = from < 0 ? (from + length()) : from;
+        final long start     = from < 0 ? from + length() : from;
         final long newLength = to - start;
         return new LongArrayData(Arrays.copyOfRange(array, (int)from, (int)to), (int)newLength);
     }
 
     @Override
+    public final ArrayData push(final boolean strict, final long item) {
+        final long      length = length();
+        final ArrayData newData = ensure(length);
+        if (newData == this) {
+            array[(int)length] = item;
+            return this;
+        }
+        return newData.set((int)length, item, strict);
+    }
+
+    @Override
     public ArrayData fastSplice(final int start, final int removed, final int added) throws UnsupportedOperationException {
         final long oldLength = length();
         final long newLength = oldLength - removed + added;
         if (newLength > SparseArrayData.MAX_DENSE_LENGTH && newLength > array.length) {
             throw new UnsupportedOperationException();
         }
-        final ArrayData returnValue = (removed == 0) ?
+        final ArrayData returnValue = removed == 0 ?
                 EMPTY_ARRAY : new LongArrayData(Arrays.copyOfRange(array, start, start + removed), removed);
 
         if (newLength != oldLength) {
--- a/nashorn/src/jdk/nashorn/internal/runtime/arrays/NumberArrayData.java	Wed Feb 26 13:17:57 2014 +0100
+++ b/nashorn/src/jdk/nashorn/internal/runtime/arrays/NumberArrayData.java	Mon Mar 03 11:24:44 2014 +0100
@@ -26,7 +26,7 @@
 package jdk.nashorn.internal.runtime.arrays;
 
 import static jdk.nashorn.internal.runtime.ScriptRuntime.UNDEFINED;
-import static jdk.nashorn.internal.codegen.CompilerConstants.virtualCall;
+import static jdk.nashorn.internal.codegen.CompilerConstants.specialCall;
 import static jdk.nashorn.internal.lookup.Lookup.MH;
 
 import java.lang.invoke.MethodHandle;
@@ -39,7 +39,7 @@
  * Implementation of {@link ArrayData} as soon as a double has been
  * written to the array
  */
-final class NumberArrayData extends ArrayData implements ContinuousArray {
+final class NumberArrayData extends ContinuousArrayData {
     /**
      * The wrapped array
      */
@@ -111,24 +111,17 @@
 
     @Override
     public ArrayData ensure(final long safeIndex) {
-        if (safeIndex >= SparseArrayData.MAX_DENSE_LENGTH && safeIndex >= array.length) {
+        if (safeIndex >= SparseArrayData.MAX_DENSE_LENGTH) {
             return new SparseArrayData(this, safeIndex + 1);
         }
-
-        int newLength = array.length;
-
-        while (newLength <= safeIndex) {
-            newLength = ArrayData.nextSize(newLength);
+        final int alen = array.length;
+        if (safeIndex >= alen) {
+            final int newLength = ArrayData.nextSize((int)safeIndex);
+            array = Arrays.copyOf(array, newLength); //todo fill with nan or never accessed?
         }
+        setLength(safeIndex + 1);
+        return this;
 
-        if (array.length <= safeIndex) {
-            array = Arrays.copyOf(array, newLength);
-            Arrays.fill(array, (int) length(), newLength, Double.NaN);
-        }
-
-        setLength(safeIndex + 1);
-
-        return this;
     }
 
     @Override
@@ -175,18 +168,12 @@
         return Type.NUMBER;
     }
 
-    private static final MethodHandle HAS_GET_ELEM = virtualCall(MethodHandles.lookup(), NumberArrayData.class, UNSAFE == null ? "getElem" : "getElemUnsafe", double.class, int.class).methodHandle();
-    private static final MethodHandle SET_ELEM     = virtualCall(MethodHandles.lookup(), NumberArrayData.class, UNSAFE == null ? "setElem" : "setElemUnsafe", void.class, int.class, double.class).methodHandle();
-    private static final MethodHandle HAS          = virtualCall(MethodHandles.lookup(), NumberArrayData.class, "has", boolean.class, int.class).methodHandle();
+    private static final MethodHandle HAS_GET_ELEM = specialCall(MethodHandles.lookup(), NumberArrayData.class, UNSAFE == null ? "getElem" : "getElemUnsafe", double.class, int.class).methodHandle();
+    private static final MethodHandle SET_ELEM     = specialCall(MethodHandles.lookup(), NumberArrayData.class, UNSAFE == null ? "setElem" : "setElemUnsafe", void.class, int.class, double.class).methodHandle();
 
     private final static long UNSAFE_BASE  = UNSAFE == null ? 0L : UNSAFE.arrayBaseOffset(double[].class);
     private final static long UNSAFE_SCALE = UNSAFE == null ? 0L : UNSAFE.arrayIndexScale(double[].class);
 
-    @Override
-    public final MethodHandle getSetGuard() {
-        return HAS;
-    }
-
     @SuppressWarnings("unused")
     private double getElemUnsafe(final int index) {
         if (has(index)) {
@@ -205,12 +192,20 @@
 
     @SuppressWarnings("unused")
     private void setElemUnsafe(final int index, final double elem) {
-        UNSAFE.putDouble(array, UNSAFE_BASE + UNSAFE_SCALE * index, elem);
+        if (hasRoomFor(index)) {
+            UNSAFE.putDouble(array, UNSAFE_BASE + UNSAFE_SCALE * index, elem);
+            return;
+        }
+        throw new ClassCastException();
     }
 
     @SuppressWarnings("unused")
     private void setElem(final int index, final double elem) {
-        array[index] = elem;
+        if (hasRoomFor(index)) {
+            array[index] = elem;
+            return;
+        }
+        throw new ClassCastException();
     }
 
     @Override
@@ -281,19 +276,30 @@
 
     @Override
     public ArrayData slice(final long from, final long to) {
-        final long start     = from < 0 ? (from + length()) : from;
+        final long start     = from < 0 ? from + length() : from;
         final long newLength = to - start;
         return new NumberArrayData(Arrays.copyOfRange(array, (int)from, (int)to), (int)newLength);
     }
 
     @Override
+    public final ArrayData push(final boolean strict, final double item) {
+        final long      length = length();
+        final ArrayData newData = ensure(length);
+        if (newData == this) {
+            array[(int)length] = item;
+            return this;
+        }
+        return newData.set((int)length, item, strict);
+    }
+
+    @Override
     public ArrayData fastSplice(final int start, final int removed, final int added) throws UnsupportedOperationException {
         final long oldLength = length();
         final long newLength = oldLength - removed + added;
         if (newLength > SparseArrayData.MAX_DENSE_LENGTH && newLength > array.length) {
             throw new UnsupportedOperationException();
         }
-        final ArrayData returnValue = (removed == 0) ?
+        final ArrayData returnValue = removed == 0 ?
                 EMPTY_ARRAY : new NumberArrayData(Arrays.copyOfRange(array, start, start + removed), removed);
 
         if (newLength != oldLength) {
--- a/nashorn/src/jdk/nashorn/internal/runtime/arrays/ObjectArrayData.java	Wed Feb 26 13:17:57 2014 +0100
+++ b/nashorn/src/jdk/nashorn/internal/runtime/arrays/ObjectArrayData.java	Mon Mar 03 11:24:44 2014 +0100
@@ -25,7 +25,7 @@
 
 package jdk.nashorn.internal.runtime.arrays;
 
-import static jdk.nashorn.internal.codegen.CompilerConstants.virtualCall;
+import static jdk.nashorn.internal.codegen.CompilerConstants.specialCall;
 
 import java.lang.invoke.MethodHandle;
 import java.lang.invoke.MethodHandles;
@@ -39,7 +39,7 @@
  * Implementation of {@link ArrayData} as soon as an Object has been
  * written to the array
  */
-final class ObjectArrayData extends ArrayData implements ContinuousArray {
+final class ObjectArrayData extends ContinuousArrayData {
 
     /**
      * The wrapped array
@@ -98,23 +98,15 @@
 
     @Override
     public ArrayData ensure(final long safeIndex) {
-        if (safeIndex >= SparseArrayData.MAX_DENSE_LENGTH && safeIndex >= array.length) {
+        if (safeIndex >= SparseArrayData.MAX_DENSE_LENGTH) {
             return new SparseArrayData(this, safeIndex + 1);
         }
-
-        int newLength = array.length;
-
-        while (newLength <= safeIndex) {
-            newLength = ArrayData.nextSize(newLength);
+        final int alen = array.length;
+        if (safeIndex >= alen) {
+            final int newLength = ArrayData.nextSize((int)safeIndex);
+            array = Arrays.copyOf(array, newLength); //fill with undefined or OK? TODO
         }
-
-        if (array.length <= safeIndex) {
-            array = Arrays.copyOf(array, newLength);
-            Arrays.fill(array, (int) length(), newLength, ScriptRuntime.UNDEFINED);
-        }
-
         setLength(safeIndex + 1);
-
         return this;
     }
 
@@ -169,18 +161,12 @@
         return Type.OBJECT;
     }
 
-    private static final MethodHandle HAS_GET_ELEM = virtualCall(MethodHandles.lookup(), ObjectArrayData.class, UNSAFE == null ? "getElem" : "getElemUnsafe", Object.class, int.class).methodHandle();
-    private static final MethodHandle SET_ELEM     = virtualCall(MethodHandles.lookup(), ObjectArrayData.class, UNSAFE == null ? "setElem" : "setElemUnsafe", void.class, int.class, Object.class).methodHandle();
-    private static final MethodHandle HAS          = virtualCall(MethodHandles.lookup(), ObjectArrayData.class, "has", boolean.class, int.class).methodHandle();
+    private static final MethodHandle HAS_GET_ELEM = specialCall(MethodHandles.lookup(), ObjectArrayData.class, UNSAFE == null ? "getElem" : "getElemUnsafe", Object.class, int.class).methodHandle();
+    private static final MethodHandle SET_ELEM     = specialCall(MethodHandles.lookup(), ObjectArrayData.class, UNSAFE == null ? "setElem" : "setElemUnsafe", void.class, int.class, Object.class).methodHandle();
 
     private final static long UNSAFE_BASE  = UNSAFE == null ? 0L : UNSAFE.arrayBaseOffset(Object[].class);
     private final static long UNSAFE_SCALE = UNSAFE == null ? 0L : UNSAFE.arrayIndexScale(Object[].class);
 
-    @Override
-    public final MethodHandle getSetGuard() {
-        return HAS;
-    }
-
     @SuppressWarnings("unused")
     private Object getElemUnsafe(final int index) {
         if (has(index)) {
@@ -199,12 +185,20 @@
 
     @SuppressWarnings("unused")
     private void setElemUnsafe(final int index, final Object elem) {
-        UNSAFE.putObject(array, UNSAFE_BASE + UNSAFE_SCALE * index, elem);
+        if (hasRoomFor(index)) {
+            UNSAFE.putObject(array, UNSAFE_BASE + UNSAFE_SCALE * index, elem);
+            return;
+        }
+        throw new ClassCastException();
     }
 
     @SuppressWarnings("unused")
     private void setElem(final int index, final Object elem) {
-        array[index] = elem;
+        if (hasRoomFor(index)) {
+            array[index] = elem;
+            return;
+        }
+        throw new ClassCastException();
     }
 
     @Override
@@ -273,19 +267,30 @@
 
     @Override
     public ArrayData slice(final long from, final long to) {
-        final long start     = from < 0 ? (from + length()) : from;
+        final long start     = from < 0 ? from + length() : from;
         final long newLength = to - start;
         return new ObjectArrayData(Arrays.copyOfRange(array, (int)from, (int)to), (int)newLength);
     }
 
     @Override
+    public ArrayData push(final boolean strict, final Object item) {
+        final long      length = length();
+        final ArrayData newData = ensure(length);
+        if (newData == this) {
+            array[(int)length] = item;
+            return this;
+        }
+        return newData.set((int)length, item, strict);
+    }
+
+    @Override
     public ArrayData fastSplice(final int start, final int removed, final int added) throws UnsupportedOperationException {
         final long oldLength = length();
         final long newLength = oldLength - removed + added;
         if (newLength > SparseArrayData.MAX_DENSE_LENGTH && newLength > array.length) {
             throw new UnsupportedOperationException();
         }
-        final ArrayData returnValue = (removed == 0) ?
+        final ArrayData returnValue = removed == 0 ?
                 EMPTY_ARRAY : new ObjectArrayData(Arrays.copyOfRange(array, start, start + removed), removed);
 
         if (newLength != oldLength) {
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/src/jdk/nashorn/internal/runtime/arrays/TypedArrayData.java	Mon Mar 03 11:24:44 2014 +0100
@@ -0,0 +1,215 @@
+/*
+ * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.nashorn.internal.runtime.arrays;
+
+import static jdk.nashorn.internal.lookup.Lookup.MH;
+
+import java.lang.invoke.MethodHandle;
+import java.nio.Buffer;
+
+import jdk.internal.dynalink.CallSiteDescriptor;
+import jdk.internal.dynalink.DynamicLinker;
+import jdk.internal.dynalink.linker.GuardedInvocation;
+import jdk.internal.dynalink.linker.LinkRequest;
+import jdk.nashorn.internal.lookup.Lookup;
+
+/**
+ * The superclass of all ArrayData used by TypedArrays
+ *
+ * @param <T> buffer implementation
+ */
+public abstract class TypedArrayData<T extends Buffer> extends ContinuousArrayData {
+
+    /** wrapped native buffer */
+    protected final T nb;
+
+    /**
+     * Constructor
+     * @param nb wrapped native buffer
+     * @param elementLength length in elements
+     */
+    protected TypedArrayData(final T nb, final int elementLength) {
+        super(elementLength); //TODO is this right?
+        this.nb = nb;
+    }
+
+    /**
+     * Length in elements. Accessed from {@code ArrayBufferView}
+     * @return element length
+     */
+    public final int getElementLength() {
+        return (int)length();
+    }
+
+    /**
+     * Is this an unsigned array data?
+     * @return true if unsigned
+     */
+    public boolean isUnsigned() {
+        return false;
+    }
+
+    /**
+     * Is this a clamped array data?
+     * @return true if clamped
+     */
+    public boolean isClamped() {
+        return false;
+    }
+
+    @Override
+    public boolean canDelete(final int index, final boolean strict) {
+        return false;
+    }
+
+    @Override
+    public boolean canDelete(final long fromIndex, final long toIndex, final boolean strict) {
+        return false;
+    }
+
+    @Override
+    public ArrayData copy() {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public Object[] asObjectArray() {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public void shiftLeft(int by) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public ArrayData shiftRight(int by) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public ArrayData ensure(long safeIndex) {
+        return this;
+    }
+
+    @Override
+    public ArrayData shrink(long newLength) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public final boolean has(final int index) {
+        return 0 <= index && index < length();
+    }
+
+    @Override
+    public ArrayData delete(int index) {
+        return this;
+    }
+
+    @Override
+    public ArrayData delete(long fromIndex, long toIndex) {
+        return this;
+    }
+
+    @Override
+    protected ArrayData convert(Class<?> type) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public Object pop() {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public ArrayData slice(long from, long to) {
+        throw new UnsupportedOperationException();
+    }
+
+    /**
+     * Element getter method handle
+     * @return getter
+     */
+    protected abstract MethodHandle getGetElem();
+
+    /**
+     * Element setter method handle
+     * @return setter
+     */
+    protected abstract MethodHandle getSetElem();
+
+    @Override
+    public MethodHandle getElementGetter(final Class<?> returnType, final int programPoint) {
+        final MethodHandle getter = getContinuousElementGetter(getClass(), getGetElem(), returnType, programPoint);
+        if (getter != null) {
+            return Lookup.filterReturnType(getter, returnType);
+        }
+        return getter;
+    }
+
+    @Override
+    public MethodHandle getElementSetter(final Class<?> elementType) {
+        return getContinuousElementSetter(getClass(), Lookup.filterArgumentType(getSetElem(), 2, elementType), elementType);
+    }
+
+    @Override
+    protected MethodHandle getContinuousElementSetter(final Class<? extends ContinuousArrayData> clazz, final MethodHandle setHas, final Class<?> elementType) {
+        final MethodHandle mh = Lookup.filterArgumentType(setHas, 2, elementType);
+        return MH.asType(mh, mh.type().changeParameterType(0, clazz));
+    }
+
+    @Override
+    public GuardedInvocation findFastGetIndexMethod(final Class<? extends ArrayData> clazz, final CallSiteDescriptor desc, final LinkRequest request) {
+        final GuardedInvocation inv = super.findFastGetIndexMethod(clazz, desc, request);
+
+        if (inv != null) {
+            return inv;
+        }
+
+        if (LOG.isEnabled()) {
+            LOG.info(clazz.getSimpleName() + ": Missed fast GETTER " + clazz.getSimpleName() + " " + desc + " " + " line:" + DynamicLinker.getLinkedCallSiteLocation().getLineNumber());
+        }
+
+        return null;
+    }
+
+    @Override
+    public GuardedInvocation findFastSetIndexMethod(final Class<? extends ArrayData> clazz, final CallSiteDescriptor desc, final LinkRequest request) { // array, index, value
+        final GuardedInvocation inv = super.findFastSetIndexMethod(clazz, desc, request);
+
+        if (inv != null) {
+            return inv;
+        }
+
+        if (LOG.isEnabled()) {
+            LOG.info(clazz.getSimpleName() + ": Missed fast SETTER " + clazz.getSimpleName() + " " + desc + " " + " line:" + DynamicLinker.getLinkedCallSiteLocation().getLineNumber());
+        }
+
+        return null;
+    }
+
+}
--- a/nashorn/src/jdk/nashorn/internal/runtime/linker/JavaAdapterFactory.java	Wed Feb 26 13:17:57 2014 +0100
+++ b/nashorn/src/jdk/nashorn/internal/runtime/linker/JavaAdapterFactory.java	Mon Mar 03 11:24:44 2014 +0100
@@ -164,7 +164,7 @@
         final StaticClass adapterClass = getAdapterClassFor(new Class<?>[] { targetType }, null, lookup);
         return MH.bindTo(Bootstrap.getLinkerServices().getGuardedInvocation(new LinkRequestImpl(
                 NashornCallSiteDescriptor.get(lookup, "dyn:new",
-                        MethodType.methodType(targetType, StaticClass.class, sourceType), 0), null, false,
+                        MethodType.methodType(targetType, StaticClass.class, sourceType), 0), null, 0, false,
                         adapterClass, null)).getInvocation(), adapterClass);
     }
 
--- a/nashorn/src/jdk/nashorn/internal/runtime/linker/LinkerCallSite.java	Wed Feb 26 13:17:57 2014 +0100
+++ b/nashorn/src/jdk/nashorn/internal/runtime/linker/LinkerCallSite.java	Mon Mar 03 11:24:44 2014 +0100
@@ -43,6 +43,7 @@
 import java.util.Random;
 import java.util.Set;
 import java.util.concurrent.atomic.AtomicInteger;
+
 import jdk.internal.dynalink.ChainedCallSite;
 import jdk.internal.dynalink.DynamicLinker;
 import jdk.internal.dynalink.linker.GuardedInvocation;
@@ -63,6 +64,9 @@
     private static final String PROFILEFILE = Options.getStringProperty("nashorn.profilefile", "NashornProfile.txt");
 
     private static final MethodHandle INCREASE_MISS_COUNTER = MH.findStatic(MethodHandles.lookup(), LinkerCallSite.class, "increaseMissCount", MH.type(Object.class, String.class, Object.class));
+    private static final MethodHandle ON_CATCH_INVALIDATION = MH.findStatic(MethodHandles.lookup(), LinkerCallSite.class, "onCatchInvalidation", MH.type(ChainedCallSite.class, LinkerCallSite.class));
+
+    private int catchInvalidations;
 
     LinkerCallSite(final NashornCallSiteDescriptor descriptor) {
         super(descriptor);
@@ -71,6 +75,34 @@
         }
     }
 
+    @Override
+    protected MethodHandle getPruneCatches() {
+        return MH.filterArguments(super.getPruneCatches(), 0, ON_CATCH_INVALIDATION);
+    }
+
+    /**
+     * Action to perform when a catch guard around a callsite triggers. Increases
+     * catch invalidation counter
+     * @param callSite callsite
+     * @return the callsite, so this can be used as argument filter
+     */
+    @SuppressWarnings("unused")
+    private static ChainedCallSite onCatchInvalidation(final LinkerCallSite callSite) {
+        ++callSite.catchInvalidations;
+        return callSite;
+    }
+
+    /**
+     * Get the number of catch invalidations that have happened at this call site so far
+     * @param callSiteToken call site token, unique to the callsite.
+     * @return number of catch invalidations, i.e. thrown exceptions caught by the linker
+     */
+    public static int getCatchInvalidationCount(final Object callSiteToken) {
+        if (callSiteToken instanceof LinkerCallSite) {
+            return ((LinkerCallSite)callSiteToken).catchInvalidations;
+        }
+        return 0;
+    }
     /**
      * Construct a new linker call site.
      * @param name     Name of method.
@@ -78,8 +110,7 @@
      * @param flags    Call site specific flags.
      * @return New LinkerCallSite.
      */
-    static LinkerCallSite newLinkerCallSite(final MethodHandles.Lookup lookup, final String name, final MethodType type,
-            final int flags) {
+    static LinkerCallSite newLinkerCallSite(final MethodHandles.Lookup lookup, final String name, final MethodType type, final int flags) {
         final NashornCallSiteDescriptor desc = NashornCallSiteDescriptor.get(lookup, name, type, flags);
 
         if (desc.isProfile()) {
--- a/nashorn/src/jdk/nashorn/internal/runtime/linker/NashornGuards.java	Wed Feb 26 13:17:57 2014 +0100
+++ b/nashorn/src/jdk/nashorn/internal/runtime/linker/NashornGuards.java	Mon Mar 03 11:24:44 2014 +0100
@@ -30,30 +30,73 @@
 import java.lang.invoke.MethodHandle;
 import java.lang.invoke.MethodHandles;
 
+import jdk.internal.dynalink.CallSiteDescriptor;
+import jdk.internal.dynalink.linker.LinkRequest;
 import jdk.nashorn.internal.runtime.PropertyMap;
+import jdk.nashorn.internal.runtime.ScriptFunction;
 import jdk.nashorn.internal.runtime.ScriptObject;
+import jdk.nashorn.internal.runtime.options.Options;
 
 /**
  * Constructor of method handles used to guard call sites.
  */
 public final class NashornGuards {
-    private static final MethodHandle IS_MAP          = findOwnMH("isMap", boolean.class, ScriptObject.class, PropertyMap.class);
-    private static final MethodHandle IS_INSTANCEOF_2 = findOwnMH("isInstanceOf2", boolean.class, Object.class, Class.class, Class.class);
+    private static final MethodHandle IS_MAP              = findOwnMH("isMap", boolean.class, ScriptObject.class, PropertyMap.class);
+    private static final MethodHandle IS_MAP_SCRIPTOBJECT = findOwnMH("isMap", boolean.class, Object.class, PropertyMap.class);
+    private static final MethodHandle IS_INSTANCEOF_2     = findOwnMH("isInstanceOf2", boolean.class, Object.class, Class.class, Class.class);
+    private static final MethodHandle IS_SCRIPTOBJECT     = findOwnMH("isScriptObject", boolean.class, Object.class);
+
+    private static final boolean CCE_ONLY = Options.getBooleanProperty("nashorn.cce");
 
     // don't create me!
     private NashornGuards() {
     }
 
     /**
+     * Given a callsite descriptor and a link request, determine whether we should use an instanceof
+     * check explicitly for the guard if needed, or if we should link it with a try/catch ClassCastException
+     * combinator as its relink criteria - i.e. relink when CCE is thrown.
+     *
+     * @param desc     callsite descriptor
+     * @param request  link request
+     * @return true of explicit instanceof check is needed
+     */
+    public static boolean explicitInstanceOfCheck(final CallSiteDescriptor desc, final LinkRequest request) {
+        //THIS is currently true, as the inliner encounters several problems with sun.misc.ValueConversions.castReference
+        //otherwise. We should only use the exception based relink where we have no choice, and the result is faster code,
+        //for example in the NativeArray, TypedArray, ContinuousArray getters. For the standard callsite, it appears that
+        //we lose performance rather than gain it, due to JVM issues. :-(
+        return !CCE_ONLY;
+    }
+
+    /**
+     * Returns a guard that does an instanceof ScriptObject check on the receiver
+     * @return guard
+     */
+    public static MethodHandle getScriptObjectGuard() {
+        return IS_SCRIPTOBJECT;
+    }
+
+    /**
+     * Returns a guard that does an instanceof ScriptObject check on the receiver
+     * @param explicitInstanceOfCheck - if false, then this is a nop, because it's all the guard does
+     * @return guard
+     */
+    public static MethodHandle getScriptObjectGuard(final boolean explicitInstanceOfCheck) {
+        return explicitInstanceOfCheck ? IS_SCRIPTOBJECT : null;
+    }
+
+    /**
      * Get the guard that checks if a {@link PropertyMap} is equal to
      * a known map, using reference comparison
      *
+     * @param explicitInstanceOfCheck true if we should do an explicit script object instanceof check instead of just casting
      * @param map The map to check against. This will be bound to the guard method handle
      *
      * @return method handle for guard
      */
-    public static MethodHandle getMapGuard(final PropertyMap map) {
-        return MH.insertArguments(IS_MAP, 1, map);
+    public static MethodHandle getMapGuard(final PropertyMap map, final boolean explicitInstanceOfCheck) {
+        return MH.insertArguments(explicitInstanceOfCheck ? IS_MAP_SCRIPTOBJECT : IS_MAP, 1, map);
     }
 
     /**
@@ -68,17 +111,37 @@
     }
 
     @SuppressWarnings("unused")
+    private static boolean isScriptObject(final Object self) {
+        return self instanceof ScriptObject;
+    }
+
+    @SuppressWarnings("unused")
+    private static boolean isScriptObject(final Class<? extends ScriptObject> clazz, final Object self) {
+        return clazz.isInstance(self);
+    }
+
+    @SuppressWarnings("unused")
     private static boolean isMap(final ScriptObject self, final PropertyMap map) {
         return self.getMap() == map;
     }
 
     @SuppressWarnings("unused")
+    private static boolean isMap(final Object self, final PropertyMap map) {
+        return self instanceof ScriptObject && ((ScriptObject)self).getMap() == map;
+    }
+
+
+    @SuppressWarnings("unused")
     private static boolean isInstanceOf2(final Object self, final Class<?> class1, final Class<?> class2) {
         return class1.isInstance(self) || class2.isInstance(self);
     }
 
+    @SuppressWarnings("unused")
+    private static boolean isScriptFunction(final Object self) {
+        return self instanceof ScriptFunction;
+    }
+
     private static MethodHandle findOwnMH(final String name, final Class<?> rtype, final Class<?>... types) {
         return MH.findStatic(MethodHandles.lookup(), NashornGuards.class, name, MH.type(rtype, types));
     }
-
 }
--- a/nashorn/src/jdk/nashorn/internal/runtime/linker/NashornLinker.java	Wed Feb 26 13:17:57 2014 +0100
+++ b/nashorn/src/jdk/nashorn/internal/runtime/linker/NashornLinker.java	Mon Mar 03 11:24:44 2014 +0100
@@ -101,7 +101,7 @@
         } else if (self instanceof Undefined) {
             inv = Undefined.lookup(desc);
         } else {
-            throw new AssertionError(); // Should never reach here.
+            throw new AssertionError(self.getClass().getName()); // Should never reach here.
         }
 
         return inv;
--- a/nashorn/src/jdk/nashorn/internal/runtime/resources/Messages.properties	Wed Feb 26 13:17:57 2014 +0100
+++ b/nashorn/src/jdk/nashorn/internal/runtime/resources/Messages.properties	Mon Mar 03 11:24:44 2014 +0100
@@ -138,6 +138,8 @@
 type.error.method.not.constructor=Java method {0} can't be used as a constructor.
 type.error.env.not.object=$ENV must be an Object.
 type.error.unsupported.java.to.type=Unsupported Java.to target type {0}.
+type.error.constructor.requires.new=Constructor {0} requires 'new'.
+
 range.error.inappropriate.array.length=inappropriate array length: {0}
 range.error.inappropriate.array.buffer.length=inappropriate array buffer length: {0}
 range.error.invalid.fraction.digits=fractionDigits argument to {0} must be in [0, 20]
--- a/nashorn/test/examples/string-micro.js	Wed Feb 26 13:17:57 2014 +0100
+++ b/nashorn/test/examples/string-micro.js	Mon Mar 03 11:24:44 2014 +0100
@@ -46,12 +46,18 @@
     str[2];
 });
 
-bench("fromCharCode", function() {
+bench("fromCharCode 1", function() {
     String.fromCharCode(97);
     String.fromCharCode(98);
     String.fromCharCode(99);
 });
 
+bench("fromCharCode 2", function() {
+    String.fromCharCode(97, 98);
+    String.fromCharCode(97, 98, 99);
+    String.fromCharCode(97, 98, 99, 100);
+});
+
 bench("charAt 1", function() {
     str.charAt(0);
     str.charAt(1);
--- a/nashorn/test/script/basic/JDK-8020357.js	Wed Feb 26 13:17:57 2014 +0100
+++ b/nashorn/test/script/basic/JDK-8020357.js	Mon Mar 03 11:24:44 2014 +0100
@@ -35,7 +35,7 @@
 
 // A value over the limit should throw a RangeError.
 try {
-    Int32Array(limit)
+    new Int32Array(limit)
 } catch(e) {
     print(e)
 }
--- a/nashorn/test/script/basic/NASHORN-377.js	Wed Feb 26 13:17:57 2014 +0100
+++ b/nashorn/test/script/basic/NASHORN-377.js	Mon Mar 03 11:24:44 2014 +0100
@@ -194,7 +194,7 @@
 })();
 
 (function test_slice() {
-  var b = ArrayBuffer(16);
+  var b = new ArrayBuffer(16);
   fillArray(new Int8Array(b));
   print(bufstr(b));
   print("slice(4,8)=" + bufstr(b.slice(4, 8)), "slice(-8,-4)=" + bufstr(b.slice(-8, -4))); // negative index refers from the end of the array
--- a/nashorn/test/script/basic/typedarrays.js	Wed Feb 26 13:17:57 2014 +0100
+++ b/nashorn/test/script/basic/typedarrays.js	Mon Mar 03 11:24:44 2014 +0100
@@ -83,7 +83,7 @@
     var arr = Object.getOwnPropertyNames(instance);
     arr.forEach(function(p) {
         var val = instance[p];
-        if(!isNaN(p)){
+        if(!isNaN(p)) {
             val[p] = 99;
         }       
     });