Bug 832883 - Move IDBKeyRange to WebIDL and define indexedDB/IDBKeyRange in all the spots. r=khuey,bent (initial work done by Ms2ger)
authorJan Varga <jan.varga@gmail.com>
Sat, 28 Sep 2013 13:25:46 +0200
changeset 149133 81f8a3c52c23cc1c12f6a4564a5f4f2b330dbe5f
parent 149132 8918bc282c8ae3e37b52af44124245616d65e181
child 149134 92f573a2f75d7f3e9312522db8fd85be7ac0d13c
push id34447
push userJan.Varga@gmail.com
push dateSat, 28 Sep 2013 11:26:23 +0000
treeherdermozilla-inbound@81f8a3c52c23 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerskhuey, bent
bugs832883
milestone27.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 832883 - Move IDBKeyRange to WebIDL and define indexedDB/IDBKeyRange in all the spots. r=khuey,bent (initial work done by Ms2ger)
addon-sdk/source/lib/sdk/indexed-db.js
addon-sdk/source/lib/toolkit/loader.js
dom/activities/src/ActivitiesService.jsm
dom/alarm/AlarmDB.jsm
dom/alarm/AlarmService.jsm
dom/base/IndexedDBHelper.jsm
dom/base/nsDOMClassInfo.cpp
dom/base/nsDOMClassInfoClasses.h
dom/bindings/Bindings.conf
dom/contacts/fallback/ContactDB.jsm
dom/contacts/fallback/ContactService.jsm
dom/contacts/tests/test_contacts_upgrade.html
dom/indexedDB/IDBFactory.cpp
dom/indexedDB/IDBIndex.cpp
dom/indexedDB/IDBKeyRange.cpp
dom/indexedDB/IDBKeyRange.h
dom/indexedDB/IndexedDatabaseManager.cpp
dom/indexedDB/IndexedDatabaseManager.h
dom/indexedDB/moz.build
dom/indexedDB/nsIIDBKeyRange.idl
dom/indexedDB/nsIIndexedDatabaseManager.idl
dom/indexedDB/test/Makefile.in
dom/indexedDB/test/browserHelpers.js
dom/indexedDB/test/chromeHelpers.js
dom/indexedDB/test/event_propagation_iframe.html
dom/indexedDB/test/exceptions_in_events_iframe.html
dom/indexedDB/test/extensions/Makefile.in
dom/indexedDB/test/extensions/bootstrap.js
dom/indexedDB/test/extensions/install.rdf
dom/indexedDB/test/extensions/moz.build
dom/indexedDB/test/moz.build
dom/indexedDB/test/test_globalObjects.html
dom/indexedDB/test/test_globalObjects.xul
dom/indexedDB/test/unit/GlobalObjectsChild.js
dom/indexedDB/test/unit/GlobalObjectsComponent.js
dom/indexedDB/test/unit/GlobalObjectsComponent.manifest
dom/indexedDB/test/unit/GlobalObjectsModule.jsm
dom/indexedDB/test/unit/GlobalObjectsSandbox.js
dom/indexedDB/test/unit/Makefile.in
dom/indexedDB/test/unit/head.js
dom/indexedDB/test/unit/test_globalObjects.js
dom/indexedDB/test/unit/test_globalObjects_ipc.js
dom/indexedDB/test/unit/xpcshell.ini
dom/mobilemessage/src/gonk/MobileMessageDatabaseService.js
dom/mobilemessage/tests/test_smsdatabaseservice.xul
dom/network/src/NetworkStatsDB.jsm
dom/network/src/NetworkStatsService.jsm
dom/network/tests/unit_stats/test_networkstats_db.js
dom/push/src/PushService.jsm
dom/settings/SettingsDB.jsm
dom/settings/SettingsManager.js
dom/settings/SettingsService.js
dom/tests/unit/test_geolocation_provider.js
dom/tests/unit/test_geolocation_timeout.js
dom/tests/unit/xpcshell.ini
dom/webidl/IDBKeyRange.webidl
dom/webidl/moz.build
js/xpconnect/src/Sandbox.cpp
js/xpconnect/src/dom_quickstubs.qsconf
js/xpconnect/src/nsXPConnect.cpp
js/xpconnect/src/xpcprivate.h
toolkit/mozapps/extensions/XPIProvider.jsm
--- a/addon-sdk/source/lib/sdk/indexed-db.js
+++ b/addon-sdk/source/lib/sdk/indexed-db.js
@@ -22,24 +22,27 @@ let sanitizeId = function(id){
     replace(/\./g, "-dot-").
     replace(uuidRe, "$1");
 
   return domain
 };
 
 const PSEUDOURI = "indexeddb://" + sanitizeId(id) // https://bugzilla.mozilla.org/show_bug.cgi?id=779197
 
-// Injects `indexedDB` to `this` scope.
-Cc["@mozilla.org/dom/indexeddb/manager;1"].
-	getService(Ci.nsIIndexedDatabaseManager).
-	initWindowless(this);
+// Firefox 26 and earlier releases don't support `indexedDB` in sandboxes
+// automatically, so we need to inject `indexedDB` to `this` scope ourselves.
+if (typeof(indexedDB) === "undefined") {
+  Cc["@mozilla.org/dom/indexeddb/manager;1"].
+    getService(Ci.nsIIndexedDatabaseManager).
+    initWindowless(this);
 
-// Firefox 14 gets this with a prefix
-if (typeof(indexedDB) === "undefined")
-  this.indexedDB = mozIndexedDB;
+  // Firefox 14 gets this with a prefix
+  if (typeof(indexedDB) === "undefined")
+    this.indexedDB = mozIndexedDB;
+}
 
 // Use XPCOM because `require("./url").URL` doesn't expose the raw uri object.
 let principaluri = Cc["@mozilla.org/network/io-service;1"].
               getService(Ci.nsIIOService).
               newURI(PSEUDOURI, null, null);
 
 let principal = Cc["@mozilla.org/scriptsecuritymanager;1"].
 	               getService(Ci.nsIScriptSecurityManager).
--- a/addon-sdk/source/lib/toolkit/loader.js
+++ b/addon-sdk/source/lib/toolkit/loader.js
@@ -176,16 +176,18 @@ const Sandbox = iced(function Sandbox(op
   // Normalize options and rename to match `Cu.Sandbox` expectations.
   options = {
     // Do not expose `Components` if you really need them (bad idea!) you
     // still can expose via prototype.
     wantComponents: false,
     sandboxName: options.name,
     principal: 'principal' in options ? options.principal : systemPrincipal,
     wantXrays: 'wantXrays' in options ? options.wantXrays : true,
+    wantGlobalProperties: 'wantGlobalProperties' in options ?
+                          options.wantGlobalProperties : [],
     sandboxPrototype: 'prototype' in options ? options.prototype : {},
     sameGroupAs: 'sandbox' in options ? options.sandbox : null
   };
 
   // Make `options.sameGroupAs` only if `sandbox` property is passed,
   // otherwise `Cu.Sandbox` will throw.
   if (!options.sameGroupAs)
     delete options.sameGroupAs;
@@ -245,17 +247,18 @@ const load = iced(function load(loader, 
   });
 
   let sandbox = sandboxes[module.uri] = Sandbox({
     name: module.uri,
     // Get an existing module sandbox, if any, so we can reuse its compartment
     // when creating the new one to reduce memory consumption.
     sandbox: sandboxes[keys(sandboxes).shift()],
     prototype: create(globals, descriptors),
-    wantXrays: false
+    wantXrays: false,
+    wantGlobalProperties: module.id == "sdk/indexed-db" ? ["indexedDB"] : []
   });
 
   try {
     evaluate(sandbox, module.uri);
   } catch (error) {
     let { message, fileName, lineNumber } = error;
     let stack = error.stack || Error().stack;
     let frames = parseStack(stack).filter(isntLoaderFrame);
--- a/dom/activities/src/ActivitiesService.jsm
+++ b/dom/activities/src/ActivitiesService.jsm
@@ -18,38 +18,33 @@ XPCOMUtils.defineLazyServiceGetter(this,
                                    "nsIMessageBroadcaster");
 
 XPCOMUtils.defineLazyServiceGetter(this, "NetUtil",
                                    "@mozilla.org/network/util;1",
                                    "nsINetUtil");
 
 this.EXPORTED_SYMBOLS = [];
 
-let idbGlobal = this;
-
 function debug(aMsg) {
   //dump("-- ActivitiesService.jsm " + Date.now() + " " + aMsg + "\n");
 }
 
 const DB_NAME    = "activities";
 const DB_VERSION = 1;
 const STORE_NAME = "activities";
 
 function ActivitiesDb() {
 
 }
 
 ActivitiesDb.prototype = {
   __proto__: IndexedDBHelper.prototype,
 
   init: function actdb_init() {
-    let idbManager = Cc["@mozilla.org/dom/indexeddb/manager;1"]
-                       .getService(Ci.nsIIndexedDatabaseManager);
-    idbManager.initWindowless(idbGlobal);
-    this.initDBHelper(DB_NAME, DB_VERSION, [STORE_NAME], idbGlobal);
+    this.initDBHelper(DB_NAME, DB_VERSION, [STORE_NAME]);
   },
 
   /**
    * Create the initial database schema.
    *
    * The schema of records stored is as follows:
    *
    * {
--- a/dom/alarm/AlarmDB.jsm
+++ b/dom/alarm/AlarmDB.jsm
@@ -18,28 +18,27 @@ const { classes: Cc, interfaces: Ci, uti
 
 Cu.import("resource://gre/modules/Services.jsm");
 Cu.import("resource://gre/modules/IndexedDBHelper.jsm");
 
 const ALARMDB_NAME    = "alarms";
 const ALARMDB_VERSION = 1;
 const ALARMSTORE_NAME = "alarms";
 
-this.AlarmDB = function AlarmDB(aGlobal) {
+this.AlarmDB = function AlarmDB() {
   debug("AlarmDB()");
-  this._global = aGlobal;
 }
 
 AlarmDB.prototype = {
   __proto__: IndexedDBHelper.prototype,
 
-  init: function init(aGlobal) {
+  init: function init() {
     debug("init()");
 
-    this.initDBHelper(ALARMDB_NAME, ALARMDB_VERSION, [ALARMSTORE_NAME], aGlobal);
+    this.initDBHelper(ALARMDB_NAME, ALARMDB_VERSION, [ALARMSTORE_NAME]);
   },
 
   upgradeSchema: function upgradeSchema(aTransaction, aDb, aOldVersion, aNewVersion) {
     debug("upgradeSchema()");
 
     let objectStore = aDb.createObjectStore(ALARMSTORE_NAME, { keyPath: "id", autoIncrement: true });
 
     objectStore.createIndex("date",           "date",           { unique: false });
--- a/dom/alarm/AlarmService.jsm
+++ b/dom/alarm/AlarmService.jsm
@@ -31,18 +31,16 @@ XPCOMUtils.defineLazyServiceGetter(this,
 XPCOMUtils.defineLazyGetter(this, "messenger", function() {
   return Cc["@mozilla.org/system-message-internal;1"].getService(Ci.nsISystemMessagesInternal);
 });
 
 XPCOMUtils.defineLazyGetter(this, "powerManagerService", function() {
   return Cc["@mozilla.org/power/powermanagerservice;1"].getService(Ci.nsIPowerManagerService);
 });
 
-let myGlobal = this;
-
 /**
  * AlarmService provides an API to schedule alarms using the device's RTC.
  *
  * AlarmService is primarily used by the mozAlarms API (navigator.mozAlarms)
  * which uses IPC to communicate with the service.
  *
  * AlarmService can also be used by Gecko code by importing the module and then
  * using AlarmService.add() and AlarmService.remove(). Only Gecko code running
@@ -68,21 +66,18 @@ this.AlarmService = {
     this._messages = ["AlarmsManager:GetAll",
                       "AlarmsManager:Add",
                       "AlarmsManager:Remove"];
     this._messages.forEach(function addMessage(msgName) {
       ppmm.addMessageListener(msgName, this);
     }.bind(this));
 
     // Set the indexeddb database.
-    let idbManager = Cc["@mozilla.org/dom/indexeddb/manager;1"]
-                     .getService(Ci.nsIIndexedDatabaseManager);
-    idbManager.initWindowless(myGlobal);
-    this._db = new AlarmDB(myGlobal);
-    this._db.init(myGlobal);
+    this._db = new AlarmDB();
+    this._db.init();
 
     // Variable to save alarms waiting to be set.
     this._alarmQueue = [];
 
     this._restoreAlarmsFromDb();
   },
 
   // Getter/setter to access the current alarm set in system.
--- a/dom/base/IndexedDBHelper.jsm
+++ b/dom/base/IndexedDBHelper.jsm
@@ -43,17 +43,17 @@ IndexedDBHelper.prototype = {
    * @param successCb
    *        Success callback to call once database is open.
    * @param failureCb
    *        Error callback to call when an error is encountered.
    */
   open: function open(aSuccessCb, aFailureCb) {
     let self = this;
     if (DEBUG) debug("Try to open database:" + self.dbName + " " + self.dbVersion);
-    let req = this.dbGlobal.indexedDB.open(this.dbName, this.dbVersion);
+    let req = indexedDB.open(this.dbName, this.dbVersion);
     req.onsuccess = function (event) {
       if (DEBUG) debug("Opened database:" + self.dbName + " " + self.dbVersion);
       self._db = event.target.result;
       self._db.onversionchange = function(event) {
         if (DEBUG) debug("WARNING: DB modified from a different window.");
       }
       aSuccessCb();
     };
@@ -145,18 +145,15 @@ IndexedDBHelper.prototype = {
    * Initialize the DB. Does not call open.
    *
    * @param aDBName
    *        DB name for the open call.
    * @param aDBVersion
    *        Current DB version. User has to implement upgradeSchema.
    * @param aDBStoreName
    *        ObjectStore that is used.
-   * @param aGlobal
-   *        Global object that has indexedDB property.
    */
-  initDBHelper: function initDBHelper(aDBName, aDBVersion, aDBStoreNames, aGlobal) {
+  initDBHelper: function initDBHelper(aDBName, aDBVersion, aDBStoreNames) {
     this.dbName = aDBName;
     this.dbVersion = aDBVersion;
     this.dbStoreNames = aDBStoreNames;
-    this.dbGlobal = aGlobal;
   }
 }
--- a/dom/base/nsDOMClassInfo.cpp
+++ b/dom/base/nsDOMClassInfo.cpp
@@ -144,17 +144,16 @@
 // Workers
 #include "mozilla/dom/workers/Workers.h"
 
 #include "nsIDOMFile.h"
 #include "nsDOMBlobBuilder.h" // nsDOMMultipartFile
 
 #include "nsIEventListenerService.h"
 #include "nsIMessageManager.h"
-#include "mozilla/dom/indexedDB/IDBKeyRange.h"
 #include "nsIDOMMediaQueryList.h"
 
 #include "nsDOMTouchEvent.h"
 
 #include "nsWrapperCacheInlines.h"
 #include "mozilla/dom/HTMLCollectionBinding.h"
 
 #include "nsIDOMWakeLock.h"
@@ -495,19 +494,16 @@ static nsDOMClassInfoData sClassInfoData
   NS_DEFINE_CHROME_ONLY_CLASSINFO_DATA(ContentFrameMessageManager, nsEventTargetSH,
                                        DOM_DEFAULT_SCRIPTABLE_FLAGS |
                                        nsIXPCScriptable::IS_GLOBAL_OBJECT)
   NS_DEFINE_CHROME_ONLY_CLASSINFO_DATA(ChromeMessageBroadcaster, nsDOMGenericSH,
                                        DOM_DEFAULT_SCRIPTABLE_FLAGS)
   NS_DEFINE_CHROME_ONLY_CLASSINFO_DATA(ChromeMessageSender, nsDOMGenericSH,
                                        DOM_DEFAULT_SCRIPTABLE_FLAGS)
 
-  NS_DEFINE_CLASSINFO_DATA(IDBKeyRange, nsDOMGenericSH,
-                           DOM_DEFAULT_SCRIPTABLE_FLAGS)
-
 
   NS_DEFINE_CLASSINFO_DATA(MozCSSKeyframeRule, nsDOMGenericSH,
                            DOM_DEFAULT_SCRIPTABLE_FLAGS)
   NS_DEFINE_CLASSINFO_DATA(MozCSSKeyframesRule, nsDOMGenericSH,
                            DOM_DEFAULT_SCRIPTABLE_FLAGS)
 
   NS_DEFINE_CLASSINFO_DATA(CSSPageRule, nsDOMGenericSH,
                            DOM_DEFAULT_SCRIPTABLE_FLAGS)
@@ -1283,20 +1279,16 @@ nsDOMClassInfo::Init()
 
   DOM_CLASSINFO_MAP_BEGIN_NO_CLASS_IF(ChromeMessageSender, nsISupports)
     DOM_CLASSINFO_MAP_ENTRY(nsIProcessChecker)
     DOM_CLASSINFO_MAP_ENTRY(nsIFrameScriptLoader)
     DOM_CLASSINFO_MAP_ENTRY(nsIMessageListenerManager)
     DOM_CLASSINFO_MAP_ENTRY(nsIMessageSender)
   DOM_CLASSINFO_MAP_END
 
-  DOM_CLASSINFO_MAP_BEGIN(IDBKeyRange, nsIIDBKeyRange)
-    DOM_CLASSINFO_MAP_ENTRY(nsIIDBKeyRange)
-  DOM_CLASSINFO_MAP_END
-
   DOM_CLASSINFO_MAP_BEGIN(MozCSSKeyframeRule, nsIDOMMozCSSKeyframeRule)
     DOM_CLASSINFO_MAP_ENTRY(nsIDOMMozCSSKeyframeRule)
   DOM_CLASSINFO_MAP_END
 
   DOM_CLASSINFO_MAP_BEGIN(MozCSSKeyframesRule, nsIDOMMozCSSKeyframesRule)
     DOM_CLASSINFO_MAP_ENTRY(nsIDOMMozCSSKeyframesRule)
   DOM_CLASSINFO_MAP_END
 
@@ -2727,22 +2719,16 @@ nsDOMConstructor::ResolveInterfaceConsta
     class_iid = class_name_struct->mData->mProtoChainInterface;
   } else {
     return NS_OK;
   }
 
   nsresult rv = DefineInterfaceConstants(cx, obj, class_iid);
   NS_ENSURE_SUCCESS(rv, rv);
 
-  // Special case for |IDBKeyRange| which gets funny "static" functions.
-  if (class_iid->Equals(NS_GET_IID(nsIIDBKeyRange)) &&
-      !indexedDB::IDBKeyRange::DefineConstructors(cx, obj)) {
-    return NS_ERROR_FAILURE;
-  }
-
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsDOMConstructor::ToString(nsAString &aResult)
 {
   aResult.AssignLiteral("[object ");
   aResult.Append(mClassName);
@@ -2857,22 +2843,16 @@ ResolvePrototype(nsIXPConnect *aXPConnec
   const char *class_parent_name = nullptr;
 
   if (!primary_iid->Equals(NS_GET_IID(nsISupports))) {
     JSAutoCompartment ac(cx, class_obj);
 
     rv = DefineInterfaceConstants(cx, class_obj, primary_iid);
     NS_ENSURE_SUCCESS(rv, rv);
 
-    // Special case for |IDBKeyRange| which gets funny "static" functions.
-    if (primary_iid->Equals(NS_GET_IID(nsIIDBKeyRange)) &&
-        !indexedDB::IDBKeyRange::DefineConstructors(cx, class_obj)) {
-      return NS_ERROR_FAILURE;
-    }
-
     nsCOMPtr<nsIInterfaceInfoManager>
       iim(do_GetService(NS_INTERFACEINFOMANAGER_SERVICE_CONTRACTID));
     NS_ENSURE_TRUE(iim, NS_ERROR_NOT_AVAILABLE);
 
     iim->GetInfoForIID(primary_iid, getter_AddRefs(if_info));
     NS_ENSURE_TRUE(if_info, NS_ERROR_UNEXPECTED);
 
     const nsIID *iid = nullptr;
--- a/dom/base/nsDOMClassInfoClasses.h
+++ b/dom/base/nsDOMClassInfoClasses.h
@@ -104,18 +104,16 @@ DOMCI_CLASS(CSSFontFaceRule)
 DOMCI_CLASS(DataTransfer)
 
 DOMCI_CLASS(EventListenerInfo)
 
 DOMCI_CLASS(ContentFrameMessageManager)
 DOMCI_CLASS(ChromeMessageBroadcaster)
 DOMCI_CLASS(ChromeMessageSender)
 
-DOMCI_CLASS(IDBKeyRange)
-
 DOMCI_CLASS(MozCSSKeyframeRule)
 DOMCI_CLASS(MozCSSKeyframesRule)
 
 DOMCI_CLASS(CSSPageRule)
 
 DOMCI_CLASS(MediaQueryList)
 
 #ifdef MOZ_B2G_RIL
--- a/dom/bindings/Bindings.conf
+++ b/dom/bindings/Bindings.conf
@@ -613,16 +613,21 @@ DOMInterfaces = {
 'IDBIndex': {
     'nativeType': 'mozilla::dom::indexedDB::IDBIndex',
     'binaryNames': {
         'mozGetAll': 'getAll',
         'mozGetAllKeys': 'getAllKeys',
     }
 },
 
+'IDBKeyRange': {
+    'nativeType': 'mozilla::dom::indexedDB::IDBKeyRange',
+    'wrapperCache': False,
+},
+
 'IDBObjectStore': {
     'nativeType': 'mozilla::dom::indexedDB::IDBObjectStore',
     'implicitJSContext': [ 'createIndex' ],
     'binaryNames': {
         'mozGetAll': 'getAll'
     }
 },
 
--- a/dom/contacts/fallback/ContactDB.jsm
+++ b/dom/contacts/fallback/ContactDB.jsm
@@ -1082,17 +1082,17 @@ ContactDB.prototype = {
             if (tmp === "" || NON_SEARCHABLE_CHARS.test(lowerCase)) {
               if (DEBUG) debug("Call continue!");
               continue;
             }
             lowerCase = tmp;
           }
         }
         if (DEBUG) debug("lowerCase: " + lowerCase);
-        let range = this.dbGlobal.IDBKeyRange.bound(lowerCase, lowerCase + "\uFFFF");
+        let range = IDBKeyRange.bound(lowerCase, lowerCase + "\uFFFF");
         let index = store.index(key + "LowerCase");
         request = index.mozGetAll(range, limit);
       }
       if (!txn.result)
         txn.result = {};
 
       request.onsuccess = function (event) {
         if (DEBUG) debug("Request successful. Record count: " + event.target.result.length);
@@ -1129,12 +1129,12 @@ ContactDB.prototype = {
     this.substringMatching = aDigits;
   },
 
   disableSubstringMatching: function disableSubstringMatching() {
     if (DEBUG) debug("MCC disabling substring matching");
     delete this.substringMatching;
   },
 
-  init: function init(aGlobal) {
-    this.initDBHelper(DB_NAME, DB_VERSION, [STORE_NAME, SAVED_GETALL_STORE_NAME, REVISION_STORE], aGlobal);
+  init: function init() {
+    this.initDBHelper(DB_NAME, DB_VERSION, [STORE_NAME, SAVED_GETALL_STORE_NAME, REVISION_STORE]);
   }
 };
--- a/dom/contacts/fallback/ContactService.jsm
+++ b/dom/contacts/fallback/ContactService.jsm
@@ -17,46 +17,41 @@ Cu.import("resource://gre/modules/XPCOMU
 Cu.import("resource://gre/modules/Services.jsm");
 Cu.import("resource://gre/modules/ContactDB.jsm");
 Cu.import("resource://gre/modules/PhoneNumberUtils.jsm");
 
 XPCOMUtils.defineLazyServiceGetter(this, "ppmm",
                                    "@mozilla.org/parentprocessmessagemanager;1",
                                    "nsIMessageListenerManager");
 
-let myGlobal = this;
-
 let ContactService = {
   init: function() {
     if (DEBUG) debug("Init");
     this._messages = ["Contacts:Find", "Contacts:GetAll", "Contacts:GetAll:SendNow",
                       "Contacts:Clear", "Contact:Save",
                       "Contact:Remove", "Contacts:RegisterForMessages",
                       "child-process-shutdown", "Contacts:GetRevision",
                       "Contacts:GetCount"];
     this._children = [];
     this._cursors = {};
     this._messages.forEach(function(msgName) {
       ppmm.addMessageListener(msgName, this);
     }.bind(this));
 
-    var idbManager = Components.classes["@mozilla.org/dom/indexeddb/manager;1"].getService(Ci.nsIIndexedDatabaseManager);
-    idbManager.initWindowless(myGlobal);
     this._db = new ContactDB();
-    this._db.init(myGlobal);
+    this._db.init();
 
     this.configureSubstringMatching();
 
     Services.obs.addObserver(this, "profile-before-change", false);
     Services.prefs.addObserver("ril.lastKnownSimMcc", this, false);
   },
 
   observe: function(aSubject, aTopic, aData) {
     if (aTopic === 'profile-before-change') {
-      myGlobal = null;
       this._messages.forEach(function(msgName) {
         ppmm.removeMessageListener(msgName, this);
       }.bind(this));
       Services.obs.removeObserver(this, "profile-before-change");
       Services.prefs.removeObserver("dom.phonenumber.substringmatching", this);
       ppmm = null;
       this._messages = null;
       if (this._db)
--- a/dom/contacts/tests/test_contacts_upgrade.html
+++ b/dom/contacts/tests/test_contacts_upgrade.html
@@ -143,23 +143,18 @@ function makeFailure(reason) {
     ok(false, reason);
     SimpleTest.finish();
   };
 };
 
 const {Cc, Ci, Cu} = SpecialPowers;
 Cu.import("resource://gre/modules/ContactDB.jsm", window);
 
-let idb = {};
-Cc["@mozilla.org/dom/indexeddb/manager;1"]
-  .getService(Ci.nsIIndexedDatabaseManager)
-  .initWindowless(idb);
-
 let cdb = new ContactDB();
-cdb.init(idb);
+cdb.init();
 
 let CONTACT_PROPS = {
   id: "ab74671e36be41b680f8f030e7e24ea2",
   properties: {
     name: ["magnificentest foo bar the third"],
     givenName: ["foo"],
     familyName: ["bar"],
     honorificPrefix: ["magnificentest"],
@@ -192,17 +187,17 @@ let CONTACT_PROPS = {
     sex: "male",
     genderIdentity: "trisexual",
     key: "iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAIAAACQkWg2AAAACXBIWXMAAC4jAAAuIwF4pT92AAACrElEQVQozwXBTW8bRRgA4Hfemf1er7/iJI4Tq7VFlEZN1VZIlapy4MQBTkXcuSH+G/APKnGAAyCVCqmtCHETp64db5zdtdf7NbMzw/OQH378HkCZpmmapqYMy8yrNnadS6026HC/Z7k+SCkEBwKEEKaUQtQAmlDqrucH23nH4BRkJVRcwmod5gcn6LehFgCaEIIalFZaEcLCq73w355RdvY7nfGQGVTlmRXfqMlrUaSUMUQkhCISJIggKj3/YBHt7PRbpy+cwbF7dN/0vEqTMoo3s0tmGAAAoJAgImMq3xZ5WTPbHj4Mho8Nf+QcPtZBLxEkqeQ2WmklkRCtNdNaI1KpVCnqOC3j5ZK++4vnm6xSWZpzwQtRV2mOiBoRpEKtNQAQggjQcCwqinRxJeKlWW93dlqEsa2QRZbF85nWBAAZY4YUgl9fRJWKVuWgmhwHhpD1+ZrfVjAN867rMCne//rq7OuXjWaLCVHnOWHgFDwMw+Tvi09PdhtJXoVC7bWDIi8Lg8qyMk3rYjLzvJh2O30hwK6TpiG7zWDcck9GR17D9wxDcH7/oNtElRa1aZuLDJN4S7/87tssLVg0/eZs/3h0D5R89vR0v+1AVT0YHX31ZDy9uv7IeJrryeyu2+nS50/PqOXM5qt8Nf/jv08UwTfN27vkchldLpPf/nx/nqSz5sbzhkTYzLRppzNYre/ycrMIZwqsHdf96fd/Xr354AYBr/jESWhgGb6zVSuGrrQS1j4Zk8nc2Hs7frFb3Phc6+fOKDGLKOJTHvlj2u85N4t6vbw7OM4YRVquboPdsPNZ9eb8pvfAOf2iN4dN3EzWadnoO5JY19Oo0TYtw1t8TBqBR9v7wbOXROLWtZ3PH937+ZfXrb6BUHEbXL+FCIfDw92e5zebg8GR54r/AaMVcBxE6hgPAAAAJXRFWHRkYXRlOmNyZWF0ZQAyMDEyLTA3LTIxVDEwOjUzOjE5LTA0OjAwYyXbYgAAACV0RVh0ZGF0ZTptb2RpZnkAMjAxMi0wNy0yMVQxMDo1MzoxOS0wNDowMBJ4Y94AAAARdEVYdGpwZWc6Y29sb3JzcGFjZQAyLHVVnwAAACB0RVh0anBlZzpzYW1wbGluZy1mYWN0b3IAMXgxLDF4MSwxeDHplfxwAAAAAElFTkSuQmCC"
   }
 };
 
 function deleteDatabase(then) {
   cdb.close();
-  let req = idb.indexedDB.deleteDatabase(DB_NAME);
+  let req = indexedDB.deleteDatabase(DB_NAME);
   req.onsuccess = then;
   req.onblocked = makeFailure("blocked");
   req.onupgradeneeded = makeFailure("onupgradeneeded");
   req.onerror = makeFailure("onerror");
 }
 
 function saveContact() {
   // takes fast upgrade path
@@ -211,17 +206,17 @@ function saveContact() {
       ok(true, "Saved contact successfully");
       next();
     }
   );
 }
 
 function getContact(callback) {
   return function() {
-    let req = idb.indexedDB.open(STORE_NAME, DB_VERSION);
+    let req = indexedDB.open(STORE_NAME, DB_VERSION);
     req.onsuccess = function(event) {
       let db = event.target.result;
       let txn = db.transaction([STORE_NAME], "readonly");
       txn.onabort = makeFailure("Failed to open transaction");
       let r2 = txn.objectStore(STORE_NAME).get(CONTACT_PROPS.id);
       r2.onsuccess = function() {
         db.close();
         callback(r2.result);
@@ -240,17 +235,17 @@ let Tests = [
     savedContact = contact;
     next();
   }),
 
   function() {
     deleteDatabase(function() {
       info("slow upgrade");
       cdb.useFastUpgrade = false;
-      cdb.init(idb);
+      cdb.init();
       next();
     });
   },
 
   saveContact,
 
   getContact(function(contact) {
     checkDBContacts(savedContact, contact);
--- a/dom/indexedDB/IDBFactory.cpp
+++ b/dom/indexedDB/IDBFactory.cpp
@@ -183,16 +183,21 @@ IDBFactory::Create(JSContext* aCx,
 {
   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
   NS_ASSERTION(aCx, "Null context!");
   NS_ASSERTION(aOwningObject, "Null object!");
   NS_ASSERTION(JS_GetGlobalForObject(aCx, aOwningObject) == aOwningObject,
                "Not a global object!");
   NS_ASSERTION(nsContentUtils::IsCallerChrome(), "Only for chrome!");
 
+  // Make sure that the manager is up before we do anything here since lots of
+  // decisions depend on which process we're running in.
+  IndexedDatabaseManager* mgr = IndexedDatabaseManager::GetOrCreate();
+  NS_ENSURE_TRUE(mgr, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
+
   nsCString group;
   nsCString origin;
   StoragePrivilege privilege;
   PersistenceType defaultPersistenceType;
   QuotaManager::GetInfoForChrome(&group, &origin, &privilege,
                                  &defaultPersistenceType);
 
   nsRefPtr<IDBFactory> factory = new IDBFactory();
--- a/dom/indexedDB/IDBIndex.cpp
+++ b/dom/indexedDB/IDBIndex.cpp
@@ -3,18 +3,16 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "base/basictypes.h"
 
 #include "IDBIndex.h"
 
-#include "nsIIDBKeyRange.h"
-
 #include <algorithm>
 #include "mozilla/dom/ContentChild.h"
 #include "mozilla/dom/ContentParent.h"
 #include "mozilla/dom/ipc/Blob.h"
 #include "mozilla/storage.h"
 #include "nsEventDispatcher.h"
 #include "nsThreadUtils.h"
 #include "xpcpublic.h"
--- a/dom/indexedDB/IDBKeyRange.cpp
+++ b/dom/indexedDB/IDBKeyRange.cpp
@@ -11,64 +11,28 @@
 #include "nsIXPConnect.h"
 
 #include "nsJSUtils.h"
 #include "nsThreadUtils.h"
 #include "nsContentUtils.h"
 #include "nsDOMClassInfoID.h"
 #include "Key.h"
 
+#include "mozilla/dom/IDBKeyRangeBinding.h"
 #include "mozilla/dom/indexedDB/PIndexedDBIndex.h"
 #include "mozilla/dom/indexedDB/PIndexedDBObjectStore.h"
 
+using namespace mozilla;
+using namespace mozilla::dom;
 USING_INDEXEDDB_NAMESPACE
 using namespace mozilla::dom::indexedDB::ipc;
 
 namespace {
 
-inline
-bool
-ReturnKeyRange(JSContext* aCx,
-               jsval* aVp,
-               IDBKeyRange* aKeyRange)
-{
-  NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
-  NS_ASSERTION(aCx, "Null pointer!");
-  NS_ASSERTION(aVp, "Null pointer!");
-  NS_ASSERTION(aKeyRange, "Null pointer!");
-
-  nsIXPConnect* xpc = nsContentUtils::XPConnect();
-  NS_ASSERTION(xpc, "This should never be null!");
-
-  JSObject* global = JS::CurrentGlobalOrNull(aCx);
-  if (!global) {
-    NS_WARNING("Couldn't get global object!");
-    return false;
-  }
-
-  nsCOMPtr<nsIXPConnectJSObjectHolder> holder;
-  if (NS_FAILED(xpc->WrapNative(aCx, global, aKeyRange,
-                                NS_GET_IID(nsIIDBKeyRange),
-                                getter_AddRefs(holder)))) {
-    JS_ReportError(aCx, "Couldn't wrap IDBKeyRange object.");
-    return false;
-  }
-
-  JS::Rooted<JSObject*> result(aCx, holder->GetJSObject());
-  if (!result) {
-    JS_ReportError(aCx, "Couldn't get JSObject from wrapper.");
-    return false;
-  }
-
-  JS_SET_RVAL(aCx, aVp, OBJECT_TO_JSVAL(result));
-  return true;
-}
-
-inline
-nsresult
+inline nsresult
 GetKeyFromJSVal(JSContext* aCx,
                 jsval aVal,
                 Key& aKey,
                 bool aAllowUnset = false)
 {
   nsresult rv = aKey.SetFromJSVal(aCx, aVal);
   if (NS_FAILED(rv)) {
     NS_ASSERTION(NS_ERROR_GET_MODULE(rv) == NS_ERROR_MODULE_DOM_INDEXEDDB,
@@ -78,218 +42,62 @@ GetKeyFromJSVal(JSContext* aCx,
 
   if (aKey.IsUnset() && !aAllowUnset) {
     return NS_ERROR_DOM_INDEXEDDB_DATA_ERR;
   }
 
   return NS_OK;
 }
 
-inline
-void
-ThrowException(JSContext* aCx,
-               nsresult aErrorCode)
-{
-  NS_ASSERTION(NS_FAILED(aErrorCode), "Not an error code!");
-  xpc::Throw(aCx, aErrorCode);
-}
-
-inline
-bool
-GetKeyFromJSValOrThrow(JSContext* aCx,
-                       jsval aVal,
-                       Key& aKey)
-{
-  nsresult rv = GetKeyFromJSVal(aCx, aVal, aKey);
-  if (NS_FAILED(rv)) {
-    ThrowException(aCx, rv);
-    return false;
-  }
-  return true;
-}
-
-bool
-MakeOnlyKeyRange(JSContext* aCx,
-                 unsigned aArgc,
-                 jsval* aVp)
-{
-  NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
-
-  JS::Rooted<JS::Value> val(aCx);
-  if (!JS_ConvertArguments(aCx, aArgc, JS_ARGV(aCx, aVp), "v", val.address())) {
-    return false;
-  }
-
-  nsRefPtr<IDBKeyRange> keyRange = new IDBKeyRange(false, false, true);
-
-  if (!GetKeyFromJSValOrThrow(aCx, val, keyRange->Lower())) {
-    return false;
-  }
-
-  return ReturnKeyRange(aCx, aVp, keyRange);
-}
-
-bool
-MakeLowerBoundKeyRange(JSContext* aCx,
-                       unsigned aArgc,
-                       jsval* aVp)
-{
-  NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
-
-  JS::Rooted<JS::Value> val(aCx);
-  bool open = false;
-  if (!JS_ConvertArguments(aCx, aArgc, JS_ARGV(aCx, aVp), "v/b", val.address(),
-                           &open)) {
-    return false;
-  }
-
-  nsRefPtr<IDBKeyRange> keyRange = new IDBKeyRange(open, true, false);
-
-  if (!GetKeyFromJSValOrThrow(aCx, val, keyRange->Lower())) {
-    return false;
-  }
-
-  return ReturnKeyRange(aCx, aVp, keyRange);
-}
-
-bool
-MakeUpperBoundKeyRange(JSContext* aCx,
-                       unsigned aArgc,
-                       jsval* aVp)
-{
-  NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
-
-  JS::Rooted<JS::Value> val(aCx);
-  bool open = false;
-  if (!JS_ConvertArguments(aCx, aArgc, JS_ARGV(aCx, aVp), "v/b", val.address(),
-                           &open)) {
-    return false;
-  }
-
-  nsRefPtr<IDBKeyRange> keyRange = new IDBKeyRange(true, open, false);
-
-  if (!GetKeyFromJSValOrThrow(aCx, val, keyRange->Upper())) {
-    return false;
-  }
-
-  return ReturnKeyRange(aCx, aVp, keyRange);
-}
-
-bool
-MakeBoundKeyRange(JSContext* aCx,
-                  unsigned aArgc,
-                  jsval* aVp)
-{
-  NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
-
-  JS::Rooted<JS::Value> lowerVal(aCx), upperVal(aCx);
-  bool lowerOpen = false, upperOpen = false;
-  if (!JS_ConvertArguments(aCx, aArgc, JS_ARGV(aCx, aVp), "vv/bb",
-                           lowerVal.address(), upperVal.address(),
-                           &lowerOpen, &upperOpen)) {
-    return false;
-  }
-
-  nsRefPtr<IDBKeyRange> keyRange = new IDBKeyRange(lowerOpen, upperOpen, false);
-
-  if (!GetKeyFromJSValOrThrow(aCx, lowerVal, keyRange->Lower()) ||
-      !GetKeyFromJSValOrThrow(aCx, upperVal, keyRange->Upper())) {
-    return false;
-  }
-
-  if (keyRange->Lower() > keyRange->Upper() ||
-      (keyRange->Lower() == keyRange->Upper() && (lowerOpen || upperOpen))) {
-    ThrowException(aCx, NS_ERROR_DOM_INDEXEDDB_DATA_ERR);
-    return false;
-  }
-
-  return ReturnKeyRange(aCx, aVp, keyRange);
-}
-
-#define KEYRANGE_FUNCTION_FLAGS (JSPROP_ENUMERATE | JSPROP_PERMANENT)
-
-const JSFunctionSpec gKeyRangeConstructors[] = {
-  JS_FN("only", MakeOnlyKeyRange, 1, KEYRANGE_FUNCTION_FLAGS),
-  JS_FN("lowerBound", MakeLowerBoundKeyRange, 1, KEYRANGE_FUNCTION_FLAGS),
-  JS_FN("upperBound", MakeUpperBoundKeyRange, 1, KEYRANGE_FUNCTION_FLAGS),
-  JS_FN("bound", MakeBoundKeyRange, 2, KEYRANGE_FUNCTION_FLAGS),
-  JS_FS_END
-};
-
-#undef KEYRANGE_FUNCTION_FLAGS
-
 } // anonymous namespace
 
 // static
-bool
-IDBKeyRange::DefineConstructors(JSContext* aCx,
-                                JSObject* aObject)
-{
-  NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
-  NS_ASSERTION(aCx, "Null pointer!");
-  NS_ASSERTION(aObject, "Null pointer!");
-
-  // Add the constructor methods for key ranges.
-  return JS_DefineFunctions(aCx, aObject, gKeyRangeConstructors);
-}
-
-// static
 nsresult
 IDBKeyRange::FromJSVal(JSContext* aCx,
                        const jsval& aVal,
                        IDBKeyRange** aKeyRange)
 {
-  nsresult rv;
   nsRefPtr<IDBKeyRange> keyRange;
 
-  if (!aVal.isNullOrUndefined()) {
+  if (aVal.isNullOrUndefined()) {
     // undefined and null returns no IDBKeyRange.
+    keyRange.forget(aKeyRange);
+    return NS_OK;
+  }
 
-    JS::RootedObject obj(aCx, aVal.isObject() ? &aVal.toObject() : NULL);
-    if (aVal.isPrimitive() || JS_IsArrayObject(aCx, obj) || JS_ObjectIsDate(aCx, obj)) {
-      // A valid key returns an 'only' IDBKeyRange.
-      keyRange = new IDBKeyRange(false, false, true);
+  JS::RootedObject obj(aCx, aVal.isObject() ? &aVal.toObject() : nullptr);
+  if (aVal.isPrimitive() || JS_IsArrayObject(aCx, obj) ||
+      JS_ObjectIsDate(aCx, obj)) {
+    // A valid key returns an 'only' IDBKeyRange.
+    keyRange = new IDBKeyRange(nullptr, false, false, true);
 
-      rv = GetKeyFromJSVal(aCx, aVal, keyRange->Lower());
-      if (NS_FAILED(rv)) {
-        return rv;
-      }
+    nsresult rv = GetKeyFromJSVal(aCx, aVal, keyRange->Lower());
+    if (NS_FAILED(rv)) {
+      return rv;
     }
-    else {
-      // An object is not permitted unless it's another IDBKeyRange.
-      nsIXPConnect* xpc = nsContentUtils::XPConnect();
-      NS_ASSERTION(xpc, "This should never be null!");
-
-      nsCOMPtr<nsIXPConnectWrappedNative> wrapper;
-      rv = xpc->GetWrappedNativeOfJSObject(aCx, obj, getter_AddRefs(wrapper));
-      if (NS_FAILED(rv)) {
-        return NS_ERROR_DOM_INDEXEDDB_DATA_ERR;
-      }
-
-      nsCOMPtr<nsIIDBKeyRange> iface;
-      if (!wrapper || !(iface = do_QueryInterface(wrapper->Native()))) {
-        // Some random JS object?
-        return NS_ERROR_DOM_INDEXEDDB_DATA_ERR;
-      }
-
-      keyRange = static_cast<IDBKeyRange*>(iface.get());
+  }
+  else {
+    MOZ_ASSERT(aVal.isObject());
+    // An object is not permitted unless it's another IDBKeyRange.
+    if (NS_FAILED(UNWRAP_OBJECT(IDBKeyRange, aCx, obj, keyRange))) {
+      return NS_ERROR_DOM_INDEXEDDB_DATA_ERR;
     }
   }
 
   keyRange.forget(aKeyRange);
   return NS_OK;
 }
 
 // static
 template <class T>
 already_AddRefed<IDBKeyRange>
 IDBKeyRange::FromSerializedKeyRange(const T& aKeyRange)
 {
   nsRefPtr<IDBKeyRange> keyRange =
-    new IDBKeyRange(aKeyRange.lowerOpen(), aKeyRange.upperOpen(),
+    new IDBKeyRange(nullptr, aKeyRange.lowerOpen(), aKeyRange.upperOpen(),
                     aKeyRange.isOnly());
   keyRange->Lower() = aKeyRange.lower();
   if (!keyRange->IsOnly()) {
     keyRange->Upper() = aKeyRange.upper();
   }
   return keyRange.forget();
 }
 
@@ -305,39 +113,37 @@ IDBKeyRange::ToSerializedKeyRange(T& aKe
   if (!IsOnly()) {
     aKeyRange.upper() = Upper();
   }
 }
 
 NS_IMPL_CYCLE_COLLECTION_CLASS(IDBKeyRange)
 
 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(IDBKeyRange)
+  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mGlobal)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS
 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
 
 NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(IDBKeyRange)
   NS_IMPL_CYCLE_COLLECTION_TRACE_JSVAL_MEMBER_CALLBACK(mCachedLowerVal)
   NS_IMPL_CYCLE_COLLECTION_TRACE_JSVAL_MEMBER_CALLBACK(mCachedUpperVal)
 NS_IMPL_CYCLE_COLLECTION_TRACE_END
 
 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(IDBKeyRange)
+  NS_IMPL_CYCLE_COLLECTION_UNLINK(mGlobal)
   tmp->DropJSObjects();
 NS_IMPL_CYCLE_COLLECTION_UNLINK_END
 
 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(IDBKeyRange)
   NS_INTERFACE_MAP_ENTRY(nsISupports)
-  NS_INTERFACE_MAP_ENTRY(nsIIDBKeyRange)
-  NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(IDBKeyRange)
 NS_INTERFACE_MAP_END
 
 NS_IMPL_CYCLE_COLLECTING_ADDREF(IDBKeyRange)
 NS_IMPL_CYCLE_COLLECTING_RELEASE(IDBKeyRange)
 
-DOMCI_DATA(IDBKeyRange, IDBKeyRange)
-
 void
 IDBKeyRange::DropJSObjects()
 {
   if (!mRooted) {
     return;
   }
   mCachedLowerVal = JSVAL_VOID;
   mCachedUpperVal = JSVAL_VOID;
@@ -347,77 +153,148 @@ IDBKeyRange::DropJSObjects()
   mozilla::DropJSObjects(this);
 }
 
 IDBKeyRange::~IDBKeyRange()
 {
   DropJSObjects();
 }
 
-NS_IMETHODIMP
-IDBKeyRange::GetLower(JSContext* aCx,
-                      jsval* aLower)
+JSObject*
+IDBKeyRange::WrapObject(JSContext* aCx, JS::HandleObject aScope)
 {
-  NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
+  return IDBKeyRangeBinding::Wrap(aCx, aScope, this);
+}
+
+JS::Value
+IDBKeyRange::GetLower(JSContext* aCx, ErrorResult& aRv)
+{
+  MOZ_ASSERT(NS_IsMainThread(), "Wrong thread!");
 
   if (!mHaveCachedLowerVal) {
     if (!mRooted) {
       mozilla::HoldJSObjects(this);
       mRooted = true;
     }
 
-    nsresult rv = Lower().ToJSVal(aCx, mCachedLowerVal);
-    NS_ENSURE_SUCCESS(rv, rv);
+    aRv = Lower().ToJSVal(aCx, mCachedLowerVal);
+    if (aRv.Failed()) {
+      return JS::UndefinedValue();
+    }
 
     mHaveCachedLowerVal = true;
   }
 
-  *aLower = mCachedLowerVal;
-  return NS_OK;
+  return mCachedLowerVal;
 }
 
-NS_IMETHODIMP
-IDBKeyRange::GetUpper(JSContext* aCx,
-                      jsval* aUpper)
+JS::Value
+IDBKeyRange::GetUpper(JSContext* aCx, ErrorResult& aRv)
 {
-  NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
+  MOZ_ASSERT(NS_IsMainThread(), "Wrong thread!");
 
   if (!mHaveCachedUpperVal) {
     if (!mRooted) {
       mozilla::HoldJSObjects(this);
       mRooted = true;
     }
 
-    nsresult rv = Upper().ToJSVal(aCx, mCachedUpperVal);
-    NS_ENSURE_SUCCESS(rv, rv);
+    aRv = Upper().ToJSVal(aCx, mCachedUpperVal);
+    if (aRv.Failed()) {
+      return JS::UndefinedValue();
+    }
 
     mHaveCachedUpperVal = true;
   }
 
-  *aUpper = mCachedUpperVal;
-  return NS_OK;
+  return mCachedUpperVal;
+}
+
+// static
+already_AddRefed<IDBKeyRange>
+IDBKeyRange::Only(const GlobalObject& aGlobal, JSContext* aCx,
+                  JS::HandleValue aValue, ErrorResult& aRv)
+{
+  MOZ_ASSERT(NS_IsMainThread(), "Wrong thread!");
+
+  nsRefPtr<IDBKeyRange> keyRange =
+    new IDBKeyRange(aGlobal.GetAsSupports(), false, false, true);
+
+  aRv = GetKeyFromJSVal(aCx, aValue, keyRange->Lower());
+  if (aRv.Failed()) {
+    return nullptr;
+  }
+
+  return keyRange.forget();
+}
+
+// static
+already_AddRefed<IDBKeyRange>
+IDBKeyRange::LowerBound(const GlobalObject& aGlobal, JSContext* aCx,
+                        JS::HandleValue aValue, bool aOpen, ErrorResult& aRv)
+{
+  MOZ_ASSERT(NS_IsMainThread(), "Wrong thread!");
+
+  nsRefPtr<IDBKeyRange> keyRange =
+    new IDBKeyRange(aGlobal.GetAsSupports(), aOpen, true, false);
+
+  aRv = GetKeyFromJSVal(aCx, aValue, keyRange->Lower());
+  if (aRv.Failed()) {
+    return nullptr;
+  }
+
+  return keyRange.forget();
 }
 
-NS_IMETHODIMP
-IDBKeyRange::GetLowerOpen(bool* aLowerOpen)
+// static
+already_AddRefed<IDBKeyRange>
+IDBKeyRange::UpperBound(const GlobalObject& aGlobal, JSContext* aCx,
+                        JS::HandleValue aValue, bool aOpen, ErrorResult& aRv)
 {
-  NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
+  MOZ_ASSERT(NS_IsMainThread(), "Wrong thread!");
+
+  nsRefPtr<IDBKeyRange> keyRange =
+    new IDBKeyRange(aGlobal.GetAsSupports(), true, aOpen, false);
 
-  *aLowerOpen = mLowerOpen;
-  return NS_OK;
+  aRv = GetKeyFromJSVal(aCx, aValue, keyRange->Upper());
+  if (aRv.Failed()) {
+    return nullptr;
+  }
+
+  return keyRange.forget();
 }
 
-
-NS_IMETHODIMP
-IDBKeyRange::GetUpperOpen(bool* aUpperOpen)
+// static
+already_AddRefed<IDBKeyRange>
+IDBKeyRange::Bound(const GlobalObject& aGlobal, JSContext* aCx,
+                   JS::HandleValue aLower, JS::HandleValue aUpper,
+                   bool aLowerOpen, bool aUpperOpen, ErrorResult& aRv)
 {
-  NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
+  MOZ_ASSERT(NS_IsMainThread(), "Wrong thread!");
+
+  nsRefPtr<IDBKeyRange> keyRange =
+    new IDBKeyRange(aGlobal.GetAsSupports(), aLowerOpen, aUpperOpen, false);
+
+  aRv = GetKeyFromJSVal(aCx, aLower, keyRange->Lower());
+  if (aRv.Failed()) {
+    return nullptr;
+  }
 
-  *aUpperOpen = mUpperOpen;
-  return NS_OK;
+  aRv = GetKeyFromJSVal(aCx, aUpper, keyRange->Upper());
+  if (aRv.Failed()) {
+    return nullptr;
+  }
+
+  if (keyRange->Lower() > keyRange->Upper() ||
+      (keyRange->Lower() == keyRange->Upper() && (aLowerOpen || aUpperOpen))) {
+    aRv.Throw(NS_ERROR_DOM_INDEXEDDB_DATA_ERR);
+    return nullptr;
+  }
+
+  return keyRange.forget();
 }
 
 // Explicitly instantiate for all our key range types... Grumble.
 template already_AddRefed<IDBKeyRange>
 IDBKeyRange::FromSerializedKeyRange<KeyRange> (const KeyRange& aKeyRange);
 
 template void
 IDBKeyRange::ToSerializedKeyRange<KeyRange> (KeyRange& aKeyRange);
--- a/dom/indexedDB/IDBKeyRange.h
+++ b/dom/indexedDB/IDBKeyRange.h
@@ -5,54 +5,49 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef mozilla_dom_indexeddb_idbkeyrange_h__
 #define mozilla_dom_indexeddb_idbkeyrange_h__
 
 #include "mozilla/dom/indexedDB/IndexedDatabase.h"
 #include "mozilla/dom/indexedDB/Key.h"
 
-#include "nsIIDBKeyRange.h"
+#include "nsISupports.h"
 
+#include "mozilla/ErrorResult.h"
 #include "nsCycleCollectionParticipant.h"
 
 class mozIStorageStatement;
 
+namespace mozilla {
+namespace dom {
+class GlobalObject;
+} // namespace dom
+} // namespace mozilla
+
 BEGIN_INDEXEDDB_NAMESPACE
 
 namespace ipc {
 class KeyRange;
 } // namespace ipc
 
-class IDBKeyRange MOZ_FINAL : public nsIIDBKeyRange
+class IDBKeyRange MOZ_FINAL : public nsISupports
 {
 public:
   NS_DECL_CYCLE_COLLECTING_ISUPPORTS
-  NS_DECL_NSIIDBKEYRANGE
   NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(IDBKeyRange)
 
-  static bool DefineConstructors(JSContext* aCx,
-                                 JSObject* aObject);
-
   static nsresult FromJSVal(JSContext* aCx,
                             const jsval& aVal,
                             IDBKeyRange** aKeyRange);
 
   template <class T>
   static already_AddRefed<IDBKeyRange>
   FromSerializedKeyRange(const T& aKeyRange);
 
-  IDBKeyRange(bool aLowerOpen,
-              bool aUpperOpen,
-              bool aIsOnly)
-  : mCachedLowerVal(JSVAL_VOID), mCachedUpperVal(JSVAL_VOID),
-    mLowerOpen(aLowerOpen), mUpperOpen(aUpperOpen), mIsOnly(aIsOnly),
-    mHaveCachedLowerVal(false), mHaveCachedUpperVal(false), mRooted(false)
-  { }
-
   const Key& Lower() const
   {
     return mLower;
   }
 
   Key& Lower()
   {
     return mLower;
@@ -63,16 +58,17 @@ public:
     return mIsOnly ? mLower : mUpper;
   }
 
   Key& Upper()
   {
     return mIsOnly ? mLower : mUpper;
   }
 
+  // TODO: Remove these in favour of LowerOpen() / UpperOpen(), bug 900578.
   bool IsLowerOpen() const
   {
     return mLowerOpen;
   }
 
   bool IsUpperOpen() const
   {
     return mUpperOpen;
@@ -145,26 +141,81 @@ public:
     return NS_OK;
   }
 
   template <class T>
   void ToSerializedKeyRange(T& aKeyRange);
 
   void DropJSObjects();
 
+  // WebIDL
+  JSObject*
+  WrapObject(JSContext* aCx, JS::HandleObject aScope);
+
+  nsISupports*
+  GetParentObject() const
+  {
+    return mGlobal;
+  }
+
+  JS::Value
+  GetLower(JSContext* aCx, ErrorResult& aRv);
+
+  JS::Value
+  GetUpper(JSContext* aCx, ErrorResult& aRv);
+
+  bool
+  LowerOpen() const
+  {
+    return mLowerOpen;
+  }
+
+  bool
+  UpperOpen() const
+  {
+    return mUpperOpen;
+  }
+
+  static already_AddRefed<IDBKeyRange>
+  Only(const GlobalObject& aGlobal, JSContext* aCx, JS::HandleValue aValue,
+       ErrorResult& aRv);
+
+  static already_AddRefed<IDBKeyRange>
+  LowerBound(const GlobalObject& aGlobal, JSContext* aCx,
+             JS::HandleValue aValue, bool aOpen, ErrorResult& aRv);
+
+  static already_AddRefed<IDBKeyRange>
+  UpperBound(const GlobalObject& aGlobal, JSContext* aCx,
+             JS::HandleValue aValue, bool aOpen, ErrorResult& aRv);
+
+  static already_AddRefed<IDBKeyRange>
+  Bound(const GlobalObject& aGlobal, JSContext* aCx, JS::HandleValue aLower,
+        JS::HandleValue aUpper, bool aLowerOpen, bool aUpperOpen,
+        ErrorResult& aRv);
+
 private:
+  IDBKeyRange(nsISupports* aGlobal,
+              bool aLowerOpen,
+              bool aUpperOpen,
+              bool aIsOnly)
+  : mGlobal(aGlobal), mCachedLowerVal(JSVAL_VOID), mCachedUpperVal(JSVAL_VOID),
+    mLowerOpen(aLowerOpen), mUpperOpen(aUpperOpen), mIsOnly(aIsOnly),
+    mHaveCachedLowerVal(false), mHaveCachedUpperVal(false), mRooted(false)
+  { }
+
   ~IDBKeyRange();
 
+  nsCOMPtr<nsISupports> mGlobal;
   Key mLower;
   Key mUpper;
   JS::Heap<JS::Value> mCachedLowerVal;
   JS::Heap<JS::Value> mCachedUpperVal;
-  bool mLowerOpen;
-  bool mUpperOpen;
-  bool mIsOnly;
+  const bool mLowerOpen;
+  const bool mUpperOpen;
+  const bool mIsOnly;
   bool mHaveCachedLowerVal;
   bool mHaveCachedUpperVal;
   bool mRooted;
 };
 
 END_INDEXEDDB_NAMESPACE
 
 #endif // mozilla_dom_indexeddb_idbkeyrange_h__
--- a/dom/indexedDB/IndexedDatabaseManager.cpp
+++ b/dom/indexedDB/IndexedDatabaseManager.cpp
@@ -32,23 +32,27 @@
 #include "IDBFactory.h"
 #include "IDBKeyRange.h"
 #include "IDBRequest.h"
 
 // Bindings for ResolveConstructors
 #include "mozilla/dom/IDBCursorBinding.h"
 #include "mozilla/dom/IDBDatabaseBinding.h"
 #include "mozilla/dom/IDBFactoryBinding.h"
+#include "mozilla/dom/IDBFileHandleBinding.h"
+#include "mozilla/dom/IDBKeyRangeBinding.h"
 #include "mozilla/dom/IDBIndexBinding.h"
 #include "mozilla/dom/IDBObjectStoreBinding.h"
 #include "mozilla/dom/IDBOpenDBRequestBinding.h"
 #include "mozilla/dom/IDBRequestBinding.h"
 #include "mozilla/dom/IDBTransactionBinding.h"
 #include "mozilla/dom/IDBVersionChangeEventBinding.h"
 
+#define IDB_STR "indexedDB"
+
 // The two possible values for the data argument when receiving the disk space
 // observer notification.
 #define LOW_DISK_SPACE_DATA_FULL "full"
 #define LOW_DISK_SPACE_DATA_FREE "free"
 
 USING_INDEXEDDB_NAMESPACE
 using namespace mozilla::dom;
 USING_QUOTA_NAMESPACE
@@ -115,24 +119,27 @@ struct ConstructorInfo {
   jsid id;
 };
 
 ConstructorInfo gConstructorInfo[] = {
 
 #define BINDING_ENTRY(_name) \
   { #_name, _name##Binding::GetConstructorObject, JSID_VOID },
 
-  BINDING_ENTRY(IDBFactory)
+  BINDING_ENTRY(IDBCursor)
+  BINDING_ENTRY(IDBCursorWithValue)
   BINDING_ENTRY(IDBDatabase)
-  BINDING_ENTRY(IDBTransaction)
+  BINDING_ENTRY(IDBFactory)
+  BINDING_ENTRY(IDBFileHandle)
+  BINDING_ENTRY(IDBIndex)
+  BINDING_ENTRY(IDBKeyRange)
   BINDING_ENTRY(IDBObjectStore)
-  BINDING_ENTRY(IDBIndex)
-  BINDING_ENTRY(IDBCursor)
+  BINDING_ENTRY(IDBOpenDBRequest)
   BINDING_ENTRY(IDBRequest)
-  BINDING_ENTRY(IDBOpenDBRequest)
+  BINDING_ENTRY(IDBTransaction)
   BINDING_ENTRY(IDBVersionChangeEvent)
 
 #undef BINDING_ENTRY
 };
 
 class AsyncDeleteFileRunnable MOZ_FINAL : public nsIRunnable
 {
 public:
@@ -195,16 +202,60 @@ struct MOZ_STACK_CLASS InvalidateInfo
   InvalidateInfo(PersistenceType aPersistenceType, const nsACString& aPattern)
   : persistenceType(aPersistenceType), pattern(aPattern)
   { }
 
   PersistenceType persistenceType;
   const nsACString& pattern;
 };
 
+bool
+GetIndexedDB(JSContext* aCx, JS::HandleObject aGlobal,
+             JS::MutableHandleValue aResult)
+{
+  MOZ_ASSERT(nsContentUtils::IsCallerChrome(), "Only for chrome!");
+  MOZ_ASSERT(js::GetObjectClass(aGlobal)->flags & JSCLASS_DOM_GLOBAL,
+             "Not a global object!");
+
+  nsRefPtr<IDBFactory> factory;
+  if (NS_FAILED(IDBFactory::Create(aCx, aGlobal, nullptr,
+                                   getter_AddRefs(factory)))) {
+    return false;
+  }
+
+  MOZ_ASSERT(factory, "This should never fail for chrome!");
+
+  return !!WrapNewBindingObject(aCx, aGlobal, factory, aResult);
+}
+
+bool
+IndexedDBLazyGetter(JSContext* aCx, JS::HandleObject aGlobal,
+                    JS::HandleId aId, JS::MutableHandleValue aVp)
+{
+  MOZ_ASSERT(nsContentUtils::IsCallerChrome(), "Only for chrome!");
+  MOZ_ASSERT(js::GetObjectClass(aGlobal)->flags & JSCLASS_DOM_GLOBAL,
+             "Not a global object!");
+  MOZ_ASSERT(JSID_IS_STRING(aId), "Bad id!");
+  MOZ_ASSERT(JS_FlatStringEqualsAscii(JSID_TO_FLAT_STRING(aId), IDB_STR),
+             "Bad id!");
+
+  JS::RootedValue indexedDB(aCx);
+  if (!GetIndexedDB(aCx, aGlobal, &indexedDB)) {
+    return false;
+  }
+
+  if (!JS_DefinePropertyById(aCx, aGlobal, aId, indexedDB, nullptr, nullptr,
+                             JSPROP_ENUMERATE)) {
+    return false;
+  }
+
+  aVp.set(indexedDB);
+  return true;
+}
+
 } // anonymous namespace
 
 IndexedDatabaseManager::IndexedDatabaseManager()
 : mFileMutex("IndexedDatabaseManager.mFileMutex")
 {
   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
 }
 
@@ -423,16 +474,65 @@ IndexedDatabaseManager::TabContextMayAcc
                                                 aContext.IsBrowserElement(),
                                                 pattern);
 
   return PatternMatchesOrigin(pattern, aOrigin);
 }
 
 // static
 bool
+IndexedDatabaseManager::DefineConstructors(JSContext* aCx,
+                                           JS::HandleObject aGlobal)
+{
+  MOZ_ASSERT(NS_IsMainThread());
+
+  for (uint32_t i = 0; i < mozilla::ArrayLength(gConstructorInfo); i++) {
+    if (!gConstructorInfo[i].resolve(aCx, aGlobal, true)) {
+      return false;
+    }
+  }
+
+  return true;
+}
+
+// static
+bool
+IndexedDatabaseManager::DefineIndexedDBGetter(JSContext* aCx,
+                                              JS::HandleObject aGlobal)
+{
+  MOZ_ASSERT(NS_IsMainThread());
+  MOZ_ASSERT(nsContentUtils::IsCallerChrome(), "Only for chrome!");
+  MOZ_ASSERT(js::GetObjectClass(aGlobal)->flags & JSCLASS_DOM_GLOBAL,
+             "Passed object is not a global object!");
+
+  JS::RootedValue indexedDB(aCx);
+  if (!GetIndexedDB(aCx, aGlobal, &indexedDB)) {
+    return false;
+  }
+
+  return JS_DefineProperty(aCx, aGlobal, IDB_STR, indexedDB, nullptr, nullptr,
+                           JSPROP_ENUMERATE);
+}
+
+// static
+bool
+IndexedDatabaseManager::DefineIndexedDBLazyGetter(JSContext* aCx,
+                                                  JS::HandleObject aGlobal)
+{
+  MOZ_ASSERT(NS_IsMainThread());
+  MOZ_ASSERT(nsContentUtils::IsCallerChrome(), "Only for chrome!");
+  MOZ_ASSERT(js::GetObjectClass(aGlobal)->flags & JSCLASS_DOM_GLOBAL,
+             "Passed object is not a global object!");
+
+  return JS_DefineProperty(aCx, aGlobal, IDB_STR, JSVAL_VOID,
+                           IndexedDBLazyGetter, nullptr, 0);
+}
+
+// static
+bool
 IndexedDatabaseManager::IsClosed()
 {
   return !!gClosed;
 }
 
 #ifdef DEBUG
 // static
 bool
@@ -621,62 +721,37 @@ IndexedDatabaseManager::BlockAndGetFileR
 }
 
 NS_IMPL_ADDREF(IndexedDatabaseManager)
 NS_IMPL_RELEASE_WITH_DESTROY(IndexedDatabaseManager, Destroy())
 NS_IMPL_QUERY_INTERFACE2(IndexedDatabaseManager, nsIIndexedDatabaseManager,
                                                  nsIObserver)
 
 NS_IMETHODIMP
-IndexedDatabaseManager::InitWindowless(const jsval& aObj, JSContext* aCx)
+IndexedDatabaseManager::InitWindowless(const jsval& aGlobal, JSContext* aCx)
 {
   NS_ENSURE_TRUE(nsContentUtils::IsCallerChrome(), NS_ERROR_NOT_AVAILABLE);
-  NS_ENSURE_ARG(!JSVAL_IS_PRIMITIVE(aObj));
 
-  JS::Rooted<JSObject*> obj(aCx, JSVAL_TO_OBJECT(aObj));
+  JS::RootedObject global(aCx, JSVAL_TO_OBJECT(aGlobal));
+  if (!(js::GetObjectClass(global)->flags & JSCLASS_DOM_GLOBAL)) {
+    NS_WARNING("Passed object is not a global object!");
+    return NS_ERROR_FAILURE;
+  }
 
   bool hasIndexedDB;
-  if (!JS_HasProperty(aCx, obj, "indexedDB", &hasIndexedDB)) {
+  if (!JS_HasProperty(aCx, global, IDB_STR, &hasIndexedDB)) {
     return NS_ERROR_FAILURE;
   }
 
   if (hasIndexedDB) {
     NS_WARNING("Passed object already has an 'indexedDB' property!");
     return NS_ERROR_FAILURE;
   }
 
-  JS::Rooted<JSObject*> global(aCx, JS_GetGlobalForObject(aCx, obj));
-  NS_ASSERTION(global, "What?! No global!");
-
-  nsRefPtr<IDBFactory> factory;
-  nsresult rv =
-    IDBFactory::Create(aCx, global, nullptr, getter_AddRefs(factory));
-  NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
-
-  NS_ASSERTION(factory, "This should never fail for chrome!");
-
-  JS::Rooted<JS::Value> indexedDBVal(aCx);
-  rv = nsContentUtils::WrapNative(aCx, obj, factory, indexedDBVal.address());
-  NS_ENSURE_SUCCESS(rv, rv);
-
-  if (!JS_DefineProperty(aCx, obj, "indexedDB", indexedDBVal, nullptr,
-                         nullptr, JSPROP_ENUMERATE)) {
-    return NS_ERROR_FAILURE;
-  }
-
-  JS::Rooted<JSObject*> keyrangeObj(aCx,
-    JS_NewObject(aCx, nullptr, nullptr, nullptr));
-  NS_ENSURE_TRUE(keyrangeObj, NS_ERROR_OUT_OF_MEMORY);
-
-  if (!IDBKeyRange::DefineConstructors(aCx, keyrangeObj)) {
-    return NS_ERROR_FAILURE;
-  }
-
-  if (!JS_DefineProperty(aCx, obj, "IDBKeyRange", OBJECT_TO_JSVAL(keyrangeObj),
-                         nullptr, nullptr, JSPROP_ENUMERATE)) {
+  if (!DefineConstructors(aCx, global) || !DefineIndexedDBGetter(aCx, global)) {
     return NS_ERROR_FAILURE;
   }
 
   return NS_OK;
 }
 
 NS_IMETHODIMP
 IndexedDatabaseManager::Observe(nsISupports* aSubject, const char* aTopic,
--- a/dom/indexedDB/IndexedDatabaseManager.h
+++ b/dom/indexedDB/IndexedDatabaseManager.h
@@ -134,16 +134,25 @@ public:
   static nsresult
   FireWindowOnError(nsPIDOMWindow* aOwner,
                     nsEventChainPostVisitor& aVisitor);
 
   static bool
   TabContextMayAccessOrigin(const mozilla::dom::TabContext& aContext,
                             const nsACString& aOrigin);
 
+  static bool
+  DefineConstructors(JSContext* aCx, JS::HandleObject aGlobal);
+
+  static bool
+  DefineIndexedDBGetter(JSContext* aCx, JS::HandleObject aGlobal);
+
+  static bool
+  DefineIndexedDBLazyGetter(JSContext* aCx, JS::HandleObject aGlobal);
+
 private:
   IndexedDatabaseManager();
   ~IndexedDatabaseManager();
 
   nsresult
   Init();
 
   void
--- a/dom/indexedDB/moz.build
+++ b/dom/indexedDB/moz.build
@@ -3,17 +3,16 @@
 # This Source Code Form is subject to the terms of the Mozilla Public
 # License, v. 2.0. If a copy of the MPL was not distributed with this
 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
 
 DIRS += ['ipc']
 TEST_DIRS += ['test']
 
 XPIDL_SOURCES += [
-    'nsIIDBKeyRange.idl',
     'nsIIndexedDatabaseManager.idl',
 ]
 
 XPIDL_MODULE = 'dom_indexeddb'
 
 MODULE = 'dom'
 
 EXPORTS.mozilla.dom.indexedDB += [
deleted file mode 100644
--- a/dom/indexedDB/nsIIDBKeyRange.idl
+++ /dev/null
@@ -1,25 +0,0 @@
-/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
-/* vim: set ts=2 et sw=2 tw=80: */
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-#include "nsISupports.idl"
-
-/**
- * IDBKeyRange interface.  See
- * http://dev.w3.org/2006/webapi/WebSimpleDB/#idl-def-IDBKeyRange for more
- * information.
- */
-[scriptable, builtinclass, uuid(8aeb8660-76b3-4651-b8c2-9894ae6dfe68)]
-interface nsIIDBKeyRange : nsISupports
-{
-  [implicit_jscontext]
-  readonly attribute jsval lower;
-
-  [implicit_jscontext]
-  readonly attribute jsval upper;
-
-  readonly attribute boolean lowerOpen;
-  readonly attribute boolean upperOpen;
-};
--- a/dom/indexedDB/nsIIndexedDatabaseManager.idl
+++ b/dom/indexedDB/nsIIndexedDatabaseManager.idl
@@ -5,17 +5,21 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "nsISupports.idl"
 
 [scriptable, builtinclass, uuid(538d1085-517e-405a-a0f0-eb575cb0b8e5)]
 interface nsIIndexedDatabaseManager : nsISupports
 {
   /**
-   * Defines indexedDB and IDBKeyrange with its static functions on 
-   * aObject and initializes DOM exception providers if needed.
+   * Defines indexedDB and IDBKeyRange with its static functions on aGlobal.
    *
-   * @param aObject
-   *        The object, indexedDB and IDBKeyrange should be defined on.
+   * This method might go away some time in the future, indexedDB and
+   * IDBKeyRange should now be defined in all the spots (content windows,
+   * chrome windows, xpcshell, JS modules, JS components, JS sandboxes,
+   * ipcshell, bootstrapped extensions and Jetpack)
+   *
+   * @param aGlobal
+   *        The global object, indexedDB and IDBKeyRange should be defined on.
    */
   [implicit_jscontext]
-  void initWindowless(in jsval aObject);
+  void initWindowless(in jsval aGlobal);
 };
--- a/dom/indexedDB/test/Makefile.in
+++ b/dom/indexedDB/test/Makefile.in
@@ -48,16 +48,17 @@ MOCHITEST_FILES = \
   test_file_resurrection_transaction_abort.html \
   test_file_sharing.html \
   test_file_transaction_abort.html \
   test_filehandle_quota.html \
   test_filehandle_serialization.html \
   test_filehandle_store_snapshot.html \
   test_getAll.html \
   test_get_filehandle.html \
+  test_globalObjects.html \
   test_global_data.html \
   test_index_empty_keyPath.html \
   test_index_getAll.html \
   test_index_getAllObjects.html \
   test_index_object_cursors.html \
   test_index_update_delete.html \
   test_indexes.html \
   test_indexes_bad_values.html \
@@ -110,16 +111,21 @@ MOCHITEST_FILES = \
   webapp_clearBrowserData.js \
   webapp_clearBrowserData_appFrame.html \
   webapp_clearBrowserData_browserFrame.html \
   $(NULL)
 
 #   test_bug847147.html disabled for timeouts
 #   test_writer_starvation.html  disabled for infinite loops, bug 595368
 
+MOCHITEST_CHROME_FILES = \
+  chromeHelpers.js \
+  test_globalObjects.xul \
+  $(NULL)
+
 ifeq (browser,$(MOZ_BUILD_APP))
 MOCHITEST_BROWSER_FILES = \
   browser_forgetThisSite.js \
   browser_forgetThisSiteAdd.html \
   browser_forgetThisSiteGet.html \
   browserHelpers.js \
   browser_permissionsPrompt.html \
   browser_permissionsPromptAllow.js \
--- a/dom/indexedDB/test/browserHelpers.js
+++ b/dom/indexedDB/test/browserHelpers.js
@@ -34,17 +34,17 @@ function finishTest()
 
 function grabEventAndContinueHandler(event)
 {
   testGenerator.send(event);
 }
 
 function errorHandler(event)
 {
-  throw new Error("indexedDB error, code " + event.target.errorCode);
+  throw new Error("indexedDB error, code " + event.target.error.name);
 }
 
 function continueToNextStep()
 {
   SimpleTest.executeSoon(function() {
     testGenerator.next();
   });
 }
new file mode 100644
--- /dev/null
+++ b/dom/indexedDB/test/chromeHelpers.js
@@ -0,0 +1,40 @@
+/**
+ * Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+const { 'classes': Cc, 'interfaces': Ci, 'utils': Cu } = Components;
+
+let testGenerator = testSteps();
+
+function runTest()
+{
+  SimpleTest.waitForExplicitFinish();
+
+  testGenerator.next();
+}
+
+function finishTest()
+{
+  SimpleTest.executeSoon(function() {
+    testGenerator.close();
+    SimpleTest.finish();
+  });
+}
+
+function grabEventAndContinueHandler(event)
+{
+  testGenerator.send(event);
+}
+
+function continueToNextStep()
+{
+  SimpleTest.executeSoon(function() {
+    testGenerator.next();
+  });
+}
+
+function errorHandler(event)
+{
+  throw new Error("indexedDB error, code " + event.target.error.name);
+}
--- a/dom/indexedDB/test/event_propagation_iframe.html
+++ b/dom/indexedDB/test/event_propagation_iframe.html
@@ -16,17 +16,17 @@
                                 "');", "*");
     }
 
     function grabEventAndContinueHandler(event) {
       testGenerator.send(event);
     }
 
     function errorHandler(event) {
-      ok(false, "indexedDB error, code " + event.target.errorCode);
+      ok(false, "indexedDB error, code " + event.target.error.name);
       finishTest();
     }
 
     function finishTest() {
       // Let window.onerror have a chance to fire
       setTimeout(function() {
         setTimeout(function() {
           testGenerator.close();
--- a/dom/indexedDB/test/exceptions_in_events_iframe.html
+++ b/dom/indexedDB/test/exceptions_in_events_iframe.html
@@ -22,17 +22,17 @@
       ok(a == b, message);
     }
 
     function grabEventAndContinueHandler(event) {
       testGenerator.send(event);
     }
 
     function errorHandler(event) {
-      ok(false, "indexedDB error, code " + event.target.errorCode);
+      ok(false, "indexedDB error, code " + event.target.error.name);
       finishTest();
     }
 
     function unexpectedSuccessHandler(event) {
       ok(false, "got success when it was not expected!");
       finishTest();
     }
 
new file mode 100644
--- /dev/null
+++ b/dom/indexedDB/test/extensions/Makefile.in
@@ -0,0 +1,19 @@
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+XPI_NAME = indexedDB
+
+DIST_FILES = \
+  bootstrap.js \
+  install.rdf \
+  $(NULL)
+
+TEST_EXTENSIONS_DIR = $(DEPTH)/_tests/testing/mochitest/extensions
+
+GENERATED_DIRS = $(TEST_EXTENSIONS_DIR)
+
+include $(topsrcdir)/config/rules.mk
+
+libs::
+	@(cd $(DIST)/xpi-stage && tar $(TAR_CREATE_FLAGS) - $(XPI_NAME)) | (cd $(TEST_EXTENSIONS_DIR) && tar -xf -)
new file mode 100644
--- /dev/null
+++ b/dom/indexedDB/test/extensions/bootstrap.js
@@ -0,0 +1,84 @@
+/**
+ * Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+const Ci = Components.interfaces;
+const Cu = Components.utils;
+
+Cu.import("resource://gre/modules/Services.jsm");
+Cu.import("resource://gre/modules/XPCOMUtils.jsm");
+
+function testForExpectedSymbols(stage, data) {
+  const expectedSymbols = [ "IDBKeyRange", "indexedDB" ];
+  for each (var symbol in expectedSymbols) {
+    Services.prefs.setBoolPref("indexeddbtest.bootstrap." + stage + "." +
+                               symbol, symbol in this);
+  }
+}
+
+function GlobalObjectsComponent() {
+  this.wrappedJSObject = this;
+}
+
+GlobalObjectsComponent.prototype =
+{
+  QueryInterface: XPCOMUtils.generateQI([Ci.nsISupports]),
+
+  runTest: function() {
+    const name = "Splendid Test";
+
+    let ok = this.ok;
+    let finishTest = this.finishTest;
+
+    let keyRange = IDBKeyRange.only(42);
+    ok(keyRange, "Got keyRange");
+
+    let request = indexedDB.open(name, 1);
+    request.onerror = function(event) {
+      ok(false, "indexedDB error, '" + event.target.error.name + "'");
+      finishTest();
+    }
+    request.onsuccess = function(event) {
+      let db = event.target.result;
+      ok(db, "Got database");
+      finishTest();
+    }
+  }
+};
+
+var gFactory = {
+  register: function() {
+    var registrar = Components.manager.QueryInterface(Ci.nsIComponentRegistrar);
+
+    var classID = Components.ID("{d6f85dcb-537d-447e-b783-75d4b405622d}");
+    var description = "IndexedDBTest";
+    var contractID = "@mozilla.org/dom/indexeddb/GlobalObjectsComponent;1";
+    var factory = XPCOMUtils._getFactory(GlobalObjectsComponent);
+
+    registrar.registerFactory(classID, description, contractID, factory);
+
+    this.unregister = function() {
+      registrar.unregisterFactory(classID, factory);
+      delete this.unregister;
+    };
+  }
+};
+
+function install(data, reason) {
+  testForExpectedSymbols("install");
+}
+
+function startup(data, reason) {
+  testForExpectedSymbols("startup");
+  gFactory.register();
+}
+
+function shutdown(data, reason) {
+  testForExpectedSymbols("shutdown");
+  gFactory.unregister();
+}
+
+function uninstall(data, reason) {
+  testForExpectedSymbols("uninstall");
+}
new file mode 100644
--- /dev/null
+++ b/dom/indexedDB/test/extensions/install.rdf
@@ -0,0 +1,22 @@
+<?xml version="1.0"?>
+
+<RDF xmlns="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+     xmlns:em="http://www.mozilla.org/2004/em-rdf#">
+
+  <Description about="urn:mozilla:install-manifest">
+    <em:name>IndexedDBTest</em:name>
+    <em:description>IndexedDB functions for use in testing.</em:description>
+    <em:creator>Mozilla</em:creator>
+    <em:version>2013.10.10</em:version>
+#expand    <em:id>__XPI_NAME__-test@mozilla.org</em:id>
+    <em:type>2</em:type>
+    <em:bootstrap>true</em:bootstrap>
+    <em:targetApplication>
+      <Description>
+        <em:id>toolkit@mozilla.org</em:id>
+#expand        <em:minVersion>__MOZILLA_VERSION_U__</em:minVersion>
+#expand        <em:maxVersion>__MOZILLA_VERSION_U__</em:maxVersion>
+      </Description>
+    </em:targetApplication>
+  </Description>
+</RDF>
new file mode 100644
--- /dev/null
+++ b/dom/indexedDB/test/extensions/moz.build
@@ -0,0 +1,6 @@
+# -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*-
+# vim: set filetype=python:
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
--- a/dom/indexedDB/test/moz.build
+++ b/dom/indexedDB/test/moz.build
@@ -1,9 +1,11 @@
 # -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*-
 # vim: set filetype=python:
 # This Source Code Form is subject to the terms of the Mozilla Public
 # License, v. 2.0. If a copy of the MPL was not distributed with this
 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
 
+DIRS += ['extensions']
+
 TEST_DIRS += ['unit']
 
 XPCSHELL_TESTS_MANIFESTS += ['unit/xpcshell.ini']
new file mode 100644
--- /dev/null
+++ b/dom/indexedDB/test/test_globalObjects.html
@@ -0,0 +1,38 @@
+<!--
+  Any copyright is dedicated to the Public Domain.
+  http://creativecommons.org/publicdomain/zero/1.0/
+-->
+<html>
+<head>
+  <title>Indexed Database Property Test</title>
+
+  <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+
+  <script type="text/javascript;version=1.7">
+  function testSteps()
+  {
+    const name = window.location.pathname;
+
+    // Test for IDBKeyRange and indexedDB availability in content windows.
+    let keyRange = IDBKeyRange.only(42);
+    ok(keyRange, "Got keyRange");
+
+    let request = indexedDB.open(name, 1);
+    request.onerror = errorHandler;
+    request.onsuccess = grabEventAndContinueHandler;
+    let event = yield undefined;
+
+    let db = event.target.result;
+    ok(db, "Got database");
+
+    finishTest();
+    yield undefined;
+  }
+  </script>
+  <script type="text/javascript;version=1.7" src="helpers.js"></script>
+</head>
+
+<body onload="runTest();"></body>
+
+</html>
new file mode 100644
--- /dev/null
+++ b/dom/indexedDB/test/test_globalObjects.xul
@@ -0,0 +1,72 @@
+<?xml version="1.0"?>
+<?xml-stylesheet type="text/css" href="chrome://global/skin"?>
+<?xml-stylesheet type="text/css" href="/tests/SimpleTest/test.css"?>
+<!--
+  Any copyright is dedicated to the Public Domain.
+  http://creativecommons.org/publicdomain/zero/1.0/
+-->
+<window title="Mozilla Bug 832883"
+        xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
+        onload="runTest();">
+  <script type="application/javascript"
+          src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"/>
+
+  <script type="application/javascript;version=1.7">
+  <![CDATA[
+  function testSteps() {
+    const name = window.location.pathname;
+
+    // Test for IDBKeyRange and indexedDB availability in chrome windows.
+    var keyRange = IDBKeyRange.only(42);
+    ok(keyRange, "Got keyRange");
+
+    var request = indexedDB.open(name, 1);
+    request.onerror = errorHandler;
+    request.onsuccess = grabEventAndContinueHandler;
+    let event = yield undefined;
+
+    let db = event.target.result;
+    ok(db, "Got database");
+
+    // Test for IDBKeyRange and indexedDB availability in bootstrap files.
+    let test = Cc["@mozilla.org/dom/indexeddb/GlobalObjectsComponent;1"].
+               createInstance(Ci.nsISupports).wrappedJSObject;
+    test.ok = ok;
+    test.finishTest = continueToNextStep;
+    test.runTest();
+    yield undefined;
+
+    Cu.import("resource://gre/modules/AddonManager.jsm");
+    AddonManager.getAddonByID("indexedDB-test@mozilla.org",
+                              grabEventAndContinueHandler);
+    let addon = yield undefined;
+    addon.uninstall();
+
+    Cu.import("resource://gre/modules/Services.jsm");
+    for each (var stage in [ "install", "startup", "shutdown", "uninstall" ]) {
+      for each (var symbol in [ "IDBKeyRange", "indexedDB" ]) {
+        let pref;
+        try {
+          pref = Services.prefs.getBoolPref("indexeddbtest.bootstrap." + stage +
+                                            "." + symbol);
+        }
+        catch(ex) {
+          pref = false;
+        }
+        ok(pref, "Symbol '" + symbol + "' present during '" + stage + "'");
+      }
+    }
+
+    finishTest();
+    yield undefined;
+  }
+  ]]>
+  </script>
+
+  <script type="text/javascript;version=1.7" src="chromeHelpers.js"></script>
+
+  <body xmlns="http://www.w3.org/1999/xhtml">
+  <a href="https://bugzilla.mozilla.org/show_bug.cgi?id=832883"
+     target="_blank">Mozilla Bug 832883</a>
+  </body>
+</window>
new file mode 100644
--- /dev/null
+++ b/dom/indexedDB/test/unit/GlobalObjectsChild.js
@@ -0,0 +1,36 @@
+/**
+ * Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+function ok(cond, msg) {
+  dump("ok(" + cond + ", \"" + msg + "\")");
+  do_check_true(!!cond, Components.stack.caller);
+}
+
+function finishTest()
+{
+  do_execute_soon(function() {
+    do_test_finished();
+  });
+}
+
+function run_test() {
+  const name = "Splendid Test";
+
+  do_test_pending();
+
+  let keyRange = IDBKeyRange.only(42);
+  ok(keyRange, "Got keyRange");
+
+  let request = indexedDB.open(name, 1);
+  request.onerror = function(event) {
+    ok(false, "indexedDB error, '" + event.target.error.name + "'");
+    finishTest();
+  }
+  request.onsuccess = function(event) {
+    let db = event.target.result;
+    ok(db, "Got database");
+    finishTest();
+  }
+}
new file mode 100644
--- /dev/null
+++ b/dom/indexedDB/test/unit/GlobalObjectsComponent.js
@@ -0,0 +1,40 @@
+/**
+ * Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+Components.utils.import("resource://gre/modules/XPCOMUtils.jsm");
+
+function GlobalObjectsComponent() {
+  this.wrappedJSObject = this;
+}
+
+GlobalObjectsComponent.prototype =
+{
+  classID: Components.ID("{949ebf50-e0da-44b9-8335-cbfd4febfdcc}"),
+
+  QueryInterface: XPCOMUtils.generateQI([Components.interfaces.nsISupports]),
+
+  runTest: function() {
+    const name = "Splendid Test";
+
+    let ok = this.ok;
+    let finishTest = this.finishTest;
+
+    let keyRange = IDBKeyRange.only(42);
+    ok(keyRange, "Got keyRange");
+
+    let request = indexedDB.open(name, 1);
+    request.onerror = function(event) {
+      ok(false, "indexedDB error, '" + event.target.error.name + "'");
+      finishTest();
+    }
+    request.onsuccess = function(event) {
+      let db = event.target.result;
+      ok(db, "Got database");
+      finishTest();
+    }
+  }
+};
+
+this.NSGetFactory = XPCOMUtils.generateNSGetFactory([GlobalObjectsComponent]);
new file mode 100644
--- /dev/null
+++ b/dom/indexedDB/test/unit/GlobalObjectsComponent.manifest
@@ -0,0 +1,2 @@
+component {949ebf50-e0da-44b9-8335-cbfd4febfdcc} GlobalObjectsComponent.js
+contract @mozilla.org/dom/indexeddb/GlobalObjectsComponent;1 {949ebf50-e0da-44b9-8335-cbfd4febfdcc}
new file mode 100644
--- /dev/null
+++ b/dom/indexedDB/test/unit/GlobalObjectsModule.jsm
@@ -0,0 +1,34 @@
+/**
+ * Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+this.EXPORTED_SYMBOLS = [
+  "GlobalObjectsModule"
+];
+
+this.GlobalObjectsModule = function GlobalObjectsModule() {
+}
+
+GlobalObjectsModule.prototype = {
+  runTest: function() {
+    const name = "Splendid Test";
+
+    let ok = this.ok;
+    let finishTest = this.finishTest;
+
+    let keyRange = IDBKeyRange.only(42);
+    ok(keyRange, "Got keyRange");
+
+    let request = indexedDB.open(name, 1);
+    request.onerror = function(event) {
+      ok(false, "indexedDB error, '" + event.target.error.name + "'");
+      finishTest();
+    }
+    request.onsuccess = function(event) {
+      let db = event.target.result;
+      ok(db, "Got database");
+      finishTest();
+    }
+  }
+}
new file mode 100644
--- /dev/null
+++ b/dom/indexedDB/test/unit/GlobalObjectsSandbox.js
@@ -0,0 +1,22 @@
+/**
+ * Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+function runTest() {
+  const name = "Splendid Test";
+
+  let keyRange = IDBKeyRange.only(42);
+  ok(keyRange, "Got keyRange");
+
+  let request = indexedDB.open(name, 1);
+  request.onerror = function(event) {
+    ok(false, "indexedDB error, '" + event.target.error.name + "'");
+    finishTest();
+  }
+  request.onsuccess = function(event) {
+    let db = event.target.result;
+    ok(db, "Got database");
+    finishTest();
+  }
+}
--- a/dom/indexedDB/test/unit/Makefile.in
+++ b/dom/indexedDB/test/unit/Makefile.in
@@ -16,16 +16,18 @@ MOCHITEST_FILES = \
   test_create_objectStore.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.js \
+  test_globalObjects_ipc.js \
   test_global_data.js \
   test_index_empty_keyPath.js \
   test_index_getAll.js \
   test_index_getAllObjects.js \
   test_index_object_cursors.js \
   test_index_update_delete.js \
   test_indexes.js \
   test_indexes_bad_values.js \
--- a/dom/indexedDB/test/unit/head.js
+++ b/dom/indexedDB/test/unit/head.js
@@ -1,14 +1,14 @@
 /**
  * Any copyright is dedicated to the Public Domain.
  * http://creativecommons.org/publicdomain/zero/1.0/
  */
 
-const { 'classes': Cc, 'interfaces': Ci } = Components;
+const { 'classes': Cc, 'interfaces': Ci, 'utils': Cu } = Components;
 
 const DOMException = Ci.nsIDOMDOMException;
 
 function is(a, b, msg) {
   dump("is(" + a + ", " + b + ", \"" + msg + "\")");
   do_check_eq(a, b, Components.stack.caller);
 }
 
@@ -38,20 +38,16 @@ function run_test() {
   runTest();
 };
 
 function runTest()
 {
   // XPCShell does not get a profile by default.
   do_get_profile();
 
-  var idbManager = Cc["@mozilla.org/dom/indexeddb/manager;1"].
-                   getService(Ci.nsIIndexedDatabaseManager);
-  idbManager.initWindowless(this);
-
   enableExperimental();
 
   do_test_pending();
   testGenerator.next();
 }
 
 function finishTest()
 {
new file mode 100644
--- /dev/null
+++ b/dom/indexedDB/test/unit/test_globalObjects.js
@@ -0,0 +1,67 @@
+/**
+ * Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+var testGenerator = testSteps();
+
+function testSteps()
+{
+  const name = "Splendid Test";
+
+  let ioService =
+    Cc["@mozilla.org/network/io-service;1"].getService(Ci.nsIIOService);
+
+  function getSpec(filename) {
+    let file = do_get_file(filename);
+    let uri = ioService.newFileURI(file);
+    return uri.spec;
+  }
+
+  // Test for IDBKeyRange and indexedDB availability in xpcshell.
+  let keyRange = IDBKeyRange.only(42);
+  ok(keyRange, "Got keyRange");
+
+  let request = indexedDB.open(name, 1);
+  request.onerror = errorHandler;
+  request.onsuccess = grabEventAndContinueHandler;
+  let event = yield undefined;
+
+  let db = event.target.result;
+  ok(db, "Got database");
+
+  // Test for IDBKeyRange and indexedDB availability in JS modules.
+  Cu.import(getSpec("GlobalObjectsModule.jsm"));
+  let test = new GlobalObjectsModule();
+  test.ok = ok;
+  test.finishTest = continueToNextStep;
+  test.runTest();
+  yield undefined;
+
+  // Test for IDBKeyRange and indexedDB availability in JS components.
+  do_load_manifest("GlobalObjectsComponent.manifest");
+  test = Cc["@mozilla.org/dom/indexeddb/GlobalObjectsComponent;1"].
+         createInstance(Ci.nsISupports).wrappedJSObject;
+  test.ok = ok;
+  test.finishTest = continueToNextStep;
+  test.runTest();
+  yield undefined;
+
+  // Test for IDBKeyRange and indexedDB availability in JS sandboxes.
+  let principal = Cc["@mozilla.org/systemprincipal;1"].
+                  createInstance(Ci.nsIPrincipal);
+  let sandbox = new Cu.Sandbox(principal,
+                               { wantGlobalProperties: ["indexedDB"] });
+  sandbox.__SCRIPT_URI_SPEC__ = getSpec("GlobalObjectsSandbox.js");
+  Cu.evalInSandbox(
+    "Components.classes['@mozilla.org/moz/jssubscript-loader;1'] \
+               .createInstance(Components.interfaces.mozIJSSubScriptLoader) \
+               .loadSubScript(__SCRIPT_URI_SPEC__);", sandbox, "1.7");
+  sandbox.ok = ok;
+  sandbox.finishTest = continueToNextStep;
+  Cu.evalInSandbox("runTest();", sandbox);
+  yield undefined;
+
+  finishTest();
+  yield undefined;
+}
new file mode 100644
--- /dev/null
+++ b/dom/indexedDB/test/unit/test_globalObjects_ipc.js
@@ -0,0 +1,19 @@
+/**
+ * Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+var testGenerator = testSteps();
+
+function testSteps()
+{
+  // Test for IDBKeyRange and indexedDB availability in ipcshell.
+  run_test_in_child("./GlobalObjectsChild.js", function() {
+    do_test_finished();
+    continueToNextStep();
+  });
+  yield undefined;
+
+  finishTest();
+  yield undefined;
+}
--- a/dom/indexedDB/test/unit/xpcshell.ini
+++ b/dom/indexedDB/test/unit/xpcshell.ini
@@ -1,11 +1,17 @@
 [DEFAULT]
 head = head.js
 tail =
+support-files =
+  GlobalObjectsChild.js
+  GlobalObjectsComponent.js
+  GlobalObjectsComponent.manifest
+  GlobalObjectsModule.jsm
+  GlobalObjectsSandbox.js
 
 # When adding files here please also update ipc/unit/xpcshell.ini!
 
 [test_add_put.js]
 [test_add_twice_failure.js]
 [test_advance.js]
 [test_autoIncrement.js]
 [test_autoIncrement_indexes.js]
@@ -17,16 +23,20 @@ tail =
 [test_create_objectStore.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.js]
+[test_globalObjects_ipc.js]
+# FIXME/bug 575918: out-of-process xpcshell is broken on OS X
+skip-if = os == "mac" || os == "android"
 [test_global_data.js]
 [test_index_empty_keyPath.js]
 [test_index_getAll.js]
 [test_index_getAllObjects.js]
 [test_index_object_cursors.js]
 [test_index_update_delete.js]
 [test_indexes.js]
 [test_indexes_bad_values.js]
--- a/dom/mobilemessage/src/gonk/MobileMessageDatabaseService.js
+++ b/dom/mobilemessage/src/gonk/MobileMessageDatabaseService.js
@@ -61,32 +61,24 @@ const NEXT = "next";
 const COLLECT_ID_END = 0;
 const COLLECT_ID_ERROR = -1;
 const COLLECT_TIMESTAMP_UNUSED = 0;
 
 XPCOMUtils.defineLazyServiceGetter(this, "gMobileMessageService",
                                    "@mozilla.org/mobilemessage/mobilemessageservice;1",
                                    "nsIMobileMessageService");
 
-XPCOMUtils.defineLazyServiceGetter(this, "gIDBManager",
-                                   "@mozilla.org/dom/indexeddb/manager;1",
-                                   "nsIIndexedDatabaseManager");
-
-const GLOBAL_SCOPE = this;
-
 /**
  * MobileMessageDatabaseService
  */
 function MobileMessageDatabaseService() {
   // Prime the directory service's cache to ensure that the ProfD entry exists
   // by the time IndexedDB queries for it off the main thread. (See bug 743635.)
   Services.dirsvc.get("ProfD", Ci.nsIFile);
 
-  gIDBManager.initWindowless(GLOBAL_SCOPE);
-
   let that = this;
   this.newTxn(READ_ONLY, function(error, txn, messageStore){
     if (error) {
       return;
     }
     // In order to get the highest key value, we open a key cursor in reverse
     // order and get only the first pointed value.
     let request = messageStore.openCursor(null, PREV);
@@ -152,17 +144,17 @@ MobileMessageDatabaseService.prototype =
     }
 
     let self = this;
     function gotDB(db) {
       self.db = db;
       callback(null, db);
     }
 
-    let request = GLOBAL_SCOPE.indexedDB.open(DB_NAME, DB_VERSION);
+    let request = indexedDB.open(DB_NAME, DB_VERSION);
     request.onsuccess = function (event) {
       if (DEBUG) debug("Opened database:", DB_NAME, DB_VERSION);
       gotDB(event.target.result);
     };
     request.onupgradeneeded = function (event) {
       if (DEBUG) {
         debug("Database needs upgrade:", DB_NAME,
               event.oldVersion, event.newVersion);
--- a/dom/mobilemessage/tests/test_smsdatabaseservice.xul
+++ b/dom/mobilemessage/tests/test_smsdatabaseservice.xul
@@ -32,19 +32,16 @@ function run_next_test() {
 }
 
 
 const {classes: Cc, interfaces: Ci, utils: Cu, results: Cr} = Components;
 
 Cu.import("resource://gre/modules/XPCOMUtils.jsm");
 Cu.import("resource://gre/modules/Services.jsm");
 
-let gIDBManager = Cc["@mozilla.org/dom/indexeddb/manager;1"]
-                    .getService(Ci.nsIIndexedDatabaseManager);
-
 let gMobileMessageDatabaseService = Cc["@mozilla.org/mobilemessage/rilmobilemessagedatabaseservice;1"]
                                       .getService(Ci.nsIMobileMessageDatabaseService);
 
 let gRegistrar = Components.manager.QueryInterface(Ci.nsIComponentRegistrar);
 
 
 let SmsRequestManagerImpl = {
   notifySmsSent: function notifySmsSent(requestId, message) {
@@ -129,18 +126,16 @@ function fakeSmsRequestManager(obj) {
 }
 
 const DB_NAME = "sms";
 const DB_VERSION = 2;
 const STORE_NAME = "sms";
 const MAX_SMS = 3;
 const LONG_MAX = 2147483647;
 
-gIDBManager.initWindowless(this);
-
 let _db;
 function ensureDB(callback) {
   if (_db) {
     callback(_db);
     return;
   }
   let request;
   try {
--- a/dom/network/src/NetworkStatsDB.jsm
+++ b/dom/network/src/NetworkStatsDB.jsm
@@ -21,22 +21,22 @@ const STORE_NAME_V2 = "net_stats_v2";
 
 // Constant defining the maximum values allowed per interface. If more, older
 // will be erased.
 const VALUES_MAX_LENGTH = 6 * 30;
 
 // Constant defining the rate of the samples. Daily.
 const SAMPLE_RATE = 1000 * 60 * 60 * 24;
 
-this.NetworkStatsDB = function NetworkStatsDB(aGlobal, aConnectionTypes) {
+this.NetworkStatsDB = function NetworkStatsDB(aConnectionTypes) {
   if (DEBUG) {
     debug("Constructor");
   }
   this._connectionTypes = aConnectionTypes;
-  this.initDBHelper(DB_NAME, DB_VERSION, [STORE_NAME_V2], aGlobal);
+  this.initDBHelper(DB_NAME, DB_VERSION, [STORE_NAME_V2]);
 }
 
 NetworkStatsDB.prototype = {
   __proto__: IndexedDBHelper.prototype,
 
   dbNewTxn: function dbNewTxn(txn_type, callback, txnCb) {
     function successCb(result) {
       txnCb(null, result);
@@ -303,17 +303,17 @@ NetworkStatsDB.prototype = {
     }
   },
 
   _removeOldStats: function _removeOldStats(txn, store, appId, connType, date) {
     // Callback function to remove old items when new ones are added.
     let filterDate = date - (SAMPLE_RATE * VALUES_MAX_LENGTH - 1);
     let lowerFilter = [appId, connType, 0];
     let upperFilter = [appId, connType, filterDate];
-    let range = this.dbGlobal.IDBKeyRange.bound(lowerFilter, upperFilter, false, false);
+    let range = IDBKeyRange.bound(lowerFilter, upperFilter, false, false);
     store.openCursor(range).onsuccess = function(event) {
       var cursor = event.target.result;
       if (cursor) {
         cursor.delete();
         cursor.continue();
       }
     }.bind(this);
   },
@@ -337,17 +337,17 @@ NetworkStatsDB.prototype = {
             aOptions.connectionType + " start: " + start + " end: " + end);
       debug("Start time: " + new Date(start));
       debug("End time: " + new Date(end));
     }
 
     this.dbNewTxn("readonly", function(txn, store) {
       let lowerFilter = [aOptions.appId, aOptions.connectionType, start];
       let upperFilter = [aOptions.appId, aOptions.connectionType, end];
-      let range = this.dbGlobal.IDBKeyRange.bound(lowerFilter, upperFilter, false, false);
+      let range = IDBKeyRange.bound(lowerFilter, upperFilter, false, false);
 
       let data = [];
 
       if (!txn.result) {
         txn.result = {};
       }
 
       let request = store.openCursor(range).onsuccess = function(event) {
@@ -382,17 +382,17 @@ NetworkStatsDB.prototype = {
       debug("FindAll: appId: " + aOptions.appId +
             " start: " + start + " end: " + end + "\n");
     }
 
     let self = this;
     this.dbNewTxn("readonly", function(txn, store) {
       let lowerFilter = start;
       let upperFilter = end;
-      let range = this.dbGlobal.IDBKeyRange.bound(lowerFilter, upperFilter, false, false);
+      let range = IDBKeyRange.bound(lowerFilter, upperFilter, false, false);
 
       let data = [];
 
       if (!txn.result) {
         txn.result = {};
       }
 
       let request = store.index("timestamp").openCursor(range).onsuccess = function(event) {
--- a/dom/network/src/NetworkStatsService.jsm
+++ b/dom/network/src/NetworkStatsService.jsm
@@ -22,34 +22,28 @@ const TOPIC_INTERFACE_REGISTERED   = "ne
 const TOPIC_INTERFACE_UNREGISTERED = "network-interface-unregistered";
 const NET_TYPE_WIFI = Ci.nsINetworkInterface.NETWORK_TYPE_WIFI;
 const NET_TYPE_MOBILE = Ci.nsINetworkInterface.NETWORK_TYPE_MOBILE;
 const NET_TYPE_UNKNOWN = Ci.nsINetworkInterface.NETWORK_TYPE_UNKNOWN;
 
 // The maximum traffic amount can be saved in the |cachedAppStats|.
 const MAX_CACHED_TRAFFIC = 500 * 1000 * 1000; // 500 MB
 
-XPCOMUtils.defineLazyServiceGetter(this, "gIDBManager",
-                                   "@mozilla.org/dom/indexeddb/manager;1",
-                                   "nsIIndexedDatabaseManager");
-
 XPCOMUtils.defineLazyServiceGetter(this, "ppmm",
                                    "@mozilla.org/parentprocessmessagemanager;1",
                                    "nsIMessageListenerManager");
 
 XPCOMUtils.defineLazyServiceGetter(this, "networkManager",
                                    "@mozilla.org/network/manager;1",
                                    "nsINetworkManager");
 
 XPCOMUtils.defineLazyServiceGetter(this, "appsService",
                                    "@mozilla.org/AppsService;1",
                                    "nsIAppsService");
 
-let myGlobal = this;
-
 this.NetworkStatsService = {
   init: function() {
     if (DEBUG) {
       debug("Service started");
     }
 
     Services.obs.addObserver(this, "xpcom-shutdown", false);
     Services.obs.addObserver(this, TOPIC_INTERFACE_REGISTERED, false);
@@ -70,18 +64,17 @@ this.NetworkStatsService = {
                      "NetworkStats:Types",
                      "NetworkStats:SampleRate",
                      "NetworkStats:MaxStorageSamples"];
 
     this.messages.forEach(function(msgName) {
       ppmm.addMessageListener(msgName, this);
     }, this);
 
-    gIDBManager.initWindowless(myGlobal);
-    this._db = new NetworkStatsDB(myGlobal, this._connectionTypes);
+    this._db = new NetworkStatsDB(this._connectionTypes);
 
     // Stats for all interfaces are updated periodically
     this.timer.initWithCallback(this, this._db.sampleRate,
                                 Ci.nsITimer.TYPE_REPEATING_PRECISE);
 
     // App stats are firstly stored in the cached.
     this.cachedAppStats = Object.create(null);
     this.cachedAppStatsDate = new Date();
--- a/dom/network/tests/unit_stats/test_networkstats_db.js
+++ b/dom/network/tests/unit_stats/test_networkstats_db.js
@@ -516,14 +516,10 @@ add_test(function test_saveMultipleAppSt
         netStatsDb.saveStats(cached[keys[index]], callback);
     });
   });
 });
 
 function run_test() {
   do_get_profile();
 
-  var idbManager = Cc["@mozilla.org/dom/indexeddb/manager;1"].
-                   getService(Ci.nsIIndexedDatabaseManager);
-  idbManager.initWindowless(this);
-
   run_next_test();
 }
--- a/dom/push/src/PushService.jsm
+++ b/dom/push/src/PushService.jsm
@@ -40,25 +40,22 @@ const kPUSHDB_STORE_NAME = "push";
 const kUDP_WAKEUP_WS_STATUS_CODE = 4774;  // WebSocket Close status code sent
                                           // by server to signal that it can
                                           // wake client up using UDP.
 
 const kCHILD_PROCESS_MESSAGES = ["Push:Register", "Push:Unregister",
                                  "Push:Registrations"];
 
 // This is a singleton
-this.PushDB = function PushDB(aGlobal) {
+this.PushDB = function PushDB() {
   debug("PushDB()");
 
   // set the indexeddb database
-  let idbManager = Cc["@mozilla.org/dom/indexeddb/manager;1"]
-                     .getService(Ci.nsIIndexedDatabaseManager);
-  idbManager.initWindowless(aGlobal);
   this.initDBHelper(kPUSHDB_DB_NAME, kPUSHDB_DB_VERSION,
-                    [kPUSHDB_STORE_NAME], aGlobal);
+                    [kPUSHDB_STORE_NAME]);
 };
 
 this.PushDB.prototype = {
   __proto__: IndexedDBHelper.prototype,
 
   upgradeSchema: function(aTransaction, aDb, aOldVersion, aNewVersion) {
     debug("PushDB.upgradeSchema()")
 
@@ -172,17 +169,17 @@ this.PushDB.prototype = {
     }
 
     let self = this;
     this.newTxn(
       "readonly",
       kPUSHDB_STORE_NAME,
       function txnCb(aTxn, aStore) {
         let index = aStore.index("manifestURL");
-        let range = self.dbGlobal.IDBKeyRange.only(aManifestURL);
+        let range = IDBKeyRange.only(aManifestURL);
         aTxn.result = [];
         index.openCursor(range).onsuccess = function(event) {
           let cursor = event.target.result;
           if (cursor) {
             debug(cursor.value.manifestURL + " " + cursor.value.channelID);
             aTxn.result.push(cursor.value);
             cursor.continue();
           }
@@ -450,17 +447,17 @@ this.PushService = {
     this._ws.sendMsg(msg);
   },
 
   init: function() {
     debug("init()");
     if (!prefs.get("enabled"))
         return null;
 
-    this._db = new PushDB(this);
+    this._db = new PushDB();
 
     let ppmm = Cc["@mozilla.org/parentprocessmessagemanager;1"]
                  .getService(Ci.nsIMessageBroadcaster);
 
     kCHILD_PROCESS_MESSAGES.forEach(function addMessage(msgName) {
         ppmm.addMessageListener(msgName, this);
     }.bind(this));
 
--- a/dom/settings/SettingsDB.jsm
+++ b/dom/settings/SettingsDB.jsm
@@ -193,13 +193,13 @@ SettingsDB.prototype = {
 
     // Fall-through, we now have a dictionary object.
     for (let prop in aObject) {
       aObject[prop] = this.prepareValue(aObject[prop]);
     }
     return aObject;
   },
 
-  init: function init(aGlobal) {
+  init: function init() {
     this.initDBHelper(SETTINGSDB_NAME, SETTINGSDB_VERSION,
-                      [SETTINGSSTORE_NAME], aGlobal);
+                      [SETTINGSSTORE_NAME]);
   }
 }
--- a/dom/settings/SettingsManager.js
+++ b/dom/settings/SettingsManager.js
@@ -244,26 +244,20 @@ SettingsLock.prototype = {
     }
   },
 
   classID: Components.ID("{60c9357c-3ae0-4222-8f55-da01428470d5}"),
   contractID: "@mozilla.org/settingsLock;1",
   QueryInterface: XPCOMUtils.generateQI([Ci.nsISupports]),
 };
 
-let myGlobal = this;
-
 function SettingsManager() {
   this._locks = new Queue();
-  if (!("indexedDB" in myGlobal)) {
-    let idbManager = Components.classes["@mozilla.org/dom/indexeddb/manager;1"].getService(Ci.nsIIndexedDatabaseManager);
-    idbManager.initWindowless(myGlobal);
-  }
   this._settingsDB = new SettingsDB();
-  this._settingsDB.init(myGlobal);
+  this._settingsDB.init();
 }
 
 SettingsManager.prototype = {
   _callbacks: null,
 
   _wrap: function _wrap(obj) {
     return ObjectWrapper.wrap(obj, this._window);
   },
@@ -284,18 +278,18 @@ SettingsManager.prototype = {
   },
 
   createLock: function() {
     if (DEBUG) debug("get lock!");
     var lock = new SettingsLock(this);
     this._locks.enqueue(lock);
     this._settingsDB.ensureDB(
       function() { lock.createTransactionAndProcess(); },
-      function() { dump("Cannot open Settings DB. Trying to open an old version?\n"); },
-      myGlobal );
+      function() { dump("Cannot open Settings DB. Trying to open an old version?\n"); }
+    );
     this.nextTick(function() { this._open = false; }, lock);
     return lock;
   },
 
   receiveMessage: function(aMessage) {
     if (DEBUG) debug("Settings::receiveMessage: " + aMessage.name);
     let msg = aMessage.json;
 
--- a/dom/settings/SettingsService.js
+++ b/dom/settings/SettingsService.js
@@ -177,46 +177,40 @@ SettingsServiceLock.prototype = {
                                       contractID: SETTINGSSERVICELOCK_CONTRACTID,
                                       classDescription: "SettingsServiceLock",
                                       interfaces: [nsISettingsServiceLock],
                                       flags: nsIClassInfo.DOM_OBJECT })
 };
 
 const SETTINGSSERVICE_CID        = Components.ID("{f656f0c0-f776-11e1-a21f-0800200c9a66}");
 
-let myGlobal = this;
-
 function SettingsService()
 {
   debug("settingsService Constructor");
   this._locks = new Queue();
-  if (!("indexedDB" in myGlobal)) {
-    let idbManager = Components.classes["@mozilla.org/dom/indexeddb/manager;1"].getService(Ci.nsIIndexedDatabaseManager);
-    idbManager.initWindowless(myGlobal);
-  }
   this._settingsDB = new SettingsDB();
-  this._settingsDB.init(myGlobal);
+  this._settingsDB.init();
 }
 
 SettingsService.prototype = {
 
   nextTick: function nextTick(aCallback, thisObj) {
     if (thisObj)
       aCallback = aCallback.bind(thisObj);
 
     Services.tm.currentThread.dispatch(aCallback, Ci.nsIThread.DISPATCH_NORMAL);
   },
 
   createLock: function createLock() {
     var lock = new SettingsServiceLock(this);
     this._locks.enqueue(lock);
     this._settingsDB.ensureDB(
       function() { lock.createTransactionAndProcess(); },
-      function() { dump("SettingsService failed to open DB!\n"); },
-      myGlobal );
+      function() { dump("SettingsService failed to open DB!\n"); }
+    );
     this.nextTick(function() { this._open = false; }, lock);
     return lock;
   },
 
   classID : SETTINGSSERVICE_CID,
   QueryInterface : XPCOMUtils.generateQI([Ci.nsISettingsService]),
   classInfo: XPCOMUtils.generateCI({
     classID: SETTINGSSERVICE_CID,
--- a/dom/tests/unit/test_geolocation_provider.js
+++ b/dom/tests/unit/test_geolocation_provider.js
@@ -60,16 +60,21 @@ function geoHandler(metadata, response)
   response.setStatusLine("1.0", 200, "OK");
   response.setHeader("Cache-Control", "no-cache", false);
   response.setHeader("Content-Type", "aplication/x-javascript", false);
   response.write(position);
 }
 
 function run_test()
 {
+    // XPCShell does not get a profile by default. The geolocation service
+    // depends on the settings service which uses IndexedDB and IndexedDB
+    // needs a place where it can store databases.
+    do_get_profile();
+
     // only kill this test when shutdown is called on the provider.
     do_test_pending();
 
     httpserver = new HttpServer();
     httpserver.registerPathHandler("/geo", geoHandler);
     httpserver.start(-1);
 
     var prefs = Cc["@mozilla.org/preferences-service;1"].getService(Ci.nsIPrefBranch);
--- a/dom/tests/unit/test_geolocation_timeout.js
+++ b/dom/tests/unit/test_geolocation_timeout.js
@@ -42,16 +42,21 @@ function errorCallback() {
 }
 
 function run_test()
 {
   do_test_pending();
 
   if (Cc["@mozilla.org/xre/app-info;1"].getService(Ci.nsIXULRuntime)
         .processType == Ci.nsIXULRuntime.PROCESS_TYPE_DEFAULT) {
+    // XPCShell does not get a profile by default. The geolocation service
+    // depends on the settings service which uses IndexedDB and IndexedDB
+    // needs a place where it can store databases.
+    do_get_profile();
+
     httpserver = new HttpServer();
     httpserver.registerPathHandler("/geo", geoHandler);
     httpserver.start(-1);
     var prefs = Cc["@mozilla.org/preferences-service;1"].getService(Ci.nsIPrefBranch);
     prefs.setBoolPref("geo.wifi.scan", false);
     prefs.setCharPref("geo.wifi.uri", "http://localhost:" +
                       httpserver.identity.primaryPort + "/geo");
     prefs.setBoolPref("geo.testing.ignore_ipc_principal", true);
--- a/dom/tests/unit/xpcshell.ini
+++ b/dom/tests/unit/xpcshell.ini
@@ -3,10 +3,12 @@ head =
 tail = 
 
 [test_bug319968.js]
 [test_bug465752.js]
 [test_geolocation_provider.js]
 # Bug 684962: test hangs consistently on Android
 skip-if = os == "android"
 [test_geolocation_timeout.js]
+# Bug 919946: test hangs consistently on Android
+skip-if = os == "android"
 [test_geolocation_timeout_wrap.js]
 skip-if = os == "mac" || os == "android"
new file mode 100644
--- /dev/null
+++ b/dom/webidl/IDBKeyRange.webidl
@@ -0,0 +1,29 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+/*
+ * The origin of this IDL file is
+ * https://dvcs.w3.org/hg/IndexedDB/raw-file/tip/Overview.html
+ *
+ * Copyright © 2012 W3C® (MIT, ERCIM, Keio), All Rights Reserved. W3C
+ * liability, trademark and document use rules apply.
+ */
+
+interface IDBKeyRange {
+  [Throws]
+  readonly attribute any     lower;
+  [Throws]
+  readonly attribute any     upper;
+  [Constant]
+  readonly attribute boolean lowerOpen;
+  [Constant]
+  readonly attribute boolean upperOpen;
+  [Creator, Throws]
+  static IDBKeyRange only (any value);
+  [Creator, Throws]
+  static IDBKeyRange lowerBound (any lower, optional boolean open = false);
+  [Creator, Throws]
+  static IDBKeyRange upperBound (any upper, optional boolean open = false);
+  [Creator, Throws]
+  static IDBKeyRange bound (any lower, any upper, optional boolean lowerOpen = false, optional boolean upperOpen = false);
+};
--- a/dom/webidl/moz.build
+++ b/dom/webidl/moz.build
@@ -174,16 +174,17 @@ WEBIDL_FILES = [
     'HTMLTrackElement.webidl',
     'HTMLUListElement.webidl',
     'HTMLVideoElement.webidl',
     'IDBCursor.webidl',
     'IDBDatabase.webidl',
     'IDBFactory.webidl',
     'IDBFileHandle.webidl',
     'IDBIndex.webidl',
+    'IDBKeyRange.webidl',
     'IDBObjectStore.webidl',
     'IDBOpenDBRequest.webidl',
     'IDBRequest.webidl',
     'IDBTransaction.webidl',
     'IDBVersionChangeEvent.webidl',
     'ImageData.webidl',
     'ImageDocument.webidl',
     'InputMethod.webidl',
--- a/js/xpconnect/src/Sandbox.cpp
+++ b/js/xpconnect/src/Sandbox.cpp
@@ -25,25 +25,27 @@
 #include "nsPrincipal.h"
 #include "nsXMLHttpRequest.h"
 #include "WrapperFactory.h"
 #include "xpcprivate.h"
 #include "XPCQuickStubs.h"
 #include "XPCWrapper.h"
 #include "XrayWrapper.h"
 #include "mozilla/dom/BindingUtils.h"
+#include "mozilla/dom/indexedDB/IndexedDatabaseManager.h"
 #include "mozilla/dom/TextDecoderBinding.h"
 #include "mozilla/dom/TextEncoderBinding.h"
 
 using namespace mozilla;
 using namespace JS;
 using namespace js;
 using namespace xpc;
 
 using mozilla::dom::DestroyProtoAndIfaceCache;
+using mozilla::dom::indexedDB::IndexedDatabaseManager;
 
 NS_IMPL_ISUPPORTS3(SandboxPrivate,
                    nsIScriptObjectPrincipal,
                    nsIGlobalObject,
                    nsISupportsWeakReference)
 
 const char kScriptSecurityManagerContractID[] = NS_SCRIPTSECURITYMANAGER_CONTRACTID;
 
@@ -884,17 +886,19 @@ xpc::GlobalProperties::Parse(JSContext *
         ok = JS_GetElement(cx, obj, i, &nameValue);
         NS_ENSURE_TRUE(ok, false);
         if (!nameValue.isString()) {
             JS_ReportError(cx, "Property names must be strings");
             return false;
         }
         JSAutoByteString name(cx, nameValue.toString());
         NS_ENSURE_TRUE(name, false);
-        if (!strcmp(name.ptr(), "XMLHttpRequest")) {
+        if (!strcmp(name.ptr(), "indexedDB")) {
+            indexedDB = true;
+        } else if (!strcmp(name.ptr(), "XMLHttpRequest")) {
             XMLHttpRequest = true;
         } else if (!strcmp(name.ptr(), "TextEncoder")) {
             TextEncoder = true;
         } else if (!strcmp(name.ptr(), "TextDecoder")) {
             TextDecoder = true;
         } else if (!strcmp(name.ptr(), "atob")) {
             atob = true;
         } else if (!strcmp(name.ptr(), "btoa")) {
@@ -905,16 +909,21 @@ xpc::GlobalProperties::Parse(JSContext *
         }
     }
     return true;
 }
 
 bool
 xpc::GlobalProperties::Define(JSContext *cx, JS::HandleObject obj)
 {
+    if (indexedDB && AccessCheck::isChrome(obj) &&
+        (!IndexedDatabaseManager::DefineConstructors(cx, obj) ||
+         !IndexedDatabaseManager::DefineIndexedDBGetter(cx, obj)))
+        return false;
+
     if (XMLHttpRequest &&
         !JS_DefineFunction(cx, obj, "XMLHttpRequest", CreateXMLHttpRequest, 0, JSFUN_CONSTRUCTOR))
         return false;
 
     if (TextEncoder &&
         !dom::TextEncoderBinding::GetConstructorObject(cx, obj))
         return false;
 
--- a/js/xpconnect/src/dom_quickstubs.qsconf
+++ b/js/xpconnect/src/dom_quickstubs.qsconf
@@ -78,17 +78,16 @@ members = [
     'nsIBoxObject.x',
     'nsIBoxObject.y',
     'nsIBoxObject.screenX',
     'nsIBoxObject.screenY',
     'nsIBoxObject.width',
     'nsIBoxObject.height',
 
     # dom/indexedDB
-    'nsIIDBKeyRange.*',
     'nsIIndexedDatabaseManager.*',
 
     # dom/file
     'nsIDOMLockedFile.*',
 
     # dom/quota
     'nsIQuotaManager.*',
     'nsIQuotaRequest.*',
--- a/js/xpconnect/src/nsXPConnect.cpp
+++ b/js/xpconnect/src/nsXPConnect.cpp
@@ -25,32 +25,35 @@
 #ifdef MOZ_JSDEBUGGER
 #include "jsdIDebuggerService.h"
 #endif
 
 #include "XPCQuickStubs.h"
 
 #include "mozilla/dom/BindingUtils.h"
 #include "mozilla/dom/Exceptions.h"
+#include "mozilla/dom/indexedDB/IndexedDatabaseManager.h"
 #include "mozilla/dom/TextDecoderBinding.h"
 #include "mozilla/dom/TextEncoderBinding.h"
 #include "mozilla/dom/DOMErrorBinding.h"
 
 #include "nsDOMMutationObserver.h"
 #include "nsICycleCollectorListener.h"
 #include "nsThread.h"
 #include "mozilla/XPTInterfaceInfoManager.h"
 #include "nsIObjectInputStream.h"
 #include "nsIObjectOutputStream.h"
 
 using namespace mozilla;
 using namespace mozilla::dom;
 using namespace xpc;
 using namespace JS;
 
+using mozilla::dom::indexedDB::IndexedDatabaseManager;
+
 NS_IMPL_ISUPPORTS5(nsXPConnect,
                    nsIXPConnect,
                    nsISupportsWeakReference,
                    nsIThreadObserver,
                    nsIJSRuntimeService,
                    nsIJSEngineTelemetryStats)
 
 nsXPConnect* nsXPConnect::gSelf = nullptr;
@@ -529,16 +532,22 @@ nsXPConnect::InitClassesWithNewWrappedGl
     // XXX Please do not add any additional classes here without the approval of
     //     the XPConnect module owner.
     if (!TextDecoderBinding::GetConstructorObject(aJSContext, global) ||
         !TextEncoderBinding::GetConstructorObject(aJSContext, global) ||
         !DOMErrorBinding::GetConstructorObject(aJSContext, global)) {
         return UnexpectedFailure(NS_ERROR_FAILURE);
     }
 
+    if (nsContentUtils::IsSystemPrincipal(aPrincipal) &&
+        !IndexedDatabaseManager::DefineIndexedDBLazyGetter(aJSContext,
+                                                           global)) {
+        return UnexpectedFailure(NS_ERROR_FAILURE);
+    }
+
     wrappedGlobal.forget(_retval);
     return NS_OK;
 }
 
 static nsresult
 NativeInterface2JSObject(HandleObject aScope,
                          nsISupports *aCOMObj,
                          nsWrapperCache *aCache,
--- a/js/xpconnect/src/xpcprivate.h
+++ b/js/xpconnect/src/xpcprivate.h
@@ -3585,16 +3585,17 @@ NewFunctionForwarder(JSContext *cx, JS::
 // Old fashioned xpc error reporter. Try to use JS_ReportError instead.
 nsresult
 ThrowAndFail(nsresult errNum, JSContext *cx, bool *retval);
 
 struct GlobalProperties {
     GlobalProperties() { mozilla::PodZero(this); }
     bool Parse(JSContext *cx, JS::HandleObject obj);
     bool Define(JSContext *cx, JS::HandleObject obj);
+    bool indexedDB;
     bool XMLHttpRequest;
     bool TextDecoder;
     bool TextEncoder;
     bool atob;
     bool btoa;
 };
 
 // Infallible.
--- a/toolkit/mozapps/extensions/XPIProvider.jsm
+++ b/toolkit/mozapps/extensions/XPIProvider.jsm
@@ -2,16 +2,17 @@
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 "use strict";
 
 const Cc = Components.classes;
 const Ci = Components.interfaces;
 const Cr = Components.results;
+const Cu = Components.utils;
 
 this.EXPORTED_SYMBOLS = [];
 
 Components.utils.import("resource://gre/modules/Services.jsm");
 Components.utils.import("resource://gre/modules/XPCOMUtils.jsm");
 Components.utils.import("resource://gre/modules/AddonManager.jsm");
 
 XPCOMUtils.defineLazyModuleGetter(this, "AddonRepository",
@@ -3897,25 +3898,27 @@ var XPIProvider = {
     }
 
     LOG("Loading bootstrap scope from " + aFile.path);
 
     let principal = Cc["@mozilla.org/systemprincipal;1"].
                     createInstance(Ci.nsIPrincipal);
 
     if (!aFile.exists()) {
-      this.bootstrapScopes[aId] = new Components.utils.Sandbox(principal,
-                                                               {sandboxName: aFile.path});
+      this.bootstrapScopes[aId] =
+        new Cu.Sandbox(principal, {sandboxName: aFile.path,
+                                   wantGlobalProperties: ["indexedDB"]});
       ERROR("Attempted to load bootstrap scope from missing directory " + aFile.path);
       return;
     }
 
     let uri = getURIForResourceInFile(aFile, "bootstrap.js").spec;
-    this.bootstrapScopes[aId] = new Components.utils.Sandbox(principal,
-                                                             {sandboxName: uri});
+    this.bootstrapScopes[aId] =
+      new Cu.Sandbox(principal, {sandboxName: uri,
+                                 wantGlobalProperties: ["indexedDB"]});
 
     let loader = Cc["@mozilla.org/moz/jssubscript-loader;1"].
                  createInstance(Ci.mozIJSSubScriptLoader);
 
     // Add a mapping for XPIProvider.mapURIToAddonID
     this._addURIMapping(aId, aFile);
 
     try {