Bug 945813 - Paper over cycle collection problem in IndexedDB. r=mccr8, r=khuey
authorAndy Wingo <wingo@igalia.com>
Wed, 04 Dec 2013 14:53:25 +0100
changeset 174860 815cd189ae2c7c5205ed053611b4e51de1667c13
parent 174859 0d405a9b2a8a252e620d2a5b4e53e1fdaa743b14
child 174861 5880bbf6182c99fa3e12928f6982834dec6bd7b1
push id445
push userffxbld
push dateMon, 10 Mar 2014 22:05:19 +0000
treeherdermozilla-release@dc38b741b04e [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmccr8, khuey
bugs945813
milestone28.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 945813 - Paper over cycle collection problem in IndexedDB. r=mccr8, r=khuey
dom/indexedDB/test/unit/test_cursor_cycle.js
dom/indexedDB/test/unit/test_cursor_mutation.js
dom/indexedDB/test/unit/test_index_object_cursors.js
dom/indexedDB/test/unit/test_index_update_delete.js
dom/indexedDB/test/unit/xpcshell.ini
xpcom/base/nsCycleCollector.cpp
new file mode 100644
--- /dev/null
+++ b/dom/indexedDB/test/unit/test_cursor_cycle.js
@@ -0,0 +1,46 @@
+/**
+ * Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+var testGenerator = testSteps();
+
+function testSteps()
+{
+  const Bob = { ss: "237-23-7732", name: "Bob" };
+
+  let request = indexedDB.open(this.window ? window.location.pathname : "Splendid Test", 1);
+  request.onerror = errorHandler;
+  request.onupgradeneeded = grabEventAndContinueHandler;
+  let event = yield undefined;
+
+  let db = event.target.result;
+  event.target.onsuccess = continueToNextStep;
+
+  let objectStore = db.createObjectStore("foo", { keyPath: "ss" });
+  objectStore.createIndex("name", "name", { unique: true });
+  objectStore.add(Bob);
+  yield undefined;
+
+  // This direct eval causes locals to be aliased, and thus allocated on
+  // the scope chain.  Comment it out (and the workarounds below) and
+  // the test passes.  Bug 943409.
+  eval('');
+
+  db.transaction("foo", "readwrite").objectStore("foo")
+    .index("name").openCursor().onsuccess = function(event) {
+    event.target.transaction.oncomplete = continueToNextStep;
+    let cursor = event.target.result;
+    if (cursor) {
+      let objectStore = event.target.transaction.objectStore("foo");
+      objectStore.delete(Bob.ss)
+                 .onsuccess = function(event) { cursor.continue(); };
+    }
+  };
+  yield undefined;
+  finishTest();
+
+  objectStore = null; // Bug 943409 workaround.
+
+  yield undefined;
+}
--- a/dom/indexedDB/test/unit/test_cursor_mutation.js
+++ b/dom/indexedDB/test/unit/test_cursor_mutation.js
@@ -30,16 +30,21 @@ function testSteps()
   let event = yield undefined;
 
   let db = event.target.result;
   event.target.onsuccess = continueToNextStep;
 
   let objectStore = db.createObjectStore("foo", { keyPath: "ss" });
   objectStore.createIndex("name", "name", { unique: true });
 
+  // This direct eval causes locals to be aliased, and thus allocated on
+  // the scope chain.  Comment it out (and the workarounds below) and
+  // the test passes.  Bug 943409.
+  eval('');
+
   for (let i = 0; i < objectStoreData.length - 1; i++) {
     objectStore.add(objectStoreData[i]);
   }
   yield undefined;
 
   let count = 0;
 
   let sawAdded = false;
@@ -106,10 +111,13 @@ function testSteps()
     };
   yield undefined;
 
   is(count, objectStoreData.length - 1, "Good final count");
   is(sawAdded, true, "Saw item that was added");
   is(sawRemoved, false, "Didn't see item that was removed");
 
   finishTest();
+
+  objectStore = null; // Bug 943409 workaround.
+
   yield undefined;
 }
--- a/dom/indexedDB/test/unit/test_index_object_cursors.js
+++ b/dom/indexedDB/test/unit/test_index_object_cursors.js
@@ -29,16 +29,19 @@ function testSteps()
   request.onupgradeneeded = grabEventAndContinueHandler;
   let event = yield undefined;
 
   let db = event.target.result;
   db.onerror = errorHandler;
 
   event.target.onsuccess = continueToNextStep;
 
+  // Bug 943409.
+  eval('');
+
   for (let objectStoreIndex in objectStoreData) {
     const objectStoreInfo = objectStoreData[objectStoreIndex];
     let objectStore = db.createObjectStore(objectStoreInfo.name,
                                            objectStoreInfo.options);
     for (let indexIndex in indexData) {
       const indexInfo = indexData[indexIndex];
       let index = objectStore.createIndex(indexInfo.name,
                                           indexInfo.keyPath,
@@ -132,14 +135,16 @@ function testSteps()
       yield undefined;
 
       is(keyIndex, 1, "Saw all the items");
 
       db.transaction(objectStoreName, "readwrite")
         .objectStore(objectStoreName).clear()
         .onsuccess = continueToNextStep;
       yield undefined;
+
+      objectStore = index = null; // Bug 943409 workaround.
     }
   }
 
   finishTest();
   yield undefined;
 }
--- a/dom/indexedDB/test/unit/test_index_update_delete.js
+++ b/dom/indexedDB/test/unit/test_index_update_delete.js
@@ -13,16 +13,19 @@ function testSteps()
   request.onupgradeneeded = grabEventAndContinueHandler;
   request.onsuccess = grabEventAndContinueHandler;
 
   let event = yield undefined;
 
   let db = event.target.result;
   db.onerror = errorHandler;
 
+  // Bug 943409.
+  eval('');
+
   for each (let autoIncrement in [false, true]) {
     let objectStore =
       db.createObjectStore(autoIncrement, { keyPath: "id",
                                             autoIncrement: autoIncrement });
 
     for (let i = 0; i < 10; i++) {
       objectStore.add({ id: i, index: i });
     }
@@ -154,14 +157,18 @@ function testSteps()
       is(event.target.result, objectStoreCount,
          "Correct number of entries in objectStore");
 
       index.count().onsuccess = grabEventAndContinueHandler;
       event = yield undefined;
 
       is(event.target.result, indexCount,
          "Correct number of entries in index");
+
+      index = event = null; // Bug 943409 workaround.
     }
+    objectStore = event = null; // Bug 943409 workaround.
   }
 
   finishTest();
+  event = db = request = null; // Bug 943409 workaround.
   yield undefined;
 }
--- a/dom/indexedDB/test/unit/xpcshell.ini
+++ b/dom/indexedDB/test/unit/xpcshell.ini
@@ -16,16 +16,17 @@ support-files =
 [test_autoIncrement.js]
 [test_autoIncrement_indexes.js]
 [test_clear.js]
 [test_complex_keyPaths.js]
 [test_count.js]
 [test_create_index.js]
 [test_create_index_with_integer_keys.js]
 [test_create_objectStore.js]
+[test_cursor_cycle.js]
 [test_cursor_mutation.js]
 [test_cursor_update_updates_indexes.js]
 [test_cursors.js]
 [test_deleteDatabase.js]
 [test_deleteDatabase_interactions.js]
 [test_event_source.js]
 [test_getAll.js]
 [test_globalObjects_ipc.js]
--- a/xpcom/base/nsCycleCollector.cpp
+++ b/xpcom/base/nsCycleCollector.cpp
@@ -2718,18 +2718,18 @@ nsCycleCollector::CleanupAfterCollection
     }
     mIncrementalPhase = IdlePhase;
 }
 
 void
 nsCycleCollector::ShutdownCollect()
 {
     SliceBudget unlimitedBudget;
-    for (uint32_t i = 0; i < DEFAULT_SHUTDOWN_COLLECTIONS; ++i) {
-        NS_ASSERTION(i < NORMAL_SHUTDOWN_COLLECTIONS, "Extra shutdown CC");
+    uint32_t i;
+    for (i = 0; i < DEFAULT_SHUTDOWN_COLLECTIONS; ++i) {
         if (!Collect(ShutdownCC, unlimitedBudget, nullptr)) {
             break;
         }
     }
 }
 
 static void
 PrintPhase(const char *aPhase)