8015355: Array.prototype functions don't honour non-writable length and / or index properties
authorsundar
Thu, 13 Jun 2013 16:08:35 +0530
changeset 18328 ebd24057f163
parent 18327 782bebd1b300
child 18329 392aaae366d6
8015355: Array.prototype functions don't honour non-writable length and / or index properties Reviewed-by: lagergren, hannesw
nashorn/src/jdk/nashorn/internal/objects/AccessorPropertyDescriptor.java
nashorn/src/jdk/nashorn/internal/objects/DataPropertyDescriptor.java
nashorn/src/jdk/nashorn/internal/objects/GenericPropertyDescriptor.java
nashorn/src/jdk/nashorn/internal/objects/Global.java
nashorn/src/jdk/nashorn/internal/objects/NativeArray.java
nashorn/src/jdk/nashorn/internal/objects/NativeError.java
nashorn/src/jdk/nashorn/internal/objects/NativeEvalError.java
nashorn/src/jdk/nashorn/internal/objects/NativeFunction.java
nashorn/src/jdk/nashorn/internal/objects/NativeJSON.java
nashorn/src/jdk/nashorn/internal/objects/NativeJavaImporter.java
nashorn/src/jdk/nashorn/internal/objects/NativeRangeError.java
nashorn/src/jdk/nashorn/internal/objects/NativeReferenceError.java
nashorn/src/jdk/nashorn/internal/objects/NativeSyntaxError.java
nashorn/src/jdk/nashorn/internal/objects/NativeTypeError.java
nashorn/src/jdk/nashorn/internal/objects/NativeURIError.java
nashorn/src/jdk/nashorn/internal/runtime/Context.java
nashorn/src/jdk/nashorn/internal/runtime/JSONFunctions.java
nashorn/src/jdk/nashorn/internal/runtime/NativeJavaPackage.java
nashorn/src/jdk/nashorn/internal/runtime/ScriptObject.java
nashorn/src/jdk/nashorn/internal/runtime/ScriptingFunctions.java
nashorn/src/jdk/nashorn/internal/runtime/arrays/ArrayIterator.java
nashorn/test/script/basic/JDK-8015355.js
--- a/nashorn/src/jdk/nashorn/internal/objects/AccessorPropertyDescriptor.java	Wed Jun 12 16:41:38 2013 +0200
+++ b/nashorn/src/jdk/nashorn/internal/objects/AccessorPropertyDescriptor.java	Thu Jun 13 16:08:35 2013 +0530
@@ -138,18 +138,16 @@
 
     @Override
     public PropertyDescriptor fillFrom(final ScriptObject sobj) {
-        final boolean strict = isStrictContext();
-
         if (sobj.has(CONFIGURABLE)) {
             this.configurable = JSType.toBoolean(sobj.get(CONFIGURABLE));
         } else {
-            delete(CONFIGURABLE, strict);
+            delete(CONFIGURABLE, false);
         }
 
         if (sobj.has(ENUMERABLE)) {
             this.enumerable = JSType.toBoolean(sobj.get(ENUMERABLE));
         } else {
-            delete(ENUMERABLE, strict);
+            delete(ENUMERABLE, false);
         }
 
         if (sobj.has(GET)) {
@@ -160,7 +158,7 @@
                 throw typeError("not.a.function", ScriptRuntime.safeToString(getter));
             }
         } else {
-            delete(GET, strict);
+            delete(GET, false);
         }
 
         if (sobj.has(SET)) {
@@ -171,7 +169,7 @@
                 throw typeError("not.a.function", ScriptRuntime.safeToString(setter));
             }
         } else {
-            delete(SET, strict);
+            delete(SET, false);
         }
 
         return this;
--- a/nashorn/src/jdk/nashorn/internal/objects/DataPropertyDescriptor.java	Wed Jun 12 16:41:38 2013 +0200
+++ b/nashorn/src/jdk/nashorn/internal/objects/DataPropertyDescriptor.java	Thu Jun 13 16:08:35 2013 +0530
@@ -136,29 +136,28 @@
 
     @Override
     public PropertyDescriptor fillFrom(final ScriptObject sobj) {
-        final boolean strict = isStrictContext();
         if (sobj.has(CONFIGURABLE)) {
             this.configurable = JSType.toBoolean(sobj.get(CONFIGURABLE));
         } else {
-            delete(CONFIGURABLE, strict);
+            delete(CONFIGURABLE, false);
         }
 
         if (sobj.has(ENUMERABLE)) {
             this.enumerable = JSType.toBoolean(sobj.get(ENUMERABLE));
         } else {
-            delete(ENUMERABLE, strict);
+            delete(ENUMERABLE, false);
         }
 
         if (sobj.has(WRITABLE)) {
             this.writable = JSType.toBoolean(sobj.get(WRITABLE));
         } else {
-            delete(WRITABLE, strict);
+            delete(WRITABLE, false);
         }
 
         if (sobj.has(VALUE)) {
             this.value = sobj.get(VALUE);
         } else {
-            delete(VALUE, strict);
+            delete(VALUE, false);
         }
 
         return this;
--- a/nashorn/src/jdk/nashorn/internal/objects/GenericPropertyDescriptor.java	Wed Jun 12 16:41:38 2013 +0200
+++ b/nashorn/src/jdk/nashorn/internal/objects/GenericPropertyDescriptor.java	Thu Jun 13 16:08:35 2013 +0530
@@ -124,17 +124,16 @@
 
     @Override
     public PropertyDescriptor fillFrom(final ScriptObject sobj) {
-        final boolean strict = isStrictContext();
         if (sobj.has(CONFIGURABLE)) {
             this.configurable = JSType.toBoolean(sobj.get(CONFIGURABLE));
         } else {
-            delete(CONFIGURABLE, strict);
+            delete(CONFIGURABLE, false);
         }
 
         if (sobj.has(ENUMERABLE)) {
             this.enumerable = JSType.toBoolean(sobj.get(ENUMERABLE));
         } else {
-            delete(ENUMERABLE, strict);
+            delete(ENUMERABLE, false);
         }
 
         return this;
--- a/nashorn/src/jdk/nashorn/internal/objects/Global.java	Wed Jun 12 16:41:38 2013 +0200
+++ b/nashorn/src/jdk/nashorn/internal/objects/Global.java	Thu Jun 13 16:08:35 2013 +0530
@@ -430,15 +430,6 @@
         return instance().context;
     }
 
-    /**
-     * Script access check for strict mode
-     *
-     * @return true if strict mode enabled in {@link Global#getThisContext()}
-     */
-    static boolean isStrict() {
-        return getEnv()._strict;
-    }
-
     // GlobalObject interface implementation
 
     @Override
@@ -616,14 +607,12 @@
     public PropertyDescriptor newAccessorDescriptor(final Object get, final Object set, final boolean configurable, final boolean enumerable) {
         final AccessorPropertyDescriptor desc = new AccessorPropertyDescriptor(configurable, enumerable, get == null ? UNDEFINED : get, set == null ? UNDEFINED : set);
 
-        final boolean strict = context.getEnv()._strict;
-
         if (get == null) {
-            desc.delete(PropertyDescriptor.GET, strict);
+            desc.delete(PropertyDescriptor.GET, false);
         }
 
         if (set == null) {
-            desc.delete(PropertyDescriptor.SET, strict);
+            desc.delete(PropertyDescriptor.SET, false);
         }
 
         return desc;
@@ -1485,7 +1474,6 @@
         // Error objects
         this.builtinError = (ScriptFunction)initConstructor("Error");
         final ScriptObject errorProto = getErrorPrototype();
-        final boolean strict = Global.isStrict();
 
         // Nashorn specific accessors on Error.prototype - stack, lineNumber, columnNumber and fileName
         final ScriptFunction getStack = ScriptFunctionImpl.makeFunction("getStack", NativeError.GET_STACK);
@@ -1503,10 +1491,10 @@
 
         // ECMA 15.11.4.2 Error.prototype.name
         // Error.prototype.name = "Error";
-        errorProto.set(NativeError.NAME, "Error", strict);
+        errorProto.set(NativeError.NAME, "Error", false);
         // ECMA 15.11.4.3 Error.prototype.message
         // Error.prototype.message = "";
-        errorProto.set(NativeError.MESSAGE, "", strict);
+        errorProto.set(NativeError.MESSAGE, "", false);
 
         this.builtinEvalError = initErrorSubtype("EvalError", errorProto);
         this.builtinRangeError = initErrorSubtype("RangeError", errorProto);
@@ -1519,9 +1507,8 @@
     private ScriptFunction initErrorSubtype(final String name, final ScriptObject errorProto) {
         final ScriptObject cons = initConstructor(name);
         final ScriptObject prototype = ScriptFunction.getPrototype(cons);
-        final boolean strict = Global.isStrict();
-        prototype.set(NativeError.NAME, name, strict);
-        prototype.set(NativeError.MESSAGE, "", strict);
+        prototype.set(NativeError.NAME, name, false);
+        prototype.set(NativeError.MESSAGE, "", false);
         prototype.setProto(errorProto);
         return (ScriptFunction)cons;
     }
@@ -1730,7 +1717,7 @@
         // <anon-function>
         builtinFunction.setProto(anon);
         builtinFunction.setPrototype(anon);
-        anon.set("constructor", builtinFunction, anon.isStrict());
+        anon.set("constructor", builtinFunction, false);
         anon.deleteOwnProperty(anon.getMap().findProperty("prototype"));
 
         // now initialize Object
--- a/nashorn/src/jdk/nashorn/internal/objects/NativeArray.java	Wed Jun 12 16:41:38 2013 +0200
+++ b/nashorn/src/jdk/nashorn/internal/objects/NativeArray.java	Thu Jun 13 16:08:35 2013 +0530
@@ -118,7 +118,7 @@
             if (value == ScriptRuntime.EMPTY) {
                 arrayData = arrayData.delete(index);
             } else {
-                arrayData = arrayData.set(index, value, isStrictContext());
+                arrayData = arrayData.set(index, value, false);
             }
         }
 
@@ -158,6 +158,11 @@
 
         // Step 3
         if ("length".equals(key)) {
+            // check for length being made non-writable
+            if (desc.has(WRITABLE) && !desc.isWritable()) {
+                setIsLengthNotWritable();
+            }
+
             // Step 3a
             if (!desc.has(VALUE)) {
                 return super.defineOwnProperty("length", desc, reject);
@@ -603,7 +608,6 @@
     public static Object pop(final Object self) {
         try {
             final ScriptObject sobj = (ScriptObject)self;
-            final boolean strict    = sobj.isStrictContext();
 
             if (bulkable(sobj)) {
                 return sobj.getArray().pop();
@@ -612,15 +616,15 @@
             final long len = JSType.toUint32(sobj.getLength());
 
             if (len == 0) {
-                sobj.set("length", 0, strict);
+                sobj.set("length", 0, true);
                 return ScriptRuntime.UNDEFINED;
             }
 
             final long   index   = len - 1;
             final Object element = sobj.get(index);
 
-            sobj.delete(index, strict);
-            sobj.set("length", index, strict);
+            sobj.delete(index, true);
+            sobj.set("length", index, true);
 
             return element;
         } catch (final ClassCastException | NullPointerException e) {
@@ -639,11 +643,10 @@
     public static Object push(final Object self, final Object... args) {
         try {
             final ScriptObject sobj   = (ScriptObject)self;
-            final boolean      strict = sobj.isStrictContext();
 
             if (bulkable(sobj)) {
                 if (sobj.getArray().length() + args.length <= JSType.MAX_UINT) {
-                    final ArrayData newData = sobj.getArray().push(sobj.isStrictContext(), args);
+                    final ArrayData newData = sobj.getArray().push(true, args);
                     sobj.setArray(newData);
                     return newData.length();
                 }
@@ -652,9 +655,9 @@
 
             long len = JSType.toUint32(sobj.getLength());
             for (final Object element : args) {
-                sobj.set(len++, element, strict);
+                sobj.set(len++, element, true);
             }
-            sobj.set("length", len, strict);
+            sobj.set("length", len, true);
 
             return len;
         } catch (final ClassCastException | NullPointerException e) {
@@ -672,7 +675,6 @@
     public static Object reverse(final Object self) {
         try {
             final ScriptObject sobj   = (ScriptObject)self;
-            final boolean      strict = sobj.isStrictContext();
             final long         len    = JSType.toUint32(sobj.getLength());
             final long         middle = len / 2;
 
@@ -684,14 +686,14 @@
                 final boolean upperExists = sobj.has(upper);
 
                 if (lowerExists && upperExists) {
-                    sobj.set(lower, upperValue, strict);
-                    sobj.set(upper, lowerValue, strict);
+                    sobj.set(lower, upperValue, true);
+                    sobj.set(upper, lowerValue, true);
                 } else if (!lowerExists && upperExists) {
-                    sobj.set(lower, upperValue, strict);
-                    sobj.delete(upper, strict);
+                    sobj.set(lower, upperValue, true);
+                    sobj.delete(upper, true);
                 } else if (lowerExists && !upperExists) {
-                    sobj.delete(lower, strict);
-                    sobj.set(upper, lowerValue, strict);
+                    sobj.delete(lower, true);
+                    sobj.set(upper, lowerValue, true);
                 }
             }
             return sobj;
@@ -717,7 +719,6 @@
         }
 
         final ScriptObject sobj   = (ScriptObject) obj;
-        final boolean      strict = Global.isStrict();
 
         long len = JSType.toUint32(sobj.getLength());
 
@@ -728,15 +729,15 @@
                 sobj.getArray().shiftLeft(1);
             } else {
                 for (long k = 1; k < len; k++) {
-                    sobj.set(k - 1, sobj.get(k), strict);
+                    sobj.set(k - 1, sobj.get(k), true);
                 }
             }
-            sobj.delete(--len, strict);
+            sobj.delete(--len, true);
         } else {
             len = 0;
         }
 
-        sobj.set("length", len, strict);
+        sobj.set("length", len, true);
 
         return first;
     }
@@ -833,7 +834,6 @@
     public static Object sort(final Object self, final Object comparefn) {
         try {
             final ScriptObject sobj    = (ScriptObject) self;
-            final boolean      strict  = sobj.isStrictContext();
             final long         len     = JSType.toUint32(sobj.getLength());
             ArrayData          array   = sobj.getArray();
 
@@ -850,7 +850,7 @@
                 final Object[] sorted = sort(src.toArray(), comparefn);
 
                 for (int i = 0; i < sorted.length; i++) {
-                    array = array.set(i, sorted[i], strict);
+                    array = array.set(i, sorted[i], true);
                 }
 
                 // delete missing elements - which are at the end of sorted array
@@ -891,7 +891,6 @@
         }
 
         final ScriptObject sobj                = (ScriptObject)obj;
-        final boolean      strict              = Global.isStrict();
         final long         len                 = JSType.toUint32(sobj.getLength());
         final long         relativeStart       = JSType.toLong(start);
 
@@ -914,14 +913,14 @@
                 final long to   = k + items.length;
 
                 if (sobj.has(from)) {
-                    sobj.set(to, sobj.get(from), strict);
+                    sobj.set(to, sobj.get(from), true);
                 } else {
-                    sobj.delete(to, strict);
+                    sobj.delete(to, true);
                 }
             }
 
             for (long k = len; k > (len - actualDeleteCount + items.length); k--) {
-                sobj.delete(k - 1, strict);
+                sobj.delete(k - 1, true);
             }
         } else if (items.length > actualDeleteCount) {
             for (long k = len - actualDeleteCount; k > actualStart; k--) {
@@ -930,20 +929,20 @@
 
                 if (sobj.has(from)) {
                     final Object fromValue = sobj.get(from);
-                    sobj.set(to, fromValue, strict);
+                    sobj.set(to, fromValue, true);
                 } else {
-                    sobj.delete(to, strict);
+                    sobj.delete(to, true);
                 }
             }
         }
 
         long k = actualStart;
         for (int i = 0; i < items.length; i++, k++) {
-            sobj.set(k, items[i], strict);
+            sobj.set(k, items[i], true);
         }
 
         final long newLength = len - actualDeleteCount + items.length;
-        sobj.set("length", newLength, strict);
+        sobj.set("length", newLength, true);
 
         return array;
     }
@@ -964,7 +963,6 @@
         }
 
         final ScriptObject sobj   = (ScriptObject)obj;
-        final boolean      strict = Global.isStrict();
         final long         len    = JSType.toUint32(sobj.getLength());
 
         if (items == null) {
@@ -975,7 +973,7 @@
             sobj.getArray().shiftRight(items.length);
 
             for (int j = 0; j < items.length; j++) {
-                sobj.setArray(sobj.getArray().set(j, items[j], sobj.isStrictContext()));
+                sobj.setArray(sobj.getArray().set(j, items[j], true));
             }
         } else {
             for (long k = len; k > 0; k--) {
@@ -984,19 +982,19 @@
 
                 if (sobj.has(from)) {
                     final Object fromValue = sobj.get(from);
-                    sobj.set(to, fromValue, strict);
+                    sobj.set(to, fromValue, true);
                 } else {
-                    sobj.delete(to, strict);
+                    sobj.delete(to, true);
                 }
             }
 
             for (int j = 0; j < items.length; j++) {
-                sobj.set(j, items[j], strict);
+                 sobj.set(j, items[j], true);
             }
         }
 
         final long newLength = len + items.length;
-        sobj.set("length", newLength, strict);
+        sobj.set("length", newLength, true);
 
         return newLength;
     }
@@ -1239,7 +1237,7 @@
      * @return true if optimizable
      */
     private static boolean bulkable(final ScriptObject self) {
-        return self.isArray() && !hasInheritedArrayEntries(self);
+        return self.isArray() && !hasInheritedArrayEntries(self) && !self.isLengthNotWritable();
     }
 
     private static boolean hasInheritedArrayEntries(final ScriptObject self) {
--- a/nashorn/src/jdk/nashorn/internal/objects/NativeError.java	Wed Jun 12 16:41:38 2013 +0200
+++ b/nashorn/src/jdk/nashorn/internal/objects/NativeError.java	Thu Jun 13 16:08:35 2013 +0530
@@ -90,7 +90,7 @@
         if (msg != UNDEFINED) {
             this.instMessage = JSType.toString(msg);
         } else {
-            this.delete(NativeError.MESSAGE, Global.isStrict());
+            this.delete(NativeError.MESSAGE, false);
         }
     }
 
@@ -166,7 +166,7 @@
     public static Object setLineNumber(final Object self, final Object value) {
         Global.checkObject(self);
         final ScriptObject sobj = (ScriptObject)self;
-        sobj.set(LINENUMBER, value, Global.isStrict());
+        sobj.set(LINENUMBER, value, false);
         return value;
     }
 
@@ -194,7 +194,7 @@
     public static Object setColumnNumber(final Object self, final Object value) {
         Global.checkObject(self);
         final ScriptObject sobj = (ScriptObject)self;
-        sobj.set(COLUMNNUMBER, value, Global.isStrict());
+        sobj.set(COLUMNNUMBER, value, false);
         return value;
     }
 
@@ -222,7 +222,7 @@
     public static Object setFileName(final Object self, final Object value) {
         Global.checkObject(self);
         final ScriptObject sobj = (ScriptObject)self;
-        sobj.set(FILENAME, value, Global.isStrict());
+        sobj.set(FILENAME, value, false);
         return value;
     }
 
@@ -278,7 +278,7 @@
     public static Object setStack(final Object self, final Object value) {
         Global.checkObject(self);
         final ScriptObject sobj = (ScriptObject)self;
-        sobj.set(STACK, value, Global.isStrict());
+        sobj.set(STACK, value, false);
         return value;
     }
 
--- a/nashorn/src/jdk/nashorn/internal/objects/NativeEvalError.java	Wed Jun 12 16:41:38 2013 +0200
+++ b/nashorn/src/jdk/nashorn/internal/objects/NativeEvalError.java	Thu Jun 13 16:08:35 2013 +0530
@@ -59,7 +59,7 @@
         if (msg != UNDEFINED) {
             this.instMessage = JSType.toString(msg);
         } else {
-            this.delete(NativeError.MESSAGE, Global.isStrict());
+            this.delete(NativeError.MESSAGE, false);
         }
     }
 
--- a/nashorn/src/jdk/nashorn/internal/objects/NativeFunction.java	Wed Jun 12 16:41:38 2013 +0200
+++ b/nashorn/src/jdk/nashorn/internal/objects/NativeFunction.java	Thu Jun 13 16:08:35 2013 +0530
@@ -216,7 +216,7 @@
 
         final Global global = Global.instance();
 
-        return Global.directEval(global, sb.toString(), global, "<function>", Global.isStrict());
+        return Global.directEval(global, sb.toString(), global, "<function>", global.isStrictContext());
     }
 
     private static void checkFunctionParameters(final String params) {
--- a/nashorn/src/jdk/nashorn/internal/objects/NativeJSON.java	Wed Jun 12 16:41:38 2013 +0200
+++ b/nashorn/src/jdk/nashorn/internal/objects/NativeJSON.java	Thu Jun 13 16:08:35 2013 +0530
@@ -158,7 +158,7 @@
         state.gap = gap;
 
         final ScriptObject wrapper = Global.newEmptyInstance();
-        wrapper.set("", value, Global.isStrict());
+        wrapper.set("", value, false);
 
         return str("", wrapper, state);
     }
--- a/nashorn/src/jdk/nashorn/internal/objects/NativeJavaImporter.java	Wed Jun 12 16:41:38 2013 +0200
+++ b/nashorn/src/jdk/nashorn/internal/objects/NativeJavaImporter.java	Thu Jun 13 16:08:35 2013 +0530
@@ -121,7 +121,7 @@
         final String name = desc.getNameToken(CallSiteDescriptor.NAME_OPERAND);
         final Object value = createProperty(name);
         if(value != null) {
-            set(name, value, isStrictContext());
+            set(name, value, false);
             return true;
         }
         return false;
--- a/nashorn/src/jdk/nashorn/internal/objects/NativeRangeError.java	Wed Jun 12 16:41:38 2013 +0200
+++ b/nashorn/src/jdk/nashorn/internal/objects/NativeRangeError.java	Thu Jun 13 16:08:35 2013 +0530
@@ -59,7 +59,7 @@
         if (msg != UNDEFINED) {
             this.instMessage = JSType.toString(msg);
         } else {
-            this.delete(NativeError.MESSAGE, Global.isStrict());
+            this.delete(NativeError.MESSAGE, false);
         }
     }
 
--- a/nashorn/src/jdk/nashorn/internal/objects/NativeReferenceError.java	Wed Jun 12 16:41:38 2013 +0200
+++ b/nashorn/src/jdk/nashorn/internal/objects/NativeReferenceError.java	Thu Jun 13 16:08:35 2013 +0530
@@ -59,7 +59,7 @@
         if (msg != UNDEFINED) {
             this.instMessage = JSType.toString(msg);
         } else {
-            this.delete(NativeError.MESSAGE, Global.isStrict());
+            this.delete(NativeError.MESSAGE, false);
         }
     }
 
--- a/nashorn/src/jdk/nashorn/internal/objects/NativeSyntaxError.java	Wed Jun 12 16:41:38 2013 +0200
+++ b/nashorn/src/jdk/nashorn/internal/objects/NativeSyntaxError.java	Thu Jun 13 16:08:35 2013 +0530
@@ -59,7 +59,7 @@
         if (msg != UNDEFINED) {
             this.instMessage = JSType.toString(msg);
         } else {
-            this.delete(NativeError.MESSAGE, Global.isStrict());
+            this.delete(NativeError.MESSAGE, false);
         }
     }
 
--- a/nashorn/src/jdk/nashorn/internal/objects/NativeTypeError.java	Wed Jun 12 16:41:38 2013 +0200
+++ b/nashorn/src/jdk/nashorn/internal/objects/NativeTypeError.java	Thu Jun 13 16:08:35 2013 +0530
@@ -59,7 +59,7 @@
         if (msg != UNDEFINED) {
             this.instMessage = JSType.toString(msg);
         } else {
-            delete(NativeError.MESSAGE, Global.isStrict());
+            delete(NativeError.MESSAGE, false);
         }
     }
 
--- a/nashorn/src/jdk/nashorn/internal/objects/NativeURIError.java	Wed Jun 12 16:41:38 2013 +0200
+++ b/nashorn/src/jdk/nashorn/internal/objects/NativeURIError.java	Thu Jun 13 16:08:35 2013 +0530
@@ -58,7 +58,7 @@
         if (msg != UNDEFINED) {
             this.instMessage = JSType.toString(msg);
         } else {
-            this.delete(NativeError.MESSAGE, Global.isStrict());
+            this.delete(NativeError.MESSAGE, false);
         }
     }
 
--- a/nashorn/src/jdk/nashorn/internal/runtime/Context.java	Wed Jun 12 16:41:38 2013 +0200
+++ b/nashorn/src/jdk/nashorn/internal/runtime/Context.java	Thu Jun 13 16:08:35 2013 +0530
@@ -188,7 +188,7 @@
     private final ScriptEnvironment env;
 
     /** is this context in strict mode? Cached from env. as this is used heavily. */
-    public final boolean _strict;
+    final boolean _strict;
 
     /** class loader to resolve classes from script. */
     private final ClassLoader  appLoader;
--- a/nashorn/src/jdk/nashorn/internal/runtime/JSONFunctions.java	Wed Jun 12 16:41:38 2013 +0200
+++ b/nashorn/src/jdk/nashorn/internal/runtime/JSONFunctions.java	Thu Jun 13 16:08:35 2013 +0530
@@ -101,7 +101,6 @@
         final Object val = holder.get(name);
         if (val instanceof ScriptObject) {
             final ScriptObject     valueObj = (ScriptObject)val;
-            final boolean          strict   = valueObj.isStrictContext();
             final Iterator<String> iter     = valueObj.propertyIterator();
 
             while (iter.hasNext()) {
@@ -109,9 +108,9 @@
                 final Object newElement = walk(valueObj, key, reviver);
 
                 if (newElement == ScriptRuntime.UNDEFINED) {
-                    valueObj.delete(key, strict);
+                    valueObj.delete(key, false);
                 } else {
-                    setPropertyValue(valueObj, key, newElement, strict);
+                    setPropertyValue(valueObj, key, newElement, false);
                 }
             }
         }
@@ -164,14 +163,13 @@
         } else if (node instanceof ObjectNode) {
             final ObjectNode   objNode  = (ObjectNode) node;
             final ScriptObject object   = ((GlobalObject)global).newObject();
-            final boolean      strict   = global.isStrictContext();
 
             for (final PropertyNode pNode: objNode.getElements()) {
                 final Node         valueNode = pNode.getValue();
 
                 final String name = pNode.getKeyName();
                 final Object value = convertNode(global, valueNode);
-                setPropertyValue(object, name, value, strict);
+                setPropertyValue(object, name, value, false);
             }
 
             return object;
--- a/nashorn/src/jdk/nashorn/internal/runtime/NativeJavaPackage.java	Wed Jun 12 16:41:38 2013 +0200
+++ b/nashorn/src/jdk/nashorn/internal/runtime/NativeJavaPackage.java	Thu Jun 13 16:08:35 2013 +0530
@@ -199,7 +199,6 @@
         final String fullName     = name.isEmpty() ? propertyName : name + "." + propertyName;
 
         final Context context = getContext();
-        final boolean strict  = context._strict;
 
         Class<?> javaClass = null;
         try {
@@ -209,9 +208,9 @@
         }
 
         if (javaClass == null) {
-            set(propertyName, new NativeJavaPackage(fullName, getProto()), strict);
+            set(propertyName, new NativeJavaPackage(fullName, getProto()), false);
         } else {
-            set(propertyName, StaticClass.forClass(javaClass), strict);
+            set(propertyName, StaticClass.forClass(javaClass), false);
         }
 
         return super.lookup(desc, request);
--- a/nashorn/src/jdk/nashorn/internal/runtime/ScriptObject.java	Wed Jun 12 16:41:38 2013 +0200
+++ b/nashorn/src/jdk/nashorn/internal/runtime/ScriptObject.java	Thu Jun 13 16:08:35 2013 +0530
@@ -105,6 +105,9 @@
     /** Is this a prototype PropertyMap? */
     public static final int IS_PROTOTYPE   = 0b0000_1000;
 
+    /** Is length property not-writable? */
+    public static final int IS_LENGTH_NOT_WRITABLE = 0b0001_0000;
+
     /** Spill growth rate - by how many elements does {@link ScriptObject#spill} when full */
     public static final int SPILL_RATE = 8;
 
@@ -443,7 +446,7 @@
             if (newValue && property != null) {
                 // Temporarily clear flags.
                 property = modifyOwnProperty(property, 0);
-                set(key, value, getContext()._strict);
+                set(key, value, false);
             }
 
             if (property == null) {
@@ -998,7 +1001,7 @@
      * @param value the value to write at the given index
      */
     public void setArgument(final int key, final Object value) {
-        set(key, value, getContext()._strict);
+        set(key, value, false);
     }
 
     /**
@@ -1277,14 +1280,14 @@
      *
      * @return {@code true} if is prototype
      */
-    public boolean isPrototype() {
+    public final boolean isPrototype() {
         return (flags & IS_PROTOTYPE) != 0;
     }
 
     /**
      * Flag this object as having a prototype.
      */
-    public void setIsPrototype() {
+    public final void setIsPrototype() {
         if (proto != null && !isPrototype()) {
             proto.addPropertyListener(this);
         }
@@ -1292,6 +1295,22 @@
     }
 
     /**
+     * Check if this object has non-writable length property
+     *
+     * @return {@code true} if 'length' property is non-writable
+     */
+    public final boolean isLengthNotWritable() {
+        return (flags & IS_LENGTH_NOT_WRITABLE) != 0;
+    }
+
+    /**
+     * Flag this object as having non-writable length property
+     */
+    public void setIsLengthNotWritable() {
+        flags |= IS_LENGTH_NOT_WRITABLE;
+    }
+
+    /**
      * Get the {@link ArrayData} for this ScriptObject if it is an array
      * @return array data
      */
@@ -1393,7 +1412,7 @@
      * (java.util.Map-like method to help ScriptObjectMirror implementation)
      */
     public void clear() {
-        final boolean strict = getContext()._strict;
+        final boolean strict = isStrictContext();
         final Iterator<String> iter = propertyIterator();
         while (iter.hasNext()) {
             delete(iter.next(), strict);
@@ -1481,7 +1500,7 @@
      */
     public Object put(final Object key, final Object value) {
         final Object oldValue = get(key);
-        set(key, value, getContext()._strict);
+        set(key, value, isStrictContext());
         return oldValue;
     }
 
@@ -1493,7 +1512,7 @@
      * @param otherMap a {@literal <key,value>} map of properties to add
      */
     public void putAll(final Map<?, ?> otherMap) {
-        final boolean strict = getContext()._strict;
+        final boolean strict = isStrictContext();
         for (final Map.Entry<?, ?> entry : otherMap.entrySet()) {
             set(entry.getKey(), entry.getValue(), strict);
         }
@@ -1508,7 +1527,7 @@
      */
     public Object remove(final Object key) {
         final Object oldValue = get(key);
-        delete(key, getContext()._strict);
+        delete(key, isStrictContext());
         return oldValue;
     }
 
@@ -1520,7 +1539,7 @@
      * @return if the delete was successful or not
      */
     public boolean delete(final Object key) {
-        return delete(key, getContext()._strict);
+        return delete(key, isStrictContext());
     }
 
     /**
@@ -2222,7 +2241,7 @@
            return;
        }
 
-       final boolean isStrict = getContext()._strict;
+       final boolean isStrict = isStrictContext();
 
        if (newLength > arrayLength) {
            setArray(getArray().ensure(newLength - 1));
--- a/nashorn/src/jdk/nashorn/internal/runtime/ScriptingFunctions.java	Wed Jun 12 16:41:38 2013 +0200
+++ b/nashorn/src/jdk/nashorn/internal/runtime/ScriptingFunctions.java	Thu Jun 13 16:08:35 2013 +0530
@@ -221,10 +221,9 @@
         final String err = errBuffer.toString();
 
         // Set globals for secondary results.
-        final boolean isStrict = global.isStrictContext();
-        global.set(OUT_NAME, out, isStrict);
-        global.set(ERR_NAME, err, isStrict);
-        global.set(EXIT_NAME, exit, isStrict);
+        global.set(OUT_NAME, out, false);
+        global.set(ERR_NAME, err, false);
+        global.set(EXIT_NAME, exit, false);
 
         // Propagate exception if present.
         for (int i = 0; i < exception.length; i++) {
--- a/nashorn/src/jdk/nashorn/internal/runtime/arrays/ArrayIterator.java	Wed Jun 12 16:41:38 2013 +0200
+++ b/nashorn/src/jdk/nashorn/internal/runtime/arrays/ArrayIterator.java	Thu Jun 13 16:08:35 2013 +0530
@@ -83,6 +83,6 @@
 
     @Override
     public void remove() {
-        array.delete(index, array.isStrictContext());
+        array.delete(index, false);
     }
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/test/script/basic/JDK-8015355.js	Thu Jun 13 16:08:35 2013 +0530
@@ -0,0 +1,122 @@
+/*
+ * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ * 
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ * 
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ * 
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ * 
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/**
+ * JDK-8015355: Array.prototype functions don't honour non-writable length and / or index properties
+ * 
+ * @test
+ * @run
+ */
+
+function fail(msg) {
+    print(msg);
+}
+
+function check(callback) {
+    try {
+        callback();
+        fail("TypeError expected for " + callback);
+    } catch (e) {
+        if (! (e instanceof TypeError)) {
+            fail("TypeError expected, got " + e);
+        }
+    }
+}
+
+var array = Object.defineProperty([],"length", { writable: false });
+
+check(function() {
+    array.push(0)
+});
+
+check(function() {
+    array.pop()
+});
+
+check(function() {
+    Object.defineProperty([,,],"0",{ writable: false }).reverse();
+});
+
+check(function() {
+    array.shift()
+});
+
+check(function() {
+    array.splice(0)
+});
+
+check(function() {
+    array.unshift()
+});
+
+// try the above via call
+
+check(function() {
+    Array.prototype.push.call(array, 0);
+});
+
+check(function() {
+    Array.prototype.pop.call(array);
+});
+
+check(function() {
+    Array.prototype.shift.call(array);
+});
+
+check(function() {
+    Array.prototype.unshift.call(array);
+});
+
+check(function() {
+    Array.prototype.splice.call(array, 0);
+});
+
+check(function() {
+    Array.prototype.reverse.call(Object.defineProperty([,,],"0",{ writable: false }));
+});
+
+// try the above via apply
+
+check(function() {
+    Array.prototype.push.apply(array, [ 0 ]);
+});
+
+check(function() {
+    Array.prototype.pop.apply(array);
+});
+
+check(function() {
+    Array.prototype.shift.apply(array);
+});
+
+check(function() {
+    Array.prototype.unshift.apply(array);
+});
+
+check(function() {
+    Array.prototype.splice.apply(array, [ 0 ]);
+});
+
+check(function() {
+    Array.prototype.reverse.apply(Object.defineProperty([,,],"0",{ writable: false }));
+});