changeset 1073:06c06c8443fd

8061391: concat as a builtin optimistic form, had to remove NoTypedArrayData and replace it, as we throw away a lot of optimistic link opportunities with NoTypedArrayData not being Continuous Reviewed-by: attila, hannesw
author lagergren
date Thu, 23 Oct 2014 15:19:00 +0400
parents 4dfa462ee93f
children 41b5976633aa
files bin/runopt.sh src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/types/Type.java src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeArray.java src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeFloat32Array.java src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeFloat64Array.java src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeInt16Array.java src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeInt32Array.java src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeInt8Array.java src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeObject.java src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeUint16Array.java src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeUint32Array.java src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeUint8Array.java src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeUint8ClampedArray.java src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/parser/JSONParser.java src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/JSType.java src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/ScriptObject.java src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/arrays/AnyElements.java src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/arrays/ArrayData.java src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/arrays/ContinuousArrayData.java src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/arrays/IntArrayData.java src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/arrays/LongArrayData.java src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/arrays/NoTypeArrayData.java src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/arrays/NonExtensibleArrayFilter.java src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/arrays/NumberArrayData.java src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/arrays/NumericElements.java src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/arrays/ObjectArrayData.java src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/arrays/TypedArrayData.java test/script/basic/JDK-8061391.js test/script/basic/JDK-8061391.js.EXPECTED test/script/basic/JDK-8061391_2.js test/script/basic/JDK-8061391_3.js test/script/basic/JDK-8061391_3.js.EXPECTED
diffstat 32 files changed, 1194 insertions(+), 335 deletions(-) [+]
line wrap: on
line diff
--- a/bin/runopt.sh	Tue Oct 21 14:27:49 2014 +0200
+++ b/bin/runopt.sh	Thu Oct 23 15:19:00 2014 +0400
@@ -69,7 +69,6 @@
 
 if [ -z $JFR_FILENAME ]; then
     JFR_FILENAME="./nashorn_$(date|sed "s/ /_/g"|sed "s/:/_/g").jfr"
-    echo "Using default JFR filename: ${JFR_FILENAME}..."
 fi
 
 # Flight recorder
--- a/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/types/Type.java	Tue Oct 21 14:27:49 2014 +0200
+++ b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/types/Type.java	Thu Oct 23 15:19:00 2014 +0400
@@ -586,6 +586,7 @@
     public int getSlots() {
         return slots;
     }
+
     /**
      * Returns the widest or most common of two types
      *
@@ -609,6 +610,18 @@
     }
 
     /**
+     * Returns the widest or most common of two types, given as classes
+     *
+     * @param type0 type one
+     * @param type1 type two
+     *
+     * @return the widest type
+     */
+    public static Class<?> widest(final Class<?> type0, final Class<?> type1) {
+        return widest(Type.typeFor(type0), Type.typeFor(type1)).getTypeClass();
+    }
+
+    /**
      * When doing widening for return types of a function or a ternary operator, it is not valid to widen a boolean to
      * anything other than object. Note that this wouldn't be necessary if {@code Type.widest} did not allow
      * boolean-to-number widening. Eventually, we should address it there, but it affects too many other parts of the
--- a/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeArray.java	Tue Oct 21 14:27:49 2014 +0200
+++ b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeArray.java	Thu Oct 23 15:19:00 2014 +0400
@@ -92,9 +92,10 @@
     private static final Object CALL_CMP                 = new Object();
     private static final Object TO_LOCALE_STRING         = new Object();
 
-    private SwitchPoint   lengthMadeNotWritableSwitchPoint;
-    private PushLinkLogic pushLinkLogic;
-    private PopLinkLogic  popLinkLogic;
+    private SwitchPoint     lengthMadeNotWritableSwitchPoint;
+    private PushLinkLogic   pushLinkLogic;
+    private PopLinkLogic    popLinkLogic;
+    private ConcatLinkLogic concatLinkLogic;
 
     /**
      * Index for the modification SwitchPoint that triggers when length
@@ -130,7 +131,9 @@
         this(ArrayData.allocate(array.length));
 
         ArrayData arrayData = this.getArray();
-        arrayData.ensure(array.length - 1);
+        if (array.length > 0) {
+            arrayData.ensure(array.length - 1);
+        }
 
         for (int index = 0; index < array.length; index++) {
             final Object value = array[index];
@@ -757,12 +760,86 @@
      * ECMA 15.4.4.4 Array.prototype.concat ( [ item1 [ , item2 [ , ... ] ] ] )
      *
      * @param self self reference
+     * @param arg argument
+     * @return resulting NativeArray
+     */
+    @SpecializedFunction(linkLogic=ConcatLinkLogic.class)
+    public static NativeArray concat(final Object self, final int arg) {
+        final ContinuousArrayData newData = getContinuousArrayDataCCE(self, Integer.class).copy(); //get at least an integer data copy of this data
+        newData.fastPush(arg); //add an integer to its end
+        return new NativeArray(newData);
+    }
+
+    /**
+     * ECMA 15.4.4.4 Array.prototype.concat ( [ item1 [ , item2 [ , ... ] ] ] )
+     *
+     * @param self self reference
+     * @param arg argument
+     * @return resulting NativeArray
+     */
+    @SpecializedFunction(linkLogic=ConcatLinkLogic.class)
+    public static NativeArray concat(final Object self, final long arg) {
+        final ContinuousArrayData newData = getContinuousArrayDataCCE(self, Long.class).copy(); //get at least a long array data copy of this data
+        newData.fastPush(arg); //add a long at the end
+        return new NativeArray(newData);
+    }
+
+    /**
+     * ECMA 15.4.4.4 Array.prototype.concat ( [ item1 [ , item2 [ , ... ] ] ] )
+     *
+     * @param self self reference
+     * @param arg argument
+     * @return resulting NativeArray
+     */
+    @SpecializedFunction(linkLogic=ConcatLinkLogic.class)
+    public static NativeArray concat(final Object self, final double arg) {
+        final ContinuousArrayData newData = getContinuousArrayDataCCE(self, Double.class).copy(); //get at least a number array data copy of this data
+        newData.fastPush(arg); //add a double at the end
+        return new NativeArray(newData);
+    }
+
+    /**
+     * ECMA 15.4.4.4 Array.prototype.concat ( [ item1 [ , item2 [ , ... ] ] ] )
+     *
+     * @param self self reference
+     * @param arg argument
+     * @return resulting NativeArray
+     */
+    @SpecializedFunction(linkLogic=ConcatLinkLogic.class)
+    public static NativeArray concat(final Object self, final Object arg) {
+        //arg is [NativeArray] of same type.
+        final ContinuousArrayData selfData = getContinuousArrayDataCCE(self);
+        final ContinuousArrayData newData;
+
+        if (arg instanceof NativeArray) {
+            final ContinuousArrayData argData = (ContinuousArrayData)((NativeArray)arg).getArray();
+            if (argData.isEmpty()) {
+                newData = selfData.copy();
+            } else if (selfData.isEmpty()) {
+                newData = argData.copy();
+            } else {
+                final Class<?> widestElementType = selfData.widest(argData).getBoxedElementType();
+                newData = ((ContinuousArrayData)selfData.convert(widestElementType)).fastConcat((ContinuousArrayData)argData.convert(widestElementType));
+            }
+        } else {
+            newData = getContinuousArrayDataCCE(self, Object.class).copy();
+            newData.fastPush(arg);
+        }
+
+        return new NativeArray(newData);
+    }
+
+    /**
+     * ECMA 15.4.4.4 Array.prototype.concat ( [ item1 [ , item2 [ , ... ] ] ] )
+     *
+     * @param self self reference
      * @param args arguments
      * @return resulting NativeArray
      */
     @Function(attributes = Attribute.NOT_ENUMERABLE, arity = 1)
     public static NativeArray concat(final Object self, final Object... args) {
         final ArrayList<Object> list = new ArrayList<>();
+
         concatToList(list, Global.toObject(self));
 
         for (final Object obj : args) {
@@ -1692,13 +1769,15 @@
             return pushLinkLogic == null ? new PushLinkLogic(this) : pushLinkLogic;
         } else if (clazz == PopLinkLogic.class) {
             return popLinkLogic == null ? new PopLinkLogic(this) : pushLinkLogic;
+        } else if (clazz == ConcatLinkLogic.class) {
+            return concatLinkLogic == null ? new ConcatLinkLogic(this) : concatLinkLogic;
         }
         return null;
     }
 
     @Override
     public boolean hasPerInstanceAssumptions() {
-        return true; //length switchpoint
+        return true; //length writable switchpoint
     }
 
     /**
@@ -1798,6 +1877,40 @@
     }
 
     /**
+     * This is linker logic for optimistic concatenations
+     */
+    private static final class ConcatLinkLogic extends ArrayLinkLogic {
+        private ConcatLinkLogic(final NativeArray array) {
+            super(array);
+        }
+
+        @Override
+        public boolean canLink(final Object self, final CallSiteDescriptor desc, final LinkRequest request) {
+            final Object[] args = request.getArguments();
+
+            if (args.length != 3) { //single argument check
+                return false;
+            }
+
+            final ContinuousArrayData selfData = getContinuousArrayData(self);
+            if (selfData == null) {
+                return false;
+            }
+
+            final Object arg = args[2];
+            //args[2] continuousarray or non arraydata, let past non array datas
+            if (arg instanceof NativeArray) {
+                final ContinuousArrayData argData = getContinuousArrayData(arg);
+                if (argData == null) {
+                    return false;
+                }
+            }
+
+            return true;
+        }
+    }
+
+    /**
      * This is linker logic for optimistic pushes
      */
     private static final class PushLinkLogic extends ArrayLinkLogic {
@@ -1864,6 +1977,14 @@
         throw new ClassCastException();
     }
 
+    private static final ContinuousArrayData getContinuousArrayDataCCE(final Object self) {
+        try {
+            return (ContinuousArrayData)((NativeArray)self).getArray();
+         } catch (final NullPointerException e) {
+             throw new ClassCastException();
+         }
+    }
+
     private static final ContinuousArrayData getContinuousArrayDataCCE(final Object self, final Class<?> elementType) {
         try {
            return (ContinuousArrayData)((NativeArray)self).getArray(elementType); //ensure element type can fit "elementType"
--- a/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeFloat32Array.java	Tue Oct 21 14:27:49 2014 +0200
+++ b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeFloat32Array.java	Thu Oct 23 15:19:00 2014 +0400
@@ -90,6 +90,11 @@
         }
 
         @Override
+        public Class<?> getBoxedElementType() {
+            return Double.class;
+        }
+
+        @Override
         protected MethodHandle getGetElem() {
             return GET_ELEM;
         }
--- a/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeFloat64Array.java	Tue Oct 21 14:27:49 2014 +0200
+++ b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeFloat64Array.java	Thu Oct 23 15:19:00 2014 +0400
@@ -99,6 +99,11 @@
             return double.class;
         }
 
+        @Override
+        public Class<?> getBoxedElementType() {
+            return Double.class;
+        }
+
         private double getElem(final int index) {
             try {
                 return nb.get(index);
--- a/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeInt16Array.java	Tue Oct 21 14:27:49 2014 +0200
+++ b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeInt16Array.java	Thu Oct 23 15:19:00 2014 +0400
@@ -100,6 +100,11 @@
             return int.class;
         }
 
+        @Override
+        public Class<?> getBoxedElementType() {
+            return Integer.class;
+        }
+
         private int getElem(final int index) {
             try {
                 return nb.get(index);
--- a/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeInt32Array.java	Tue Oct 21 14:27:49 2014 +0200
+++ b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeInt32Array.java	Thu Oct 23 15:19:00 2014 +0400
@@ -118,6 +118,11 @@
         }
 
         @Override
+        public Class<?> getBoxedElementType() {
+            return Integer.class;
+        }
+
+        @Override
         public int getInt(final int index) {
             return getElem(index);
         }
--- a/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeInt8Array.java	Tue Oct 21 14:27:49 2014 +0200
+++ b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeInt8Array.java	Thu Oct 23 15:19:00 2014 +0400
@@ -98,6 +98,11 @@
             return int.class;
         }
 
+        @Override
+        public Class<?> getBoxedElementType() {
+            return Integer.class;
+        }
+
         private int getElem(final int index) {
             try {
                 return nb.get(index);
--- a/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeObject.java	Tue Oct 21 14:27:49 2014 +0200
+++ b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeObject.java	Thu Oct 23 15:19:00 2014 +0400
@@ -28,7 +28,6 @@
 import static jdk.nashorn.internal.lookup.Lookup.MH;
 import static jdk.nashorn.internal.runtime.ECMAErrors.typeError;
 import static jdk.nashorn.internal.runtime.ScriptRuntime.UNDEFINED;
-
 import java.lang.invoke.MethodHandle;
 import java.lang.invoke.MethodHandles;
 import java.lang.invoke.MethodType;
--- a/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeUint16Array.java	Tue Oct 21 14:27:49 2014 +0200
+++ b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeUint16Array.java	Thu Oct 23 15:19:00 2014 +0400
@@ -124,6 +124,11 @@
         }
 
         @Override
+        public Class<?> getBoxedElementType() {
+            return Integer.class;
+        }
+
+        @Override
         public int getInt(final int index) {
             return getElem(index);
         }
--- a/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeUint32Array.java	Tue Oct 21 14:27:49 2014 +0200
+++ b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeUint32Array.java	Thu Oct 23 15:19:00 2014 +0400
@@ -133,6 +133,11 @@
         }
 
         @Override
+        public Class<?> getBoxedElementType() {
+            return Integer.class;
+        }
+
+        @Override
         public int getInt(final int index) {
             return (int)getLong(index);
         }
--- a/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeUint8Array.java	Tue Oct 21 14:27:49 2014 +0200
+++ b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeUint8Array.java	Thu Oct 23 15:19:00 2014 +0400
@@ -124,6 +124,11 @@
         }
 
         @Override
+        public Class<?> getBoxedElementType() {
+            return Integer.class;
+        }
+
+        @Override
         public int getInt(final int index) {
             return getElem(index);
         }
--- a/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeUint8ClampedArray.java	Tue Oct 21 14:27:49 2014 +0200
+++ b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeUint8ClampedArray.java	Thu Oct 23 15:19:00 2014 +0400
@@ -103,6 +103,11 @@
             return int.class;
         }
 
+        @Override
+        public Class<?> getBoxedElementType() {
+            return int.class;
+        }
+
         private int getElem(final int index) {
             try {
                 return nb.get(index) & 0xff;
--- a/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/parser/JSONParser.java	Tue Oct 21 14:27:49 2014 +0200
+++ b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/parser/JSONParser.java	Thu Oct 23 15:19:00 2014 +0400
@@ -32,7 +32,6 @@
 import static jdk.nashorn.internal.parser.TokenType.RBRACE;
 import static jdk.nashorn.internal.parser.TokenType.RBRACKET;
 import static jdk.nashorn.internal.parser.TokenType.STRING;
-
 import java.util.ArrayList;
 import java.util.List;
 import jdk.nashorn.internal.ir.Expression;
--- a/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/JSType.java	Tue Oct 21 14:27:49 2014 +0200
+++ b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/JSType.java	Thu Oct 23 15:19:00 2014 +0400
@@ -29,7 +29,6 @@
 import static jdk.nashorn.internal.codegen.ObjectClassGenerator.OBJECT_FIELDS_ONLY;
 import static jdk.nashorn.internal.lookup.Lookup.MH;
 import static jdk.nashorn.internal.runtime.ECMAErrors.typeError;
-
 import java.lang.invoke.MethodHandle;
 import java.lang.invoke.MethodHandles;
 import java.lang.reflect.Array;
@@ -1776,6 +1775,23 @@
     }
 
     /**
+     * Returns the boxed version of a primitive class
+     * @param clazz the class
+     * @return the boxed type of clazz, or unchanged if not primitive
+     */
+    public static Class<?> getBoxedClass(final Class<?> clazz) {
+        if (clazz == int.class) {
+            return Integer.class;
+        } else if (clazz == long.class) {
+            return Long.class;
+        } else if (clazz == double.class) {
+            return Double.class;
+        }
+        assert !clazz.isPrimitive();
+        return clazz;
+    }
+
+    /**
      * Create a method handle constant of the correct primitive type
      * for a constant object
      * @param o object
--- a/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/ScriptObject.java	Tue Oct 21 14:27:49 2014 +0200
+++ b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/ScriptObject.java	Thu Oct 23 15:19:00 2014 +0400
@@ -692,8 +692,7 @@
         assert isValidArrayIndex(index) : "invalid array index";
         final long longIndex = ArrayIndex.toLongIndex(index);
         doesNotHaveEnsureDelete(longIndex, getArray().length(), false);
-        setArray(getArray().ensure(longIndex));
-        setArray(getArray().set(index, value, false));
+        setArray(getArray().ensure(longIndex).set(index,value, false));
     }
 
     private void checkIntegerKey(final String key) {
@@ -1462,9 +1461,8 @@
 
         //invalidate any fast array setters
         final ArrayData array = getArray();
-        if (array != null) {
-            array.invalidateSetters();
-        }
+        assert array != null;
+        setArray(ArrayData.preventExtension(array));
         return this;
     }
 
@@ -2645,20 +2643,22 @@
       * @param newLength new length to set
       */
     public final void setLength(final long newLength) {
-       final long arrayLength = getArray().length();
-       if (newLength == arrayLength) {
-           return;
-       }
-
-       if (newLength > arrayLength) {
-           setArray(getArray().ensure(newLength - 1));
-            if (getArray().canDelete(arrayLength, newLength - 1, false)) {
-               setArray(getArray().delete(arrayLength, newLength - 1));
-           }
-           return;
-       }
-
-       if (newLength < arrayLength) {
+        ArrayData data = getArray();
+        final long arrayLength = data.length();
+        if (newLength == arrayLength) {
+            return;
+        }
+
+        if (newLength > arrayLength) {
+            data = data.ensure(newLength - 1);
+            if (data.canDelete(arrayLength, newLength - 1, false)) {
+               data = data.delete(arrayLength, newLength - 1);
+            }
+            setArray(data);
+            return;
+        }
+
+        if (newLength < arrayLength) {
            long actualLength = newLength;
 
            // Check for numeric keys in property map and delete them or adjust length, depending on whether
@@ -2680,8 +2680,8 @@
                }
            }
 
-           setArray(getArray().shrink(actualLength));
-           getArray().setLength(actualLength);
+           setArray(data.shrink(actualLength));
+           data.setLength(actualLength);
        }
     }
 
@@ -3194,8 +3194,9 @@
         final int    index        = getArrayIndex(primitiveKey);
 
         if (isValidArrayIndex(index)) {
-            if (getArray().has(index)) {
-                setArray(getArray().set(index, value, NashornCallSiteDescriptor.isStrictFlag(callSiteFlags)));
+            final ArrayData data = getArray();
+            if (data.has(index)) {
+                setArray(data.set(index, value, NashornCallSiteDescriptor.isStrictFlag(callSiteFlags)));
             } else {
                 doesNotHave(index, value, callSiteFlags);
             }
@@ -3213,8 +3214,9 @@
         final int    index        = getArrayIndex(primitiveKey);
 
         if (isValidArrayIndex(index)) {
-            if (getArray().has(index)) {
-                setArray(getArray().set(index, value, NashornCallSiteDescriptor.isStrictFlag(callSiteFlags)));
+            final ArrayData data = getArray();
+            if (data.has(index)) {
+                setArray(data.set(index, value, NashornCallSiteDescriptor.isStrictFlag(callSiteFlags)));
             } else {
                 doesNotHave(index, value, callSiteFlags);
             }
@@ -3232,8 +3234,9 @@
         final int    index        = getArrayIndex(primitiveKey);
 
         if (isValidArrayIndex(index)) {
-            if (getArray().has(index)) {
-                setArray(getArray().set(index, value, NashornCallSiteDescriptor.isStrictFlag(callSiteFlags)));
+            final ArrayData data = getArray();
+            if (data.has(index)) {
+                setArray(data.set(index, value, NashornCallSiteDescriptor.isStrictFlag(callSiteFlags)));
             } else {
                 doesNotHave(index, value, callSiteFlags);
             }
@@ -3251,8 +3254,9 @@
         final int    index        = getArrayIndex(primitiveKey);
 
         if (isValidArrayIndex(index)) {
-            if (getArray().has(index)) {
-                setArray(getArray().set(index, value, NashornCallSiteDescriptor.isStrictFlag(callSiteFlags)));
+            final ArrayData data = getArray();
+            if (data.has(index)) {
+                setArray(data.set(index, value, NashornCallSiteDescriptor.isStrictFlag(callSiteFlags)));
             } else {
                 doesNotHave(index, value, callSiteFlags);
             }
@@ -3269,8 +3273,9 @@
         final int index = getArrayIndex(key);
 
         if (isValidArrayIndex(index)) {
-            if (getArray().has(index)) {
-                setArray(getArray().set(index, value, NashornCallSiteDescriptor.isStrictFlag(callSiteFlags)));
+            final ArrayData data = getArray();
+            if (data.has(index)) {
+                setArray(data.set(index, value, NashornCallSiteDescriptor.isStrictFlag(callSiteFlags)));
             } else {
                 doesNotHave(index, value, callSiteFlags);
             }
@@ -3287,8 +3292,9 @@
         final int index = getArrayIndex(key);
 
         if (isValidArrayIndex(index)) {
-            if (getArray().has(index)) {
-                setArray(getArray().set(index, value, NashornCallSiteDescriptor.isStrictFlag(callSiteFlags)));
+            final ArrayData data = getArray();
+            if (data.has(index)) {
+                setArray(data.set(index, value, NashornCallSiteDescriptor.isStrictFlag(callSiteFlags)));
             } else {
                 doesNotHave(index, value, callSiteFlags);
             }
@@ -3305,8 +3311,9 @@
         final int index = getArrayIndex(key);
 
         if (isValidArrayIndex(index)) {
-            if (getArray().has(index)) {
-                setArray(getArray().set(index, value, NashornCallSiteDescriptor.isStrictFlag(callSiteFlags)));
+            final ArrayData data = getArray();
+            if (data.has(index)) {
+                setArray(data.set(index, value, NashornCallSiteDescriptor.isStrictFlag(callSiteFlags)));
             } else {
                 doesNotHave(index, value, callSiteFlags);
             }
@@ -3323,8 +3330,9 @@
         final int index = getArrayIndex(key);
 
         if (isValidArrayIndex(index)) {
-            if (getArray().has(index)) {
-                setArray(getArray().set(index, value, NashornCallSiteDescriptor.isStrictFlag(callSiteFlags)));
+            final ArrayData data = getArray();
+            if (data.has(index)) {
+                setArray(data.set(index, value, NashornCallSiteDescriptor.isStrictFlag(callSiteFlags)));
             } else {
                 doesNotHave(index, value, callSiteFlags);
             }
@@ -3341,8 +3349,9 @@
         final int index = getArrayIndex(key);
 
         if (isValidArrayIndex(index)) {
-            if (getArray().has(index)) {
-                setArray(getArray().set(index, value, NashornCallSiteDescriptor.isStrictFlag(callSiteFlags)));
+            final ArrayData data = getArray();
+            if (data.has(index)) {
+                setArray(data.set(index, value, NashornCallSiteDescriptor.isStrictFlag(callSiteFlags)));
             } else {
                 doesNotHave(index, value, callSiteFlags);
             }
@@ -3359,8 +3368,9 @@
         final int index = getArrayIndex(key);
 
         if (isValidArrayIndex(index)) {
-            if (getArray().has(index)) {
-                setArray(getArray().set(index, value, NashornCallSiteDescriptor.isStrictFlag(callSiteFlags)));
+            final ArrayData data = getArray();
+            if (data.has(index)) {
+                setArray(data.set(index, value, NashornCallSiteDescriptor.isStrictFlag(callSiteFlags)));
             } else {
                 doesNotHave(index, value, callSiteFlags);
             }
@@ -3377,8 +3387,9 @@
         final int index = getArrayIndex(key);
 
         if (isValidArrayIndex(index)) {
-            if (getArray().has(index)) {
-                setArray(getArray().set(index, value, NashornCallSiteDescriptor.isStrictFlag(callSiteFlags)));
+            final ArrayData data = getArray();
+            if (data.has(index)) {
+                setArray(data.set(index, value, NashornCallSiteDescriptor.isStrictFlag(callSiteFlags)));
             } else {
                 doesNotHave(index, value, callSiteFlags);
             }
@@ -3395,8 +3406,9 @@
         final int index = getArrayIndex(key);
 
         if (isValidArrayIndex(index)) {
-            if (getArray().has(index)) {
-                setArray(getArray().set(index, value, NashornCallSiteDescriptor.isStrictFlag(callSiteFlags)));
+            final ArrayData data = getArray();
+            if (data.has(index)) {
+                setArray(data.set(index, value, NashornCallSiteDescriptor.isStrictFlag(callSiteFlags)));
             } else {
                 doesNotHave(index, value, callSiteFlags);
             }
@@ -3413,7 +3425,8 @@
         final int index = getArrayIndex(key);
         if (isValidArrayIndex(index)) {
             if (getArray().has(index)) {
-                setArray(getArray().set(index, value, NashornCallSiteDescriptor.isStrictFlag(callSiteFlags)));
+                final ArrayData data = getArray();
+                setArray(data.set(index, value, NashornCallSiteDescriptor.isStrictFlag(callSiteFlags)));
             } else {
                 doesNotHave(index, value, callSiteFlags);
             }
@@ -3429,8 +3442,9 @@
         final int index = getArrayIndex(key);
 
         if (isValidArrayIndex(index)) {
-            if (getArray().has(index)) {
-                setArray(getArray().set(index, value, NashornCallSiteDescriptor.isStrictFlag(callSiteFlags)));
+            final ArrayData data = getArray();
+            if (data.has(index)) {
+                setArray(data.set(index, value, NashornCallSiteDescriptor.isStrictFlag(callSiteFlags)));
             } else {
                 doesNotHave(index, value, callSiteFlags);
             }
@@ -3447,8 +3461,9 @@
         final int index = getArrayIndex(key);
 
         if (isValidArrayIndex(index)) {
-            if (getArray().has(index)) {
-                setArray(getArray().set(index, value, NashornCallSiteDescriptor.isStrictFlag(callSiteFlags)));
+            final ArrayData data = getArray();
+            if (data.has(index)) {
+                setArray(data.set(index, value, NashornCallSiteDescriptor.isStrictFlag(callSiteFlags)));
             } else {
                 doesNotHave(index, value, callSiteFlags);
             }
@@ -3465,8 +3480,9 @@
         final int index = getArrayIndex(key);
 
         if (isValidArrayIndex(index)) {
-            if (getArray().has(index)) {
-                setArray(getArray().set(index, value, NashornCallSiteDescriptor.isStrictFlag(callSiteFlags)));
+            final ArrayData data = getArray();
+            if (data.has(index)) {
+                setArray(data.set(index, value, NashornCallSiteDescriptor.isStrictFlag(callSiteFlags)));
             } else {
                 doesNotHave(index, value, callSiteFlags);
             }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/arrays/AnyElements.java	Thu Oct 23 15:19:00 2014 +0400
@@ -0,0 +1,38 @@
+/*
+ * Copyright (c) 2010, 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package jdk.nashorn.internal.runtime.arrays;
+
+/**
+ * Marker interface for any ContinuousArray with any elements
+ * Used for type checks that throw ClassCastExceptions and force relinks
+ * for fast NativeArray specializations of builtin methods
+ */
+public interface AnyElements {
+    /**
+     * Return a numeric weight of the element type - wider is higher
+     * @return element type weight
+     */
+    public int getElementWeight();
+}
\ No newline at end of file
--- a/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/arrays/ArrayData.java	Tue Oct 21 14:27:49 2014 +0200
+++ b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/arrays/ArrayData.java	Thu Oct 23 15:19:00 2014 +0400
@@ -28,6 +28,7 @@
 import static jdk.nashorn.internal.codegen.CompilerConstants.staticCall;
 import java.lang.invoke.MethodHandle;
 import java.lang.invoke.MethodHandles;
+import java.lang.reflect.Array;
 import java.nio.ByteBuffer;
 import jdk.internal.dynalink.CallSiteDescriptor;
 import jdk.internal.dynalink.linker.GuardedInvocation;
@@ -37,6 +38,7 @@
 import jdk.nashorn.internal.objects.Global;
 import jdk.nashorn.internal.runtime.JSType;
 import jdk.nashorn.internal.runtime.PropertyDescriptor;
+import jdk.nashorn.internal.runtime.ScriptRuntime;
 import jdk.nashorn.internal.runtime.UnwarrantedOptimismException;
 
 /**
@@ -49,10 +51,180 @@
     /** Mask for getting a chunk */
     protected static final int CHUNK_MASK = CHUNK_SIZE - 1;
 
+    /** Untouched data - still link callsites as IntArrayData, but expands to
+     *  a proper ArrayData when we try to write to it */
+    public static final ArrayData EMPTY_ARRAY = new UntouchedArrayData();
+
     /**
      * Immutable empty array to get ScriptObjects started.
+     * Use the same array and convert it to mutable as soon as it is modified
      */
-    public static final ArrayData EMPTY_ARRAY = new NoTypeArrayData();
+    private static class UntouchedArrayData extends ContinuousArrayData {
+        private UntouchedArrayData() {
+            this(0);
+        }
+
+        private UntouchedArrayData(final int length) {
+            super(length);
+        }
+
+        private ArrayData toRealArrayData() {
+            return toRealArrayData(0);
+        }
+
+        private ArrayData toRealArrayData(final int index) {
+            final IntArrayData newData = new IntArrayData(index + 1);
+            if (index == 0) {
+                return newData;
+            }
+            return new DeletedRangeArrayFilter(newData, 0, index);
+        }
+
+        @Override
+        public ContinuousArrayData copy() {
+            return new UntouchedArrayData((int)length);
+        }
+
+        @Override
+        public Object asArrayOfType(final Class<?> componentType) {
+            return Array.newInstance(componentType, 0);
+        }
+
+        @Override
+        public Object[] asObjectArray() {
+            return ScriptRuntime.EMPTY_ARRAY;
+        }
+
+        @Override
+        public ArrayData ensure(final long safeIndex) {
+            if (safeIndex > 0L) {
+                return toRealArrayData((int)safeIndex).ensure(safeIndex);
+           }
+           return this;
+        }
+
+        @Override
+        public ArrayData convert(final Class<?> type) {
+            return toRealArrayData(0).convert(type);
+        }
+
+        @Override
+        public void shiftLeft(final int by) {
+            //nop, always empty or we wouldn't be of this class
+        }
+
+        @Override
+        public ArrayData shiftRight(final int by) {
+            return this; //always empty or we wouldn't be of this class
+        }
+
+        @Override
+        public ArrayData shrink(final long newLength) {
+            return this;
+        }
+
+        @Override
+        public ArrayData set(final int index, final Object value, final boolean strict) {
+            return toRealArrayData(index).set(index, value, strict);
+        }
+
+        @Override
+        public ArrayData set(final int index, final int value, final boolean strict) {
+            return toRealArrayData(index).set(index, value, strict);
+        }
+
+        @Override
+        public ArrayData set(final int index, final long value, final boolean strict) {
+            return toRealArrayData(index).set(index, value, strict);
+        }
+
+        @Override
+        public ArrayData set(final int index, final double value, final boolean strict) {
+            return toRealArrayData(index).set(index, value, strict);
+        }
+
+        @Override
+        public int getInt(final int index) {
+            throw new ArrayIndexOutOfBoundsException(index); //empty
+        }
+
+        @Override
+        public long getLong(final int index) {
+            throw new ArrayIndexOutOfBoundsException(index); //empty
+        }
+
+        @Override
+        public double getDouble(final int index) {
+            throw new ArrayIndexOutOfBoundsException(index); //empty
+        }
+
+        @Override
+        public Object getObject(final int index) {
+            throw new ArrayIndexOutOfBoundsException(index); //empty
+        }
+
+        @Override
+        public boolean has(final int index) {
+            return false; //empty
+        }
+
+        @Override
+        public ArrayData delete(final int index) {
+            return new DeletedRangeArrayFilter(this, index, index);
+        }
+
+        @Override
+        public ArrayData delete(final long fromIndex, final long toIndex) {
+            return new DeletedRangeArrayFilter(this, fromIndex, toIndex);
+        }
+
+        @Override
+        public Object pop() {
+            return ScriptRuntime.UNDEFINED;
+        }
+
+        @Override
+        public ArrayData push(final boolean strict, final Object item) {
+            return toRealArrayData().push(strict, item);
+        }
+
+        @Override
+        public ArrayData slice(final long from, final long to) {
+            return this; //empty
+        }
+
+        @Override
+        public ContinuousArrayData fastConcat(final ContinuousArrayData otherData) {
+            return otherData.copy();
+        }
+
+        //no need to override fastPopInt, as the default behavior is to throw classcast exception so we
+        //can relink and return an undefined, this is the IntArrayData default behavior
+        @Override
+        public String toString() {
+            return getClass().getSimpleName();
+        }
+
+        @Override
+        public MethodHandle getElementGetter(final Class<?> returnType, final int programPoint) {
+            return null;
+        }
+
+        @Override
+        public MethodHandle getElementSetter(final Class<?> elementType) {
+            return null;
+        }
+
+        @Override
+        public Class<?> getElementType() {
+            return int.class;
+        }
+
+        @Override
+        public Class<?> getBoxedElementType() {
+            return Integer.class;
+        }
+    };
 
     /**
      * Length of the array data. Not necessarily length of the wrapped array.
@@ -77,7 +249,7 @@
      * Factory method for unspecified array - start as int
      * @return ArrayData
      */
-    public static ArrayData initialArray() {
+    public final static ArrayData initialArray() {
         return new IntArrayData();
     }
 
@@ -92,33 +264,22 @@
         throw new UnwarrantedOptimismException(data.getObject(index), programPoint);
     }
 
-    private static int alignUp(final int size) {
+    /**
+     * Align an array size up to the nearest array chunk size
+     * @param size size required
+     * @return size given, always >= size
+     */
+    protected final static int alignUp(final int size) {
         return size + CHUNK_SIZE - 1 & ~(CHUNK_SIZE - 1);
     }
 
     /**
-     * Generic invalidation hook for script object to have call sites to this array indexing
-     * relinked, e.g. when a native array is marked as non extensible
-     */
-    public void invalidateGetters() {
-        //subclass responsibility
-    }
-
-    /**
-     * Generic invalidation hook for script object to have call sites to this array indexing
-     * relinked, e.g. when a native array is marked as non extensible
-     */
-    public void invalidateSetters() {
-        //subclass responsibility
-    }
-
-    /**
      * Factory method for unspecified array with given length - start as int array data
      *
      * @param length the initial length
      * @return ArrayData
      */
-    public static ArrayData allocate(final int length) {
+    public static final ArrayData allocate(final int length) {
         if (length == 0) {
             return new IntArrayData();
         } else if (length >= SparseArrayData.MAX_DENSE_LENGTH) {
@@ -134,7 +295,7 @@
      * @param  array the array
      * @return ArrayData wrapping this array
      */
-    public static ArrayData allocate(final Object array) {
+    public static final ArrayData allocate(final Object array) {
         final Class<?> clazz = array.getClass();
 
         if (clazz == int[].class) {
@@ -154,7 +315,7 @@
      * @param array the array to use for initial elements
      * @return the ArrayData
      */
-    public static ArrayData allocate(final int[] array) {
+    public static final ArrayData allocate(final int[] array) {
          return new IntArrayData(array, array.length);
     }
 
@@ -164,7 +325,7 @@
      * @param array the array to use for initial elements
      * @return the ArrayData
      */
-    public static ArrayData allocate(final long[] array) {
+    public static final ArrayData allocate(final long[] array) {
         return new LongArrayData(array, array.length);
     }
 
@@ -174,7 +335,7 @@
      * @param array the array to use for initial elements
      * @return the ArrayData
      */
-    public static ArrayData allocate(final double[] array) {
+    public static final ArrayData allocate(final double[] array) {
         return new NumberArrayData(array, array.length);
     }
 
@@ -184,7 +345,7 @@
      * @param array the array to use for initial elements
      * @return the ArrayData
      */
-    public static ArrayData allocate(final Object[] array) {
+    public static final ArrayData allocate(final Object[] array) {
         return new ObjectArrayData(array, array.length);
     }
 
@@ -194,7 +355,7 @@
      * @param buf the nio ByteBuffer to wrap
      * @return the ArrayData
      */
-    public static ArrayData allocate(final ByteBuffer buf) {
+    public static final ArrayData allocate(final ByteBuffer buf) {
         return new ByteBufferArrayData(buf);
     }
 
@@ -204,7 +365,7 @@
      * @param underlying  the underlying ArrayData to wrap in the freeze filter
      * @return the frozen ArrayData
      */
-    public static ArrayData freeze(final ArrayData underlying) {
+    public static final ArrayData freeze(final ArrayData underlying) {
         return new FrozenArrayFilter(underlying);
     }
 
@@ -214,11 +375,21 @@
      * @param underlying  the underlying ArrayData to wrap in the seal filter
      * @return the sealed ArrayData
      */
-    public static ArrayData seal(final ArrayData underlying) {
+    public static final ArrayData seal(final ArrayData underlying) {
         return new SealedArrayFilter(underlying);
     }
 
     /**
+     * Prevent this array from being extended
+     *
+     * @param  underlying the underlying ArrayData to wrap in the non extensible filter
+     * @return new array data, filtered
+     */
+    public static final ArrayData preventExtension(final ArrayData underlying) {
+        return new NonExtensibleArrayFilter(underlying);
+    }
+
+    /**
      * Return the length of the array data. This may differ from the actual
      * length of the array this wraps as length may be set or gotten as any
      * other JavaScript Property
@@ -728,5 +899,4 @@
     public GuardedInvocation findFastSetIndexMethod(final Class<? extends ArrayData> clazz, final CallSiteDescriptor desc, final LinkRequest request) { // array, index, value
         return null;
     }
-
 }
--- a/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/arrays/ContinuousArrayData.java	Tue Oct 21 14:27:49 2014 +0200
+++ b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/arrays/ContinuousArrayData.java	Thu Oct 23 15:19:00 2014 +0400
@@ -1,5 +1,4 @@
 /*
- * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -30,7 +29,6 @@
 import static jdk.nashorn.internal.runtime.JSType.getAccessorTypeIndex;
 import static jdk.nashorn.internal.runtime.UnwarrantedOptimismException.INVALID_PROGRAM_POINT;
 import static jdk.nashorn.internal.runtime.UnwarrantedOptimismException.isValid;
-
 import java.lang.invoke.MethodHandle;
 import java.lang.invoke.MethodHandles;
 import java.lang.invoke.MethodType;
@@ -50,9 +48,6 @@
  */
 @Logger(name="arrays")
 public abstract class ContinuousArrayData extends ArrayData {
-
-    private SwitchPoint sp;
-
     /**
      * Constructor
      * @param length length (elementLength)
@@ -61,18 +56,6 @@
         super(length);
     }
 
-    private SwitchPoint ensureSwitchPointExists() {
-        if (sp == null){
-            sp = new SwitchPoint();
-        }
-        return sp;
-    }
-
-    @Override
-    public void invalidateSetters() {
-        SwitchPoint.invalidateAll(new SwitchPoint[] { ensureSwitchPointExists() });
-    }
-
     /**
      * Check if we can put one more element at the end of this continous
      * array without reallocating, or if we are overwriting an already
@@ -86,6 +69,14 @@
     }
 
     /**
+     * Check if an arraydata is empty
+     * @return true if empty
+     */
+    public boolean isEmpty() {
+        return length == 0L;
+    }
+
+    /**
      * Return element getter for a certain type at a certain program point
      * @param returnType   return type
      * @param programPoint program point
@@ -109,13 +100,16 @@
      * @param index index to check - currently only int indexes
      * @return index
      */
-    protected int throwHas(final int index) {
+    protected final int throwHas(final int index) {
         if (!has(index)) {
             throw new ClassCastException();
         }
         return index;
     }
 
+    @Override
+    public abstract ContinuousArrayData copy();
+
     /**
      * Returns the type used to store an element in this array
      * @return element type
@@ -128,6 +122,25 @@
     }
 
     /**
+     * Returns the boxed type of the type used to store an element in this array
+     * @return element type
+     */
+    public abstract Class<?> getBoxedElementType();
+
+    /**
+     * Get the widest element type of two arrays. This can be done faster in subclasses, but
+     * this works for all ContinuousArrayDatas and for where more optimal checks haven't been
+     * implemented.
+     *
+     * @param otherData another ContinuousArrayData
+     * @return the widest boxed element type
+     */
+    public ContinuousArrayData widest(final ContinuousArrayData otherData) {
+        final Class<?> elementType = getElementType();
+        return Type.widest(elementType, otherData.getElementType()) == elementType ? this : otherData;
+    }
+
+    /**
      * Look up a continuous array element getter
      * @param get          getter, sometimes combined with a has check that throws CCE on failure for relink
      * @param returnType   return type
@@ -256,12 +269,7 @@
             final Object[]        args  = request.getArguments();
             final int             index = (int)args[args.length - 2];
 
-            //sp may be invalidated by e.g. preventExtensions before the first setter is linked
-            //then it is already created. otherwise, create it here to guard against future
-            //invalidations
-            ensureSwitchPointExists();
-
-            if (!sp.hasBeenInvalidated() && hasRoomFor(index)) {
+            if (hasRoomFor(index)) {
                 MethodHandle setElement = getElementSetter(elementType); //Z(continuousarraydata, int, int), return true if successful
                 if (setElement != null) {
                     //else we are dealing with a wider type than supported by this callsite
@@ -269,7 +277,7 @@
                     getArray   = MH.asType(getArray, getArray.type().changeReturnType(getClass()));
                     setElement = MH.filterArguments(setElement, 0, getArray);
                     final MethodHandle guard = MH.insertArguments(FAST_ACCESS_GUARD, 0, clazz);
-                    return new GuardedInvocation(setElement, guard, sp, ClassCastException.class); //CCE if not a scriptObject anymore
+                    return new GuardedInvocation(setElement, guard, (SwitchPoint)null, ClassCastException.class); //CCE if not a scriptObject anymore
                 }
             }
         }
@@ -344,4 +352,13 @@
     public Object fastPopObject() {
         throw new ClassCastException(String.valueOf(getClass())); //type is wrong, relink
     }
+
+    /**
+     * Specialization - fast concat implementation
+     * @param otherData data to concat
+     * @return new arraydata
+     */
+    public ContinuousArrayData fastConcat(final ContinuousArrayData otherData) {
+        throw new ClassCastException(String.valueOf(getClass()) + " != " + String.valueOf(otherData.getClass()));
+    }
 }
--- a/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/arrays/IntArrayData.java	Tue Oct 21 14:27:49 2014 +0200
+++ b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/arrays/IntArrayData.java	Thu Oct 23 15:19:00 2014 +0400
@@ -26,7 +26,6 @@
 package jdk.nashorn.internal.runtime.arrays;
 
 import static jdk.nashorn.internal.codegen.CompilerConstants.specialCall;
-
 import java.lang.invoke.MethodHandle;
 import java.lang.invoke.MethodHandles;
 import java.util.Arrays;
@@ -57,17 +56,32 @@
      * @param array an int array
      * @param length a length, not necessarily array.length
      */
-    IntArrayData(final int array[], final int length) {
+    IntArrayData(final int[] array, final int length) {
         super(length);
-        assert array.length >= length;
+        assert array == null || array.length >= length;
         this.array = array;
     }
 
     @Override
-    public Class<?> getElementType() {
+    public final Class<?> getElementType() {
         return int.class;
     }
 
+    @Override
+    public final Class<?> getBoxedElementType() {
+        return Integer.class;
+    }
+
+    @Override
+    public final int getElementWeight() {
+        return 1;
+    }
+
+    @Override
+    public final ContinuousArrayData widest(final ContinuousArrayData otherData) {
+        return otherData;
+    }
+
     private static final MethodHandle HAS_GET_ELEM = specialCall(MethodHandles.lookup(), IntArrayData.class, "getElem", int.class, int.class).methodHandle();
     private static final MethodHandle SET_ELEM     = specialCall(MethodHandles.lookup(), IntArrayData.class, "setElem", void.class, int.class, int.class).methodHandle();
 
@@ -104,7 +118,7 @@
     }
 
     @Override
-    public ArrayData copy() {
+    public IntArrayData copy() {
         return new IntArrayData(array.clone(), (int)length);
     }
 
@@ -165,8 +179,7 @@
     public ArrayData convert(final Class<?> type) {
         if (type == Integer.class) {
             return this;
-        }
-        if (type == Long.class) {
+        } else if (type == Long.class) {
             return convertToLong();
         } else if (type == Double.class) {
             return convertToDouble();
@@ -209,8 +222,7 @@
 
     @Override
     public ArrayData shrink(final long newLength) {
-        Arrays.fill(array, (int) newLength, array.length, 0);
-
+        Arrays.fill(array, (int)newLength, array.length, 0);
         return this;
     }
 
@@ -322,10 +334,7 @@
 
     @Override
     public ArrayData slice(final long from, final long to) {
-        final long start     = from < 0 ? from + length : from;
-        final long newLength = to - start;
-
-        return new IntArrayData(Arrays.copyOfRange(array, (int)from, (int)to), (int)newLength);
+        return new IntArrayData(Arrays.copyOfRange(array, (int)from, (int)to), (int)(to - (from < 0 ? from + length : from)));
     }
 
     @Override
@@ -347,7 +356,13 @@
             throw new UnsupportedOperationException();
         }
         final ArrayData returnValue = removed == 0 ?
-                EMPTY_ARRAY : new IntArrayData(Arrays.copyOfRange(array, start, start + removed), removed);
+                EMPTY_ARRAY :
+                new IntArrayData(
+                        Arrays.copyOfRange(
+                                array,
+                                start,
+                                start + removed),
+                        removed);
 
         if (newLength != oldLength) {
             final int[] newArray;
@@ -403,4 +418,26 @@
     public Object fastPopObject() {
         return fastPopInt();
     }
+
+    @Override
+    public ContinuousArrayData fastConcat(final ContinuousArrayData otherData) {
+        final int   otherLength = (int)otherData.length;
+        final int   thisLength  = (int)length;
+        assert otherLength > 0 && thisLength > 0;
+
+        final int[] otherArray  = ((IntArrayData)otherData).array;
+        final int   newLength   = otherLength + thisLength;
+        final int[] newArray    = new int[ArrayData.alignUp(newLength)];
+
+        System.arraycopy(array, 0, newArray, 0, thisLength);
+        System.arraycopy(otherArray, 0, newArray, thisLength, otherLength);
+
+        return new IntArrayData(newArray, newLength);
+    }
+
+    @Override
+    public String toString() {
+        assert length <= array.length : length + " > " + array.length;
+        return getClass().getSimpleName() + ':' + Arrays.toString(Arrays.copyOf(array, (int)length));
+    }
 }
--- a/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/arrays/LongArrayData.java	Tue Oct 21 14:27:49 2014 +0200
+++ b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/arrays/LongArrayData.java	Thu Oct 23 15:19:00 2014 +0400
@@ -52,16 +52,31 @@
     LongArrayData(final long array[], final int length) {
         super(length);
         assert array.length >= length;
-        this.array  = array;
+        this.array = array;
     }
 
     @Override
-    public Class<?> getElementType() {
+    public final Class<?> getElementType() {
         return long.class;
     }
 
     @Override
-    public ArrayData copy() {
+    public final Class<?> getBoxedElementType() {
+        return Long.class;
+    }
+
+    @Override
+    public final ContinuousArrayData widest(final ContinuousArrayData otherData) {
+        return otherData instanceof IntElements ? this : otherData;
+    }
+
+    @Override
+    public final int getElementWeight() {
+        return 2;
+    }
+
+    @Override
+    public LongArrayData copy() {
         return new LongArrayData(array.clone(), (int)length);
     }
 
@@ -101,7 +116,7 @@
     }
 
     @Override
-    public ArrayData convert(final Class<?> type) {
+    public ContinuousArrayData convert(final Class<?> type) {
         if (type == Integer.class || type == Long.class) {
             return this;
         }
@@ -145,8 +160,7 @@
 
     @Override
     public ArrayData shrink(final long newLength) {
-        Arrays.fill(array, (int) newLength, array.length, 0);
-
+        Arrays.fill(array, (int)newLength, array.length, 0L);
         return this;
     }
 
@@ -359,4 +373,37 @@
     public Object fastPopObject() {
         return fastPopLong();
     }
+
+    @Override
+    public ContinuousArrayData fastConcat(final ContinuousArrayData otherData) {
+        final int   otherLength = (int)otherData.length;
+        final int   thisLength  = (int)length;
+        assert otherLength > 0 && thisLength > 0;
+
+        final long[] otherArray  = ((LongArrayData)otherData).array;
+        final int    newLength   = otherLength + thisLength;
+        final long[] newArray   = new long[ArrayData.alignUp(newLength)];
+
+        System.arraycopy(array, 0, newArray, 0, thisLength);
+        System.arraycopy(otherArray, 0, newArray, thisLength, otherLength);
+
+        return new LongArrayData(newArray, newLength);
+    }
+
+    @Override
+    public String toString() {
+        assert length <= array.length : length + " > " + array.length;
+
+        final StringBuilder sb = new StringBuilder(getClass().getSimpleName()).
+                append(": [");
+        for (int i = 0; i < length; i++) {
+            sb.append(array[i]).append('L'); //make sure L suffix is on elements, to discriminate this from IntArrayData.toString()
+            if (i + 1 < length) {
+                sb.append(", ");
+            }
+        }
+        sb.append(']');
+
+        return sb.toString();
+    }
 }
--- a/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/arrays/NoTypeArrayData.java	Tue Oct 21 14:27:49 2014 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,186 +0,0 @@
-/*
- * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.  Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-package jdk.nashorn.internal.runtime.arrays;
-
-import java.lang.reflect.Array;
-import jdk.nashorn.internal.runtime.ScriptRuntime;
-
-/**
- * Place holding array data for non-array objects.  Activates a true array when
- * accessed.  Should only exist as a singleton defined in ArrayData.
- */
-final class NoTypeArrayData extends ArrayData {
-    NoTypeArrayData() {
-        super(0);
-    }
-
-    NoTypeArrayData(final long length) {
-         super(length);
-    }
-
-    @Override
-    public Object[] asObjectArray() {
-        return ScriptRuntime.EMPTY_ARRAY;
-    }
-
-    @Override
-    public ArrayData copy() {
-        return new NoTypeArrayData();
-    }
-
-    @Override
-    public Object asArrayOfType(final Class<?> componentType) {
-        return Array.newInstance(componentType, 0);
-    }
-
-    @Override
-    public ArrayData convert(final Class<?> type) {
-        final long len = length;
-        final ArrayData arrayData;
-        if (type == Long.class) {
-            arrayData = new LongArrayData(new long[ArrayData.nextSize((int)len)], (int)len);
-        } else if (type == Double.class) {
-            arrayData = new NumberArrayData(new double[ArrayData.nextSize((int)len)], (int)len);
-        } else if (type == Integer.class) {
-            arrayData = new IntArrayData(new int[ArrayData.nextSize((int)len)], (int)len);
-        } else {
-            assert !type.isPrimitive();
-            arrayData = new ObjectArrayData(new Object[ArrayData.nextSize((int)len)], (int)len);
-        }
-        return length == 0 ? arrayData : new DeletedRangeArrayFilter(arrayData, 0, len - 1);
-    }
-
-    @Override
-    public void shiftLeft(final int by) {
-        //empty
-    }
-
-    @Override
-    public ArrayData shiftRight(final int by) {
-        return this;
-    }
-
-    @Override
-    public ArrayData ensure(final long safeIndex) {
-        if (safeIndex >= SparseArrayData.MAX_DENSE_LENGTH) {
-            return new SparseArrayData(this, safeIndex + 1);
-        }
-
-        // Don't trample the shared EMPTY_ARRAY.
-        if (length == 0) {
-            return new NoTypeArrayData(Math.max(safeIndex + 1, length));
-        }
-
-        setLength(Math.max(safeIndex + 1, length));
-        return this;
-    }
-
-    @Override
-    public ArrayData shrink(final long newLength) {
-        return this;
-    }
-
-    @Override
-    public ArrayData set(final int index, final Object value, final boolean strict) {
-        ArrayData newData;
-
-        if (value instanceof Double) {
-            newData = convert(Double.class);
-        } else if (value instanceof Long) {
-            newData = convert(Long.class);
-        } else if (value instanceof Integer) {
-            newData = convert(Integer.class);
-        } else {
-            assert !(value instanceof Number);
-            newData = convert(value == null ? Object.class : value.getClass());
-        }
-
-        return newData.set(index, value, strict);
-    }
-
-    @Override
-    public ArrayData set(final int index, final int value, final boolean strict) {
-        final ArrayData newData = convert(Integer.class);
-        return newData.set(index, value, strict);
-    }
-
-    @Override
-    public ArrayData set(final int index, final long value, final boolean strict) {
-        final ArrayData newData = convert(Long.class);
-        return newData.set(index, value, strict);
-    }
-
-    @Override
-    public ArrayData set(final int index, final double value, final boolean strict) {
-        final ArrayData newData = convert(Double.class);
-        return newData.set(index, value, strict);
-    }
-
-    @Override
-    public int getInt(final int index) {
-        throw new ArrayIndexOutOfBoundsException(index);
-    }
-
-    @Override
-    public long getLong(final int index) {
-        throw new ArrayIndexOutOfBoundsException(index);
-    }
-
-    @Override
-    public double getDouble(final int index) {
-        throw new ArrayIndexOutOfBoundsException(index);
-    }
-
-    @Override
-    public Object getObject(final int index) {
-        throw new ArrayIndexOutOfBoundsException(index);
-    }
-
-    @Override
-    public boolean has(final int index) {
-        return false;
-    }
-
-    @Override
-    public ArrayData delete(final int index) {
-        return new DeletedRangeArrayFilter(this, index, index);
-    }
-
-    @Override
-    public ArrayData delete(final long fromIndex, final long toIndex) {
-        return new DeletedRangeArrayFilter(this, fromIndex, toIndex);
-    }
-
-    @Override
-    public Object pop() {
-        return ScriptRuntime.UNDEFINED;
-    }
-
-    @Override
-    public ArrayData slice(final long from, final long to) {
-        return this;
-    }
-}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/arrays/NonExtensibleArrayFilter.java	Thu Oct 23 15:19:00 2014 +0400
@@ -0,0 +1,68 @@
+package jdk.nashorn.internal.runtime.arrays;
+
+import static jdk.nashorn.internal.runtime.ECMAErrors.typeError;
+import jdk.nashorn.internal.objects.Global;
+import jdk.nashorn.internal.runtime.ScriptRuntime;
+
+/**
+ * Filter class that wrap arrays that have been tagged non extensible
+ */
+public class NonExtensibleArrayFilter extends ArrayFilter {
+
+    /**
+     * Constructor
+     * @param underlying array
+     */
+    public NonExtensibleArrayFilter(final ArrayData underlying) {
+        super(underlying);
+    }
+
+    @Override
+    public ArrayData copy() {
+        return new NonExtensibleArrayFilter(underlying.copy());
+    }
+
+    @Override
+    public ArrayData slice(final long from, final long to) {
+        return new NonExtensibleArrayFilter(underlying.slice(from, to));
+    }
+
+    private ArrayData extensionCheck(final boolean strict, final int index) {
+        if (!strict) {
+            return this;
+        }
+        throw typeError(Global.instance(), "object.non.extensible", String.valueOf(index), ScriptRuntime.safeToString(this));
+    }
+
+    @Override
+    public ArrayData set(final int index, final Object value, final boolean strict) {
+        if (has(index)) {
+            return underlying.set(index, value, strict);
+        }
+        return extensionCheck(strict, index);
+    }
+
+    @Override
+    public ArrayData set(final int index, final int value, final boolean strict) {
+        if (has(index)) {
+            return underlying.set(index, value, strict);
+        }
+        return extensionCheck(strict, index);
+    }
+
+    @Override
+    public ArrayData set(final int index, final long value, final boolean strict) {
+        if (has(index)) {
+            return underlying.set(index, value, strict);
+        }
+        return extensionCheck(strict, index);
+    }
+
+    @Override
+    public ArrayData set(final int index, final double value, final boolean strict) {
+        if (has(index)) {
+            return underlying.set(index, value, strict);
+        }
+        return extensionCheck(strict, index);
+    }
+}
--- a/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/arrays/NumberArrayData.java	Tue Oct 21 14:27:49 2014 +0200
+++ b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/arrays/NumberArrayData.java	Thu Oct 23 15:19:00 2014 +0400
@@ -48,19 +48,34 @@
      * @param array an int array
      * @param length a length, not necessarily array.length
      */
-    NumberArrayData(final double array[], final int length) {
+    NumberArrayData(final double[] array, final int length) {
         super(length);
         assert array.length >= length;
-        this.array  = array;
+        this.array = array;
     }
 
     @Override
-    public Class<?> getElementType() {
+    public final Class<?> getElementType() {
         return double.class;
     }
 
     @Override
-    public ArrayData copy() {
+    public final Class<?> getBoxedElementType() {
+        return Double.class;
+    }
+
+    @Override
+    public final int getElementWeight() {
+        return 3;
+    }
+
+    @Override
+    public final ContinuousArrayData widest(final ContinuousArrayData otherData) {
+        return otherData instanceof IntOrLongElements ? this : otherData;
+    }
+
+    @Override
+    public NumberArrayData copy() {
         return new NumberArrayData(array.clone(), (int)length);
     }
 
@@ -88,7 +103,7 @@
     }
 
     @Override
-    public ArrayData convert(final Class<?> type) {
+    public ContinuousArrayData convert(final Class<?> type) {
         if (type != Double.class && type != Integer.class && type != Long.class) {
             final int len = (int)length;
             return new ObjectArrayData(toObjectArray(false), len);
@@ -129,7 +144,7 @@
 
     @Override
     public ArrayData shrink(final long newLength) {
-        Arrays.fill(array, (int) newLength, array.length, 0.0);
+        Arrays.fill(array, (int)newLength, array.length, 0.0);
         return this;
     }
 
@@ -334,4 +349,26 @@
     public Object fastPopObject() {
         return fastPopDouble();
     }
+
+    @Override
+    public ContinuousArrayData fastConcat(final ContinuousArrayData otherData) {
+        final int   otherLength = (int)otherData.length;
+        final int   thisLength  = (int)length;
+        assert otherLength > 0 && thisLength > 0;
+
+        final double[] otherArray = ((NumberArrayData)otherData).array;
+        final int      newLength  = otherLength + thisLength;
+        final double[] newArray   = new double[ArrayData.alignUp(newLength)];
+
+        System.arraycopy(array, 0, newArray, 0, thisLength);
+        System.arraycopy(otherArray, 0, newArray, thisLength, otherLength);
+
+        return new NumberArrayData(newArray, newLength);
+    }
+
+    @Override
+    public String toString() {
+        assert length <= array.length : length + " > " + array.length;
+        return getClass().getSimpleName() + ':' + Arrays.toString(Arrays.copyOf(array, (int)length));
+    }
 }
--- a/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/arrays/NumericElements.java	Tue Oct 21 14:27:49 2014 +0200
+++ b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/arrays/NumericElements.java	Thu Oct 23 15:19:00 2014 +0400
@@ -30,6 +30,6 @@
  * Used for type checks that throw ClassCastExceptions and force relinks
  * for fast NativeArray specializations of builtin methods
  */
-public interface NumericElements {
+public interface NumericElements extends AnyElements {
     //empty
 }
--- a/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/arrays/ObjectArrayData.java	Tue Oct 21 14:27:49 2014 +0200
+++ b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/arrays/ObjectArrayData.java	Thu Oct 23 15:19:00 2014 +0400
@@ -37,7 +37,7 @@
  * Implementation of {@link ArrayData} as soon as an Object has been
  * written to the array
  */
-final class ObjectArrayData extends ContinuousArrayData {
+final class ObjectArrayData extends ContinuousArrayData implements AnyElements {
 
     /**
      * The wrapped array
@@ -49,19 +49,34 @@
      * @param array an int array
      * @param length a length, not necessarily array.length
      */
-    ObjectArrayData(final Object array[], final int length) {
+    ObjectArrayData(final Object[] array, final int length) {
         super(length);
         assert array.length >= length;
         this.array  = array;
     }
 
     @Override
-    public Class<?> getElementType() {
+    public final Class<?> getElementType() {
         return Object.class;
     }
 
     @Override
-    public ArrayData copy() {
+    public final Class<?> getBoxedElementType() {
+        return getElementType();
+    }
+
+    @Override
+    public final int getElementWeight() {
+        return 4;
+    }
+
+    @Override
+    public final ContinuousArrayData widest(final ContinuousArrayData otherData) {
+        return otherData instanceof NumericElements ? this : otherData;
+    }
+
+    @Override
+    public ObjectArrayData copy() {
         return new ObjectArrayData(array.clone(), (int)length);
     }
 
@@ -79,7 +94,7 @@
     }
 
     @Override
-    public ArrayData convert(final Class<?> type) {
+    public ObjectArrayData convert(final Class<?> type) {
         return this;
     }
 
@@ -325,4 +340,26 @@
 
         return returnValue;
     }
+
+    @Override
+    public ContinuousArrayData fastConcat(final ContinuousArrayData otherData) {
+        final int   otherLength = (int)otherData.length;
+        final int   thisLength  = (int)length;
+        assert otherLength > 0 && thisLength > 0;
+
+        final Object[] otherArray = ((ObjectArrayData)otherData).array;
+        final int      newLength  = otherLength + thisLength;
+        final Object[] newArray   = new Object[ArrayData.alignUp(newLength)];
+
+        System.arraycopy(array, 0, newArray, 0, thisLength);
+        System.arraycopy(otherArray, 0, newArray, thisLength, otherLength);
+
+        return new ObjectArrayData(newArray, newLength);
+    }
+
+    @Override
+    public String toString() {
+        assert length <= array.length : length + " > " + array.length;
+        return getClass().getSimpleName() + ':' + Arrays.toString(Arrays.copyOf(array, (int)length));
+    }
 }
--- a/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/arrays/TypedArrayData.java	Tue Oct 21 14:27:49 2014 +0200
+++ b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/arrays/TypedArrayData.java	Thu Oct 23 15:19:00 2014 +0400
@@ -88,7 +88,7 @@
     }
 
     @Override
-    public ArrayData copy() {
+    public TypedArrayData<T> copy() {
         throw new UnsupportedOperationException();
     }
 
@@ -133,7 +133,7 @@
     }
 
     @Override
-    public ArrayData convert(final Class<?> type) {
+    public TypedArrayData<T> convert(final Class<?> type) {
         throw new UnsupportedOperationException();
     }
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/script/basic/JDK-8061391.js	Thu Oct 23 15:19:00 2014 +0400
@@ -0,0 +1,151 @@
+/*
+ * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/**
+ * JDK-8061391 - Checks that the optimistic builtin for concat is semantically
+ * correct.
+ *
+ * @test
+ * @run
+ */
+
+var maxJavaInt = 0x7fffffff;
+
+var ia = [1, 2, 3, 4];
+var la = [maxJavaInt + 1000, maxJavaInt + 2000, maxJavaInt + 3000, maxJavaInt + 4000];
+var da = [1.1, 2.2, 3.3, 4.4];
+var oa = ["one", "two", "three", "four"];  
+
+var aa = [ia, la, da, oa];
+
+function concats() {
+    print("shared callsite");
+
+    print(ia);
+    print(la);
+    print(da);
+    print(oa);
+    print(aa);
+    
+    for (var i = 0; i < aa.length; i++) {
+	print(aa[i].concat(aa[i][0]));
+	for (var j = 0; j < aa.length ; j++) {
+	    print(aa[i].concat(aa[j]));
+	}
+    }
+}
+
+function concats_inline() {
+    print("separate callsites");
+
+    print(ia);
+    print(la);
+    print(da);
+    print(oa);
+    print(aa);
+    
+    print(aa[0].concat(aa[0]));
+    print(aa[0].concat(aa[1]));
+    print(aa[0].concat(aa[2]));
+    print(aa[0].concat(aa[3]));
+    print(aa[0].concat(aa[0][0]));    
+
+    print(aa[1].concat(aa[0]));
+    print(aa[1].concat(aa[1]));
+    print(aa[1].concat(aa[2]));
+    print(aa[1].concat(aa[3]));
+    print(aa[1].concat(aa[1][0]));    
+
+    print(aa[2].concat(aa[0]));
+    print(aa[2].concat(aa[1]));
+    print(aa[2].concat(aa[2]));
+    print(aa[2].concat(aa[3]));
+    print(aa[2].concat(aa[2][0]));    
+
+    print(aa[3].concat(aa[0]));
+    print(aa[3].concat(aa[1]));
+    print(aa[3].concat(aa[2]));
+    print(aa[3].concat(aa[3]));
+    print(aa[3].concat(aa[3][0]));    
+}
+
+concats();
+concats_inline();
+
+print();
+var oldia = ia.slice(0); //clone ia
+print("oldia = " + oldia);
+ia[10] = "sparse";
+print("oldia = " + oldia);
+
+print();
+print("Redoing with sparse arrays");
+
+concats();
+concats_inline();
+
+ia = oldia;
+print("Restored ia = " + ia);
+
+function concat_expand() {
+    print("concat type expansion");
+    print(ia.concat(la));
+    print(ia.concat(da));
+    print(ia.concat(oa));
+    print(la.concat(ia));
+    print(la.concat(da));
+    print(la.concat(oa));
+    print(da.concat(ia));
+    print(da.concat(la));
+    print(da.concat(oa));
+}
+
+print();
+concat_expand();
+
+print();
+
+function concat_varargs() {
+    print("concat varargs");
+    print(ia.concat(la)); //fast
+    print(ia.concat(la, da, oa)); //slow
+    var slow = ia.concat(1, maxJavaInt * 2, 4711.17, function() { print("hello, world") }); //slow
+    print(slow);
+    return slow;
+}
+
+var slow = concat_varargs();
+
+print();
+print("sanity checks");
+slow.map(
+	 function(elem) {
+	     if (elem instanceof Function) {
+		 elem();
+	     } else {
+		 print((typeof elem) + " = " + elem);
+	     }
+	 });
+
+print(ia.concat({key: "value"}));
+print(ia.concat({key: "value"}, {key2: "value2"}));
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/script/basic/JDK-8061391.js.EXPECTED	Thu Oct 23 15:19:00 2014 +0400
@@ -0,0 +1,138 @@
+shared callsite
+1,2,3,4
+2147484647,2147485647,2147486647,2147487647
+1.1,2.2,3.3,4.4
+one,two,three,four
+1,2,3,4,2147484647,2147485647,2147486647,2147487647,1.1,2.2,3.3,4.4,one,two,three,four
+1,2,3,4,1
+1,2,3,4,1,2,3,4
+1,2,3,4,2147484647,2147485647,2147486647,2147487647
+1,2,3,4,1.1,2.2,3.3,4.4
+1,2,3,4,one,two,three,four
+2147484647,2147485647,2147486647,2147487647,2147484647
+2147484647,2147485647,2147486647,2147487647,1,2,3,4
+2147484647,2147485647,2147486647,2147487647,2147484647,2147485647,2147486647,2147487647
+2147484647,2147485647,2147486647,2147487647,1.1,2.2,3.3,4.4
+2147484647,2147485647,2147486647,2147487647,one,two,three,four
+1.1,2.2,3.3,4.4,1.1
+1.1,2.2,3.3,4.4,1,2,3,4
+1.1,2.2,3.3,4.4,2147484647,2147485647,2147486647,2147487647
+1.1,2.2,3.3,4.4,1.1,2.2,3.3,4.4
+1.1,2.2,3.3,4.4,one,two,three,four
+one,two,three,four,one
+one,two,three,four,1,2,3,4
+one,two,three,four,2147484647,2147485647,2147486647,2147487647
+one,two,three,four,1.1,2.2,3.3,4.4
+one,two,three,four,one,two,three,four
+separate callsites
+1,2,3,4
+2147484647,2147485647,2147486647,2147487647
+1.1,2.2,3.3,4.4
+one,two,three,four
+1,2,3,4,2147484647,2147485647,2147486647,2147487647,1.1,2.2,3.3,4.4,one,two,three,four
+1,2,3,4,1,2,3,4
+1,2,3,4,2147484647,2147485647,2147486647,2147487647
+1,2,3,4,1.1,2.2,3.3,4.4
+1,2,3,4,one,two,three,four
+1,2,3,4,1
+2147484647,2147485647,2147486647,2147487647,1,2,3,4
+2147484647,2147485647,2147486647,2147487647,2147484647,2147485647,2147486647,2147487647
+2147484647,2147485647,2147486647,2147487647,1.1,2.2,3.3,4.4
+2147484647,2147485647,2147486647,2147487647,one,two,three,four
+2147484647,2147485647,2147486647,2147487647,2147484647
+1.1,2.2,3.3,4.4,1,2,3,4
+1.1,2.2,3.3,4.4,2147484647,2147485647,2147486647,2147487647
+1.1,2.2,3.3,4.4,1.1,2.2,3.3,4.4
+1.1,2.2,3.3,4.4,one,two,three,four
+1.1,2.2,3.3,4.4,1.1
+one,two,three,four,1,2,3,4
+one,two,three,four,2147484647,2147485647,2147486647,2147487647
+one,two,three,four,1.1,2.2,3.3,4.4
+one,two,three,four,one,two,three,four
+one,two,three,four,one
+
+oldia = 1,2,3,4
+oldia = 1,2,3,4
+
+Redoing with sparse arrays
+shared callsite
+1,2,3,4,,,,,,,sparse
+2147484647,2147485647,2147486647,2147487647
+1.1,2.2,3.3,4.4
+one,two,three,four
+1,2,3,4,,,,,,,sparse,2147484647,2147485647,2147486647,2147487647,1.1,2.2,3.3,4.4,one,two,three,four
+1,2,3,4,,,,,,,sparse,1
+1,2,3,4,,,,,,,sparse,1,2,3,4,,,,,,,sparse
+1,2,3,4,,,,,,,sparse,2147484647,2147485647,2147486647,2147487647
+1,2,3,4,,,,,,,sparse,1.1,2.2,3.3,4.4
+1,2,3,4,,,,,,,sparse,one,two,three,four
+2147484647,2147485647,2147486647,2147487647,2147484647
+2147484647,2147485647,2147486647,2147487647,1,2,3,4,,,,,,,sparse
+2147484647,2147485647,2147486647,2147487647,2147484647,2147485647,2147486647,2147487647
+2147484647,2147485647,2147486647,2147487647,1.1,2.2,3.3,4.4
+2147484647,2147485647,2147486647,2147487647,one,two,three,four
+1.1,2.2,3.3,4.4,1.1
+1.1,2.2,3.3,4.4,1,2,3,4,,,,,,,sparse
+1.1,2.2,3.3,4.4,2147484647,2147485647,2147486647,2147487647
+1.1,2.2,3.3,4.4,1.1,2.2,3.3,4.4
+1.1,2.2,3.3,4.4,one,two,three,four
+one,two,three,four,one
+one,two,three,four,1,2,3,4,,,,,,,sparse
+one,two,three,four,2147484647,2147485647,2147486647,2147487647
+one,two,three,four,1.1,2.2,3.3,4.4
+one,two,three,four,one,two,three,four
+separate callsites
+1,2,3,4,,,,,,,sparse
+2147484647,2147485647,2147486647,2147487647
+1.1,2.2,3.3,4.4
+one,two,three,four
+1,2,3,4,,,,,,,sparse,2147484647,2147485647,2147486647,2147487647,1.1,2.2,3.3,4.4,one,two,three,four
+1,2,3,4,,,,,,,sparse,1,2,3,4,,,,,,,sparse
+1,2,3,4,,,,,,,sparse,2147484647,2147485647,2147486647,2147487647
+1,2,3,4,,,,,,,sparse,1.1,2.2,3.3,4.4
+1,2,3,4,,,,,,,sparse,one,two,three,four
+1,2,3,4,,,,,,,sparse,1
+2147484647,2147485647,2147486647,2147487647,1,2,3,4,,,,,,,sparse
+2147484647,2147485647,2147486647,2147487647,2147484647,2147485647,2147486647,2147487647
+2147484647,2147485647,2147486647,2147487647,1.1,2.2,3.3,4.4
+2147484647,2147485647,2147486647,2147487647,one,two,three,four
+2147484647,2147485647,2147486647,2147487647,2147484647
+1.1,2.2,3.3,4.4,1,2,3,4,,,,,,,sparse
+1.1,2.2,3.3,4.4,2147484647,2147485647,2147486647,2147487647
+1.1,2.2,3.3,4.4,1.1,2.2,3.3,4.4
+1.1,2.2,3.3,4.4,one,two,three,four
+1.1,2.2,3.3,4.4,1.1
+one,two,three,four,1,2,3,4,,,,,,,sparse
+one,two,three,four,2147484647,2147485647,2147486647,2147487647
+one,two,three,four,1.1,2.2,3.3,4.4
+one,two,three,four,one,two,three,four
+one,two,three,four,one
+Restored ia = 1,2,3,4
+
+concat type expansion
+1,2,3,4,2147484647,2147485647,2147486647,2147487647
+1,2,3,4,1.1,2.2,3.3,4.4
+1,2,3,4,one,two,three,four
+2147484647,2147485647,2147486647,2147487647,1,2,3,4
+2147484647,2147485647,2147486647,2147487647,1.1,2.2,3.3,4.4
+2147484647,2147485647,2147486647,2147487647,one,two,three,four
+1.1,2.2,3.3,4.4,1,2,3,4
+1.1,2.2,3.3,4.4,2147484647,2147485647,2147486647,2147487647
+1.1,2.2,3.3,4.4,one,two,three,four
+
+concat varargs
+1,2,3,4,2147484647,2147485647,2147486647,2147487647
+1,2,3,4,2147484647,2147485647,2147486647,2147487647,1.1,2.2,3.3,4.4,one,two,three,four
+1,2,3,4,1,4294967294,4711.17,function() { print("hello, world") }
+
+sanity checks
+number = 1
+number = 2
+number = 3
+number = 4
+number = 1
+number = 4294967294
+number = 4711.17
+hello, world
+1,2,3,4,[object Object]
+1,2,3,4,[object Object],[object Object]
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/script/basic/JDK-8061391_2.js	Thu Oct 23 15:19:00 2014 +0400
@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) 2010, 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/**
+ * Array extension check
+ *
+ * @test
+ * @run
+ */
+
+"use strict";
+var a = [1,2,3];
+Object.preventExtensions(a);
+try {
+    a[4] = 4;
+    print(a);
+} catch (e) {
+    if (!(e instanceof TypeError)) {
+	print("TypeError expected but got e");
+    }
+}
+
+if (a[0] != 1) {
+    throw "element 0 is wrong";
+}
+if (a[1] != 2) {
+    throw "element 1 is wrong";
+}
+if (a[2] != 3) {
+    throw "element 2 is wrong";
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/script/basic/JDK-8061391_3.js	Thu Oct 23 15:19:00 2014 +0400
@@ -0,0 +1,44 @@
+/*
+ * Copyright (c) 2010, 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/**
+ * Array extension check
+ *
+ * @test
+ * @run
+ */
+
+var a = [1,2,3];
+Object.preventExtensions(a);
+a[4] = 4;
+print(a);
+if (a[0] != 1) {
+    throw "element 0 is wrong";
+}
+if (a[1] != 2) {
+    throw "element 1 is wrong";
+}
+if (a[2] != 3) {
+    throw "element 2 is wrong";
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/script/basic/JDK-8061391_3.js.EXPECTED	Thu Oct 23 15:19:00 2014 +0400
@@ -0,0 +1,1 @@
+1,2,3