Bug 1368978 - Skip non-initialized elements when deleting a property range in Array.prototype.splice. r=jandem
authorAndré Bargull <andre.bargull@gmail.com>
Thu, 27 Jul 2017 04:37:43 -0700
changeset 420107 4335408842416a32f46657d1567c79ebad4ae049
parent 420106 ad37214e0d8f3a4e34c3bf0244377eb062e65805
child 420108 fe31a71693ae5df1c7917da05727bd821fff01b0
push id7566
push usermtabara@mozilla.com
push dateWed, 02 Aug 2017 08:25:16 +0000
treeherdermozilla-beta@86913f512c3c [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjandem
bugs1368978
milestone56.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1368978 - Skip non-initialized elements when deleting a property range in Array.prototype.splice. r=jandem
js/src/jit-test/tests/arrays/too-long-array-splice.js
js/src/jsarray.cpp
--- a/js/src/jit-test/tests/arrays/too-long-array-splice.js
+++ b/js/src/jit-test/tests/arrays/too-long-array-splice.js
@@ -1,6 +1,10 @@
 // |jit-test| allow-oom
 // array.splice should throw if array.length is too large.
 
 var length = 4294967295;
 var array = new Array(length);
+
+// Disable any fast paths by adding an indexed property on the prototype chain.
+Array.prototype[0] = 0;
+
 array.splice(100);
--- a/js/src/jsarray.cpp
+++ b/js/src/jsarray.cpp
@@ -563,16 +563,38 @@ DeletePropertyOrThrow(JSContext* cx, Han
         if (!ToId(cx, index, &id))
             return false;
         return success.reportError(cx, obj, id);
     }
     return true;
 }
 
 static bool
+DeletePropertiesOrThrow(JSContext* cx, HandleObject obj, uint64_t len, uint64_t finalLength)
+{
+    if (obj->is<ArrayObject>() && !obj->isIndexed() &&
+        !obj->as<NativeObject>().denseElementsAreFrozen())
+    {
+        if (len <= UINT32_MAX) {
+            // Skip forward to the initialized elements of this array.
+            len = Min(uint32_t(len), obj->as<ArrayObject>().getDenseInitializedLength());
+        }
+    }
+
+    for (uint64_t k = len; k > finalLength; k--) {
+        if (!CheckForInterrupt(cx))
+            return false;
+
+        if (!DeletePropertyOrThrow(cx, obj, k - 1))
+            return false;
+    }
+    return true;
+}
+
+static bool
 SetArrayLengthProperty(JSContext* cx, HandleArrayObject obj, HandleValue value)
 {
     RootedId id(cx, NameToId(cx->names().length));
     ObjectOpResult result;
     if (obj->lengthIsWritable()) {
         if (!ArraySetLength(cx, obj, id, JSPROP_PERMANENT, value, result))
             return false;
     } else {
@@ -2941,21 +2963,18 @@ array_splice_impl(JSContext* cx, unsigne
                 } else {
                     /* Step 15.b.iv.2. */
                     if (!SetArrayElement(cx, obj, to, fromValue))
                         return false;
                 }
             }
 
             /* Steps 15.c-d. */
-            for (uint64_t k = len; k > finalLength; k--) {
-                /* Steps 15.d.i-ii. */
-                if (!DeletePropertyOrThrow(cx, obj, k - 1))
-                    return false;
-            }
+            if (!DeletePropertiesOrThrow(cx, obj, len, finalLength))
+                return false;
         }
     } else if (itemCount > actualDeleteCount) {
         MOZ_ASSERT(actualDeleteCount <= UINT32_MAX);
         uint32_t deleteCount = uint32_t(actualDeleteCount);
 
         /* Step 16. */
 
         /*