Bug 1012887 - DataStoreCursorImpl.jsm must check if the window is still available, r=gene
authorAndrea Marchesini <amarchesini@mozilla.com>
Tue, 20 May 2014 10:03:35 +0100
changeset 196311 162d32ed3b9c7071cbb394ed7b54ef3dbf1dc5c5
parent 196310 ec4b23a08c5e058082c2ccf227bfc78e7824a82f
child 196312 c4142e3c7a6b51f7ee8101afa5577657aa0572d6
push id5990
push userasasaki@mozilla.com
push dateMon, 09 Jun 2014 21:40:24 +0000
treeherdermozilla-aurora@0796197efbc9 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersgene
bugs1012887
milestone32.0a1
Bug 1012887 - DataStoreCursorImpl.jsm must check if the window is still available, r=gene
dom/datastore/DataStoreCursorImpl.jsm
--- a/dom/datastore/DataStoreCursorImpl.jsm
+++ b/dom/datastore/DataStoreCursorImpl.jsm
@@ -22,16 +22,17 @@ const STATE_REVISION_SEND = 4;
 const STATE_DONE = 5;
 
 const REVISION_ADDED = 'added';
 const REVISION_UPDATED = 'updated';
 const REVISION_REMOVED = 'removed';
 const REVISION_VOID = 'void';
 const REVISION_SKIP = 'skip'
 
+Cu.import('resource://gre/modules/Services.jsm');
 Cu.import('resource://gre/modules/XPCOMUtils.jsm');
 
 /**
  * legend:
  * - RID = revision ID
  * - R = revision object (with the internalRevisionId that is a number)
  * - X = current object ID.
  * - L = the list of revisions that we have to send
@@ -82,38 +83,59 @@ this.DataStoreCursor = function(aWindow,
 }
 
 this.DataStoreCursor.prototype = {
   classDescription: 'DataStoreCursor XPCOM Component',
   classID: Components.ID('{b6d14349-1eab-46b8-8513-584a7328a26b}'),
   contractID: '@mozilla.org/dom/datastore-cursor-impl;1',
   QueryInterface: XPCOMUtils.generateQI([Components.interfaces.nsISupports]),
 
+  _shuttingdown: false,
+
   _window: null,
   _dataStore: null,
   _revisionId: null,
   _revision: null,
   _revisionsList: null,
   _objectId: 0,
 
   _state: STATE_INIT,
 
   init: function(aWindow, aDataStore, aRevisionId) {
     debug('DataStoreCursor init');
 
     this._window = aWindow;
     this._dataStore = aDataStore;
     this._revisionId = aRevisionId;
+
+    Services.obs.addObserver(this, "inner-window-destroyed", false);
+
+    let util = aWindow.QueryInterface(Ci.nsIInterfaceRequestor)
+                      .getInterface(Ci.nsIDOMWindowUtils);
+    this._innerWindowID = util.currentInnerWindowID;
+  },
+
+  observe: function(aSubject, aTopic, aData) {
+    let wId = aSubject.QueryInterface(Ci.nsISupportsPRUint64).data;
+    if (wId == this._innerWindowID) {
+      Services.obs.removeObserver(this, "inner-window-destroyed");
+      this._shuttingdown = true;
+    }
   },
 
   // This is the implementation of the state machine.
   // Read the comments at the top of this file in order to follow what it does.
   stateMachine: function(aStore, aRevisionStore, aResolve, aReject) {
     debug('StateMachine: ' + this._state);
 
+    // If the window has been destroyed we cannot create the Promise object.
+    if (this._shuttingdown) {
+      return;
+    }
+
     switch (this._state) {
       case STATE_INIT:
         this.stateMachineInit(aStore, aRevisionStore, aResolve, aReject);
         break;
 
       case STATE_REVISION_INIT:
         this.stateMachineRevisionInit(aStore, aRevisionStore, aResolve, aReject);
         break;
@@ -382,16 +404,21 @@ this.DataStoreCursor.prototype = {
 
   get store() {
     return this._dataStore.exposedObject;
   },
 
   next: function() {
     debug('Next');
 
+    // If the window has been destroyed we cannot create the Promise object.
+    if (this._shuttingdown) {
+      throw Cr.NS_ERROR_FAILURE;
+    }
+
     let self = this;
     return new this._window.Promise(function(aResolve, aReject) {
       self._dataStore._db.cursorTxn(
         function(aTxn, aStore, aRevisionStore) {
           self.stateMachine(aStore, aRevisionStore, aResolve, aReject);
         },
         function(aEvent) {
           aReject(createDOMError(self._window, aEvent));