Bug 624041: skip elements deleted via shift or reverse in iteration, r=igor
☠☠ backed out by 39bac86bb168 ☠ ☠
authorDavid Mandelin <dmandelin@mozilla.com>
Mon, 10 Jan 2011 18:39:46 -0800
changeset 60551 72ac46e9f64e676b9d7de5d86eb2017fe31d4679
parent 60550 161cdd8d9ffab2d37e05dc313c3e638b360fb697
child 60552 7aef1aece1f49b605e7240969f8e9fc852c558a8
push id18037
push usercleary@mozilla.com
push dateFri, 14 Jan 2011 17:42:55 +0000
treeherdermozilla-central@4e0501a0c5e5 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersigor
bugs624041
milestone2.0b9pre
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 624041: skip elements deleted via shift or reverse in iteration, r=igor
js/src/jit-test/tests/basic/bug624041-1.js
js/src/jit-test/tests/basic/bug624041-2.js
js/src/jsarray.cpp
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/basic/bug624041-1.js
@@ -0,0 +1,8 @@
+var count = 0;
+
+var a = [0, 1];
+for (var i in a) {
+    assertEq(++count <= 1, true);
+    a.shift();
+}
+
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/basic/bug624041-2.js
@@ -0,0 +1,11 @@
+var s = '';
+
+var a = [, 0, 1];
+for (var i in a) {
+    a.reverse();
+    s += i + ',';
+}
+
+// Index of the element with value '0'.
+assertEq(s, '1,');
+
--- a/js/src/jsarray.cpp
+++ b/js/src/jsarray.cpp
@@ -1479,20 +1479,25 @@ array_reverse(JSContext *cx, uintN argc,
             if (result == JSObject::ED_FAILED)
                 return false;
             JS_ASSERT(result == JSObject::ED_SPARSE);
             break;
         }
 
         uint32 lo = 0, hi = len - 1;
         for (; lo < hi; lo++, hi--) {
-            Value tmp = obj->getDenseArrayElement(lo);
-            obj->setDenseArrayElement(lo, obj->getDenseArrayElement(hi));
-            obj->setDenseArrayElement(hi, tmp);
-        }
+            Value origlo = obj->getDenseArrayElement(lo);
+            Value orighi = obj->getDenseArrayElement(hi);
+            obj->setDenseArrayElement(lo, orighi);
+            if (orighi.isMagic(JS_ARRAY_HOLE))
+                js_SuppressDeletedProperty(cx, obj, INT_TO_JSID(lo));
+            obj->setDenseArrayElement(hi, origlo);
+            if (origlo.isMagic(JS_ARRAY_HOLE))
+                js_SuppressDeletedProperty(cx, obj, INT_TO_JSID(hi));
+            }
 
         /*
          * Per ECMA-262, don't update the length of the array, even if the new
          * array has trailing holes (and thus the original array began with
          * holes).
          */
         return JS_TRUE;
     } while (false);
@@ -2151,16 +2156,18 @@ array_shift(JSContext *cx, uintN argc, V
             length < obj->getDenseArrayCapacity()) {
             *vp = obj->getDenseArrayElement(0);
             if (vp->isMagic(JS_ARRAY_HOLE))
                 vp->setUndefined();
             Value *elems = obj->getDenseArrayElements();
             memmove(elems, elems + 1, length * sizeof(jsval));
             obj->setDenseArrayElement(length, MagicValue(JS_ARRAY_HOLE));
             obj->setArrayLength(length);
+            if (!js_SuppressDeletedProperty(cx, obj, INT_TO_JSID(length)));
+                return JS_FALSE;
             return JS_TRUE;
         }
 
         /* Get the to-be-deleted property's value into vp ASAP. */
         if (!GetElement(cx, obj, 0, &hole, vp))
             return JS_FALSE;
 
         /* Slide down the array above the first element. */