[INFER] Clear initialized length when changing clasp during array slowification, bug 648773.
authorBrian Hackett <bhackett1024@gmail.com>
Mon, 11 Apr 2011 06:52:23 -0700
changeset 74924 b6d65a4eb2b3c538903262707e22f364c38a1794
parent 74923 5469f5d077acaea23fc7db181a38fe9a9bea7073
child 74925 100ab867dda157e7cd2bb81d9780c0218526e083
push id2
push userbsmedberg@mozilla.com
push dateFri, 19 Aug 2011 14:38:13 +0000
bugs648773
milestone2.2a1pre
[INFER] Clear initialized length when changing clasp during array slowification, bug 648773.
js/src/jit-test/tests/basic/bug648773.js
js/src/jsarray.cpp
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/basic/bug648773.js
@@ -0,0 +1,4 @@
+gczeal(2);
+for (var loopa2 = 0; loopa2 < 13; loopa2++) {
+  [, , , , , , ][Float64Array()] = 72413.8139177333;
+}
--- a/js/src/jsarray.cpp
+++ b/js/src/jsarray.cpp
@@ -1061,51 +1061,58 @@ JSObject::makeDenseArraySlow(JSContext *
     JS_ASSERT(isDenseArray());
 
     if (!cx->markTypeArrayNotPacked(getType(), true))
         return false;
     JS_ALWAYS_TRUE(setDenseArrayNotPacked(cx));
 
     /*
      * Save old map now, before calling InitScopeForObject. We'll have to undo
-     * on error. This is gross, but a better way is not obvious.
+     * on error. This is gross, but a better way is not obvious. Note: the
+     * exact contents of the array are not preserved on error.
      */
     JSObjectMap *oldMap = map;
 
     /* Create a native scope. */
     js::gc::FinalizeKind kind = js::gc::FinalizeKind(arena()->header()->thingKind);
     if (!InitScopeForObject(cx, this, &js_SlowArrayClass, getType(), kind))
         return false;
 
     backfillDenseArrayHoles();
 
     uint32 arrayCapacity = getDenseArrayCapacity();
+    uint32 arrayInitialized = getDenseArrayInitializedLength();
 
     /*
      * Adjust the slots to account for the different layout between dense
      * arrays and other objects. The slots must be dynamic, and the fixed slots
      * are now available for newly added properties.
      */
     if (denseArrayHasInlineSlots()) {
         if (!allocSlots(cx, numSlots())) {
             setMap(oldMap);
             return false;
         }
         JS_ASSERT(!denseArrayHasInlineSlots());
     }
     capacity = numFixedSlots() + arrayCapacity;
     clasp = &js_SlowArrayClass;
 
+    /* The initialized length is used iff this is a dense array. */
+    initializedLength = 0;
+    JS_ASSERT(newType == NULL);
+
     /*
      * Begin with the length property to share more of the property tree.
      * The getter/setter here will directly access the object's private value.
      */
     if (!AddLengthProperty(cx, this)) {
         setMap(oldMap);
         capacity = arrayCapacity;
+        initializedLength = arrayInitialized;
         clasp = &js_ArrayClass;
         return false;
     }
 
     /*
      * Create new properties pointing to existing elements. Pack the array to
      * remove holes, so that shapes use successive slots (as for other objects).
      */
@@ -1118,29 +1125,26 @@ JSObject::makeDenseArraySlow(JSContext *
         if (slots[i].isMagic(JS_ARRAY_HOLE))
             continue;
 
         setSlot(next, slots[i]);
 
         if (!addDataProperty(cx, id, next, JSPROP_ENUMERATE)) {
             setMap(oldMap);
             capacity = arrayCapacity;
+            initializedLength = arrayInitialized;
             clasp = &js_ArrayClass;
             return false;
         }
 
         next++;
     }
 
     clearSlotRange(next, capacity - next);
 
-    /* initialized length is not used anymore. */
-    initializedLength = 0;
-    JS_ASSERT(newType == NULL);
-
     /*
      * Finally, update class. If |this| is Array.prototype, then js_InitClass
      * will create an emptyShape whose class is &js_SlowArrayClass, to ensure
      * that delegating instances can share shapes in the tree rooted at the
      * proto's empty shape.
      */
     return true;
 }