8035312: Various array and ScriptObject length issues for non writable length fields
authorlagergren
Wed, 12 Nov 2014 14:12:01 +0100
changeset 27525 e7d3c00b9fb8
parent 27524 f34b84c9f880
child 27526 1ed00adaaed0
8035312: Various array and ScriptObject length issues for non writable length fields Reviewed-by: hannesw, attila
nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeArray.java
nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeDebug.java
nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/annotations/SpecializedFunction.java
nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/ScriptFunction.java
nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/ScriptObject.java
nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/arrays/ArrayData.java
nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/arrays/ArrayFilter.java
nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/arrays/ContinuousArrayData.java
nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/arrays/DeletedArrayFilter.java
nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/arrays/DeletedRangeArrayFilter.java
nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/arrays/FrozenArrayFilter.java
nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/arrays/IntArrayData.java
nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/arrays/LengthNotWritableFilter.java
nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/arrays/LongArrayData.java
nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/arrays/NonExtensibleArrayFilter.java
nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/arrays/NumberArrayData.java
nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/arrays/ObjectArrayData.java
nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/arrays/SparseArrayData.java
nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/arrays/TypedArrayData.java
nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/arrays/UndefinedArrayFilter.java
nashorn/test/script/basic/JDK-8035312.js
nashorn/test/script/basic/JDK-8035312.js.EXPECTED
nashorn/test/script/basic/JDK-8035312_2.js
nashorn/test/script/basic/JDK-8035312_2.js.EXPECTED
nashorn/test/script/basic/JDK-8035312_3.js
nashorn/test/script/basic/JDK-8035312_3.js.EXPECTED
nashorn/test/script/basic/JDK-8035312_4.js
nashorn/test/script/basic/JDK-8035312_4.js.EXPECTED
nashorn/test/script/basic/JDK-8035312_5.js
nashorn/test/script/basic/JDK-8035312_5.js.EXPECTED
nashorn/test/script/basic/fastpushpop.js.EXPECTED
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeArray.java	Tue Nov 11 17:27:44 2014 +0100
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeArray.java	Wed Nov 12 14:12:01 2014 +0100
@@ -33,9 +33,7 @@
 import static jdk.nashorn.internal.runtime.arrays.ArrayLikeIterator.arrayLikeIterator;
 import static jdk.nashorn.internal.runtime.arrays.ArrayLikeIterator.reverseArrayLikeIterator;
 import static jdk.nashorn.internal.runtime.linker.NashornCallSiteDescriptor.CALLSITE_STRICT;
-
 import java.lang.invoke.MethodHandle;
-import java.lang.invoke.SwitchPoint;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collections;
@@ -93,17 +91,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 ConcatLinkLogic concatLinkLogic;
 
-    /**
-     * Index for the modification SwitchPoint that triggers when length
-     * becomes not writable
-     */
-    private static final int LENGTH_NOT_WRITABLE_SWITCHPOINT = 0;
-
     /*
      * Constructors.
      */
@@ -271,12 +262,83 @@
     @Override
     public Object getLength() {
         final long length = JSType.toUint32(getArray().length());
-        if(length < Integer.MAX_VALUE) {
+        if (length < Integer.MAX_VALUE) {
             return (int)length;
         }
         return length;
     }
 
+    private boolean defineLength(final long oldLen, final PropertyDescriptor oldLenDesc, final PropertyDescriptor desc, final boolean reject) {
+        // Step 3a
+        if (!desc.has(VALUE)) {
+            return super.defineOwnProperty("length", desc, reject);
+        }
+
+        // Step 3b
+        final PropertyDescriptor newLenDesc = desc;
+
+        // Step 3c and 3d - get new length and convert to long
+        final long newLen = NativeArray.validLength(newLenDesc.getValue(), true);
+
+        // Step 3e
+        newLenDesc.setValue(newLen);
+
+        // Step 3f
+        // increasing array length - just need to set new length value (and attributes if any) and return
+        if (newLen >= oldLen) {
+            return super.defineOwnProperty("length", newLenDesc, reject);
+        }
+
+        // Step 3g
+        if (!oldLenDesc.isWritable()) {
+            if (reject) {
+                throw typeError("property.not.writable", "length", ScriptRuntime.safeToString(this));
+            }
+            return false;
+        }
+
+        // Step 3h and 3i
+        final boolean newWritable = !newLenDesc.has(WRITABLE) || newLenDesc.isWritable();
+        if (!newWritable) {
+            newLenDesc.setWritable(true);
+        }
+
+        // Step 3j and 3k
+        final boolean succeeded = super.defineOwnProperty("length", newLenDesc, reject);
+        if (!succeeded) {
+            return false;
+        }
+
+        // Step 3l
+        // make sure that length is set till the point we can delete the old elements
+        long o = oldLen;
+        while (newLen < o) {
+            o--;
+            final boolean deleteSucceeded = delete(o, false);
+            if (!deleteSucceeded) {
+                newLenDesc.setValue(o + 1);
+                if (!newWritable) {
+                    newLenDesc.setWritable(false);
+                }
+                super.defineOwnProperty("length", newLenDesc, false);
+                if (reject) {
+                    throw typeError("property.not.writable", "length", ScriptRuntime.safeToString(this));
+                }
+                return false;
+            }
+        }
+
+        // Step 3m
+        if (!newWritable) {
+            // make 'length' property not writable
+            final ScriptObject newDesc = Global.newEmptyInstance();
+            newDesc.set(WRITABLE, false, 0);
+            return super.defineOwnProperty("length", newDesc, false);
+        }
+
+        return true;
+    }
+
     /**
      * ECMA 15.4.5.1 [[DefineOwnProperty]] ( P, Desc, Throw )
      */
@@ -290,82 +352,16 @@
 
         // Step 2
         // get old length and convert to long
-        long oldLen = NativeArray.validLength(oldLenDesc.getValue(), true);
+        final long oldLen = NativeArray.validLength(oldLenDesc.getValue(), true);
 
         // Step 3
         if ("length".equals(key)) {
             // check for length being made non-writable
+            final boolean result = defineLength(oldLen, oldLenDesc, desc, reject);
             if (desc.has(WRITABLE) && !desc.isWritable()) {
                 setIsLengthNotWritable();
             }
-
-            // Step 3a
-            if (!desc.has(VALUE)) {
-                return super.defineOwnProperty("length", desc, reject);
-            }
-
-            // Step 3b
-            final PropertyDescriptor newLenDesc = desc;
-
-            // Step 3c and 3d - get new length and convert to long
-            final long newLen = NativeArray.validLength(newLenDesc.getValue(), true);
-
-            // Step 3e
-            newLenDesc.setValue(newLen);
-
-            // Step 3f
-            // increasing array length - just need to set new length value (and attributes if any) and return
-            if (newLen >= oldLen) {
-                return super.defineOwnProperty("length", newLenDesc, reject);
-            }
-
-            // Step 3g
-            if (!oldLenDesc.isWritable()) {
-                if (reject) {
-                    throw typeError("property.not.writable", "length", ScriptRuntime.safeToString(this));
-                }
-                return false;
-            }
-
-            // Step 3h and 3i
-            final boolean newWritable = !newLenDesc.has(WRITABLE) || newLenDesc.isWritable();
-            if (!newWritable) {
-                newLenDesc.setWritable(true);
-            }
-
-            // Step 3j and 3k
-            final boolean succeeded = super.defineOwnProperty("length", newLenDesc, reject);
-            if (!succeeded) {
-                return false;
-            }
-
-            // Step 3l
-            // make sure that length is set till the point we can delete the old elements
-            while (newLen < oldLen) {
-                oldLen--;
-                final boolean deleteSucceeded = delete(oldLen, false);
-                if (!deleteSucceeded) {
-                    newLenDesc.setValue(oldLen + 1);
-                    if (!newWritable) {
-                        newLenDesc.setWritable(false);
-                    }
-                    super.defineOwnProperty("length", newLenDesc, false);
-                    if (reject) {
-                        throw typeError("property.not.writable", "length", ScriptRuntime.safeToString(this));
-                    }
-                    return false;
-                }
-            }
-
-            // Step 3m
-            if (!newWritable) {
-                // make 'length' property not writable
-                final ScriptObject newDesc = Global.newEmptyInstance();
-                newDesc.set(WRITABLE, false, 0);
-                return super.defineOwnProperty("length", newDesc, false);
-            }
-
-            return true;
+            return result;
         }
 
         // Step 4a
@@ -441,23 +437,7 @@
     @Override
     public void setIsLengthNotWritable() {
         super.setIsLengthNotWritable();
-        /*
-         * Switchpoints are created lazily. If we link any push or pop site,
-         * we need to create the "length made not writable" switchpoint, if it
-         * doesn't exist.
-         *
-         * If the switchpoint already exists, we will find it here, and invalidate
-         * it, invalidating all previous callsites that use it.
-         *
-         * If the switchpoint doesn't exist, no push/pop has been linked so far,
-         * because that would create it too. We invalidate it immediately and the
-         * check link logic for all future callsites will fail immediately at link
-         * time
-         */
-        if (lengthMadeNotWritableSwitchPoint == null) {
-            lengthMadeNotWritableSwitchPoint = new SwitchPoint();
-        }
-        SwitchPoint.invalidateAll(new SwitchPoint[] { lengthMadeNotWritableSwitchPoint });
+        setArray(ArrayData.setIsLengthNotWritable(getArray()));
     }
 
     /**
@@ -494,7 +474,7 @@
     @Setter(attributes = Attribute.NOT_ENUMERABLE | Attribute.NOT_CONFIGURABLE)
     public static void length(final Object self, final Object length) {
         if (isArray(self)) {
-            ((ScriptObject) self).setLength(validLength(length, true));
+            ((ScriptObject)self).setLength(validLength(length, true));
         }
     }
 
@@ -1306,10 +1286,13 @@
                 // Get only non-missing elements. Missing elements go at the end
                 // of the sorted array. So, just don't copy these to sort input.
                 final ArrayList<Object> src = new ArrayList<>();
-                for (long i = 0; i < len; i = array.nextIndex(i)) {
-                    if (array.has((int) i)) {
-                        src.add(array.getObject((int) i));
+
+                for (final Iterator<Long> iter = array.indexIterator(); iter.hasNext(); ) {
+                    final long index = iter.next();
+                    if (index >= len) {
+                        break;
                     }
+                    src.add(array.getObject((int)index));
                 }
 
                 final Object[] sorted = sort(src.toArray(), comparefn);
@@ -1767,11 +1750,11 @@
     @Override
     public SpecializedFunction.LinkLogic getLinkLogic(final Class<? extends LinkLogic> clazz) {
         if (clazz == PushLinkLogic.class) {
-            return pushLinkLogic == null ? new PushLinkLogic(this) : pushLinkLogic;
+            return pushLinkLogic == null ? new PushLinkLogic() : pushLinkLogic;
         } else if (clazz == PopLinkLogic.class) {
-            return popLinkLogic == null ? new PopLinkLogic(this) : pushLinkLogic;
+            return popLinkLogic == null ? new PopLinkLogic() : pushLinkLogic;
         } else if (clazz == ConcatLinkLogic.class) {
-            return concatLinkLogic == null ? new ConcatLinkLogic(this) : concatLinkLogic;
+            return concatLinkLogic == null ? new ConcatLinkLogic() : concatLinkLogic;
         }
         return null;
     }
@@ -1787,21 +1770,7 @@
      * modification switchpoint which is touched when length is written.
      */
     private static abstract class ArrayLinkLogic extends SpecializedFunction.LinkLogic {
-        private final NativeArray array;
-
-        protected ArrayLinkLogic(final NativeArray array) {
-            this.array = array;
-        }
-
-        private SwitchPoint getSwitchPoint() {
-            return array.lengthMadeNotWritableSwitchPoint;
-        }
-
-        private SwitchPoint newSwitchPoint() {
-            assert array.lengthMadeNotWritableSwitchPoint == null;
-            final SwitchPoint sp = new SwitchPoint();
-            array.lengthMadeNotWritableSwitchPoint = sp;
-            return sp;
+        protected ArrayLinkLogic() {
         }
 
         protected static ContinuousArrayData getContinuousArrayData(final Object self) {
@@ -1822,69 +1791,12 @@
         public Class<? extends Throwable> getRelinkException() {
             return ClassCastException.class;
         }
-
-        @Override
-        public boolean hasModificationSwitchPoints() {
-            return getSwitchPoint() != null;
-        }
-
-        @Override
-        public boolean hasModificationSwitchPoint(final int index) {
-            assert index == LENGTH_NOT_WRITABLE_SWITCHPOINT;
-            return hasModificationSwitchPoints();
-        }
-
-        @Override
-        public SwitchPoint getOrCreateModificationSwitchPoint(final int index) {
-            assert index == LENGTH_NOT_WRITABLE_SWITCHPOINT;
-            SwitchPoint sp = getSwitchPoint();
-            if (sp == null) {
-                sp = newSwitchPoint();
-            }
-            return sp;
-        }
-
-        @Override
-        public SwitchPoint[] getOrCreateModificationSwitchPoints() {
-            return new SwitchPoint[] { getOrCreateModificationSwitchPoint(LENGTH_NOT_WRITABLE_SWITCHPOINT) };
-        }
-
-        @Override
-        public void invalidateModificationSwitchPoint(final int index) {
-            assert index == LENGTH_NOT_WRITABLE_SWITCHPOINT;
-            invalidateModificationSwitchPoints();
-        }
-
-        @Override
-        public void invalidateModificationSwitchPoints() {
-            final SwitchPoint sp = getSwitchPoint();
-            assert sp != null : "trying to invalidate non-existant modified SwitchPoint";
-            if (!sp.hasBeenInvalidated()) {
-                SwitchPoint.invalidateAll(new SwitchPoint[] { sp });
-            }
-        }
-
-        @Override
-        public boolean hasInvalidatedModificationSwitchPoint(final int index) {
-            assert index == LENGTH_NOT_WRITABLE_SWITCHPOINT;
-            return hasInvalidatedModificationSwitchPoints();
-        }
-
-        @Override
-        public boolean hasInvalidatedModificationSwitchPoints() {
-            final SwitchPoint sp = getSwitchPoint();
-            return sp != null && !sp.hasBeenInvalidated();
-        }
     }
 
     /**
      * 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();
@@ -1915,10 +1827,6 @@
      * This is linker logic for optimistic pushes
      */
     private static final class PushLinkLogic extends ArrayLinkLogic {
-        private PushLinkLogic(final NativeArray array) {
-            super(array);
-        }
-
         @Override
         public boolean canLink(final Object self, final CallSiteDescriptor desc, final LinkRequest request) {
             return getContinuousArrayData(self) != null;
@@ -1929,10 +1837,6 @@
      * This is linker logic for optimistic pops
      */
     private static final class PopLinkLogic extends ArrayLinkLogic {
-        private PopLinkLogic(final NativeArray array) {
-            super(array);
-        }
-
         /**
          * We need to check if we are dealing with a continuous non empty array data here,
          * as pop with a primitive return value returns undefined for arrays with length 0
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeDebug.java	Tue Nov 11 17:27:44 2014 +0100
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeDebug.java	Wed Nov 12 14:12:01 2014 +0100
@@ -39,6 +39,7 @@
 import jdk.nashorn.internal.runtime.PropertyMap;
 import jdk.nashorn.internal.runtime.ScriptFunction;
 import jdk.nashorn.internal.runtime.ScriptObject;
+import jdk.nashorn.internal.runtime.ScriptRuntime;
 import jdk.nashorn.internal.runtime.events.RuntimeEvent;
 import jdk.nashorn.internal.runtime.linker.LinkerCallSite;
 import jdk.nashorn.internal.runtime.linker.NashornCallSiteDescriptor;
@@ -66,6 +67,36 @@
     }
 
     /**
+     * Return the ArrayData class for this ScriptObject
+     * @param self self
+     * @param obj script object to check
+     * @return ArrayData class, or undefined if no ArrayData is present
+     */
+    @Function(attributes = Attribute.NOT_ENUMERABLE, where = Where.CONSTRUCTOR)
+    public static Object getArrayDataClass(final Object self, final Object obj) {
+        try {
+            return ((ScriptObject)obj).getArray().getClass();
+        } catch (final ClassCastException e) {
+            return ScriptRuntime.UNDEFINED;
+        }
+    }
+
+    /**
+     * Return the ArrayData for this ScriptObject
+     * @param self self
+     * @param obj script object to check
+     * @return ArrayData, ArrayDatas have toString methods, return Undefined if data missing
+     */
+    @Function(attributes = Attribute.NOT_ENUMERABLE, where = Where.CONSTRUCTOR)
+    public static Object getArrayData(final Object self, final Object obj) {
+        try {
+            return ((ScriptObject)obj).getArray();
+        } catch (final ClassCastException e) {
+            return ScriptRuntime.UNDEFINED;
+        }
+    }
+
+    /**
      * Nashorn extension: get context, context utility
      *
      * @param self self reference
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/annotations/SpecializedFunction.java	Tue Nov 11 17:27:44 2014 +0100
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/annotations/SpecializedFunction.java	Wed Nov 12 14:12:01 2014 +0100
@@ -30,7 +30,6 @@
 import java.lang.annotation.RetentionPolicy;
 import java.lang.annotation.Target;
 import java.lang.invoke.MethodHandle;
-import java.lang.invoke.SwitchPoint;
 import jdk.internal.dynalink.CallSiteDescriptor;
 import jdk.internal.dynalink.linker.LinkRequest;
 import jdk.nashorn.internal.runtime.ScriptFunction;
@@ -62,10 +61,6 @@
          */
         public static final LinkLogic EMPTY_INSTANCE = new Empty();
 
-        private static final SwitchPoint[] INVALIDATED_SWITCHPOINTS = new SwitchPoint[0];
-
-        private SwitchPoint[] modificationSwitchPoints; //cache
-
         /** Empty link logic class - allow all linking, no guards */
         private static final class Empty extends LinkLogic {
             @Override
@@ -167,92 +162,6 @@
         }
 
         /**
-         * Return the modification SwitchPoint of a particular index from this OptimisticBuiltins
-         * If none exists, one is created and that one is return.
-         *
-         * The implementor must map indexes to specific SwitchPoints for specific events and keep
-         * track of what they mean, for example NativeArray.LENGTH_NOT_WRITABLE_SWITCHPOINT
-         * might be a useful index mapping
-         *
-         * @param index index for SwitchPoint to get or create
-         * @return modification SwitchPoint of particular index for the receiver
-         */
-        public SwitchPoint getOrCreateModificationSwitchPoint(final int index) {
-            return null;
-        }
-
-        /**
-         * Return the modification SwitchPoint from this OptimisticBuiltins. If none
-         * exists, one is created and that one is return.
-         *
-         * @return modification SwitchPoint for the receiver
-         */
-        public SwitchPoint[] getOrCreateModificationSwitchPoints() {
-            return null;
-        }
-
-        /**
-         * Hook to invalidate a modification SwitchPoint by index.
-         *
-         * @param index index for SwitchPoint to invalidate
-         */
-        public void invalidateModificationSwitchPoint(final int index) {
-            //empty
-        }
-
-        /**
-         * Hook to invalidate all modification SwitchPoints for a receiver
-         */
-        public void invalidateModificationSwitchPoints() {
-            //empty
-        }
-
-        /**
-         * Check whether the receiver has an invalidated modification SwitchPoint.
-         *
-         * @param  index index for the modification SwitchPoint
-         * @return true if the particular SwitchPoint at the index is invalidated
-         */
-        public boolean hasInvalidatedModificationSwitchPoint(final int index) {
-            return false;
-        }
-
-        /**
-         * Check whether at least one of the modification SwitchPoints has been
-         * invalidated
-         * @return true if one of the SwitchPoints has been invalidated
-         */
-        public boolean hasInvalidatedModificationSwitchPoints() {
-            return false;
-        }
-
-        /**
-         * Check whether this OptimisticBuiltins has a SwitchPoints of particular
-         * index.
-         *
-         * As creation overhead for a SwitchPoint is non-zero, we have to create them lazily instead of,
-         * e.g. in the constructor of every subclass.
-         *
-         * @param index index for the modification SwitchPoint
-         * @return true if a modification SwitchPoint exists, no matter if it has been invalidated or not
-         */
-        public boolean hasModificationSwitchPoint(final int index) {
-            return false;
-        }
-
-        /**
-         * Check whether this OptimisticBuiltins has SwitchPoints.
-         *
-         * As creation overhead for a SwitchPoint is non-zero, we have to create them lazily instead of,
-         * e.g. in the constructor of every subclass.
-         *
-         * @return true if a modification SwitchPoint exists, no matter if it has been invalidated or not
-         */
-        public boolean hasModificationSwitchPoints() {
-            return false;
-        }
-
-        /**
          * Check, given a link request and a receiver, if this specialization
          * fits This is used by the linker in {@link ScriptFunction} to figure
          * out if an optimistic builtin can be linked when first discovered
@@ -265,47 +174,9 @@
          *         pick a non specialized target
          */
         public boolean checkLinkable(final Object self, final CallSiteDescriptor desc, final LinkRequest request) {
-            // no matter what the modification switchpoints are, if any of them are invalidated,
-            // we can't link. Side effect is that if it's the first time we see this callsite,
-            // we have to create the SwitchPoint(s) so future modification switchpoint invalidations
-            // relink it
-            final SwitchPoint[] sps = getOrCreateModificationSwitchPoints(self);
-            if (sps == INVALIDATED_SWITCHPOINTS) {
-                // nope, can't do the fast link as this assumption
-                // has been invalidated already, e.g. length of an
-                // array set to not writable
-                return false;
-            }
-            modificationSwitchPoints = sps; //cache
-
             // check the link guard, if it says we can link, go ahead
             return canLink(self, desc, request);
         }
-
-        private SwitchPoint[] getOrCreateModificationSwitchPoints(final Object self) {
-            final SwitchPoint[] sps = getOrCreateModificationSwitchPoints(); //ask for all my switchpoints
-            if (sps != null) { //switchpoint exists, but some may be invalidated
-                for (final SwitchPoint sp : sps) {
-                    if (sp.hasBeenInvalidated()) {
-                        return INVALIDATED_SWITCHPOINTS;
-                    }
-                }
-            }
-            return sps;
-        }
-
-        /**
-         * Get the cached modification switchpoints. Only possible to do after a link
-         * check call has been performed, one that has answered "true", or you will get the
-         * wrong information.
-         *
-         * Should be used only from {@link ScriptFunction#findCallMethod}
-         *
-         * @return cached modification switchpoints for this callsite, null if none
-         */
-        public SwitchPoint[] getModificationSwitchPoints() {
-            return modificationSwitchPoints == null ? null : modificationSwitchPoints.clone();
-        }
     }
 
     /**
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/ScriptFunction.java	Tue Nov 11 17:27:44 2014 +0100
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/ScriptFunction.java	Wed Nov 12 14:12:01 2014 +0100
@@ -603,16 +603,6 @@
                     log.info("Linking optimistic builtin function: '", name, "' args=", Arrays.toString(request.getArguments()), " desc=", desc);
                 }
 
-                final SwitchPoint[] msps = linkLogic.getModificationSwitchPoints();
-                if (msps != null) {
-                    for (final SwitchPoint sp : msps) {
-                        if (sp != null) {
-                            assert !sp.hasBeenInvalidated();
-                            sps.add(sp);
-                        }
-                    }
-                }
-
                 exceptionGuard = linkLogic.getRelinkException();
 
                 break;
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/ScriptObject.java	Tue Nov 11 17:27:44 2014 +0100
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/ScriptObject.java	Wed Nov 12 14:12:01 2014 +0100
@@ -1352,12 +1352,9 @@
         final PropertyMap  selfMap = this.getMap();
 
         final ArrayData array  = getArray();
-        final long length      = array.length();
-
-        for (long i = 0; i < length; i = array.nextIndex(i)) {
-            if (array.has((int)i)) {
-                keys.add(JSType.toString(i));
-            }
+
+        for (final Iterator<Long> iter = array.indexIterator(); iter.hasNext(); ) {
+            keys.add(JSType.toString(iter.next().longValue()));
         }
 
         for (final Property property : selfMap.getProperties()) {
@@ -1516,12 +1513,12 @@
      *
      * @return {@code true} if 'length' property is non-writable
      */
-    public final boolean isLengthNotWritable() {
+    public boolean isLengthNotWritable() {
         return (flags & IS_LENGTH_NOT_WRITABLE) != 0;
     }
 
     /**
-     * Flag this object as having non-writable length property
+     * Flag this object as having non-writable length property.
      */
     public void setIsLengthNotWritable() {
         flags |= IS_LENGTH_NOT_WRITABLE;
@@ -3151,7 +3148,6 @@
      */
     public final void setObject(final FindProperty find, final int callSiteFlags, final String key, final Object value) {
         FindProperty f = find;
-
         if (f != null && f.isInherited() && !(f.getProperty() instanceof UserAccessorProperty)) {
             final boolean isScope = NashornCallSiteDescriptor.isScopeFlag(callSiteFlags);
             // If the start object of the find is not this object it means the property was found inside a
@@ -3177,7 +3173,6 @@
                 if (NashornCallSiteDescriptor.isStrictFlag(callSiteFlags)) {
                     throw typeError("property.not.writable", key, ScriptRuntime.safeToString(this));
                 }
-
                 return;
             }
 
@@ -3588,7 +3583,6 @@
             }
             return false;
         }
-
         return deleteObject(JSType.toObject(key), strict);
     }
 
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/arrays/ArrayData.java	Tue Nov 11 17:27:44 2014 +0100
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/arrays/ArrayData.java	Wed Nov 12 14:12:01 2014 +0100
@@ -30,6 +30,9 @@
 import java.lang.invoke.MethodHandles;
 import java.lang.reflect.Array;
 import java.nio.ByteBuffer;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
 import jdk.internal.dynalink.CallSiteDescriptor;
 import jdk.internal.dynalink.linker.GuardedInvocation;
 import jdk.internal.dynalink.linker.LinkRequest;
@@ -56,6 +59,21 @@
     public static final ArrayData EMPTY_ARRAY = new UntouchedArrayData();
 
     /**
+     * Length of the array data. Not necessarily length of the wrapped array.
+     * This is private to ensure that no one in a subclass is able to touch the length
+     * without going through {@link setLength}. This is used to implement
+     * {@link LengthNotWritableFilter}s, ensuring that there are no ways past
+     * a {@link setLength} function replaced by a nop
+     */
+    private long length;
+
+    /**
+     * Method handle to throw an {@link UnwarrantedOptimismException} when getting an element
+     * of the wrong type
+     */
+    protected static final CompilerConstants.Call THROW_UNWARRANTED = staticCall(MethodHandles.lookup(), ArrayData.class, "throwUnwarranted", void.class, ArrayData.class, int.class, int.class);
+
+    /**
      * Immutable empty array to get ScriptObjects started.
      * Use the same array and convert it to mutable as soon as it is modified
      */
@@ -82,7 +100,7 @@
 
         @Override
         public ContinuousArrayData copy() {
-            return new UntouchedArrayData((int)length);
+            return new UntouchedArrayData((int)length());
         }
 
         @Override
@@ -113,6 +131,16 @@
         }
 
         @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 void shiftLeft(final int by) {
             //nop, always empty or we wouldn't be of this class
         }
@@ -173,16 +201,6 @@
         }
 
         @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;
         }
@@ -231,17 +249,6 @@
     };
 
     /**
-     * Length of the array data. Not necessarily length of the wrapped array.
-     */
-    protected long length;
-
-    /**
-     * Method handle to throw an {@link UnwarrantedOptimismException} when getting an element
-     * of the wrong type
-     */
-    protected static final CompilerConstants.Call THROW_UNWARRANTED = staticCall(MethodHandles.lookup(), ArrayData.class, "throwUnwarranted", void.class, ArrayData.class, int.class, int.class);
-
-    /**
      * Constructor
      * @param length Virtual length of the array.
      */
@@ -394,6 +401,16 @@
     }
 
     /**
+     * Prevent this array from having its length reset
+     *
+     * @param underlying the underlying ArrayDAta to wrap in the non extensible filter
+     * @return new array data, filtered
+     */
+    public static final ArrayData setIsLengthNotWritable(final ArrayData underlying) {
+        return new LengthNotWritableFilter(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
@@ -446,6 +463,22 @@
     }
 
     /**
+     * Increase length by 1
+     * @return the new length, not the old one (i.e. pre-increment)
+     */
+    protected final long increaseLength() {
+        return ++this.length;
+    }
+
+    /**
+     * Decrease length by 1.
+     * @return the new length, not the old one (i.e. pre-decrement)
+     */
+    protected final long decreaseLength() {
+        return --this.length;
+    }
+
+    /**
      * Shift the array data left
      *
      * TODO: explore start at an index and not at zero, to make these operations
@@ -454,7 +487,7 @@
      *
      * @param by offset to shift
      */
-    public abstract void shiftLeft(int by);
+    public abstract void shiftLeft(final int by);
 
     /**
      * Shift the array right
@@ -463,7 +496,7 @@
 
      * @return New arraydata (or same)
      */
-    public abstract ArrayData shiftRight(int by);
+    public abstract ArrayData shiftRight(final int by);
 
     /**
      * Ensure that the given index exists and won't fail subsequent
@@ -471,7 +504,7 @@
      * @param safeIndex the index to ensure wont go out of bounds
      * @return new array data (or same)
      */
-    public abstract ArrayData ensure(long safeIndex);
+    public abstract ArrayData ensure(final long safeIndex);
 
     /**
      * Shrink the array to a new length, may or may not retain the
@@ -481,7 +514,7 @@
      *
      * @return new array data (or same)
      */
-    public abstract ArrayData shrink(long newLength);
+    public abstract ArrayData shrink(final long newLength);
 
     /**
      * Set an object value at a given index
@@ -491,7 +524,7 @@
      * @param strict are we in strict mode
      * @return new array data (or same)
      */
-    public abstract ArrayData set(int index, Object value, boolean strict);
+    public abstract ArrayData set(final int index, final Object value, final boolean strict);
 
     /**
      * Set an int value at a given index
@@ -501,7 +534,7 @@
      * @param strict are we in strict mode
      * @return new array data (or same)
      */
-    public abstract ArrayData set(int index, int value, boolean strict);
+    public abstract ArrayData set(final int index, final int value, final boolean strict);
 
     /**
      * Set a long value at a given index
@@ -511,7 +544,7 @@
      * @param strict are we in strict mode
      * @return new array data (or same)
      */
-    public abstract ArrayData set(int index, long value, boolean strict);
+    public abstract ArrayData set(final int index, final long value, final boolean strict);
 
     /**
      * Set an double value at a given index
@@ -521,7 +554,7 @@
      * @param strict are we in strict mode
      * @return new array data (or same)
      */
-    public abstract ArrayData set(int index, double value, boolean strict);
+    public abstract ArrayData set(final int index, final double value, final boolean strict);
 
     /**
      * Set an empty value at a given index. Should only affect Object array.
@@ -552,7 +585,7 @@
      * @param index the index
      * @return the value
      */
-    public abstract int getInt(int index);
+    public abstract int getInt(final int index);
 
     /**
      * Returns the optimistic type of this array data. Basically, when an array data object needs to throw an
@@ -581,7 +614,7 @@
      * @param index the index
      * @return the value
      */
-    public abstract long getLong(int index);
+    public abstract long getLong(final int index);
 
     /**
      * Get optimistic long - default is that it's impossible. Overridden
@@ -601,7 +634,7 @@
      * @param index the index
      * @return the value
      */
-    public abstract double getDouble(int index);
+    public abstract double getDouble(final int index);
 
     /**
      * Get optimistic double - default is that it's impossible. Overridden
@@ -621,14 +654,14 @@
      * @param index the index
      * @return the value
      */
-    public abstract Object getObject(int index);
+    public abstract Object getObject(final int index);
 
     /**
      * Tests to see if an entry exists (avoids boxing.)
      * @param index the index
      * @return true if entry exists
      */
-    public abstract boolean has(int index);
+    public abstract boolean has(final int index);
 
     /**
      * Returns if element at specific index can be deleted or not.
@@ -674,7 +707,7 @@
      * @param index the index
      * @return new array data (or same)
      */
-    public abstract ArrayData delete(int index);
+    public abstract ArrayData delete(final int index);
 
     /**
      * Delete a given range from this array;
@@ -684,7 +717,7 @@
      *
      * @return new ArrayData after deletion
      */
-    public abstract ArrayData delete(long fromIndex, long toIndex);
+    public abstract ArrayData delete(final long fromIndex, final long toIndex);
 
     /**
      * Convert the ArrayData to one with a different element type
@@ -694,7 +727,7 @@
      * @param type new element type
      * @return new array data
      */
-    public abstract ArrayData convert(Class<?> type);
+    public abstract ArrayData convert(final Class<?> type);
 
     /**
      * Push an array of items to the end of the array
@@ -778,7 +811,7 @@
      * @param to   end index + 1
      * @return new array data
      */
-    public abstract ArrayData slice(long from, long to);
+    public abstract ArrayData slice(final long from, final long to);
 
     /**
      * Fast splice operation. This just modifies the array according to the number of
@@ -823,6 +856,34 @@
     }
 
     /**
+     * Return a list of keys in the array for the iterators
+     * @return iterator key list
+     */
+    protected List<Long> computeIteratorKeys() {
+        final List<Long> keys = new ArrayList<>();
+
+        final long len = length();
+        for (long i = 0L; i < len; i = nextIndex(i)) {
+            if (has((int)i)) {
+                keys.add(i);
+            }
+        }
+
+        return keys;
+    }
+
+    /**
+     * Return an iterator that goes through all indexes of elements
+     * in this array. This includes those after array.length if
+     * they exist
+     *
+     * @return iterator
+     */
+    public Iterator<Long> indexIterator() {
+        return computeIteratorKeys().iterator();
+    }
+
+    /**
      * Exponential growth function for array size when in
      * need of resizing.
      *
@@ -841,7 +902,7 @@
      *
      * @return the next index
      */
-    public long nextIndex(final long index) {
+    long nextIndex(final long index) {
         return index + 1;
     }
 
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/arrays/ArrayFilter.java	Tue Nov 11 17:27:44 2014 +0100
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/arrays/ArrayFilter.java	Wed Nov 12 14:12:01 2014 +0100
@@ -39,7 +39,7 @@
     protected ArrayData underlying;
 
     ArrayFilter(final ArrayData underlying) {
-        super(underlying.length);
+        super(underlying.length());
         this.underlying = underlying;
     }
 
@@ -70,62 +70,55 @@
     @Override
     public void shiftLeft(final int by) {
         underlying.shiftLeft(by);
-        setLength(underlying.length);
+        setLength(underlying.length());
     }
 
     @Override
     public ArrayData shiftRight(final int by) {
         underlying = underlying.shiftRight(by);
-        setLength(underlying.length);
-
+        setLength(underlying.length());
         return this;
     }
 
     @Override
     public ArrayData ensure(final long safeIndex) {
         underlying = underlying.ensure(safeIndex);
-        setLength(underlying.length);
-
+        setLength(underlying.length());
         return this;
     }
 
     @Override
     public ArrayData shrink(final long newLength) {
         underlying = underlying.shrink(newLength);
-        setLength(underlying.length);
-
+        setLength(underlying.length());
         return this;
     }
 
     @Override
     public ArrayData set(final int index, final Object value, final boolean strict) {
         underlying = underlying.set(index, value, strict);
-        setLength(underlying.length);
-
+        setLength(underlying.length());
         return this;
     }
 
     @Override
     public ArrayData set(final int index, final int value, final boolean strict) {
         underlying = underlying.set(index, value, strict);
-        setLength(underlying.length);
-
+        setLength(underlying.length());
         return this;
     }
 
     @Override
     public ArrayData set(final int index, final long value, final boolean strict) {
         underlying = underlying.set(index, value, strict);
-        setLength(underlying.length);
-
+        setLength(underlying.length());
         return this;
     }
 
     @Override
     public ArrayData set(final int index, final double value, final boolean strict) {
         underlying = underlying.set(index, value, strict);
-        setLength(underlying.length);
-
+        setLength(underlying.length());
         return this;
     }
 
@@ -189,29 +182,28 @@
     @Override
     public ArrayData delete(final int index) {
         underlying = underlying.delete(index);
-        setLength(underlying.length);
+        setLength(underlying.length());
         return this;
     }
 
     @Override
     public ArrayData delete(final long from, final long to) {
         underlying = underlying.delete(from, to);
-        setLength(underlying.length);
+        setLength(underlying.length());
         return this;
     }
 
     @Override
     public ArrayData convert(final Class<?> type) {
         underlying = underlying.convert(type);
-        setLength(underlying.length);
+        setLength(underlying.length());
         return this;
     }
 
     @Override
     public Object pop() {
         final Object value = underlying.pop();
-        setLength(underlying.length);
-
+        setLength(underlying.length());
         return value;
     }
 
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/arrays/ContinuousArrayData.java	Tue Nov 11 17:27:44 2014 +0100
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/arrays/ContinuousArrayData.java	Wed Nov 12 14:12:01 2014 +0100
@@ -65,7 +65,7 @@
      * @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 has(index) || (index == length() && ensure(index) == this);
     }
 
     /**
@@ -73,7 +73,7 @@
      * @return true if empty
      */
     public boolean isEmpty() {
-        return length == 0L;
+        return length() == 0L;
     }
 
     /**
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/arrays/DeletedArrayFilter.java	Tue Nov 11 17:27:44 2014 +0100
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/arrays/DeletedArrayFilter.java	Wed Nov 12 14:12:01 2014 +0100
@@ -38,8 +38,7 @@
 
     DeletedArrayFilter(final ArrayData underlying) {
         super(underlying);
-
-        this.deleted = new BitVector(underlying.length);
+        this.deleted = new BitVector(underlying.length());
     }
 
     @Override
@@ -79,25 +78,24 @@
     @Override
     public void shiftLeft(final int by) {
         super.shiftLeft(by);
-        deleted.shiftLeft(by, length);
+        deleted.shiftLeft(by, length());
     }
 
     @Override
     public ArrayData shiftRight(final int by) {
         super.shiftRight(by);
-        deleted.shiftRight(by, length);
-
+        deleted.shiftRight(by, length());
         return this;
     }
 
     @Override
     public ArrayData ensure(final long safeIndex) {
-        if (safeIndex >= SparseArrayData.MAX_DENSE_LENGTH && safeIndex >= length) {
+        if (safeIndex >= SparseArrayData.MAX_DENSE_LENGTH && safeIndex >= length()) {
             return new SparseArrayData(this, safeIndex + 1);
         }
 
         super.ensure(safeIndex);
-        deleted.resize(length);
+        deleted.resize(length());
 
         return this;
     }
@@ -105,36 +103,31 @@
     @Override
     public ArrayData shrink(final long newLength) {
         super.shrink(newLength);
-        deleted.resize(length);
-
+        deleted.resize(length());
         return this;
     }
 
     @Override
     public ArrayData set(final int index, final Object value, final boolean strict) {
         deleted.clear(ArrayIndex.toLongIndex(index));
-
         return super.set(index, value, strict);
     }
 
     @Override
     public ArrayData set(final int index, final int value, final boolean strict) {
         deleted.clear(ArrayIndex.toLongIndex(index));
-
         return super.set(index, value, strict);
     }
 
     @Override
     public ArrayData set(final int index, final long value, final boolean strict) {
         deleted.clear(ArrayIndex.toLongIndex(index));
-
         return super.set(index, value, strict);
     }
 
     @Override
     public ArrayData set(final int index, final double value, final boolean strict) {
         deleted.clear(ArrayIndex.toLongIndex(index));
-
         return super.set(index, value, strict);
     }
 
@@ -146,7 +139,7 @@
     @Override
     public ArrayData delete(final int index) {
         final long longIndex = ArrayIndex.toLongIndex(index);
-        assert longIndex >= 0 && longIndex < length;
+        assert longIndex >= 0 && longIndex < length();
         deleted.set(longIndex);
         underlying.setEmpty(index);
         return this;
@@ -154,7 +147,7 @@
 
     @Override
     public ArrayData delete(final long fromIndex, final long toIndex) {
-        assert fromIndex >= 0 && fromIndex <= toIndex && toIndex < length;
+        assert fromIndex >= 0 && fromIndex <= toIndex && toIndex < length();
         deleted.setRange(fromIndex, toIndex + 1);
         underlying.setEmpty(fromIndex, toIndex);
         return this;
@@ -162,7 +155,7 @@
 
     @Override
     public Object pop() {
-        final long index = length - 1;
+        final long index = length() - 1;
 
         if (super.has((int)index)) {
             final boolean isDeleted = deleted.isSet(index);
@@ -179,7 +172,7 @@
         final ArrayData newArray = underlying.slice(from, to);
         final DeletedArrayFilter newFilter = new DeletedArrayFilter(newArray);
         newFilter.getDeleted().copy(deleted);
-        newFilter.getDeleted().shiftLeft(from, newFilter.length);
+        newFilter.getDeleted().shiftLeft(from, newFilter.length());
 
         return newFilter;
     }
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/arrays/DeletedRangeArrayFilter.java	Tue Nov 11 17:27:44 2014 +0100
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/arrays/DeletedRangeArrayFilter.java	Wed Nov 12 14:12:01 2014 +0100
@@ -42,10 +42,10 @@
     }
 
     private static ArrayData maybeSparse(final ArrayData underlying, final long hi) {
-        if(hi < SparseArrayData.MAX_DENSE_LENGTH || underlying instanceof SparseArrayData) {
+        if (hi < SparseArrayData.MAX_DENSE_LENGTH || underlying instanceof SparseArrayData) {
             return underlying;
         }
-        return new SparseArrayData(underlying, underlying.length);
+        return new SparseArrayData(underlying, underlying.length());
     }
 
     private boolean isEmpty() {
@@ -93,7 +93,7 @@
 
     @Override
     public ArrayData ensure(final long safeIndex) {
-        if (safeIndex >= SparseArrayData.MAX_DENSE_LENGTH && safeIndex >= length) {
+        if (safeIndex >= SparseArrayData.MAX_DENSE_LENGTH && safeIndex >= length()) {
             return new SparseArrayData(this, safeIndex + 1);
         }
 
@@ -110,7 +110,7 @@
     @Override
     public ArrayData shiftRight(final int by) {
         super.shiftRight(by);
-        final long len = length;
+        final long len = length();
         lo = Math.min(len, lo + by);
         hi = Math.min(len - 1, hi + by);
 
@@ -238,7 +238,7 @@
 
     @Override
     public Object pop() {
-        final int index = (int)length - 1;
+        final int index = (int)length() - 1;
         if (super.has(index)) {
             final boolean isDeleted = isDeleted(index);
             final Object value      = super.pop();
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/arrays/FrozenArrayFilter.java	Tue Nov 11 17:27:44 2014 +0100
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/arrays/FrozenArrayFilter.java	Wed Nov 12 14:12:01 2014 +0100
@@ -26,9 +26,9 @@
 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.PropertyDescriptor;
+import jdk.nashorn.internal.runtime.ScriptRuntime;
 
 /**
  * ArrayData after the array has been frozen by Object.freeze call.
@@ -79,4 +79,15 @@
         }
         return this;
     }
+
+    @Override
+    public ArrayData push(final boolean strict, final Object... items) {
+        return this; //nop
+    }
+
+    @Override
+    public Object pop() {
+        final int len = (int)underlying.length();
+        return len == 0 ? ScriptRuntime.UNDEFINED : underlying.getObject(len - 1);
+    }
 }
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/arrays/IntArrayData.java	Tue Nov 11 17:27:44 2014 +0100
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/arrays/IntArrayData.java	Wed Nov 12 14:12:01 2014 +0100
@@ -119,22 +119,24 @@
 
     @Override
     public IntArrayData copy() {
-        return new IntArrayData(array.clone(), (int)length);
+        return new IntArrayData(array.clone(), (int)length());
     }
 
     @Override
     public Object asArrayOfType(final Class<?> componentType) {
         if (componentType == int.class) {
-            return array.length == length ? array.clone() : Arrays.copyOf(array, (int)length);
+            final int len = (int)length();
+            return array.length == len ? array.clone() : Arrays.copyOf(array, len);
         }
         return super.asArrayOfType(componentType);
     }
 
     private Object[] toObjectArray(final boolean trim) {
-        assert length <= array.length : "length exceeds internal array size";
-        final Object[] oarray = new Object[trim ? (int)length : array.length];
+        assert length() <= array.length : "length exceeds internal array size";
+        final int len = (int)length();
+        final Object[] oarray = new Object[trim ? len : array.length];
 
-        for (int index = 0; index < length; index++) {
+        for (int index = 0; index < len; index++) {
             oarray[index] = Integer.valueOf(array[index]);
         }
 
@@ -142,10 +144,11 @@
     }
 
     private double[] toDoubleArray() {
-        assert length <= array.length : "length exceeds internal array size";
+        assert length() <= array.length : "length exceeds internal array size";
+        final int len = (int)length();
         final double[] darray = new double[array.length];
 
-        for (int index = 0; index < length; index++) {
+        for (int index = 0; index < len; index++) {
             darray[index] = array[index];
         }
 
@@ -153,10 +156,11 @@
     }
 
     private long[] toLongArray() {
-        assert length <= array.length : "length exceeds internal array size";
+        assert length() <= array.length : "length exceeds internal array size";
+        final int len = (int)length();
         final long[] larray = new long[array.length];
 
-        for (int index = 0; index < length; index++) {
+        for (int index = 0; index < len; index++) {
             larray[index] = array[index];
         }
 
@@ -164,15 +168,15 @@
     }
 
     private LongArrayData convertToLong() {
-        return new LongArrayData(toLongArray(), (int)length);
+        return new LongArrayData(toLongArray(), (int)length());
     }
 
     private NumberArrayData convertToDouble() {
-        return new NumberArrayData(toDoubleArray(), (int)length);
+        return new NumberArrayData(toDoubleArray(), (int)length());
     }
 
     private ObjectArrayData convertToObject() {
-        return new ObjectArrayData(toObjectArray(false), (int)length);
+        return new ObjectArrayData(toObjectArray(false), (int)length());
     }
 
     @Override
@@ -196,7 +200,7 @@
 
     @Override
     public ArrayData shiftRight(final int by) {
-        final ArrayData newData = ensure(by + length - 1);
+        final ArrayData newData = ensure(by + length() - 1);
         if (newData != this) {
             newData.shiftRight(by);
             return newData;
@@ -241,7 +245,7 @@
     @Override
     public ArrayData set(final int index, final int value, final boolean strict) {
         array[index] = value;
-        setLength(Math.max(index + 1, length));
+        setLength(Math.max(index + 1, length()));
 
         return this;
     }
@@ -250,7 +254,7 @@
     public ArrayData set(final int index, final long value, final boolean strict) {
         if (JSType.isRepresentableAsInt(value)) {
             array[index] = JSType.toInt32(value);
-            setLength(Math.max(index + 1, length));
+            setLength(Math.max(index + 1, length()));
             return this;
         }
 
@@ -261,7 +265,7 @@
     public ArrayData set(final int index, final double value, final boolean strict) {
         if (JSType.isRepresentableAsInt(value)) {
             array[index] = (int)(long)value;
-            setLength(Math.max(index + 1, length));
+            setLength(Math.max(index + 1, length()));
             return this;
         }
 
@@ -305,7 +309,7 @@
 
     @Override
     public boolean has(final int index) {
-        return 0 <= index && index < length;
+        return 0 <= index && index < length();
     }
 
     @Override
@@ -320,11 +324,12 @@
 
     @Override
     public Object pop() {
-        if (length == 0) {
+        final int len = (int)length();
+        if (len == 0) {
             return ScriptRuntime.UNDEFINED;
         }
 
-        final int newLength = (int)length - 1;
+        final int newLength = len - 1;
         final int elem = array[newLength];
         array[newLength] = 0;
         setLength(newLength);
@@ -334,12 +339,12 @@
 
     @Override
     public ArrayData slice(final long from, final long to) {
-        return new IntArrayData(Arrays.copyOfRange(array, (int)from, (int)to), (int)(to - (from < 0 ? from + length : from)));
+        return new IntArrayData(Arrays.copyOfRange(array, (int)from, (int)to), (int)(to - (from < 0 ? from + length() : from)));
     }
 
     @Override
     public final ArrayData push(final boolean strict, final int item) {
-        final long      len     = length;
+        final long      len     = length();
         final ArrayData newData = ensure(len);
         if (newData == this) {
             array[(int)len] = item;
@@ -350,7 +355,7 @@
 
     @Override
     public ArrayData fastSplice(final int start, final int removed, final int added) throws UnsupportedOperationException {
-        final long oldLength = length;
+        final long oldLength = length();
         final long newLength = oldLength - removed + added;
         if (newLength > SparseArrayData.MAX_DENSE_LENGTH && newLength > array.length) {
             throw new UnsupportedOperationException();
@@ -384,21 +389,21 @@
 
     @Override
     public long fastPush(final int arg) {
-        final int len = (int)length;
+        final int len = (int)length();
         if (len == array.length) {
             array = Arrays.copyOf(array, nextSize(len));
         }
         array[len] = arg;
-        return ++length;
+        return increaseLength();
     }
 
     //length must not be zero
     @Override
     public int fastPopInt() {
-        if (length == 0) {
+        if (length() == 0) {
             throw new ClassCastException(); //relink
         }
-        final int newLength = (int)--length;
+        final int newLength = (int)decreaseLength();
         final int elem = array[newLength];
         array[newLength] = 0;
         return elem;
@@ -421,8 +426,8 @@
 
     @Override
     public ContinuousArrayData fastConcat(final ContinuousArrayData otherData) {
-        final int   otherLength = (int)otherData.length;
-        final int   thisLength  = (int)length;
+        final int   otherLength = (int)otherData.length();
+        final int   thisLength  = (int)length();
         assert otherLength > 0 && thisLength > 0;
 
         final int[] otherArray  = ((IntArrayData)otherData).array;
@@ -437,7 +442,7 @@
 
     @Override
     public String toString() {
-        assert length <= array.length : length + " > " + array.length;
-        return getClass().getSimpleName() + ':' + Arrays.toString(Arrays.copyOf(array, (int)length));
+        assert length() <= array.length : length() + " > " + array.length;
+        return getClass().getSimpleName() + ':' + Arrays.toString(Arrays.copyOf(array, (int)length()));
     }
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/arrays/LengthNotWritableFilter.java	Wed Nov 12 14:12:01 2014 +0100
@@ -0,0 +1,198 @@
+package jdk.nashorn.internal.runtime.arrays;
+
+import java.util.Iterator;
+import java.util.List;
+import java.util.SortedMap;
+import java.util.TreeMap;
+import jdk.nashorn.internal.runtime.JSType;
+import jdk.nashorn.internal.runtime.ScriptRuntime;
+
+/**
+ * Filter to use for ArrayData where the length is not writable.
+ * The default behavior is just to ignore {@link ArrayData#setLength}
+ */
+final class LengthNotWritableFilter extends ArrayFilter {
+    private final SortedMap<Long, Object> extraElements; //elements with index >= length
+
+    /**
+     * Constructor
+     * @param underlying array
+     */
+    LengthNotWritableFilter(final ArrayData underlying) {
+        this(underlying, new TreeMap<>());
+    }
+
+    private LengthNotWritableFilter(final ArrayData underlying, final SortedMap<Long, Object> extraElements) {
+        super(underlying);
+        this.extraElements = extraElements;
+    }
+
+    @Override
+    public ArrayData copy() {
+        return new LengthNotWritableFilter(underlying.copy(), new TreeMap<>(extraElements));
+    }
+
+    @Override
+    public boolean has(final int index) {
+        return super.has(index) || extraElements.containsKey((long)index);
+    }
+
+    /**
+     * Set the length of the data array
+     *
+     * @param length the new length for the data array
+     */
+    @Override
+    public void setLength(final long length) {
+        //empty - setting length for a LengthNotWritableFilter is always a nop
+    }
+
+    @Override
+    public ArrayData ensure(final long index) {
+        return this;
+    }
+
+    @Override
+    public ArrayData slice(final long from, final long to) {
+        //return array[from...to), or array[from...length] if undefined, in this case not as we are an ArrayData
+        return new LengthNotWritableFilter(underlying.slice(from, to), extraElements.subMap(from, to));
+    }
+
+    private boolean checkAdd(final long index, final Object value) {
+        if (index >= length()) {
+            extraElements.put(index, value);
+            return true;
+        }
+        return false;
+    }
+
+    private Object get(final long index) {
+        final Object obj = extraElements.get(index);
+        if (obj == null) {
+            return ScriptRuntime.UNDEFINED;
+        }
+        return obj;
+    }
+
+    @Override
+    public int getInt(final int index) {
+        if (index >= length()) {
+            return JSType.toInt32(get(index));
+        }
+        return underlying.getInt(index);
+    }
+
+    @Override
+    public int getIntOptimistic(final int index, final int programPoint) {
+        if (index >= length()) {
+            return JSType.toInt32Optimistic(get(index), programPoint);
+        }
+        return underlying.getIntOptimistic(index, programPoint);
+    }
+
+    @Override
+    public long getLong(final int index) {
+        if (index >= length()) {
+            return JSType.toLong(get(index));
+        }
+        return underlying.getLong(index);
+    }
+
+    @Override
+    public long getLongOptimistic(final int index, final int programPoint) {
+        if (index >= length()) {
+            return JSType.toLongOptimistic(get(index), programPoint);
+        }
+        return underlying.getLongOptimistic(index, programPoint);
+    }
+
+    @Override
+    public double getDouble(final int index) {
+        if (index >= length()) {
+            return JSType.toNumber(get(index));
+        }
+        return underlying.getDouble(index);
+    }
+
+    @Override
+    public double getDoubleOptimistic(final int index, final int programPoint) {
+        if (index >= length()) {
+            return JSType.toNumberOptimistic(get(index), programPoint);
+        }
+        return underlying.getDoubleOptimistic(index, programPoint);
+    }
+
+    @Override
+    public Object getObject(final int index) {
+        if (index >= length()) {
+            return get(index);
+        }
+        return underlying.getObject(index);
+    }
+
+    @Override
+    public ArrayData set(final int index, final Object value, final boolean strict) {
+        if (checkAdd(index, value)) {
+            return this;
+        }
+        underlying = underlying.set(index, value, strict);
+        return this;
+    }
+
+    @Override
+    public ArrayData set(final int index, final int value, final boolean strict) {
+        if (checkAdd(index, value)) {
+            return this;
+        }
+        underlying = underlying.set(index, value, strict);
+        return this;
+    }
+
+    @Override
+    public ArrayData set(final int index, final long value, final boolean strict) {
+        if (checkAdd(index, value)) {
+            return this;
+        }
+        underlying = underlying.set(index, value, strict);
+        return this;
+    }
+
+    @Override
+    public ArrayData set(final int index, final double value, final boolean strict) {
+        if (checkAdd(index, value)) {
+            return this;
+        }
+        underlying = underlying.set(index, value, strict);
+        return this;
+    }
+
+    @Override
+    public ArrayData delete(final int index) {
+        extraElements.remove(index);
+        underlying = underlying.delete(index);
+        return this;
+    }
+
+    @Override
+    public ArrayData delete(final long fromIndex, final long toIndex) {
+        for (final Iterator<Long> iter = extraElements.keySet().iterator(); iter.hasNext();) {
+            final long next = iter.next();
+            if (next >= fromIndex && next <= toIndex) {
+                iter.remove();
+            }
+            if (next > toIndex) { //ordering guaranteed because TreeSet
+                break;
+            }
+        }
+        underlying = underlying.delete(fromIndex, toIndex);
+        return this;
+    }
+
+    @Override
+    public Iterator<Long> indexIterator() {
+        final List<Long> keys = computeIteratorKeys();
+        keys.addAll(extraElements.keySet()); //even if they are outside length this is fine
+        return keys.iterator();
+    }
+
+}
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/arrays/LongArrayData.java	Tue Nov 11 17:27:44 2014 +0100
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/arrays/LongArrayData.java	Wed Nov 12 14:12:01 2014 +0100
@@ -27,7 +27,6 @@
 
 import static jdk.nashorn.internal.codegen.CompilerConstants.specialCall;
 import static jdk.nashorn.internal.lookup.Lookup.MH;
-
 import java.lang.invoke.MethodHandle;
 import java.lang.invoke.MethodHandles;
 import java.util.Arrays;
@@ -77,7 +76,7 @@
 
     @Override
     public LongArrayData copy() {
-        return new LongArrayData(array.clone(), (int)length);
+        return new LongArrayData(array.clone(), (int)length());
     }
 
     @Override
@@ -86,10 +85,11 @@
     }
 
     private Object[] toObjectArray(final boolean trim) {
-        assert length <= array.length : "length exceeds internal array size";
-        final Object[] oarray = new Object[trim ? (int)length : array.length];
+        assert length() <= array.length : "length exceeds internal array size";
+        final int len = (int)length();
+        final Object[] oarray = new Object[trim ? len : array.length];
 
-        for (int index = 0; index < length; index++) {
+        for (int index = 0; index < len; index++) {
             oarray[index] = Long.valueOf(array[index]);
         }
 
@@ -99,16 +99,18 @@
     @Override
     public Object asArrayOfType(final Class<?> componentType) {
         if (componentType == long.class) {
-            return array.length == length ? array.clone() : Arrays.copyOf(array, (int)length);
+            final int len = (int)length();
+            return array.length == len ? array.clone() : Arrays.copyOf(array, len);
         }
         return super.asArrayOfType(componentType);
     }
 
     private double[] toDoubleArray() {
-        assert length <= array.length : "length exceeds internal array size";
+        assert length() <= array.length : "length exceeds internal array size";
+        final int len = (int)length();
         final double[] darray = new double[array.length];
 
-        for (int index = 0; index < length; index++) {
+        for (int index = 0; index < len; index++) {
             darray[index] = array[index];
         }
 
@@ -120,7 +122,7 @@
         if (type == Integer.class || type == Long.class) {
             return this;
         }
-        final int len = (int)length;
+        final int len = (int)length();
         if (type == Double.class) {
             return new NumberArrayData(toDoubleArray(), len);
         }
@@ -134,7 +136,7 @@
 
     @Override
     public ArrayData shiftRight(final int by) {
-        final ArrayData newData = ensure(by + length - 1);
+        final ArrayData newData = ensure(by + length() - 1);
         if (newData != this) {
             newData.shiftRight(by);
             return newData;
@@ -179,14 +181,14 @@
     @Override
     public ArrayData set(final int index, final int value, final boolean strict) {
         array[index] = value;
-        setLength(Math.max(index + 1, length));
+        setLength(Math.max(index + 1, length()));
         return this;
     }
 
     @Override
     public ArrayData set(final int index, final long value, final boolean strict) {
         array[index] = value;
-        setLength(Math.max(index + 1, length));
+        setLength(Math.max(index + 1, length()));
         return this;
     }
 
@@ -194,7 +196,7 @@
     public ArrayData set(final int index, final double value, final boolean strict) {
         if (JSType.isRepresentableAsLong(value)) {
             array[index] = (long)value;
-            setLength(Math.max(index + 1, length));
+            setLength(Math.max(index + 1, length()));
             return this;
         }
         return convert(Double.class).set(index, value, strict);
@@ -265,7 +267,7 @@
 
     @Override
     public boolean has(final int index) {
-        return 0 <= index && index < length;
+        return 0 <= index && index < length();
     }
 
     @Override
@@ -280,11 +282,12 @@
 
     @Override
     public Object pop() {
-        if (length == 0) {
+        final int len = (int)length();
+        if (len == 0) {
             return ScriptRuntime.UNDEFINED;
         }
 
-        final int newLength = (int)length - 1;
+        final int newLength = len - 1;
         final long elem = array[newLength];
         array[newLength] = 0;
         setLength(newLength);
@@ -294,14 +297,14 @@
 
     @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      len     = length;
+        final long      len     = length();
         final ArrayData newData = ensure(len);
         if (newData == this) {
             array[(int)len] = item;
@@ -312,7 +315,7 @@
 
     @Override
     public ArrayData fastSplice(final int start, final int removed, final int added) throws UnsupportedOperationException {
-        final long oldLength = length;
+        final long oldLength = length();
         final long newLength = oldLength - removed + added;
         if (newLength > SparseArrayData.MAX_DENSE_LENGTH && newLength > array.length) {
             throw new UnsupportedOperationException();
@@ -345,20 +348,20 @@
 
     @Override
     public long fastPush(final long arg) {
-        final int len = (int)length;
+        final int len = (int)length();
         if (len == array.length) {
             array = Arrays.copyOf(array, nextSize(len));
         }
         array[len] = arg;
-        return ++length;
+        return increaseLength();
     }
 
     @Override
     public long fastPopLong() {
-        if (length == 0) {
-            throw new ClassCastException();
+        if (length() == 0) {
+            throw new ClassCastException(); //undefined result
         }
-        final int newLength = (int)--length;
+        final int newLength = (int)decreaseLength();
         final long elem = array[newLength];
         array[newLength] = 0;
         return elem;
@@ -376,8 +379,8 @@
 
     @Override
     public ContinuousArrayData fastConcat(final ContinuousArrayData otherData) {
-        final int   otherLength = (int)otherData.length;
-        final int   thisLength  = (int)length;
+        final int   otherLength = (int)otherData.length();
+        final int   thisLength  = (int)length();
         assert otherLength > 0 && thisLength > 0;
 
         final long[] otherArray  = ((LongArrayData)otherData).array;
@@ -392,13 +395,14 @@
 
     @Override
     public String toString() {
-        assert length <= array.length : length + " > " + array.length;
+        assert length() <= array.length : length() + " > " + array.length;
 
         final StringBuilder sb = new StringBuilder(getClass().getSimpleName()).
                 append(": [");
-        for (int i = 0; i < length; i++) {
+        final int len = (int)length();
+        for (int i = 0; i < len; i++) {
             sb.append(array[i]).append('L'); //make sure L suffix is on elements, to discriminate this from IntArrayData.toString()
-            if (i + 1 < length) {
+            if (i + 1 < len) {
                 sb.append(", ");
             }
         }
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/arrays/NonExtensibleArrayFilter.java	Tue Nov 11 17:27:44 2014 +0100
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/arrays/NonExtensibleArrayFilter.java	Wed Nov 12 14:12:01 2014 +0100
@@ -7,13 +7,13 @@
 /**
  * Filter class that wrap arrays that have been tagged non extensible
  */
-public class NonExtensibleArrayFilter extends ArrayFilter {
+final class NonExtensibleArrayFilter extends ArrayFilter {
 
     /**
      * Constructor
      * @param underlying array
      */
-    public NonExtensibleArrayFilter(final ArrayData underlying) {
+    NonExtensibleArrayFilter(final ArrayData underlying) {
         super(underlying);
     }
 
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/arrays/NumberArrayData.java	Tue Nov 11 17:27:44 2014 +0100
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/arrays/NumberArrayData.java	Wed Nov 12 14:12:01 2014 +0100
@@ -28,7 +28,6 @@
 import static jdk.nashorn.internal.codegen.CompilerConstants.specialCall;
 import static jdk.nashorn.internal.lookup.Lookup.MH;
 import static jdk.nashorn.internal.runtime.ScriptRuntime.UNDEFINED;
-
 import java.lang.invoke.MethodHandle;
 import java.lang.invoke.MethodHandles;
 import java.util.Arrays;
@@ -76,7 +75,7 @@
 
     @Override
     public NumberArrayData copy() {
-        return new NumberArrayData(array.clone(), (int)length);
+        return new NumberArrayData(array.clone(), (int)length());
     }
 
     @Override
@@ -85,10 +84,11 @@
     }
 
     private Object[] toObjectArray(final boolean trim) {
-        assert length <= array.length : "length exceeds internal array size";
-        final Object[] oarray = new Object[trim ? (int)length : array.length];
+        assert length() <= array.length : "length exceeds internal array size";
+        final int len = (int)length();
+        final Object[] oarray = new Object[trim ? len : array.length];
 
-        for (int index = 0; index < length; index++) {
+        for (int index = 0; index < len; index++) {
             oarray[index] = Double.valueOf(array[index]);
         }
         return oarray;
@@ -96,8 +96,9 @@
 
     @Override
     public Object asArrayOfType(final Class<?> componentType) {
-        if(componentType == double.class) {
-            return array.length == length ? array.clone() : Arrays.copyOf(array, (int)length);
+        if (componentType == double.class) {
+            final int len = (int)length();
+            return array.length == len ? array.clone() : Arrays.copyOf(array, len);
         }
         return super.asArrayOfType(componentType);
     }
@@ -105,7 +106,7 @@
     @Override
     public ContinuousArrayData convert(final Class<?> type) {
         if (type != Double.class && type != Integer.class && type != Long.class) {
-            final int len = (int)length;
+            final int len = (int)length();
             return new ObjectArrayData(toObjectArray(false), len);
         }
         return this;
@@ -118,7 +119,7 @@
 
     @Override
     public ArrayData shiftRight(final int by) {
-        final ArrayData newData = ensure(by + length - 1);
+        final ArrayData newData = ensure(by + length() - 1);
         if (newData != this) {
             newData.shiftRight(by);
             return newData;
@@ -163,21 +164,21 @@
     @Override
     public ArrayData set(final int index, final int value, final boolean strict) {
         array[index] = value;
-        setLength(Math.max(index + 1, length));
+        setLength(Math.max(index + 1, length()));
         return this;
     }
 
     @Override
     public ArrayData set(final int index, final long value, final boolean strict) {
         array[index] = value;
-        setLength(Math.max(index + 1, length));
+        setLength(Math.max(index + 1, length()));
         return this;
     }
 
     @Override
     public ArrayData set(final int index, final double value, final boolean strict) {
         array[index] = value;
-        setLength(Math.max(index + 1, length));
+        setLength(Math.max(index + 1, length()));
         return this;
     }
 
@@ -241,7 +242,7 @@
 
     @Override
     public boolean has(final int index) {
-        return 0 <= index && index < length;
+        return 0 <= index && index < length();
     }
 
     @Override
@@ -256,11 +257,12 @@
 
     @Override
     public Object pop() {
-        if (length == 0) {
+        final int len = (int)length();
+        if (len == 0) {
             return UNDEFINED;
         }
 
-        final int newLength = (int)length - 1;
+        final int newLength = len - 1;
         final double elem = array[newLength];
         array[newLength] = 0;
         setLength(newLength);
@@ -269,14 +271,14 @@
 
     @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      len     = length;
+        final long      len     = length();
         final ArrayData newData = ensure(len);
         if (newData == this) {
             array[(int)len] = item;
@@ -287,7 +289,7 @@
 
     @Override
     public ArrayData fastSplice(final int start, final int removed, final int added) throws UnsupportedOperationException {
-        final long oldLength = length;
+        final long oldLength = length();
         final long newLength = oldLength - removed + added;
         if (newLength > SparseArrayData.MAX_DENSE_LENGTH && newLength > array.length) {
             throw new UnsupportedOperationException();
@@ -325,21 +327,21 @@
 
     @Override
     public long fastPush(final double arg) {
-        final int len = (int)length;
+        final int len = (int)length();
         if (len == array.length) {
            //note that fastpush never creates spares arrays, there is nothing to gain by that - it will just use even more memory
            array = Arrays.copyOf(array, nextSize(len));
         }
         array[len] = arg;
-        return ++length;
+        return increaseLength();
     }
 
     @Override
     public double fastPopDouble() {
-        if (length == 0) {
+        if (length() == 0) {
             throw new ClassCastException();
         }
-        final int newLength = (int)--length;
+        final int newLength = (int)decreaseLength();
         final double elem = array[newLength];
         array[newLength] = 0;
         return elem;
@@ -352,8 +354,8 @@
 
     @Override
     public ContinuousArrayData fastConcat(final ContinuousArrayData otherData) {
-        final int   otherLength = (int)otherData.length;
-        final int   thisLength  = (int)length;
+        final int   otherLength = (int)otherData.length();
+        final int   thisLength  = (int)length();
         assert otherLength > 0 && thisLength > 0;
 
         final double[] otherArray = ((NumberArrayData)otherData).array;
@@ -368,7 +370,7 @@
 
     @Override
     public String toString() {
-        assert length <= array.length : length + " > " + array.length;
-        return getClass().getSimpleName() + ':' + Arrays.toString(Arrays.copyOf(array, (int)length));
+        assert length() <= array.length : length() + " > " + array.length;
+        return getClass().getSimpleName() + ':' + Arrays.toString(Arrays.copyOf(array, (int)length()));
     }
 }
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/arrays/ObjectArrayData.java	Tue Nov 11 17:27:44 2014 +0100
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/arrays/ObjectArrayData.java	Wed Nov 12 14:12:01 2014 +0100
@@ -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;
@@ -77,16 +76,16 @@
 
     @Override
     public ObjectArrayData copy() {
-        return new ObjectArrayData(array.clone(), (int)length);
+        return new ObjectArrayData(array.clone(), (int)length());
     }
 
     @Override
     public Object[] asObjectArray() {
-        return array.length == length ? array.clone() : asObjectArrayCopy();
+        return array.length == length() ? array.clone() : asObjectArrayCopy();
     }
 
     private Object[] asObjectArrayCopy() {
-        final long len = length;
+        final long len = length();
         assert len <= Integer.MAX_VALUE;
         final Object[] copy = new Object[(int)len];
         System.arraycopy(array, 0, copy, 0, (int)len);
@@ -105,7 +104,7 @@
 
     @Override
     public ArrayData shiftRight(final int by) {
-        final ArrayData newData = ensure(by + length - 1);
+        final ArrayData newData = ensure(by + length() - 1);
         if (newData != this) {
             newData.shiftRight(by);
             return newData;
@@ -137,28 +136,28 @@
     @Override
     public ArrayData set(final int index, final Object value, final boolean strict) {
         array[index] = value;
-        setLength(Math.max(index + 1, length));
+        setLength(Math.max(index + 1, length()));
         return this;
     }
 
     @Override
     public ArrayData set(final int index, final int value, final boolean strict) {
         array[index] = value;
-        setLength(Math.max(index + 1, length));
+        setLength(Math.max(index + 1, length()));
         return this;
     }
 
     @Override
     public ArrayData set(final int index, final long value, final boolean strict) {
         array[index] = value;
-        setLength(Math.max(index + 1, length));
+        setLength(Math.max(index + 1, length()));
         return this;
     }
 
     @Override
     public ArrayData set(final int index, final double value, final boolean strict) {
         array[index] = value;
-        setLength(Math.max(index + 1, length));
+        setLength(Math.max(index + 1, length()));
         return this;
     }
 
@@ -231,7 +230,7 @@
 
     @Override
     public boolean has(final int index) {
-        return 0 <= index && index < length;
+        return 0 <= index && index < length();
     }
 
     @Override
@@ -263,20 +262,20 @@
 
     @Override
     public long fastPush(final Object arg) {
-        final int len = (int)length;
+        final int len = (int)length();
         if (len == array.length) {
             array = Arrays.copyOf(array, nextSize(len));
         }
         array[len] = arg;
-        return ++length;
+        return increaseLength();
     }
 
     @Override
     public Object fastPopObject() {
-        if (length == 0) {
+        if (length() == 0) {
             return ScriptRuntime.UNDEFINED;
         }
-        final int newLength = (int)--length;
+        final int newLength = (int)decreaseLength();
         final Object elem = array[newLength];
         array[newLength] = ScriptRuntime.EMPTY;
         return elem;
@@ -284,11 +283,11 @@
 
     @Override
     public Object pop() {
-        if (length == 0) {
+        if (length() == 0) {
             return ScriptRuntime.UNDEFINED;
         }
 
-        final int newLength = (int)length - 1;
+        final int newLength = (int)length() - 1;
         final Object elem = array[newLength];
         setEmpty(newLength);
         setLength(newLength);
@@ -297,14 +296,14 @@
 
     @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      len     = length;
+        final long      len     = length();
         final ArrayData newData = ensure(len);
         if (newData == this) {
             array[(int)len] = item;
@@ -315,7 +314,7 @@
 
     @Override
     public ArrayData fastSplice(final int start, final int removed, final int added) throws UnsupportedOperationException {
-        final long oldLength = length;
+        final long oldLength = length();
         final long newLength = oldLength - removed + added;
         if (newLength > SparseArrayData.MAX_DENSE_LENGTH && newLength > array.length) {
             throw new UnsupportedOperationException();
@@ -343,8 +342,8 @@
 
     @Override
     public ContinuousArrayData fastConcat(final ContinuousArrayData otherData) {
-        final int   otherLength = (int)otherData.length;
-        final int   thisLength  = (int)length;
+        final int   otherLength = (int)otherData.length();
+        final int   thisLength  = (int)length();
         assert otherLength > 0 && thisLength > 0;
 
         final Object[] otherArray = ((ObjectArrayData)otherData).array;
@@ -359,7 +358,7 @@
 
     @Override
     public String toString() {
-        assert length <= array.length : length + " > " + array.length;
-        return getClass().getSimpleName() + ':' + Arrays.toString(Arrays.copyOf(array, (int)length));
+        assert length() <= array.length : length() + " > " + array.length;
+        return getClass().getSimpleName() + ':' + Arrays.toString(Arrays.copyOf(array, (int)length()));
     }
 }
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/arrays/SparseArrayData.java	Tue Nov 11 17:27:44 2014 +0100
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/arrays/SparseArrayData.java	Wed Nov 12 14:12:01 2014 +0100
@@ -53,21 +53,21 @@
 
     SparseArrayData(final ArrayData underlying, final long length, final TreeMap<Long, Object> sparseMap) {
         super(length);
-        assert underlying.length <= length;
+        assert underlying.length() <= length;
         this.underlying = underlying;
-        this.maxDenseLength = Math.max(MAX_DENSE_LENGTH, underlying.length);
+        this.maxDenseLength = Math.max(MAX_DENSE_LENGTH, underlying.length());
         this.sparseMap = sparseMap;
     }
 
     @Override
     public ArrayData copy() {
-        return new SparseArrayData(underlying.copy(), length, new TreeMap<>(sparseMap));
+        return new SparseArrayData(underlying.copy(), length(), new TreeMap<>(sparseMap));
     }
 
     @Override
     public Object[] asObjectArray() {
-        final int len = (int)Math.min(length, Integer.MAX_VALUE);
-        final int underlyingLength = (int)Math.min(len, underlying.length);
+        final int len = (int)Math.min(length(), Integer.MAX_VALUE);
+        final int underlyingLength = (int)Math.min(len, underlying.length());
         final Object[] objArray = new Object[len];
 
         for (int i = 0; i < underlyingLength; i++) {
@@ -104,14 +104,15 @@
         }
 
         sparseMap = newSparseMap;
-        setLength(Math.max(length - by, 0));
+        setLength(Math.max(length() - by, 0));
     }
 
     @Override
     public ArrayData shiftRight(final int by) {
         final TreeMap<Long, Object> newSparseMap = new TreeMap<>();
-        if (underlying.length + by > maxDenseLength) {
-            for (long i = maxDenseLength - by; i < underlying.length; i++) {
+        final long len = underlying.length();
+        if (len + by > maxDenseLength) {
+            for (long i = maxDenseLength - by; i < len; i++) {
                 if (underlying.has((int) i)) {
                     newSparseMap.put(Long.valueOf(i + by), underlying.getObject((int) i));
                 }
@@ -127,23 +128,23 @@
         }
 
         sparseMap = newSparseMap;
-        setLength(length + by);
+        setLength(length() + by);
 
         return this;
     }
 
     @Override
     public ArrayData ensure(final long safeIndex) {
-        if (safeIndex < maxDenseLength && underlying.length <= safeIndex) {
+        if (safeIndex < maxDenseLength && underlying.length() <= safeIndex) {
             underlying = underlying.ensure(safeIndex);
         }
-        setLength(Math.max(safeIndex + 1, length));
+        setLength(Math.max(safeIndex + 1, length()));
         return this;
     }
 
     @Override
     public ArrayData shrink(final long newLength) {
-        if (newLength < underlying.length) {
+        if (newLength < underlying.length()) {
             underlying = underlying.shrink(newLength);
             underlying.setLength(newLength);
             sparseMap.clear();
@@ -160,11 +161,11 @@
         if (index >= 0 && index < maxDenseLength) {
             ensure(index);
             underlying = underlying.set(index, value, strict);
-            setLength(Math.max(underlying.length, length));
+            setLength(Math.max(underlying.length(), length()));
         } else {
             final Long longIndex = indexToKey(index);
             sparseMap.put(longIndex, value);
-            setLength(Math.max(longIndex + 1, length));
+            setLength(Math.max(longIndex + 1, length()));
         }
 
         return this;
@@ -175,11 +176,11 @@
         if (index >= 0 && index < maxDenseLength) {
             ensure(index);
             underlying = underlying.set(index, value, strict);
-            setLength(Math.max(underlying.length, length));
+            setLength(Math.max(underlying.length(), length()));
         } else {
             final Long longIndex = indexToKey(index);
             sparseMap.put(longIndex, value);
-            setLength(Math.max(longIndex + 1, length));
+            setLength(Math.max(longIndex + 1, length()));
         }
         return this;
     }
@@ -189,11 +190,11 @@
         if (index >= 0 && index < maxDenseLength) {
             ensure(index);
             underlying = underlying.set(index, value, strict);
-            setLength(Math.max(underlying.length, length));
+            setLength(Math.max(underlying.length(), length()));
         } else {
             final Long longIndex = indexToKey(index);
             sparseMap.put(longIndex, value);
-            setLength(Math.max(longIndex + 1, length));
+            setLength(Math.max(longIndex + 1, length()));
         }
         return this;
     }
@@ -203,11 +204,11 @@
         if (index >= 0 && index < maxDenseLength) {
             ensure(index);
             underlying = underlying.set(index, value, strict);
-            setLength(Math.max(underlying.length, length));
+            setLength(Math.max(underlying.length(), length()));
         } else {
             final Long longIndex = indexToKey(index);
             sparseMap.put(longIndex, value);
-            setLength(Math.max(longIndex + 1, length));
+            setLength(Math.max(longIndex + 1, length()));
         }
         return this;
     }
@@ -294,7 +295,7 @@
     @Override
     public boolean has(final int index) {
         if (index >= 0 && index < maxDenseLength) {
-            return index < underlying.length && underlying.has(index);
+            return index < underlying.length() && underlying.has(index);
         }
 
         return sparseMap.containsKey(indexToKey(index));
@@ -303,7 +304,7 @@
     @Override
     public ArrayData delete(final int index) {
         if (index >= 0 && index < maxDenseLength) {
-            if (index < underlying.length) {
+            if (index < underlying.length()) {
                 underlying = underlying.delete(index);
             }
         } else {
@@ -315,8 +316,8 @@
 
     @Override
     public ArrayData delete(final long fromIndex, final long toIndex) {
-        if (fromIndex < maxDenseLength && fromIndex < underlying.length) {
-            underlying = underlying.delete(fromIndex, Math.min(toIndex, underlying.length - 1));
+        if (fromIndex < maxDenseLength && fromIndex < underlying.length()) {
+            underlying = underlying.delete(fromIndex, Math.min(toIndex, underlying.length() - 1));
         }
         if (toIndex >= maxDenseLength) {
             sparseMap.subMap(fromIndex, true, toIndex, true).clear();
@@ -336,30 +337,34 @@
 
     @Override
     public Object pop() {
-        if (length == 0) {
+        final long len = length();
+        final long underlyingLen = underlying.length();
+        if (len == 0) {
             return ScriptRuntime.UNDEFINED;
         }
-        if (length == underlying.length) {
+        if (len == underlyingLen) {
             final Object result = underlying.pop();
-            setLength(underlying.length);
+            setLength(underlying.length());
             return result;
         }
-        setLength(length - 1);
-        final Long key = Long.valueOf(length);
+        setLength(len - 1);
+        final Long key = Long.valueOf(len - 1);
         return sparseMap.containsKey(key) ? sparseMap.remove(key) : ScriptRuntime.UNDEFINED;
     }
 
     @Override
     public ArrayData slice(final long from, final long to) {
-        assert to <= length;
-        final long start = from < 0 ? (from + length) : from;
+        assert to <= length();
+        final long start = from < 0 ? (from + length()) : from;
         final long newLength = to - start;
 
+        final long underlyingLength = underlying.length();
+
         if (start >= 0 && to <= maxDenseLength) {
-            if (newLength <= underlying.length) {
+            if (newLength <= underlyingLength) {
                 return underlying.slice(from, to);
             }
-            return underlying.slice(from, to).ensure(newLength - 1).delete(underlying.length, newLength);
+            return underlying.slice(from, to).ensure(newLength - 1).delete(underlyingLength, newLength);
         }
 
         ArrayData sliced = EMPTY_ARRAY;
@@ -369,13 +374,13 @@
                 sliced = sliced.set((int)(i - start), getObject((int)i), false);
             }
         }
-        assert sliced.length == newLength;
+        assert sliced.length() == newLength;
         return sliced;
     }
 
     @Override
     public long nextIndex(final long index) {
-        if (index < underlying.length - 1) {
+        if (index < underlying.length() - 1) {
             return underlying.nextIndex(index);
         }
 
@@ -383,6 +388,7 @@
         if (nextKey != null) {
             return nextKey;
         }
-        return length;
+
+        return length();
     }
 }
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/arrays/TypedArrayData.java	Tue Nov 11 17:27:44 2014 +0100
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/arrays/TypedArrayData.java	Wed Nov 12 14:12:01 2014 +0100
@@ -58,7 +58,7 @@
      * @return element length
      */
     public final int getElementLength() {
-        return (int)length;
+        return (int)length();
     }
 
     /**
@@ -119,7 +119,7 @@
 
     @Override
     public final boolean has(final int index) {
-        return 0 <= index && index < length;
+        return 0 <= index && index < length();
     }
 
     @Override
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/arrays/UndefinedArrayFilter.java	Tue Nov 11 17:27:44 2014 +0100
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/arrays/UndefinedArrayFilter.java	Wed Nov 12 14:12:01 2014 +0100
@@ -39,8 +39,7 @@
 
     UndefinedArrayFilter(final ArrayData underlying) {
         super(underlying);
-
-        this.undefined = new BitVector(underlying.length);
+        this.undefined = new BitVector(underlying.length());
     }
 
     @Override
@@ -80,25 +79,24 @@
     @Override
     public void shiftLeft(final int by) {
         super.shiftLeft(by);
-        undefined.shiftLeft(by, length);
+        undefined.shiftLeft(by, length());
     }
 
     @Override
     public ArrayData shiftRight(final int by) {
         super.shiftRight(by);
-        undefined.shiftRight(by, length);
-
+        undefined.shiftRight(by, length());
         return this;
     }
 
     @Override
     public ArrayData ensure(final long safeIndex) {
-        if (safeIndex >= SparseArrayData.MAX_DENSE_LENGTH && safeIndex >= length) {
+        if (safeIndex >= SparseArrayData.MAX_DENSE_LENGTH && safeIndex >= length()) {
             return new SparseArrayData(this, safeIndex + 1);
         }
 
         super.ensure(safeIndex);
-        undefined.resize(length);
+        undefined.resize(length());
 
         return this;
     }
@@ -106,8 +104,7 @@
     @Override
     public ArrayData shrink(final long newLength) {
         super.shrink(newLength);
-        undefined.resize(length);
-
+        undefined.resize(length());
         return this;
     }
 
@@ -216,7 +213,7 @@
 
     @Override
     public Object pop() {
-        final long index = length - 1;
+        final long index = length() - 1;
 
         if (super.has((int)index)) {
             final boolean isUndefined = undefined.isSet(index);
@@ -233,7 +230,7 @@
         final ArrayData newArray = underlying.slice(from, to);
         final UndefinedArrayFilter newFilter = new UndefinedArrayFilter(newArray);
         newFilter.getUndefined().copy(undefined);
-        newFilter.getUndefined().shiftLeft(from, newFilter.length);
+        newFilter.getUndefined().shiftLeft(from, newFilter.length());
 
         return newFilter;
     }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/test/script/basic/JDK-8035312.js	Wed Nov 12 14:12:01 2014 +0100
@@ -0,0 +1,225 @@
+/*
+ * 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.
+ */
+
+/**
+ * JDK-8035312 push to frozen array must not increase length property
+ *
+ * @test
+ * @run
+ * @fork
+ * @option -Dnashorn.debug=true
+ */
+
+function printArrayDataClass(x) {
+    if (typeof Debug !== 'undefined') {
+	print(Debug.getArrayDataClass(x));
+    }
+}
+
+function gpush(x, elem) {
+    try {
+	print("Pushing " + elem + " to " + x);
+	x.push(elem);
+    } catch (e) {
+	print("caught error" + e);
+    }
+    print("\tarray is now [" + x + "] length is = " + x.length);
+    print();
+    printArrayDataClass(x);
+}
+
+function gpop(x) {
+    try {
+	print("Popping from " + x);
+	x.pop();
+    } catch (e) {
+	if (!(e instanceof TypeError)) {
+	    print("e of wrong type " + e);
+	}
+    }
+    print("\tarray is now [" + x + "] length is = " + x.length);
+    print();
+    printArrayDataClass(x);
+}
+
+function checkArray(x) {
+    print();
+    print(">>> Push test");
+
+    var olen = x.length;
+    gpush(x, 0);
+
+    print("x.length === " + x.length + " (should be " + olen + ")");
+    print("x[3] === " + x[3] + " (should be 0)");
+    print("x[4] === " + x[4] + " (should be undefined)");
+
+    print();
+    print(">>> Pop test");
+    gpop(x);
+    gpop(x);
+    print("x.length === " + x.length + " (should be " + olen + ")");
+    print("x === " + x);
+
+    for (var i = 0 ; i < 5; i++) {
+	gpop(x);
+    }
+
+    print("x.length === " + x.length + " (should be " + olen + ")");
+    print("x === " + x);
+}
+
+print("*** Freezing");
+var frozen = [1,2,3];
+Object.freeze(frozen);
+checkArray(frozen);
+printArrayDataClass(frozen);
+
+//so far so good
+
+print();
+print("*** Other length not writable issues");
+var lengthNotWritable = [1,2,3];
+Object.defineProperty(lengthNotWritable, "length", { writable: false });
+checkArray(lengthNotWritable);
+printArrayDataClass(lengthNotWritable);
+
+function set(array, from, to, stride) {
+    //add three elements
+    for (var i = from; i < to; i+=stride) {
+	try {
+	    print("Writing " + i);
+	    array[i] = i;
+	    printArrayDataClass(array);
+	} catch (e) {
+	    print(e instanceof TypeError);
+	}
+    }
+}
+
+//define empty array with non writable length
+var arr = [1];
+Object.defineProperty(arr, "length", { writable: false });
+
+var olen2 = arr.length;
+
+set(arr, 0, 3, 1);
+
+if (arr.length != olen2) {
+    throw new ("error: " +  arr.length + " != " + olen2);
+}
+
+print();
+print("array writing 0-3, with 1 stride, array = " + arr);
+print("length = " + arr.length + ", but elements are: " + arr[0] + " " + arr[1] + " " + arr[2]);
+print();
+
+//do the same but sparse/deleted range
+var arr2 = [1];
+Object.defineProperty(arr2, "length", { writable: false });
+
+print("initial length = " + arr2.length);
+var olen3 = arr2.length;
+
+set(arr2, 0, 30, 3);
+
+if (arr2.length != olen3) {
+    throw new ("error: " +  arr2.length + " != " + olen3);
+}
+
+print();
+var larger = 20;
+print("array writing 0-" + larger + ", with 3 stride, array = " + arr2);
+print("length = " + arr2.length + ", but elements are: " + arr2[0] + " " + arr2[1] + " " + arr2[2]);
+
+for (var i = 0; i < larger; i++) {
+    if (arr2[i] === undefined) {
+	continue;
+    }
+    print(arr2[i] + " has length " + arr2.length);
+}
+
+print();
+var elem = 0x7fffffff - 10;
+printArrayDataClass(arr2);
+print("adding a new element high up in the array");
+print("length before element was added " + arr2.length);
+print("putting sparse at " + elem);
+arr2[elem] = "sparse";
+print("length after element was added " + arr2.length + " should be the same");
+printArrayDataClass(arr2);
+
+print();
+print("Printing arr2 - this will fail if length is > 28 and it is " + arr2.length);
+print("arr2 = [" + arr2 + "]");
+print("new length that should not be writable = " + arr2.length);
+print(arr2[elem] === "sparse");
+print(arr2[elem]);
+for (var i = 0; i < larger; i++) {
+    print(arr2[i]);
+}
+for (var key in arr2) {
+    print(key + ":" + arr2[key]);
+}
+
+//issues reported by sundar - generic setter doesn't go through push/pop bulkable
+
+function sundarExample2(arr, _writable) {
+    print("Checking if push works for bulkable non bulkable arrays - Setting length property not allowed");
+    arr[0] = "bar";
+    print(arr.length + " should be 1"); // should be 1
+    print(arr[0] + " should be bar");
+    print("["+ arr + "] should be [bar]");
+
+    //    Object.defineProperty(arr, "length", { configurable: _writable });
+    Object.defineProperty(arr, "length", { writable: _writable });
+    arr[1] = "baz";
+
+    if (_writable) {
+	print(arr.length + " should be 2");
+	print(arr[0] + " should be bar");
+	print(arr[1] + " should be baz");
+	print("["+ arr + "] should be [bar,baz]");
+    } else {
+	print(arr.length + " should STILL be 1");
+	print(arr[0] + " should be bar");
+	print(arr[1] + " should be baz");
+	print("["+ arr + "] should be [bar]");
+    }
+}
+
+var newArr1 = [];
+sundarExample2(newArr1, false);
+print();
+try {
+    sundarExample2(newArr1, true);
+    print("should not get here");
+} catch (e) {
+    if (!(e instanceof TypeError)) {
+	print("Wrong exception");
+    }
+    print("got TypeError when redefining length, as expected")
+}
+print();
+
+sundarExample2([], true);
+print("Done");
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/test/script/basic/JDK-8035312.js.EXPECTED	Wed Nov 12 14:12:01 2014 +0100
@@ -0,0 +1,186 @@
+*** Freezing
+
+>>> Push test
+Pushing 0 to 1,2,3
+	array is now [1,2,3] length is = 3
+
+class jdk.nashorn.internal.runtime.arrays.FrozenArrayFilter
+x.length === 3 (should be 3)
+x[3] === undefined (should be 0)
+x[4] === undefined (should be undefined)
+
+>>> Pop test
+Popping from 1,2,3
+	array is now [1,2,3] length is = 3
+
+class jdk.nashorn.internal.runtime.arrays.FrozenArrayFilter
+Popping from 1,2,3
+	array is now [1,2,3] length is = 3
+
+class jdk.nashorn.internal.runtime.arrays.FrozenArrayFilter
+x.length === 3 (should be 3)
+x === 1,2,3
+Popping from 1,2,3
+	array is now [1,2,3] length is = 3
+
+class jdk.nashorn.internal.runtime.arrays.FrozenArrayFilter
+Popping from 1,2,3
+	array is now [1,2,3] length is = 3
+
+class jdk.nashorn.internal.runtime.arrays.FrozenArrayFilter
+Popping from 1,2,3
+	array is now [1,2,3] length is = 3
+
+class jdk.nashorn.internal.runtime.arrays.FrozenArrayFilter
+Popping from 1,2,3
+	array is now [1,2,3] length is = 3
+
+class jdk.nashorn.internal.runtime.arrays.FrozenArrayFilter
+Popping from 1,2,3
+	array is now [1,2,3] length is = 3
+
+class jdk.nashorn.internal.runtime.arrays.FrozenArrayFilter
+x.length === 3 (should be 3)
+x === 1,2,3
+class jdk.nashorn.internal.runtime.arrays.FrozenArrayFilter
+
+*** Other length not writable issues
+
+>>> Push test
+Pushing 0 to 1,2,3
+caught errorTypeError: "length" is not a writable property of [object Array]
+	array is now [1,2,3] length is = 3
+
+class jdk.nashorn.internal.runtime.arrays.LengthNotWritableFilter
+x.length === 3 (should be 3)
+x[3] === 0 (should be 0)
+x[4] === undefined (should be undefined)
+
+>>> Pop test
+Popping from 1,2,3
+	array is now [1,2,3] length is = 3
+
+class jdk.nashorn.internal.runtime.arrays.LengthNotWritableFilter
+Popping from 1,2,3
+	array is now [1,2,3] length is = 3
+
+class jdk.nashorn.internal.runtime.arrays.LengthNotWritableFilter
+x.length === 3 (should be 3)
+x === 1,2,3
+Popping from 1,2,3
+	array is now [1,2,3] length is = 3
+
+class jdk.nashorn.internal.runtime.arrays.LengthNotWritableFilter
+Popping from 1,2,3
+	array is now [1,2,3] length is = 3
+
+class jdk.nashorn.internal.runtime.arrays.LengthNotWritableFilter
+Popping from 1,2,3
+	array is now [1,2,3] length is = 3
+
+class jdk.nashorn.internal.runtime.arrays.LengthNotWritableFilter
+Popping from 1,2,3
+	array is now [1,2,3] length is = 3
+
+class jdk.nashorn.internal.runtime.arrays.LengthNotWritableFilter
+Popping from 1,2,3
+	array is now [1,2,3] length is = 3
+
+class jdk.nashorn.internal.runtime.arrays.LengthNotWritableFilter
+x.length === 3 (should be 3)
+x === 1,2,3
+class jdk.nashorn.internal.runtime.arrays.LengthNotWritableFilter
+Writing 0
+class jdk.nashorn.internal.runtime.arrays.LengthNotWritableFilter
+Writing 1
+class jdk.nashorn.internal.runtime.arrays.LengthNotWritableFilter
+Writing 2
+class jdk.nashorn.internal.runtime.arrays.LengthNotWritableFilter
+
+array writing 0-3, with 1 stride, array = 0
+length = 1, but elements are: 0 undefined 2
+
+initial length = 1
+Writing 0
+class jdk.nashorn.internal.runtime.arrays.LengthNotWritableFilter
+Writing 3
+class jdk.nashorn.internal.runtime.arrays.LengthNotWritableFilter
+Writing 6
+class jdk.nashorn.internal.runtime.arrays.LengthNotWritableFilter
+Writing 9
+class jdk.nashorn.internal.runtime.arrays.LengthNotWritableFilter
+Writing 12
+class jdk.nashorn.internal.runtime.arrays.LengthNotWritableFilter
+Writing 15
+class jdk.nashorn.internal.runtime.arrays.LengthNotWritableFilter
+Writing 18
+class jdk.nashorn.internal.runtime.arrays.LengthNotWritableFilter
+Writing 21
+class jdk.nashorn.internal.runtime.arrays.LengthNotWritableFilter
+Writing 24
+class jdk.nashorn.internal.runtime.arrays.LengthNotWritableFilter
+Writing 27
+class jdk.nashorn.internal.runtime.arrays.LengthNotWritableFilter
+
+array writing 0-20, with 3 stride, array = 0
+length = 1, but elements are: 0 undefined undefined
+0 has length 1
+
+class jdk.nashorn.internal.runtime.arrays.LengthNotWritableFilter
+adding a new element high up in the array
+length before element was added 1
+putting sparse at 2147483637
+length after element was added 1 should be the same
+class jdk.nashorn.internal.runtime.arrays.LengthNotWritableFilter
+
+Printing arr2 - this will fail if length is > 28 and it is 1
+arr2 = [0]
+new length that should not be writable = 1
+true
+sparse
+0
+undefined
+undefined
+undefined
+undefined
+undefined
+undefined
+undefined
+undefined
+undefined
+undefined
+undefined
+undefined
+undefined
+undefined
+undefined
+undefined
+undefined
+undefined
+undefined
+0:0
+2147483637:sparse
+Checking if push works for bulkable non bulkable arrays - Setting length property not allowed
+1 should be 1
+bar should be bar
+[bar] should be [bar]
+1 should STILL be 1
+bar should be bar
+baz should be baz
+[bar] should be [bar]
+
+Checking if push works for bulkable non bulkable arrays - Setting length property not allowed
+1 should be 1
+bar should be bar
+[bar] should be [bar]
+got TypeError when redefining length, as expected
+
+Checking if push works for bulkable non bulkable arrays - Setting length property not allowed
+1 should be 1
+bar should be bar
+[bar] should be [bar]
+2 should be 2
+bar should be bar
+baz should be baz
+[bar,baz] should be [bar,baz]
+Done
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/test/script/basic/JDK-8035312_2.js	Wed Nov 12 14:12:01 2014 +0100
@@ -0,0 +1,65 @@
+/*
+ * 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.
+ */
+
+/**
+ * JDK-8035312_2 - length setter and iterators
+ *
+ * @test
+ * @run
+ */
+
+"use strict"
+
+function printArray(a,n) {
+    print("PRINT_ARRAY CALLED: length = " + a.length);
+    print();
+
+    print("INDEXED");
+    for (var x = 0; x<n; x++) {
+	print("\t" + x + ":"+a[x]);
+    }
+    print("KEYS");
+    for (var key in a) {
+	print("\t" + key + ";" + a[key]);
+    }
+}
+
+var b = [1,2,3];
+
+Object.defineProperty(b, "length", { writable: false });
+var high = 8;
+b[high] = high;
+
+printArray(b, high + 5);
+
+var c = [1,2,3];
+c[high] = high;
+print();
+print("element[" + high + "]: " + c.length + " " + c[high]);
+print("Resetting length");
+c.length = 3;
+print("element[" + high + "]: " + c.length + " " + c[high]);
+print();
+
+printArray(c, high + 5);
+print();
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/test/script/basic/JDK-8035312_2.js.EXPECTED	Wed Nov 12 14:12:01 2014 +0100
@@ -0,0 +1,47 @@
+PRINT_ARRAY CALLED: length = 3
+
+INDEXED
+	0:1
+	1:2
+	2:3
+	3:undefined
+	4:undefined
+	5:undefined
+	6:undefined
+	7:undefined
+	8:8
+	9:undefined
+	10:undefined
+	11:undefined
+	12:undefined
+KEYS
+	0;1
+	1;2
+	2;3
+	8;8
+
+element[8]: 9 8
+Resetting length
+element[8]: 3 undefined
+
+PRINT_ARRAY CALLED: length = 3
+
+INDEXED
+	0:1
+	1:2
+	2:3
+	3:undefined
+	4:undefined
+	5:undefined
+	6:undefined
+	7:undefined
+	8:undefined
+	9:undefined
+	10:undefined
+	11:undefined
+	12:undefined
+KEYS
+	0;1
+	1;2
+	2;3
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/test/script/basic/JDK-8035312_3.js	Wed Nov 12 14:12:01 2014 +0100
@@ -0,0 +1,43 @@
+/*
+ * 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.
+ */
+
+/**
+ * JDK-8035312_3 - sparse array, non writable length
+ *
+ * @test
+ * @run
+ */
+
+var b = [1,2,3];
+
+Object.defineProperty(b, "length", { writable: false });
+var high = 23534343;
+b[high-10] = high-10;
+
+print(b[high-10]);
+
+var c = [1,2,3];
+c[high-10] = high-10;
+c.length = 3;
+print(c);
+print(c[high-10]);
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/test/script/basic/JDK-8035312_3.js.EXPECTED	Wed Nov 12 14:12:01 2014 +0100
@@ -0,0 +1,3 @@
+23534333
+1,2,3
+undefined
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/test/script/basic/JDK-8035312_4.js	Wed Nov 12 14:12:01 2014 +0100
@@ -0,0 +1,59 @@
+/*
+ * 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.
+ */
+
+/**
+ * JDK-8035312_4 - pushes and pops for non writable length
+ *
+ * @test
+ * @run
+ */
+
+var b = [1,2,3];
+Object.defineProperty(b, "length", { writable: false });
+
+try {
+    b.push(4);
+} catch (e) {
+    print("length = " + b.length);
+    print("i caught an error");
+}
+print(b);
+print(b[3]);
+print("length = " + b.length);
+
+var c = [1,2,3];
+Object.defineProperty(c, "length", { writable: false });
+
+for (var i = 0; i < 5; i++) {
+    try {
+	c.pop();
+    } catch (e) {
+	print("length = " + c.length);
+	print("I caught an error");
+	print(c);
+    }
+}
+
+print(c);
+print(c[3]);
+print("length = " + b.length);
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/test/script/basic/JDK-8035312_4.js.EXPECTED	Wed Nov 12 14:12:01 2014 +0100
@@ -0,0 +1,23 @@
+length = 3
+i caught an error
+1,2,3
+4
+length = 3
+length = 3
+I caught an error
+1,2,
+length = 3
+I caught an error
+1,2,
+length = 3
+I caught an error
+1,2,
+length = 3
+I caught an error
+1,2,
+length = 3
+I caught an error
+1,2,
+1,2,
+undefined
+length = 3
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/test/script/basic/JDK-8035312_5.js	Wed Nov 12 14:12:01 2014 +0100
@@ -0,0 +1,60 @@
+/*
+ * 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.
+ */
+
+/**
+ * JDK-8035312_5 - pushes and pops for frozen array
+ *
+ * @test
+ * @run
+ */
+
+var b = [1,2,3];
+Object.freeze(b);
+
+try {
+    b.push(4);
+} catch (e) {
+    print("length = " + b.length);
+    print("i caught an error"); 
+}
+print(b);
+print(b[3]);
+print("length = " + b.length);
+
+var c = [1,2,3];
+Object.freeze(c);
+
+for (var i = 0; i < 5; i++) {
+    try { 
+	c.pop();
+    } catch (e) { 
+	print("length = " + c.length);
+	print("I caught an error");
+	print(c);
+    }
+}
+
+print(c);
+print(c[3]);
+print("length = " + b.length);
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/test/script/basic/JDK-8035312_5.js.EXPECTED	Wed Nov 12 14:12:01 2014 +0100
@@ -0,0 +1,6 @@
+1,2,3
+undefined
+length = 3
+1,2,3
+undefined
+length = 3
--- a/nashorn/test/script/basic/fastpushpop.js.EXPECTED	Tue Nov 11 17:27:44 2014 +0100
+++ b/nashorn/test/script/basic/fastpushpop.js.EXPECTED	Wed Nov 12 14:12:01 2014 +0100
@@ -1,6 +1,6 @@
 1,2,3,4,5,6
 first: true
-1,2,3,4,5,6,7
+1,2,3,4,5,6
 1,2,3,,,,4711.17,dingo!,4,5,6
 second: true
-1,2,3,,,,4711.17,dingo!,4,5,6,7
+1,2,3,,,,4711.17,dingo!,4,5,6