Merge m-c to b-i
authorPhil Ringnalda <philringnalda@gmail.com>
Sun, 01 Feb 2015 09:20:02 -0800
changeset 226991 a18319b624f5f60eb062d53c0500168f50214abf
parent 226990 eee814a878a41e1d9d3737b2d78973b875598fa6 (current diff)
parent 226961 940118b1adcd83967fbd49c96217857a91a2b2d0 (diff)
child 226992 3f8ba7e36be7822b3492616a74c0e4c19b712057
push id54982
push usercbook@mozilla.com
push dateMon, 02 Feb 2015 12:25:45 +0000
treeherdermozilla-inbound@7e188718dea2 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
milestone38.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
Merge m-c to b-i
--- a/CLOBBER
+++ b/CLOBBER
@@ -17,9 +17,9 @@
 #
 # Modifying this file will now automatically clobber the buildbot machines \o/
 #
 
 # Are you updating CLOBBER because you think it's needed for your WebIDL
 # changes to stick? As of bug 928195, this shouldn't be necessary! Please
 # don't change CLOBBER for WebIDL changes any more.
 
-Bug 870366 - Blacklisting PREF_JS_EXPORTS in Makefile.ins (because of 852814)
+Bug 1109248 - This needed a CLOBBER on Windows and OSX.
--- a/browser/devtools/performance/modules/recording-utils.js
+++ b/browser/devtools/performance/modules/recording-utils.js
@@ -78,20 +78,24 @@ exports.RecordingUtils.getSamplesFromAll
     let timestamp = timestamps[i];
     let frame = frames[site];
     let count = counts[site];
 
     let sample = { time: timestamp, frames: [] };
     samples.push(sample);
 
     while (frame) {
+      let source = frame.source + ":" + frame.line + ":" + frame.column;
+      let funcName = frame.functionDisplayName || "";
+
       sample.frames.push({
-        location: frame.source + ":" + frame.line + ":" + frame.column,
+        location: funcName ? funcName + " (" + source + ")" : source,
         allocations: count
       });
+
       site = frame.parent;
       frame = frames[site];
       count = counts[site];
     }
 
     sample.frames.reverse();
   }
 
--- a/browser/devtools/performance/test/browser_perf-allocations-to-samples.js
+++ b/browser/devtools/performance/test/browser_perf-allocations-to-samples.js
@@ -20,60 +20,63 @@ let TEST_DATA = {
   sites: [0, 0, 1, 2, 3],
   timestamps: [50, 100, 150, 200, 250],
   frames: [
     null,
     {
       source: "A",
       line: 1,
       column: 2,
+      functionDisplayName: "x",
       parent: 0
     },
     {
       source: "B",
       line: 3,
       column: 4,
+      functionDisplayName: "y",
       parent: 1
     },
     {
       source: "C",
       line: 5,
       column: 6,
+      functionDisplayName: null,
       parent: 2
     }
   ],
   counts: [11, 22, 33, 44]
 };
 
 let EXPECTED_OUTPUT = [{
   time: 50,
   frames: []
 }, {
   time: 100,
   frames: []
 }, {
   time: 150,
   frames: [{
-    location: "A:1:2",
+    location: "x (A:1:2)",
     allocations: 22
   }]
 }, {
   time: 200,
   frames: [{
-    location: "A:1:2",
+    location: "x (A:1:2)",
     allocations: 22
   }, {
-    location: "B:3:4",
+    location: "y (B:3:4)",
     allocations: 33
   }]
 }, {
   time: 250,
   frames: [{
-    location: "A:1:2",
+    location: "x (A:1:2)",
     allocations: 22
   }, {
-    location: "B:3:4",
+    location: "y (B:3:4)",
     allocations: 33
   }, {
     location: "C:5:6",
     allocations: 44
   }]
 }];
--- a/config/baseconfig.mk
+++ b/config/baseconfig.mk
@@ -85,17 +85,16 @@ else
   LIBRARY_NAME \
   LIBS \
   MAKE_FRAMEWORK \
   MODULE \
   MSVC_ENABLE_PGO \
   NO_DIST_INSTALL \
   OS_LIBS \
   PARALLEL_DIRS \
-  PREF_JS_EXPORTS \
   PROGRAM \
   PYTHON_UNIT_TESTS \
   RESOURCE_FILES \
   SDK_HEADERS \
   SDK_LIBRARY \
   SHARED_LIBRARY_LIBS \
   SHARED_LIBRARY_NAME \
   SIMPLE_PROGRAMS \
--- a/configure.in
+++ b/configure.in
@@ -66,17 +66,17 @@ GTK3_VERSION=3.0.0
 WINDRES_VERSION=2.14.90
 W32API_VERSION=3.14
 GNOMEVFS_VERSION=2.0
 GNOMEUI_VERSION=2.2.0
 GCONF_VERSION=1.2.1
 GIO_VERSION=2.20
 STARTUP_NOTIFICATION_VERSION=0.8
 DBUS_VERSION=0.60
-SQLITE_VERSION=3.8.8.1
+SQLITE_VERSION=3.8.8.2
 
 MSMANIFEST_TOOL=
 
 dnl Set various checks
 dnl ========================================================
 MISSING_X=
 AC_PROG_AWK
 
--- a/db/sqlite3/README.MOZILLA
+++ b/db/sqlite3/README.MOZILLA
@@ -1,9 +1,10 @@
-This is SQLite 3.8.8.1
+This is the SQLite amalgamation.
+Check sqlite3.h for the version number and source id.
 
 See http://www.sqlite.org/ for more info.
 
 We have a mozilla-specific Makefile.in in src/ (normally no
 Makefile.in there) that we use to build.
 
 To move to a new version:
 
--- a/db/sqlite3/src/sqlite3.c
+++ b/db/sqlite3/src/sqlite3.c
@@ -1,11 +1,11 @@
 /******************************************************************************
 ** This file is an amalgamation of many separate C source files from SQLite
-** version 3.8.8.1.  By combining all the individual C code files into this 
+** version 3.8.8.2.  By combining all the individual C code files into this 
 ** single large file, the entire code can be compiled as a single translation
 ** unit.  This allows many compilers to do optimizations that would not be
 ** possible if the files were compiled separately.  Performance improvements
 ** of 5% or more are commonly seen when SQLite is compiled as a single
 ** translation unit.
 **
 ** This file is all you need to compile SQLite.  To use SQLite in other
 ** programs, you need this file and the "sqlite3.h" header file that defines
@@ -273,19 +273,19 @@ extern "C" {
 ** within its configuration management system.  ^The SQLITE_SOURCE_ID
 ** string contains the date and time of the check-in (UTC) and an SHA1
 ** hash of the entire source tree.
 **
 ** See also: [sqlite3_libversion()],
 ** [sqlite3_libversion_number()], [sqlite3_sourceid()],
 ** [sqlite_version()] and [sqlite_source_id()].
 */
-#define SQLITE_VERSION        "3.8.8.1"
+#define SQLITE_VERSION        "3.8.8.2"
 #define SQLITE_VERSION_NUMBER 3008008
-#define SQLITE_SOURCE_ID      "2015-01-20 16:51:25 f73337e3e289915a76ca96e7a05a1a8d4e890d55"
+#define SQLITE_SOURCE_ID      "2015-01-30 14:30:45 7757fc721220e136620a89c9d28247f28bbbc098"
 
 /*
 ** CAPI3REF: Run-Time Library Version Numbers
 ** KEYWORDS: sqlite3_version, sqlite3_sourceid
 **
 ** These interfaces provide the same information as the [SQLITE_VERSION],
 ** [SQLITE_VERSION_NUMBER], and [SQLITE_SOURCE_ID] C preprocessor macros
 ** but are associated with the library instead of the header file.  ^(Cautious
@@ -50192,143 +50192,146 @@ static void walRestartHdr(Wal *pWal, u32
 static int walCheckpoint(
   Wal *pWal,                      /* Wal connection */
   int eMode,                      /* One of PASSIVE, FULL or RESTART */
   int (*xBusy)(void*),            /* Function to call when busy */
   void *pBusyArg,                 /* Context argument for xBusyHandler */
   int sync_flags,                 /* Flags for OsSync() (or 0) */
   u8 *zBuf                        /* Temporary buffer to use */
 ){
-  int rc;                         /* Return code */
+  int rc = SQLITE_OK;             /* Return code */
   int szPage;                     /* Database page-size */
   WalIterator *pIter = 0;         /* Wal iterator context */
   u32 iDbpage = 0;                /* Next database page to write */
   u32 iFrame = 0;                 /* Wal frame containing data for iDbpage */
   u32 mxSafeFrame;                /* Max frame that can be backfilled */
   u32 mxPage;                     /* Max database page to write */
   int i;                          /* Loop counter */
   volatile WalCkptInfo *pInfo;    /* The checkpoint status information */
 
   szPage = walPagesize(pWal);
   testcase( szPage<=32768 );
   testcase( szPage>=65536 );
   pInfo = walCkptInfo(pWal);
-  if( pInfo->nBackfill>=pWal->hdr.mxFrame ) return SQLITE_OK;
-
-  /* Allocate the iterator */
-  rc = walIteratorInit(pWal, &pIter);
-  if( rc!=SQLITE_OK ){
-    return rc;
-  }
-  assert( pIter );
-
-  /* EVIDENCE-OF: R-62920-47450 The busy-handler callback is never invoked
-  ** in the SQLITE_CHECKPOINT_PASSIVE mode. */
-  assert( eMode!=SQLITE_CHECKPOINT_PASSIVE || xBusy==0 );
-
-  /* Compute in mxSafeFrame the index of the last frame of the WAL that is
-  ** safe to write into the database.  Frames beyond mxSafeFrame might
-  ** overwrite database pages that are in use by active readers and thus
-  ** cannot be backfilled from the WAL.
-  */
-  mxSafeFrame = pWal->hdr.mxFrame;
-  mxPage = pWal->hdr.nPage;
-  for(i=1; i<WAL_NREADER; i++){
-    u32 y = pInfo->aReadMark[i];
-    if( mxSafeFrame>y ){
-      assert( y<=pWal->hdr.mxFrame );
-      rc = walBusyLock(pWal, xBusy, pBusyArg, WAL_READ_LOCK(i), 1);
+  if( pInfo->nBackfill<pWal->hdr.mxFrame ){
+
+    /* Allocate the iterator */
+    rc = walIteratorInit(pWal, &pIter);
+    if( rc!=SQLITE_OK ){
+      return rc;
+    }
+    assert( pIter );
+
+    /* EVIDENCE-OF: R-62920-47450 The busy-handler callback is never invoked
+    ** in the SQLITE_CHECKPOINT_PASSIVE mode. */
+    assert( eMode!=SQLITE_CHECKPOINT_PASSIVE || xBusy==0 );
+
+    /* Compute in mxSafeFrame the index of the last frame of the WAL that is
+    ** safe to write into the database.  Frames beyond mxSafeFrame might
+    ** overwrite database pages that are in use by active readers and thus
+    ** cannot be backfilled from the WAL.
+    */
+    mxSafeFrame = pWal->hdr.mxFrame;
+    mxPage = pWal->hdr.nPage;
+    for(i=1; i<WAL_NREADER; i++){
+      u32 y = pInfo->aReadMark[i];
+      if( mxSafeFrame>y ){
+        assert( y<=pWal->hdr.mxFrame );
+        rc = walBusyLock(pWal, xBusy, pBusyArg, WAL_READ_LOCK(i), 1);
+        if( rc==SQLITE_OK ){
+          pInfo->aReadMark[i] = (i==1 ? mxSafeFrame : READMARK_NOT_USED);
+          walUnlockExclusive(pWal, WAL_READ_LOCK(i), 1);
+        }else if( rc==SQLITE_BUSY ){
+          mxSafeFrame = y;
+          xBusy = 0;
+        }else{
+          goto walcheckpoint_out;
+        }
+      }
+    }
+
+    if( pInfo->nBackfill<mxSafeFrame
+     && (rc = walBusyLock(pWal, xBusy, pBusyArg, WAL_READ_LOCK(0),1))==SQLITE_OK
+    ){
+      i64 nSize;                    /* Current size of database file */
+      u32 nBackfill = pInfo->nBackfill;
+
+      /* Sync the WAL to disk */
+      if( sync_flags ){
+        rc = sqlite3OsSync(pWal->pWalFd, sync_flags);
+      }
+
+      /* If the database may grow as a result of this checkpoint, hint
+      ** about the eventual size of the db file to the VFS layer.
+      */
       if( rc==SQLITE_OK ){
-        pInfo->aReadMark[i] = (i==1 ? mxSafeFrame : READMARK_NOT_USED);
-        walUnlockExclusive(pWal, WAL_READ_LOCK(i), 1);
-      }else if( rc==SQLITE_BUSY ){
-        mxSafeFrame = y;
-        xBusy = 0;
-      }else{
-        goto walcheckpoint_out;
-      }
-    }
-  }
-
-  if( pInfo->nBackfill<mxSafeFrame
-   && (rc = walBusyLock(pWal, xBusy, pBusyArg, WAL_READ_LOCK(0), 1))==SQLITE_OK
-  ){
-    i64 nSize;                    /* Current size of database file */
-    u32 nBackfill = pInfo->nBackfill;
-
-    /* Sync the WAL to disk */
-    if( sync_flags ){
-      rc = sqlite3OsSync(pWal->pWalFd, sync_flags);
-    }
-
-    /* If the database may grow as a result of this checkpoint, hint
-    ** about the eventual size of the db file to the VFS layer.
-    */
-    if( rc==SQLITE_OK ){
-      i64 nReq = ((i64)mxPage * szPage);
-      rc = sqlite3OsFileSize(pWal->pDbFd, &nSize);
-      if( rc==SQLITE_OK && nSize<nReq ){
-        sqlite3OsFileControlHint(pWal->pDbFd, SQLITE_FCNTL_SIZE_HINT, &nReq);
-      }
-    }
-
-
-    /* Iterate through the contents of the WAL, copying data to the db file. */
-    while( rc==SQLITE_OK && 0==walIteratorNext(pIter, &iDbpage, &iFrame) ){
-      i64 iOffset;
-      assert( walFramePgno(pWal, iFrame)==iDbpage );
-      if( iFrame<=nBackfill || iFrame>mxSafeFrame || iDbpage>mxPage ) continue;
-      iOffset = walFrameOffset(iFrame, szPage) + WAL_FRAME_HDRSIZE;
-      /* testcase( IS_BIG_INT(iOffset) ); // requires a 4GiB WAL file */
-      rc = sqlite3OsRead(pWal->pWalFd, zBuf, szPage, iOffset);
-      if( rc!=SQLITE_OK ) break;
-      iOffset = (iDbpage-1)*(i64)szPage;
-      testcase( IS_BIG_INT(iOffset) );
-      rc = sqlite3OsWrite(pWal->pDbFd, zBuf, szPage, iOffset);
-      if( rc!=SQLITE_OK ) break;
-    }
-
-    /* If work was actually accomplished... */
-    if( rc==SQLITE_OK ){
-      if( mxSafeFrame==walIndexHdr(pWal)->mxFrame ){
-        i64 szDb = pWal->hdr.nPage*(i64)szPage;
-        testcase( IS_BIG_INT(szDb) );
-        rc = sqlite3OsTruncate(pWal->pDbFd, szDb);
-        if( rc==SQLITE_OK && sync_flags ){
-          rc = sqlite3OsSync(pWal->pDbFd, sync_flags);
-        }
-      }
+        i64 nReq = ((i64)mxPage * szPage);
+        rc = sqlite3OsFileSize(pWal->pDbFd, &nSize);
+        if( rc==SQLITE_OK && nSize<nReq ){
+          sqlite3OsFileControlHint(pWal->pDbFd, SQLITE_FCNTL_SIZE_HINT, &nReq);
+        }
+      }
+
+
+      /* Iterate through the contents of the WAL, copying data to the db file */
+      while( rc==SQLITE_OK && 0==walIteratorNext(pIter, &iDbpage, &iFrame) ){
+        i64 iOffset;
+        assert( walFramePgno(pWal, iFrame)==iDbpage );
+        if( iFrame<=nBackfill || iFrame>mxSafeFrame || iDbpage>mxPage ){
+          continue;
+        }
+        iOffset = walFrameOffset(iFrame, szPage) + WAL_FRAME_HDRSIZE;
+        /* testcase( IS_BIG_INT(iOffset) ); // requires a 4GiB WAL file */
+        rc = sqlite3OsRead(pWal->pWalFd, zBuf, szPage, iOffset);
+        if( rc!=SQLITE_OK ) break;
+        iOffset = (iDbpage-1)*(i64)szPage;
+        testcase( IS_BIG_INT(iOffset) );
+        rc = sqlite3OsWrite(pWal->pDbFd, zBuf, szPage, iOffset);
+        if( rc!=SQLITE_OK ) break;
+      }
+
+      /* If work was actually accomplished... */
       if( rc==SQLITE_OK ){
-        pInfo->nBackfill = mxSafeFrame;
-      }
-    }
-
-    /* Release the reader lock held while backfilling */
-    walUnlockExclusive(pWal, WAL_READ_LOCK(0), 1);
-  }
-
-  if( rc==SQLITE_BUSY ){
-    /* Reset the return code so as not to report a checkpoint failure
-    ** just because there are active readers.  */
-    rc = SQLITE_OK;
+        if( mxSafeFrame==walIndexHdr(pWal)->mxFrame ){
+          i64 szDb = pWal->hdr.nPage*(i64)szPage;
+          testcase( IS_BIG_INT(szDb) );
+          rc = sqlite3OsTruncate(pWal->pDbFd, szDb);
+          if( rc==SQLITE_OK && sync_flags ){
+            rc = sqlite3OsSync(pWal->pDbFd, sync_flags);
+          }
+        }
+        if( rc==SQLITE_OK ){
+          pInfo->nBackfill = mxSafeFrame;
+        }
+      }
+
+      /* Release the reader lock held while backfilling */
+      walUnlockExclusive(pWal, WAL_READ_LOCK(0), 1);
+    }
+
+    if( rc==SQLITE_BUSY ){
+      /* Reset the return code so as not to report a checkpoint failure
+      ** just because there are active readers.  */
+      rc = SQLITE_OK;
+    }
   }
 
   /* If this is an SQLITE_CHECKPOINT_RESTART or TRUNCATE operation, and the
   ** entire wal file has been copied into the database file, then block 
   ** until all readers have finished using the wal file. This ensures that 
   ** the next process to write to the database restarts the wal file.
   */
   if( rc==SQLITE_OK && eMode!=SQLITE_CHECKPOINT_PASSIVE ){
     assert( pWal->writeLock );
     if( pInfo->nBackfill<pWal->hdr.mxFrame ){
       rc = SQLITE_BUSY;
     }else if( eMode>=SQLITE_CHECKPOINT_RESTART ){
       u32 salt1;
       sqlite3_randomness(4, &salt1);
-      assert( mxSafeFrame==pWal->hdr.mxFrame );
+      assert( pInfo->nBackfill==pWal->hdr.mxFrame );
       rc = walBusyLock(pWal, xBusy, pBusyArg, WAL_READ_LOCK(1), WAL_NREADER-1);
       if( rc==SQLITE_OK ){
         if( eMode==SQLITE_CHECKPOINT_TRUNCATE ){
           /* IMPLEMENTATION-OF: R-44699-57140 This mode works the same way as
           ** SQLITE_CHECKPOINT_RESTART with the addition that it also
           ** truncates the log file to zero bytes just prior to a
           ** successful return.
           **
@@ -128364,16 +128367,17 @@ SQLITE_API int sqlite3_wal_checkpoint_v2
   sqlite3_mutex_enter(db->mutex);
   if( zDb && zDb[0] ){
     iDb = sqlite3FindDbName(db, zDb);
   }
   if( iDb<0 ){
     rc = SQLITE_ERROR;
     sqlite3ErrorWithMsg(db, SQLITE_ERROR, "unknown database: %s", zDb);
   }else{
+    db->busyHandler.nBusy = 0;
     rc = sqlite3Checkpoint(db, iDb, eMode, pnLog, pnCkpt);
     sqlite3Error(db, rc);
   }
   rc = sqlite3ApiExit(db, rc);
   sqlite3_mutex_leave(db->mutex);
   return rc;
 #endif
 }
--- a/db/sqlite3/src/sqlite3.h
+++ b/db/sqlite3/src/sqlite3.h
@@ -102,19 +102,19 @@ extern "C" {
 ** within its configuration management system.  ^The SQLITE_SOURCE_ID
 ** string contains the date and time of the check-in (UTC) and an SHA1
 ** hash of the entire source tree.
 **
 ** See also: [sqlite3_libversion()],
 ** [sqlite3_libversion_number()], [sqlite3_sourceid()],
 ** [sqlite_version()] and [sqlite_source_id()].
 */
-#define SQLITE_VERSION        "3.8.8.1"
+#define SQLITE_VERSION        "3.8.8.2"
 #define SQLITE_VERSION_NUMBER 3008008
-#define SQLITE_SOURCE_ID      "2015-01-20 16:51:25 f73337e3e289915a76ca96e7a05a1a8d4e890d55"
+#define SQLITE_SOURCE_ID      "2015-01-30 14:30:45 7757fc721220e136620a89c9d28247f28bbbc098"
 
 /*
 ** CAPI3REF: Run-Time Library Version Numbers
 ** KEYWORDS: sqlite3_version, sqlite3_sourceid
 **
 ** These interfaces provide the same information as the [SQLITE_VERSION],
 ** [SQLITE_VERSION_NUMBER], and [SQLITE_SOURCE_ID] C preprocessor macros
 ** but are associated with the library instead of the header file.  ^(Cautious
--- a/dom/base/nsDOMClassInfo.cpp
+++ b/dom/base/nsDOMClassInfo.cpp
@@ -2070,17 +2070,17 @@ nsWindowSH::GlobalResolve(nsGlobalWindow
   // hooked up yet.
   if (id == XPCJSRuntime::Get()->GetStringID(XPCJSRuntime::IDX_CONTROLLERS) &&
       !xpc::IsXrayWrapper(obj) &&
       !nsContentUtils::IsSystemPrincipal(nsContentUtils::ObjectPrincipal(obj)))
   {
     if (aWin->GetDoc()) {
       aWin->GetDoc()->WarnOnceAbout(nsIDocument::eWindow_Controllers);
     }
-    JS::Rooted<JSObject*> shim(cx, JS_NewObject(cx, &ControllersShimClass, JS::NullPtr(), obj));
+    JS::Rooted<JSObject*> shim(cx, JS_NewObject(cx, &ControllersShimClass, obj));
     if (NS_WARN_IF(!shim)) {
       return NS_ERROR_OUT_OF_MEMORY;
     }
     FillPropertyDescriptor(desc, obj, JS::ObjectValue(*shim), /* readOnly = */ false);
     return NS_OK;
   }
 #endif
 
--- a/dom/base/nsDocument.cpp
+++ b/dom/base/nsDocument.cpp
@@ -6149,17 +6149,17 @@ nsDocument::RegisterElement(JSContext* a
     JS::Handle<JSObject*> htmlProto(
       HTMLElementBinding::GetProtoObjectHandle(aCx, global));
     if (!htmlProto) {
       rv.Throw(NS_ERROR_OUT_OF_MEMORY);
       return;
     }
 
     if (!aOptions.mPrototype) {
-      protoObject = JS_NewObject(aCx, nullptr, htmlProto, JS::NullPtr());
+      protoObject = JS_NewObjectWithGivenProto(aCx, nullptr, htmlProto, JS::NullPtr());
       if (!protoObject) {
         rv.Throw(NS_ERROR_UNEXPECTED);
         return;
       }
     } else {
       protoObject = aOptions.mPrototype;
 
       // We are already operating on the document's (/global's) compartment. Let's
--- a/dom/bindings/BindingUtils.cpp
+++ b/dom/bindings/BindingUtils.cpp
@@ -476,18 +476,18 @@ CreateInterfaceObject(JSContext* cx, JS:
                       JS::Handle<JSObject*> proto,
                       const NativeProperties* properties,
                       const NativeProperties* chromeOnlyProperties,
                       const char* name, bool defineOnGlobal)
 {
   JS::Rooted<JSObject*> constructor(cx);
   if (constructorClass) {
     MOZ_ASSERT(constructorProto);
-    constructor = JS_NewObject(cx, Jsvalify(constructorClass), constructorProto,
-                               global);
+    constructor = JS_NewObjectWithGivenProto(cx, Jsvalify(constructorClass),
+                                             constructorProto, global);
   } else {
     MOZ_ASSERT(constructorNative);
     MOZ_ASSERT(constructorProto == JS_GetFunctionPrototype(cx, global));
     constructor = CreateConstructor(cx, global, name, constructorNative,
                                     ctorNargs);
   }
   if (!constructor) {
     return nullptr;
--- a/dom/bindings/BindingUtils.h
+++ b/dom/bindings/BindingUtils.h
@@ -2793,17 +2793,17 @@ public:
     }
   }
 
   void
   CreateObject(JSContext* aCx, const JSClass* aClass,
                JS::Handle<JSObject*> aProto, JS::Handle<JSObject*> aParent,
                T* aNative, JS::MutableHandle<JSObject*> aReflector)
   {
-    aReflector.set(JS_NewObject(aCx, aClass, aProto, aParent));
+    aReflector.set(JS_NewObjectWithGivenProto(aCx, aClass, aProto, aParent));
     if (aReflector) {
       js::SetReservedSlot(aReflector, DOM_OBJECT_SLOT, JS::PrivateValue(aNative));
       mNative = aNative;
       mReflector = aReflector;
     }
   }
 
   void
--- a/dom/indexedDB/KeyPath.cpp
+++ b/dom/indexedDB/KeyPath.cpp
@@ -167,18 +167,17 @@ GetJSValFromKeyPathString(JSContext* aCx
           rv = NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
           break;
         }
 
         obj = dummy;
       }
       else {
         JS::Rooted<JSObject*> dummy(aCx,
-          JS_NewObject(aCx, IDBObjectStore::DummyPropClass(), JS::NullPtr(),
-                       JS::NullPtr()));
+          JS_NewObject(aCx, IDBObjectStore::DummyPropClass()));
         if (!dummy) {
           IDB_REPORT_INTERNAL_ERR();
           rv = NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
           break;
         }
 
         if (!JS_DefineUCProperty(aCx, obj, token.BeginReading(),
                                  token.Length(), dummy, JSPROP_ENUMERATE)) {
--- a/dom/ipc/TabChild.cpp
+++ b/dom/ipc/TabChild.cpp
@@ -119,46 +119,46 @@ static bool sActiveDurationMsSet = false
 typedef nsDataHashtable<nsUint64HashKey, TabChild*> TabChildMap;
 static TabChildMap* sTabChildren;
 
 class TabChild::DelayedFireSingleTapEvent MOZ_FINAL : public nsITimerCallback
 {
 public:
   NS_DECL_ISUPPORTS
 
-  DelayedFireSingleTapEvent(TabChild* aTabChild,
+  DelayedFireSingleTapEvent(nsIWidget* aWidget,
                             LayoutDevicePoint& aPoint,
                             nsITimer* aTimer)
-    : mTabChild(do_GetWeakReference(static_cast<nsITabChild*>(aTabChild)))
+    : mWidget(do_GetWeakReference(aWidget))
     , mPoint(aPoint)
     // Hold the reference count until we are called back.
     , mTimer(aTimer)
   {
   }
 
   NS_IMETHODIMP Notify(nsITimer*) MOZ_OVERRIDE
   {
-    nsCOMPtr<nsITabChild> tabChild = do_QueryReferent(mTabChild);
-    if (tabChild) {
-      static_cast<TabChild*>(tabChild.get())->FireSingleTapEvent(mPoint);
+    nsCOMPtr<nsIWidget> widget = do_QueryReferent(mWidget);
+    if (widget) {
+      APZCCallbackHelper::FireSingleTapEvent(mPoint, widget);
     }
     mTimer = nullptr;
     return NS_OK;
   }
 
   void ClearTimer() {
     mTimer = nullptr;
   }
 
 private:
   ~DelayedFireSingleTapEvent()
   {
   }
 
-  nsWeakPtr mTabChild;
+  nsWeakPtr mWidget;
   LayoutDevicePoint mPoint;
   nsCOMPtr<nsITimer> mTimer;
 };
 
 NS_IMPL_ISUPPORTS(TabChild::DelayedFireSingleTapEvent,
                   nsITimerCallback)
 
 class TabChild::DelayedFireContextMenuEvent MOZ_FINAL : public nsITimerCallback
@@ -597,56 +597,16 @@ TabChildBase::ProcessUpdateFrame(const F
         data.AppendFloat(cssCompositedSize.height);
         data.AppendLiteral(" }");
     data.AppendLiteral(" }");
 
     DispatchMessageManagerMessage(NS_LITERAL_STRING("Viewport:Change"), data);
     return newMetrics;
 }
 
-nsEventStatus
-TabChildBase::DispatchSynthesizedMouseEvent(uint32_t aMsg, uint64_t aTime,
-                                            const LayoutDevicePoint& aRefPoint,
-                                            nsIWidget* aWidget)
-{
-  MOZ_ASSERT(aMsg == NS_MOUSE_MOVE || aMsg == NS_MOUSE_BUTTON_DOWN ||
-             aMsg == NS_MOUSE_BUTTON_UP || aMsg == NS_MOUSE_MOZLONGTAP);
-
-  WidgetMouseEvent event(true, aMsg, nullptr,
-                         WidgetMouseEvent::eReal, WidgetMouseEvent::eNormal);
-  event.refPoint = LayoutDeviceIntPoint(aRefPoint.x, aRefPoint.y);
-  event.time = aTime;
-  event.button = WidgetMouseEvent::eLeftButton;
-  event.inputSource = nsIDOMMouseEvent::MOZ_SOURCE_TOUCH;
-  event.ignoreRootScrollFrame = true;
-  if (aMsg != NS_MOUSE_MOVE) {
-    event.clickCount = 1;
-  }
-  event.widget = aWidget;
-
-  return DispatchWidgetEvent(event);
-}
-
-nsEventStatus
-TabChildBase::DispatchWidgetEvent(WidgetGUIEvent& event)
-{
-  if (!event.widget)
-    return nsEventStatus_eConsumeNoDefault;
-
-  if (TabParent* capturer = TabParent::GetEventCapturer()) {
-    if (capturer->TryCapture(event)) {
-      return nsEventStatus_eConsumeNoDefault;
-    }
-  }
-  nsEventStatus status;
-  NS_ENSURE_SUCCESS(event.widget->DispatchEvent(&event, status),
-                    nsEventStatus_eConsumeNoDefault);
-  return status;
-}
-
 bool
 TabChildBase::IsAsyncPanZoomEnabled()
 {
     return mScrolling == ASYNC_PAN_ZOOM;
 }
 
 NS_IMETHODIMP
 ContentListener::HandleEvent(nsIDOMEvent* aEvent)
@@ -2150,49 +2110,35 @@ TabChild::RecvHandleSingleTap(const CSSP
 
   LayoutDevicePoint currentPoint =
       APZCCallbackHelper::ApplyCallbackTransform(aPoint, aGuid, GetPresShellResolution())
     * mWidget->GetDefaultScale();;
   if (!mActiveElementManager->ActiveElementUsesStyle()) {
     // If the active element isn't visually affected by the :active style, we
     // have no need to wait the extra sActiveDurationMs to make the activation
     // visually obvious to the user.
-    FireSingleTapEvent(currentPoint);
+    APZCCallbackHelper::FireSingleTapEvent(currentPoint, mWidget);
     return true;
   }
 
   TABC_LOG("Active element uses style, scheduling timer for click event\n");
   nsCOMPtr<nsITimer> timer = do_CreateInstance(NS_TIMER_CONTRACTID);
   nsRefPtr<DelayedFireSingleTapEvent> callback =
-    new DelayedFireSingleTapEvent(this, currentPoint, timer);
+    new DelayedFireSingleTapEvent(mWidget, currentPoint, timer);
   nsresult rv = timer->InitWithCallback(callback,
                                         sActiveDurationMs,
                                         nsITimer::TYPE_ONE_SHOT);
   if (NS_FAILED(rv)) {
     // Make |callback| not hold the timer, so they will both be destructed when
     // we leave the scope of this function.
     callback->ClearTimer();
   }
   return true;
 }
 
-void
-TabChild::FireSingleTapEvent(LayoutDevicePoint aPoint)
-{
-  if (mDestroyed) {
-    return;
-  }
-  TABC_LOG("Dispatching single-tap component events to %s\n",
-    Stringify(aPoint).c_str());
-  int time = 0;
-  DispatchSynthesizedMouseEvent(NS_MOUSE_MOVE, time, aPoint, mWidget);
-  DispatchSynthesizedMouseEvent(NS_MOUSE_BUTTON_DOWN, time, aPoint, mWidget);
-  DispatchSynthesizedMouseEvent(NS_MOUSE_BUTTON_UP, time, aPoint, mWidget);
-}
-
 bool
 TabChild::RecvHandleLongTap(const CSSPoint& aPoint, const ScrollableLayerGuid& aGuid, const uint64_t& aInputBlockId)
 {
   TABC_LOG("Handling long tap at %s with %p %p\n",
     Stringify(aPoint).c_str(), mGlobal.get(), mTabChildGlobal.get());
 
   if (!mGlobal || !mTabChildGlobal) {
     return true;
@@ -2210,17 +2156,17 @@ TabChild::RecvHandleLongTap(const CSSPoi
 
   // If no one handle context menu, fire MOZLONGTAP event
   if (!eventHandled) {
     LayoutDevicePoint currentPoint =
         APZCCallbackHelper::ApplyCallbackTransform(aPoint, aGuid, GetPresShellResolution())
       * mWidget->GetDefaultScale();
     int time = 0;
     nsEventStatus status =
-      DispatchSynthesizedMouseEvent(NS_MOUSE_MOZLONGTAP, time, currentPoint, mWidget);
+        APZCCallbackHelper::DispatchSynthesizedMouseEvent(NS_MOUSE_MOZLONGTAP, time, currentPoint, mWidget);
     eventHandled = (status == nsEventStatus_eConsumeNoDefault);
     TABC_LOG("MOZLONGTAP event handled: %d\n", eventHandled);
   }
 
   SendContentReceivedInputBlock(aGuid, aInputBlockId, eventHandled);
 
   return true;
 }
@@ -2337,17 +2283,17 @@ TabChild::RecvMouseEvent(const nsString&
   return true;
 }
 
 bool
 TabChild::RecvRealMouseEvent(const WidgetMouseEvent& event)
 {
   WidgetMouseEvent localEvent(event);
   localEvent.widget = mWidget;
-  DispatchWidgetEvent(localEvent);
+  APZCCallbackHelper::DispatchWidgetEvent(localEvent);
   return true;
 }
 
 bool
 TabChild::RecvMouseWheelEvent(const WidgetWheelEvent& aEvent,
                               const ScrollableLayerGuid& aGuid,
                               const uint64_t& aInputBlockId)
 {
@@ -2362,17 +2308,17 @@ TabChild::RecvMouseWheelEvent(const Widg
 
         SendSetTargetAPZCNotification(shell, aInputBlockId, targets, waitForRefresh);
       }
     }
   }
 
   WidgetWheelEvent event(aEvent);
   event.widget = mWidget;
-  DispatchWidgetEvent(event);
+  APZCCallbackHelper::DispatchWidgetEvent(event);
 
   if (IsAsyncPanZoomEnabled()) {
     SendContentReceivedInputBlock(aGuid, aInputBlockId, event.mFlags.mDefaultPrevented);
   }
   return true;
 }
 
 static Touch*
@@ -2456,19 +2402,19 @@ TabChild::UpdateTapState(const WidgetTou
     if (std::abs(currentPoint.x - mGestureDownPoint.x) > sDragThreshold.width ||
         std::abs(currentPoint.y - mGestureDownPoint.y) > sDragThreshold.height) {
       CancelTapTracking();
     }
     return;
 
   case NS_TOUCH_END:
     if (!nsIPresShell::gPreventMouseEvents) {
-      DispatchSynthesizedMouseEvent(NS_MOUSE_MOVE, time, currentPoint, mWidget);
-      DispatchSynthesizedMouseEvent(NS_MOUSE_BUTTON_DOWN, time, currentPoint, mWidget);
-      DispatchSynthesizedMouseEvent(NS_MOUSE_BUTTON_UP, time, currentPoint, mWidget);
+      APZCCallbackHelper::DispatchSynthesizedMouseEvent(NS_MOUSE_MOVE, time, currentPoint, mWidget);
+      APZCCallbackHelper::DispatchSynthesizedMouseEvent(NS_MOUSE_BUTTON_DOWN, time, currentPoint, mWidget);
+      APZCCallbackHelper::DispatchSynthesizedMouseEvent(NS_MOUSE_BUTTON_UP, time, currentPoint, mWidget);
     }
     // fall through
   case NS_TOUCH_CANCEL:
     CancelTapTracking();
     return;
 
   default:
     NS_WARNING("Unknown touch event type");
@@ -2697,17 +2643,17 @@ TabChild::RecvRealTouchEvent(const Widge
 
   if (aEvent.message == NS_TOUCH_START && IsAsyncPanZoomEnabled()) {
     SendSetTargetAPZCNotification(aEvent, aGuid, aInputBlockId);
   }
 
   WidgetTouchEvent localEvent(aEvent);
   localEvent.widget = mWidget;
   // Dispatch event to content (potentially a long-running operation)
-  nsEventStatus status = DispatchWidgetEvent(localEvent);
+  nsEventStatus status = APZCCallbackHelper::DispatchWidgetEvent(localEvent);
 
   if (!IsAsyncPanZoomEnabled()) {
     UpdateTapState(localEvent, status);
     return true;
   }
 
   if (aEvent.message == NS_TOUCH_START && localEvent.touches.Length() > 0) {
     mActiveElementManager->SetTargetElement(localEvent.touches[0]->GetTarget());
@@ -2802,17 +2748,17 @@ TabChild::RecvRealKeyEvent(const WidgetK
   // If content code called preventDefault() on a keydown event, then we don't
   // want to process any following keypress events.
   if (event.message == NS_KEY_PRESS && mIgnoreKeyPressEvent) {
     return true;
   }
 
   WidgetKeyboardEvent localEvent(event);
   localEvent.widget = mWidget;
-  nsEventStatus status = DispatchWidgetEvent(localEvent);
+  nsEventStatus status = APZCCallbackHelper::DispatchWidgetEvent(localEvent);
 
   if (event.message == NS_KEY_DOWN) {
     mIgnoreKeyPressEvent = status == nsEventStatus_eConsumeNoDefault;
   }
 
   if (localEvent.mFlags.mWantReplyFromContentProcess) {
     SendReplyKeyEvent(localEvent);
   }
@@ -2839,26 +2785,26 @@ TabChild::RecvKeyEvent(const nsString& a
   return true;
 }
 
 bool
 TabChild::RecvCompositionEvent(const WidgetCompositionEvent& event)
 {
   WidgetCompositionEvent localEvent(event);
   localEvent.widget = mWidget;
-  DispatchWidgetEvent(localEvent);
+  APZCCallbackHelper::DispatchWidgetEvent(localEvent);
   return true;
 }
 
 bool
 TabChild::RecvSelectionEvent(const WidgetSelectionEvent& event)
 {
   WidgetSelectionEvent localEvent(event);
   localEvent.widget = mWidget;
-  DispatchWidgetEvent(localEvent);
+  APZCCallbackHelper::DispatchWidgetEvent(localEvent);
   return true;
 }
 
 PDocumentRendererChild*
 TabChild::AllocPDocumentRendererChild(const nsRect& documentRect,
                                       const mozilla::gfx::Matrix& transform,
                                       const nsString& bgcolor,
                                       const uint32_t& renderFlags,
--- a/dom/ipc/TabChild.h
+++ b/dom/ipc/TabChild.h
@@ -191,20 +191,16 @@ public:
     // change, this function doesn't do anything.  However, it should
     // not be called all the time as it is fairly expensive.
     bool HandlePossibleViewportChange(const ScreenIntSize& aOldScreenSize);
     virtual bool DoUpdateZoomConstraints(const uint32_t& aPresShellId,
                                          const mozilla::layers::FrameMetrics::ViewID& aViewId,
                                          const bool& aIsRoot,
                                          const mozilla::layers::ZoomConstraints& aConstraints) = 0;
 
-    nsEventStatus DispatchSynthesizedMouseEvent(uint32_t aMsg, uint64_t aTime,
-                                                const LayoutDevicePoint& aRefPoint,
-                                                nsIWidget* aWidget);
-
 protected:
     virtual ~TabChildBase();
     CSSSize GetPageSize(nsCOMPtr<nsIDocument> aDocument, const CSSSize& aViewport);
 
     // Get the DOMWindowUtils for the top-level window in this tab.
     already_AddRefed<nsIDOMWindowUtils> GetDOMWindowUtils();
     // Get the Document for the top-level window in this tab.
     already_AddRefed<nsIDocument> GetDocument() const;
@@ -216,18 +212,16 @@ protected:
     // Wraps up a JSON object as a structured clone and sends it to the browser
     // chrome script.
     //
     // XXX/bug 780335: Do the work the browser chrome script does in C++ instead
     // so we don't need things like this.
     void DispatchMessageManagerMessage(const nsAString& aMessageName,
                                        const nsAString& aJSONData);
 
-    nsEventStatus DispatchWidgetEvent(WidgetGUIEvent& event);
-
     void InitializeRootMetrics();
 
     mozilla::layers::FrameMetrics ProcessUpdateFrame(const mozilla::layers::FrameMetrics& aFrameMetrics);
 
     bool UpdateFrameHandler(const mozilla::layers::FrameMetrics& aFrameMetrics);
 
 protected:
     CSSSize mOldViewportSize;
@@ -654,17 +648,16 @@ private:
     bool mDidFakeShow;
     bool mNotified;
     bool mTriedBrowserInit;
     ScreenOrientation mOrientation;
     bool mUpdateHitRegion;
     bool mPendingTouchPreventedResponse;
     ScrollableLayerGuid mPendingTouchPreventedGuid;
     uint64_t mPendingTouchPreventedBlockId;
-    void FireSingleTapEvent(LayoutDevicePoint aPoint);
 
     bool mTouchEndCancelled;
     bool mEndTouchIsClick;
 
     bool mIgnoreKeyPressEvent;
     nsRefPtr<ActiveElementManager> mActiveElementManager;
     bool mHasValidInnerSize;
     bool mDestroyed;
--- a/dom/media/eme/MediaKeyStatusMap.cpp
+++ b/dom/media/eme/MediaKeyStatusMap.cpp
@@ -177,17 +177,19 @@ MediaKeyStatusMap::GetSize(JSContext* aC
   return JS::MapSize(aCx, map);
 }
 
 static MediaKeyStatus
 ToMediaKeyStatus(GMPMediaKeyStatus aStatus) {
   switch (aStatus) {
     case kGMPUsable: return MediaKeyStatus::Usable;
     case kGMPExpired: return MediaKeyStatus::Expired;
+    case kGMPOutputDownscaled: return MediaKeyStatus::Output_downscaled;
     case kGMPOutputNotAllowed: return MediaKeyStatus::Output_not_allowed;
+    case kGMPInternalError: return MediaKeyStatus::Internal_error;
     default: return MediaKeyStatus::Internal_error;
   }
 }
 
 static bool
 ToJSString(JSContext* aCx, GMPMediaKeyStatus aStatus,
            JS::MutableHandle<JS::Value> aResult)
 {
--- a/dom/media/gmp-plugin/fake.info
+++ b/dom/media/gmp-plugin/fake.info
@@ -1,5 +1,5 @@
 Name: fake
 Description: Fake GMP Plugin
 Version: 1.0
-APIs: encode-video[h264], decode-video[h264], eme-decrypt-v5[fake]
+APIs: encode-video[h264], decode-video[h264], eme-decrypt-v6[fake]
 Libraries: dxva2.dll
--- a/dom/media/gmp/gmp-api/gmp-decryption.h
+++ b/dom/media/gmp/gmp-api/gmp-decryption.h
@@ -74,19 +74,21 @@ enum GMPSessionMessageType {
   kGMPLicenseRelease = 2,
   kGMPIndividualizationRequest = 3,
   kGMPMessageInvalid = 4 // Must always be last.
 };
 
 enum GMPMediaKeyStatus {
   kGMPUsable = 0,
   kGMPExpired = 1,
-  kGMPOutputNotAllowed = 2,
-  kGMPUnknown = 3,
-  kGMPMediaKeyStatusInvalid = 4 // Must always be last.
+  kGMPOutputDownscaled = 2,
+  kGMPOutputNotAllowed = 3,
+  kGMPInternalError = 4,
+  kGMPUnknown = 5,
+  kGMPMediaKeyStatusInvalid = 6 // Must always be last.
 };
 
 // Time in milliseconds, as offset from epoch, 1 Jan 1970.
 typedef int64_t GMPTimestamp;
 
 // Capability definitions. The capabilities of the EME GMP are reported
 // to Gecko by calling the GMPDecryptorCallback::SetCapabilities()
 // callback and specifying the logical OR of the GMP_EME_CAP_* flags below.
@@ -217,17 +219,17 @@ public:
 };
 
 enum GMPSessionType {
   kGMPTemporySession = 0,
   kGMPPersistentSession = 1,
   kGMPSessionInvalid = 2 // Must always be last.
 };
 
-#define GMP_API_DECRYPTOR "eme-decrypt-v5"
+#define GMP_API_DECRYPTOR "eme-decrypt-v6"
 
 // API exposed by plugin library to manage decryption sessions.
 // When the Host requests this by calling GMPGetAPIFunc().
 //
 // API name macro: GMP_API_DECRYPTOR
 // Host API: GMPDecryptorHost
 class GMPDecryptor {
 public:
--- a/dom/plugins/base/nsJSNPRuntime.cpp
+++ b/dom/plugins/base/nsJSNPRuntime.cpp
@@ -1901,18 +1901,17 @@ nsNPObjWrapper::GetNewOrUsed(NPP npp, JS
 
   entry->mNPObj = npobj;
   entry->mNpp = npp;
 
   uint32_t generation = sNPObjWrappers.Generation();
 
   // No existing JSObject, create one.
 
-  JS::Rooted<JSObject*> obj(cx, ::JS_NewObject(cx, js::Jsvalify(&sNPObjectJSWrapperClass),
-                                               JS::NullPtr(), JS::NullPtr()));
+  JS::Rooted<JSObject*> obj(cx, ::JS_NewObject(cx, js::Jsvalify(&sNPObjectJSWrapperClass)));
 
   if (generation != sNPObjWrappers.Generation()) {
       // Reload entry if the JS_NewObject call caused a GC and reallocated
       // the table (see bug 445229). This is guaranteed to succeed.
 
       NS_ASSERTION(PL_DHashTableSearch(&sNPObjWrappers, npobj),
                    "Hashtable didn't find what we just added?");
   }
@@ -2071,17 +2070,17 @@ CreateNPObjectMember(NPP npp, JSContext 
     (NPObjectMemberPrivate *)PR_Malloc(sizeof(NPObjectMemberPrivate));
   if (!memberPrivate)
     return false;
 
   // Make sure to clear all members in case something fails here
   // during initialization.
   memset(memberPrivate, 0, sizeof(NPObjectMemberPrivate));
 
-  JSObject *memobj = ::JS_NewObject(cx, &sNPObjectMemberClass, JS::NullPtr(), JS::NullPtr());
+  JSObject *memobj = ::JS_NewObject(cx, &sNPObjectMemberClass);
   if (!memobj) {
     PR_Free(memberPrivate);
     return false;
   }
 
   vp.setObject(*memobj);
 
   ::JS_SetPrivate(memobj, (void *)memberPrivate);
--- a/gfx/layers/apz/util/APZCCallbackHelper.cpp
+++ b/gfx/layers/apz/util/APZCCallbackHelper.cpp
@@ -1,26 +1,33 @@
 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* 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 "APZCCallbackHelper.h"
+
 #include "gfxPlatform.h" // For gfxPlatform::UseTiling
+#include "mozilla/dom/TabParent.h"
 #include "nsIScrollableFrame.h"
 #include "nsLayoutUtils.h"
 #include "nsIDOMElement.h"
 #include "nsIInterfaceRequestorUtils.h"
 #include "nsIContent.h"
 #include "nsIDocument.h"
 #include "nsIDOMWindow.h"
 
+#define APZCCH_LOG(...)
+// #define APZCCH_LOG(...) printf_stderr("APZCCH: " __VA_ARGS__)
+
 namespace mozilla {
 namespace layers {
 
+using dom::TabParent;
+
 bool
 APZCCallbackHelper::HasValidPresShellId(nsIDOMWindowUtils* aUtils,
                                         const FrameMetrics& aMetrics)
 {
     MOZ_ASSERT(aUtils);
 
     uint32_t presShellId;
     nsresult rv = aUtils->GetPresShellId(&presShellId);
@@ -355,10 +362,72 @@ APZCCallbackHelper::ApplyCallbackTransfo
                                            float aPresShellResolution)
 {
     LayoutDevicePoint point = LayoutDevicePoint(aPoint.x, aPoint.y);
     point = ApplyCallbackTransform(point / aScale, aGuid, aPresShellResolution) * aScale;
     LayoutDeviceIntPoint ret = gfx::RoundedToInt(point);
     return nsIntPoint(ret.x, ret.y);
 }
 
+nsEventStatus
+APZCCallbackHelper::DispatchWidgetEvent(WidgetGUIEvent& aEvent)
+{
+  if (!aEvent.widget)
+    return nsEventStatus_eConsumeNoDefault;
+
+  // A nested process may be capturing events.
+  if (TabParent* capturer = TabParent::GetEventCapturer()) {
+    if (capturer->TryCapture(aEvent)) {
+      // Only touch events should be captured, and touch events from a parent
+      // process should not make it here. Capture for those is done elsewhere
+      // (for gonk, in nsWindow::DispatchTouchInputViaAPZ).
+      MOZ_ASSERT(!XRE_IsParentProcess());
+
+      return nsEventStatus_eConsumeNoDefault;
+    }
+  }
+  nsEventStatus status;
+  NS_ENSURE_SUCCESS(aEvent.widget->DispatchEvent(&aEvent, status),
+                    nsEventStatus_eConsumeNoDefault);
+  return status;
+}
+
+nsEventStatus
+APZCCallbackHelper::DispatchSynthesizedMouseEvent(uint32_t aMsg,
+                                                  uint64_t aTime,
+                                                  const LayoutDevicePoint& aRefPoint,
+                                                  nsIWidget* aWidget)
+{
+  MOZ_ASSERT(aMsg == NS_MOUSE_MOVE || aMsg == NS_MOUSE_BUTTON_DOWN ||
+             aMsg == NS_MOUSE_BUTTON_UP || aMsg == NS_MOUSE_MOZLONGTAP);
+
+  WidgetMouseEvent event(true, aMsg, nullptr,
+                         WidgetMouseEvent::eReal, WidgetMouseEvent::eNormal);
+  event.refPoint = LayoutDeviceIntPoint(aRefPoint.x, aRefPoint.y);
+  event.time = aTime;
+  event.button = WidgetMouseEvent::eLeftButton;
+  event.inputSource = nsIDOMMouseEvent::MOZ_SOURCE_TOUCH;
+  event.ignoreRootScrollFrame = true;
+  if (aMsg != NS_MOUSE_MOVE) {
+    event.clickCount = 1;
+  }
+  event.widget = aWidget;
+
+  return DispatchWidgetEvent(event);
+}
+
+void
+APZCCallbackHelper::FireSingleTapEvent(const LayoutDevicePoint& aPoint,
+                                       nsIWidget* aWidget)
+{
+  if (aWidget->Destroyed()) {
+    return;
+  }
+  APZCCH_LOG("Dispatching single-tap component events to %s\n",
+    Stringify(aPoint).c_str());
+  int time = 0;
+  DispatchSynthesizedMouseEvent(NS_MOUSE_MOVE, time, aPoint, aWidget);
+  DispatchSynthesizedMouseEvent(NS_MOUSE_BUTTON_DOWN, time, aPoint, aWidget);
+  DispatchSynthesizedMouseEvent(NS_MOUSE_BUTTON_UP, time, aPoint, aWidget);
+}
+
 }
 }
--- a/gfx/layers/apz/util/APZCCallbackHelper.h
+++ b/gfx/layers/apz/util/APZCCallbackHelper.h
@@ -2,20 +2,22 @@
 /* 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/. */
 
 #ifndef mozilla_layers_APZCCallbackHelper_h
 #define mozilla_layers_APZCCallbackHelper_h
 
 #include "FrameMetrics.h"
+#include "mozilla/EventForwards.h"
 #include "nsIDOMWindowUtils.h"
 
 class nsIContent;
 class nsIDocument;
+class nsIWidget;
 template<class T> struct already_AddRefed;
 
 namespace mozilla {
 namespace layers {
 
 /* This class contains some helper methods that facilitate implementing the
    GeckoContentController callback interface required by the AsyncPanZoomController.
    Since different platforms need to implement this interface in similar-but-
@@ -99,14 +101,31 @@ public:
 
     /* Same as above, but operates on nsIntPoint that are assumed to be in LayoutDevice
        pixel space. Requires an additonal |aScale| parameter to convert between CSS and
        LayoutDevice space. */
     static nsIntPoint ApplyCallbackTransform(const nsIntPoint& aPoint,
                                              const ScrollableLayerGuid& aGuid,
                                              const CSSToLayoutDeviceScale& aScale,
                                              float aPresShellResolution);
+
+    /* Dispatch a widget event via the widget stored in the event, if any.
+     * In a child process, allows the TabParent event-capture mechanism to
+     * intercept the event. */
+    static nsEventStatus DispatchWidgetEvent(WidgetGUIEvent& aEvent);
+
+    /* Synthesize a mouse event with the given parameters, and dispatch it
+     * via the given widget. */
+    static nsEventStatus DispatchSynthesizedMouseEvent(uint32_t aMsg,
+                                                       uint64_t aTime,
+                                                       const LayoutDevicePoint& aRefPoint,
+                                                       nsIWidget* aWidget);
+
+    /* Fire a single-tap event at the given point. The event is dispatched
+     * via the given widget. */
+    static void FireSingleTapEvent(const LayoutDevicePoint& aPoint,
+                                   nsIWidget* aWidget);
 };
 
 }
 }
 
 #endif /* mozilla_layers_APZCCallbackHelper_h */
--- a/gfx/layers/apz/util/ChromeProcessController.cpp
+++ b/gfx/layers/apz/util/ChromeProcessController.cpp
@@ -92,8 +92,36 @@ ChromeProcessController::Destroy()
       FROM_HERE,
       NewRunnableMethod(this, &ChromeProcessController::Destroy));
     return;
   }
 
   MOZ_ASSERT(MessageLoop::current() == mUILoop);
   mWidget = nullptr;
 }
+
+float
+ChromeProcessController::GetPresShellResolution() const
+{
+  // The document in the chrome process cannot be zoomed, so its pres shell
+  // resolution is 1.
+  return 1.0f;
+}
+
+void
+ChromeProcessController::HandleSingleTap(const CSSPoint& aPoint,
+                                         int32_t aModifiers,
+                                         const ScrollableLayerGuid& aGuid)
+{
+  if (MessageLoop::current() != mUILoop) {
+    mUILoop->PostTask(
+        FROM_HERE,
+        NewRunnableMethod(this, &ChromeProcessController::HandleSingleTap,
+                          aPoint, aModifiers, aGuid));
+    return;
+  }
+
+  LayoutDevicePoint point =
+      APZCCallbackHelper::ApplyCallbackTransform(aPoint, aGuid, GetPresShellResolution())
+    * mWidget->GetDefaultScale();
+
+  APZCCallbackHelper::FireSingleTapEvent(point, mWidget);
+}
--- a/gfx/layers/apz/util/ChromeProcessController.h
+++ b/gfx/layers/apz/util/ChromeProcessController.h
@@ -33,28 +33,29 @@ public:
   virtual void RequestContentRepaint(const FrameMetrics& aFrameMetrics) MOZ_OVERRIDE;
   virtual void PostDelayedTask(Task* aTask, int aDelayMs) MOZ_OVERRIDE;
   virtual void AcknowledgeScrollUpdate(const FrameMetrics::ViewID& aScrollId,
                                        const uint32_t& aScrollGeneration) MOZ_OVERRIDE;
 
   virtual void HandleDoubleTap(const mozilla::CSSPoint& aPoint, int32_t aModifiers,
                                const ScrollableLayerGuid& aGuid) MOZ_OVERRIDE {}
   virtual void HandleSingleTap(const mozilla::CSSPoint& aPoint, int32_t aModifiers,
-                               const ScrollableLayerGuid& aGuid) MOZ_OVERRIDE {}
+                               const ScrollableLayerGuid& aGuid) MOZ_OVERRIDE;
   virtual void HandleLongTap(const mozilla::CSSPoint& aPoint, int32_t aModifiers,
                                const ScrollableLayerGuid& aGuid,
                                uint64_t aInputBlockId) MOZ_OVERRIDE {}
   virtual void HandleLongTapUp(const CSSPoint& aPoint, int32_t aModifiers,
                                const ScrollableLayerGuid& aGuid) MOZ_OVERRIDE {}
   virtual void SendAsyncScrollDOMEvent(bool aIsRoot, const mozilla::CSSRect &aContentRect,
                                        const mozilla::CSSSize &aScrollableSize) MOZ_OVERRIDE {}
 
 private:
   nsCOMPtr<nsIWidget> mWidget;
   MessageLoop* mUILoop;
 
   void InitializeRoot();
+  float GetPresShellResolution() const;
 };
 
 } // namespace layers
 } // namespace mozilla
 
 #endif /* mozilla_layers_ChromeProcessController_h */
--- a/image/src/RasterImage.cpp
+++ b/image/src/RasterImage.cpp
@@ -609,26 +609,21 @@ RasterImage::IsOpaque()
 
   // Other, we're opaque if FLAG_HAS_TRANSPARENCY is not set.
   return !(progress & FLAG_HAS_TRANSPARENCY);
 }
 
 void
 RasterImage::OnSurfaceDiscarded()
 {
-  if (!NS_IsMainThread()) {
-    nsCOMPtr<nsIRunnable> runnable =
-      NS_NewRunnableMethod(this, &RasterImage::OnSurfaceDiscarded);
-    NS_DispatchToMainThread(runnable);
-    return;
-  }
+  MOZ_ASSERT(mProgressTracker);
 
-  if (mProgressTracker) {
-    mProgressTracker->OnDiscard();
-  }
+  nsCOMPtr<nsIRunnable> runnable =
+    NS_NewRunnableMethod(mProgressTracker, &ProgressTracker::OnDiscard);
+  NS_DispatchToMainThread(runnable);
 }
 
 //******************************************************************************
 /* readonly attribute boolean animated; */
 NS_IMETHODIMP
 RasterImage::GetAnimated(bool *aAnimated)
 {
   if (mError)
--- a/image/src/SurfaceCache.cpp
+++ b/image/src/SurfaceCache.cpp
@@ -357,17 +357,17 @@ private:
 class SurfaceCacheImpl MOZ_FINAL : public nsIMemoryReporter
 {
 public:
   NS_DECL_ISUPPORTS
 
   SurfaceCacheImpl(uint32_t aSurfaceCacheExpirationTimeMS,
                    uint32_t aSurfaceCacheDiscardFactor,
                    uint32_t aSurfaceCacheSize)
-    : mExpirationTracker(this, aSurfaceCacheExpirationTimeMS)
+    : mExpirationTracker(aSurfaceCacheExpirationTimeMS)
     , mMemoryPressureObserver(new MemoryPressureObserver)
     , mMutex("SurfaceCache")
     , mDiscardFactor(aSurfaceCacheDiscardFactor)
     , mMaxCost(aSurfaceCacheSize)
     , mAvailableCost(aSurfaceCacheSize)
     , mLockedCost(0)
   {
     nsCOMPtr<nsIObserverService> os = services::GetObserverService();
@@ -737,16 +737,18 @@ public:
     return PL_DHASH_NEXT;
   }
 
   NS_IMETHOD
   CollectReports(nsIHandleReportCallback* aHandleReport,
                  nsISupports*             aData,
                  bool                     aAnonymize) MOZ_OVERRIDE
   {
+    MutexAutoLock lock(mMutex);
+
     // We have explicit memory reporting for the surface cache which is more
     // accurate than the cost metrics we report here, but these metrics are
     // still useful to report, since they control the cache's behavior.
     nsresult rv;
 
     rv = MOZ_COLLECT_REPORT("imagelib-surface-cache-estimated-total",
                             KIND_OTHER, UNITS_BYTES,
                             (mMaxCost - mAvailableCost),
@@ -804,42 +806,40 @@ private:
   // thread could insert a persistent surface or lock an image at any time.
   bool CanHoldAfterDiscarding(const Cost aCost) const
   {
     return aCost <= mMaxCost - mLockedCost;
   }
 
   struct SurfaceTracker : public nsExpirationTracker<CachedSurface, 2>
   {
-    SurfaceTracker(SurfaceCacheImpl* aCache, uint32_t aSurfaceCacheExpirationTimeMS)
+    explicit SurfaceTracker(uint32_t aSurfaceCacheExpirationTimeMS)
       : nsExpirationTracker<CachedSurface, 2>(aSurfaceCacheExpirationTimeMS)
-      , mCache(aCache)
     { }
 
   protected:
     virtual void NotifyExpired(CachedSurface* aSurface) MOZ_OVERRIDE
     {
-      if (mCache) {
-        mCache->Remove(aSurface);
+      if (sInstance) {
+        MutexAutoLock lock(sInstance->GetMutex());
+        sInstance->Remove(aSurface);
       }
     }
-
-  private:
-    SurfaceCacheImpl* const mCache;  // Weak pointer to owner.
   };
 
   struct MemoryPressureObserver : public nsIObserver
   {
     NS_DECL_ISUPPORTS
 
     NS_IMETHOD Observe(nsISupports*,
                        const char* aTopic,
                        const char16_t*) MOZ_OVERRIDE
     {
       if (sInstance && strcmp(aTopic, "memory-pressure") == 0) {
+        MutexAutoLock lock(sInstance->GetMutex());
         sInstance->DiscardForMemoryPressure();
       }
       return NS_OK;
     }
 
   private:
     virtual ~MemoryPressureObserver() { }
   };
--- a/image/test/browser/browser_bug666317.js
+++ b/image/test/browser/browser_bug666317.js
@@ -22,28 +22,16 @@ function ImageDiscardObserver(result) {
 
 function currentRequest() {
   let img = gBrowser.getBrowserForTab(newTab).contentWindow
             .document.getElementById('testImg');
   img.QueryInterface(Ci.nsIImageLoadingContent);
   return img.getRequest(Ci.nsIImageLoadingContent.CURRENT_REQUEST);
 }
 
-function attachDiscardObserver(result) {
-  // Create the discard observer.
-  let observer = new ImageDiscardObserver(result);
-  let scriptedObserver = Cc["@mozilla.org/image/tools;1"]
-                           .getService(Ci.imgITools)
-                           .createScriptedObserver(observer);
-
-  // Clone the current imgIRequest with our new observer.
-  let request = currentRequest();
-  return request.clone(scriptedObserver);
-}
-
 function isImgDecoded() {
   let request = currentRequest();
   return request.imageStatus & Ci.imgIRequest.STATUS_FRAME_COMPLETE ? true : false;
 }
 
 // Ensure that the image is decoded by drawing it to a canvas.
 function forceDecodeImg() {
   let doc = gBrowser.getBrowserForTab(newTab).contentWindow.document;
@@ -64,30 +52,52 @@ function test() {
   gBrowser.selectedTab = newTab;
 
   // Run step2 after the tab loads.
   gBrowser.getBrowserForTab(newTab)
           .addEventListener("pageshow", step2 );
 }
 
 function step2() {
-  // Attach a discard listener and create a place to hold the result.
+  // Create a place to hold the result.
   var result = { wasDiscarded: false };
-  var clonedRequest = attachDiscardObserver(result);
+
+  // Create the discard observer.
+  var observer = new ImageDiscardObserver(result);
+  var scriptedObserver = Cc["@mozilla.org/image/tools;1"]
+                           .getService(Ci.imgITools)
+                           .createScriptedObserver(observer);
+
+  // Clone the current imgIRequest with our new observer.
+  var request = currentRequest();
+  var clonedRequest = request.clone(scriptedObserver);
 
   // Check that the image is decoded.
   forceDecodeImg();
   ok(isImgDecoded(), 'Image should initially be decoded.');
 
   // Focus the old tab, then fire a memory-pressure notification.  This should
   // cause the decoded image in the new tab to be discarded.
   gBrowser.selectedTab = oldTab;
   var os = Cc["@mozilla.org/observer-service;1"]
              .getService(Ci.nsIObserverService);
   os.notifyObservers(null, 'memory-pressure', 'heap-minimize');
+
+  // The discard notification is delivered asynchronously, so pump the event
+  // loop before checking.
+  window.addEventListener('message', function (event) {
+    if (event.data == 'step3') {
+      step3(result, scriptedObserver, clonedRequest);
+    }
+  }, false);
+
+  window.postMessage('step3', '*');
+}
+
+function step3(result, scriptedObserver, clonedRequest) {
   ok(result.wasDiscarded, 'Image should be discarded.');
 
   // And we're done.
   gBrowser.removeTab(newTab);
   prefBranch.setBoolPref('discardable', oldDiscardingPref);
   clonedRequest.cancelAndForgetObserver(0);
   finish();
 }
--- a/js/src/builtin/TestingFunctions.cpp
+++ b/js/src/builtin/TestingFunctions.cpp
@@ -1543,17 +1543,17 @@ class CloneBufferObject : public NativeO
     static const size_t DATA_SLOT   = 0;
     static const size_t LENGTH_SLOT = 1;
     static const size_t NUM_SLOTS   = 2;
 
   public:
     static const Class class_;
 
     static CloneBufferObject *Create(JSContext *cx) {
-        RootedObject obj(cx, JS_NewObject(cx, Jsvalify(&class_), JS::NullPtr(), JS::NullPtr()));
+        RootedObject obj(cx, JS_NewObject(cx, Jsvalify(&class_)));
         if (!obj)
             return nullptr;
         obj->as<CloneBufferObject>().setReservedSlot(DATA_SLOT, PrivateValue(nullptr));
         obj->as<CloneBufferObject>().setReservedSlot(LENGTH_SLOT, Int32Value(0));
 
         if (!JS_DefineProperties(cx, obj, props_))
             return nullptr;
 
--- a/js/src/builtin/TypedObject.cpp
+++ b/js/src/builtin/TypedObject.cpp
@@ -1695,29 +1695,29 @@ TypedObject::obj_lookupGeneric(JSContext
 
       case type::Array:
       {
         uint32_t index;
         if (js_IdIsIndex(id, &index))
             return obj_lookupElement(cx, obj, index, objp, propp);
 
         if (JSID_IS_ATOM(id, cx->names().length)) {
-            MarkNonNativePropertyFound(propp);
+            MarkNonNativePropertyFound<CanGC>(propp);
             objp.set(obj);
             return true;
         }
         break;
       }
 
       case type::Struct:
       {
         StructTypeDescr &structDescr = descr->as<StructTypeDescr>();
         size_t index;
         if (structDescr.fieldIndex(id, &index)) {
-            MarkNonNativePropertyFound(propp);
+            MarkNonNativePropertyFound<CanGC>(propp);
             objp.set(obj);
             return true;
         }
         break;
       }
     }
 
     RootedObject proto(cx, obj->getProto());
@@ -1741,17 +1741,17 @@ TypedObject::obj_lookupProperty(JSContex
     return obj_lookupGeneric(cx, obj, id, objp, propp);
 }
 
 bool
 TypedObject::obj_lookupElement(JSContext *cx, HandleObject obj, uint32_t index,
                                 MutableHandleObject objp, MutableHandleShape propp)
 {
     MOZ_ASSERT(obj->is<TypedObject>());
-    MarkNonNativePropertyFound(propp);
+    MarkNonNativePropertyFound<CanGC>(propp);
     objp.set(obj);
     return true;
 }
 
 static bool
 ReportPropertyError(JSContext *cx,
                     const unsigned errorNumber,
                     HandleId id)
--- a/js/src/ctypes/CTypes.cpp
+++ b/js/src/ctypes/CTypes.cpp
@@ -904,17 +904,17 @@ InitCTypeClass(JSContext* cx, HandleObje
   RootedObject ctor(cx, JS_GetFunctionObject(fun));
   RootedObject fnproto(cx);
   if (!JS_GetPrototype(cx, ctor, &fnproto))
     return nullptr;
   MOZ_ASSERT(ctor);
   MOZ_ASSERT(fnproto);
 
   // Set up ctypes.CType.prototype.
-  RootedObject prototype(cx, JS_NewObject(cx, &sCTypeProtoClass, fnproto, parent));
+  RootedObject prototype(cx, JS_NewObjectWithGivenProto(cx, &sCTypeProtoClass, fnproto, parent));
   if (!prototype)
     return nullptr;
 
   if (!JS_DefineProperty(cx, ctor, "prototype", prototype,
                          JSPROP_ENUMERATE | JSPROP_READONLY | JSPROP_PERMANENT))
     return nullptr;
 
   if (!JS_DefineProperty(cx, prototype, "constructor", ctor,
@@ -960,17 +960,17 @@ InitCDataClass(JSContext* cx, HandleObje
 
   // Set up ctypes.CData.__proto__ === ctypes.CType.prototype.
   // (Note that 'ctypes.CData instanceof Function' is still true, thanks to the
   // prototype chain.)
   if (!JS_SetPrototype(cx, ctor, CTypeProto))
     return nullptr;
 
   // Set up ctypes.CData.prototype.
-  RootedObject prototype(cx, JS_NewObject(cx, &sCDataProtoClass, NullPtr(), parent));
+  RootedObject prototype(cx, JS_NewObject(cx, &sCDataProtoClass, parent));
   if (!prototype)
     return nullptr;
 
   if (!JS_DefineProperty(cx, ctor, "prototype", prototype,
                          JSPROP_ENUMERATE | JSPROP_READONLY | JSPROP_PERMANENT))
     return nullptr;
 
   if (!JS_DefineProperty(cx, prototype, "constructor", ctor,
@@ -1024,17 +1024,17 @@ InitTypeConstructor(JSContext* cx,
   if (!fun)
     return false;
 
   RootedObject obj(cx, JS_GetFunctionObject(fun));
   if (!obj)
     return false;
 
   // Set up the .prototype and .prototype.constructor properties.
-  typeProto.set(JS_NewObject(cx, &sCTypeProtoClass, CTypeProto, parent));
+  typeProto.set(JS_NewObjectWithGivenProto(cx, &sCTypeProtoClass, CTypeProto, parent));
   if (!typeProto)
     return false;
 
   // Define property before proceeding, for GC safety.
   if (!JS_DefineProperty(cx, obj, "prototype", typeProto,
                          JSPROP_ENUMERATE | JSPROP_READONLY | JSPROP_PERMANENT))
     return false;
 
@@ -1051,17 +1051,17 @@ InitTypeConstructor(JSContext* cx,
   // Stash ctypes.{Pointer,Array,Struct}Type.prototype on a reserved slot of
   // the type constructor, for faster lookup.
   js::SetFunctionNativeReserved(obj, SLOT_FN_CTORPROTO, OBJECT_TO_JSVAL(typeProto));
 
   // Create an object to serve as the common ancestor for all CData objects
   // created from the given type constructor. This has ctypes.CData.prototype
   // as its prototype, such that it inherits the properties and functions
   // common to all CDatas.
-  dataProto.set(JS_NewObject(cx, &sCDataProtoClass, CDataProto, parent));
+  dataProto.set(JS_NewObjectWithGivenProto(cx, &sCDataProtoClass, CDataProto, parent));
   if (!dataProto)
     return false;
 
   // Define functions and properties on the 'dataProto' object that are common
   // to all CData objects created from this type constructor. (These will
   // become functions and properties on CData objects created from this type.)
   if (instanceFns && !JS_DefineFunctions(cx, dataProto, instanceFns))
     return false;
@@ -1358,17 +1358,17 @@ static bool GetObjectProperty(JSContext 
 
 using namespace js;
 using namespace js::ctypes;
 
 JS_PUBLIC_API(bool)
 JS_InitCTypesClass(JSContext* cx, HandleObject global)
 {
   // attach ctypes property to global object
-  RootedObject ctypes(cx, JS_NewObject(cx, &sCTypesGlobalClass, NullPtr(), NullPtr()));
+  RootedObject ctypes(cx, JS_NewObject(cx, &sCTypesGlobalClass));
   if (!ctypes)
     return false;
 
   if (!JS_DefineProperty(cx, global, "ctypes", ctypes,
                          JSPROP_READONLY | JSPROP_PERMANENT,
                          JS_STUBGETTER, JS_STUBSETTER)){
     return false;
   }
@@ -1381,17 +1381,17 @@ JS_InitCTypesClass(JSContext* cx, Handle
       !JS_DefineProperties(cx, ctypes, sModuleProps))
     return false;
 
   // Set up ctypes.CDataFinalizer.prototype.
   RootedObject ctor(cx);
   if (!GetObjectProperty(cx, ctypes, "CDataFinalizer", &ctor))
     return false;
 
-  RootedObject prototype(cx, JS_NewObject(cx, &sCDataFinalizerProtoClass, NullPtr(), ctypes));
+  RootedObject prototype(cx, JS_NewObject(cx, &sCDataFinalizerProtoClass, ctypes));
   if (!prototype)
     return false;
 
   if (!JS_DefineFunctions(cx, prototype, sCDataFinalizerFunctions))
     return false;
 
   if (!JS_DefineProperty(cx, ctor, "prototype", prototype,
                          JSPROP_ENUMERATE | JSPROP_READONLY | JSPROP_PERMANENT))
@@ -3296,32 +3296,32 @@ CType::Create(JSContext* cx,
   //     * [[Class]] "CDataProto"
   //     * __proto__ === 'dataProto'; an object containing properties and
   //       functions common to all CData objects of types derived from
   //       'typeProto'. (For instance, this could be ctypes.CData.prototype
   //       for simple types, or something representing structs for StructTypes.)
   //     * 'constructor' property === 't'
   //     * Additional properties specified by 'ps', as appropriate for the
   //       specific type instance 't'.
-  RootedObject typeObj(cx, JS_NewObject(cx, &sCTypeClass, typeProto, parent));
+  RootedObject typeObj(cx, JS_NewObjectWithGivenProto(cx, &sCTypeClass, typeProto, parent));
   if (!typeObj)
     return nullptr;
 
   // Set up the reserved slots.
   JS_SetReservedSlot(typeObj, SLOT_TYPECODE, INT_TO_JSVAL(type));
   if (ffiType)
     JS_SetReservedSlot(typeObj, SLOT_FFITYPE, PRIVATE_TO_JSVAL(ffiType));
   if (name)
     JS_SetReservedSlot(typeObj, SLOT_NAME, STRING_TO_JSVAL(name));
   JS_SetReservedSlot(typeObj, SLOT_SIZE, size);
   JS_SetReservedSlot(typeObj, SLOT_ALIGN, align);
 
   if (dataProto) {
     // Set up the 'prototype' and 'prototype.constructor' properties.
-    RootedObject prototype(cx, JS_NewObject(cx, &sCDataProtoClass, dataProto, parent));
+    RootedObject prototype(cx, JS_NewObjectWithGivenProto(cx, &sCDataProtoClass, dataProto, parent));
     if (!prototype)
       return nullptr;
 
     if (!JS_DefineProperty(cx, prototype, "constructor", typeObj,
                            JSPROP_READONLY | JSPROP_PERMANENT))
       return nullptr;
 
     // Set the 'prototype' object.
@@ -4863,17 +4863,17 @@ StructType::DefineInternal(JSContext* cx
   // ctypes.CType.prototype.
   RootedObject dataProto(cx, CType::GetProtoFromType(cx, typeObj, SLOT_STRUCTDATAPROTO));
   if (!dataProto)
     return false;
 
   // Set up the 'prototype' and 'prototype.constructor' properties.
   // The prototype will reflect the struct fields as properties on CData objects
   // created from this type.
-  RootedObject prototype(cx, JS_NewObject(cx, &sCDataProtoClass, dataProto, NullPtr()));
+  RootedObject prototype(cx, JS_NewObjectWithGivenProto(cx, &sCDataProtoClass, dataProto, NullPtr()));
   if (!prototype)
     return false;
 
   if (!JS_DefineProperty(cx, prototype, "constructor", typeObj,
                          JSPROP_READONLY | JSPROP_PERMANENT))
     return false;
 
   // Create a FieldInfoHash to stash on the type object, and an array to root
@@ -6070,17 +6070,17 @@ CClosure::Create(JSContext* cx,
                  HandleObject fnObj,
                  HandleObject thisObj,
                  jsval errVal_,
                  PRFuncPtr* fnptr)
 {
   RootedValue errVal(cx, errVal_);
   MOZ_ASSERT(fnObj);
 
-  RootedObject result(cx, JS_NewObject(cx, &sCClosureClass, NullPtr(), NullPtr()));
+  RootedObject result(cx, JS_NewObject(cx, &sCClosureClass));
   if (!result)
     return nullptr;
 
   // Get the FunctionInfo from the FunctionType.
   FunctionInfo* fninfo = FunctionType::GetFunctionInfo(typeObj);
   MOZ_ASSERT(!fninfo->mIsVariadic);
   MOZ_ASSERT(GetABICode(fninfo->mABI) != ABI_WINAPI);
 
@@ -6372,17 +6372,17 @@ CData::Create(JSContext* cx,
   // Get the 'prototype' property from the type.
   jsval slot = JS_GetReservedSlot(typeObj, SLOT_PROTO);
   MOZ_ASSERT(slot.isObject());
 
   RootedObject proto(cx, &slot.toObject());
   RootedObject parent(cx, JS_GetParent(typeObj));
   MOZ_ASSERT(parent);
 
-  RootedObject dataObj(cx, JS_NewObject(cx, &sCDataClass, proto, parent));
+  RootedObject dataObj(cx, JS_NewObjectWithGivenProto(cx, &sCDataClass, proto, parent));
   if (!dataObj)
     return nullptr;
 
   // set the CData's associated type
   JS_SetReservedSlot(dataObj, SLOT_CTYPE, OBJECT_TO_JSVAL(typeObj));
 
   // Stash the referent object, if any, for GC safety.
   if (refObj)
@@ -6953,17 +6953,18 @@ CDataFinalizer::Construct(JSContext* cx,
   RootedObject objProto(cx);
   if (!GetObjectProperty(cx, objSelf, "prototype", &objProto)) {
     JS_ReportError(cx, "CDataFinalizer.prototype does not exist");
     return false;
   }
 
   // Get arguments
   if (args.length() == 0) { // Special case: the empty (already finalized) object
-    JSObject *objResult = JS_NewObject(cx, &sCDataFinalizerClass, objProto, NullPtr());
+    JSObject *objResult = JS_NewObjectWithGivenProto(cx, &sCDataFinalizerClass, objProto,
+                                                     NullPtr());
     args.rval().setObject(*objResult);
     return true;
   }
 
   if (args.length() != 2) {
     JS_ReportError(cx, "CDataFinalizer takes 2 arguments");
     return false;
   }
@@ -7052,17 +7053,17 @@ CDataFinalizer::Construct(JSContext* cx,
   ScopedJSFreePtr<void> rvalue;
   if (CType::GetTypeCode(returnType) != TYPE_void_t) {
     rvalue = malloc(Align(CType::GetSize(returnType),
                           sizeof(ffi_arg)));
   } //Otherwise, simply do not allocate
 
   // 5. Create |objResult|
 
-  JSObject *objResult = JS_NewObject(cx, &sCDataFinalizerClass, objProto, NullPtr());
+  JSObject *objResult = JS_NewObjectWithGivenProto(cx, &sCDataFinalizerClass, objProto, NullPtr());
   if (!objResult) {
     return false;
   }
 
   // If our argument is a CData, it holds a type.
   // This is the type that we should capture, not that
   // of the function, which may be less precise.
   JSObject *objBestArgType = objArgType;
@@ -7352,17 +7353,17 @@ CDataFinalizer::Cleanup(CDataFinalizer::
 JSObject*
 Int64Base::Construct(JSContext* cx,
                      HandleObject proto,
                      uint64_t data,
                      bool isUnsigned)
 {
   const JSClass* clasp = isUnsigned ? &sUInt64Class : &sInt64Class;
   RootedObject parent(cx, JS_GetParent(proto));
-  RootedObject result(cx, JS_NewObject(cx, clasp, proto, parent));
+  RootedObject result(cx, JS_NewObjectWithGivenProto(cx, clasp, proto, parent));
   if (!result)
     return nullptr;
 
   // attach the Int64's data
   uint64_t* buffer = cx->new_<uint64_t>(data);
   if (!buffer) {
     JS_ReportOutOfMemory(cx);
     return nullptr;
--- a/js/src/ctypes/Library.cpp
+++ b/js/src/ctypes/Library.cpp
@@ -78,18 +78,17 @@ Library::Name(JSContext* cx, unsigned ar
   args.rval().setString(result);
   return true;
 }
 
 JSObject*
 Library::Create(JSContext* cx, jsval path_, const JSCTypesCallbacks* callbacks)
 {
   RootedValue path(cx, path_);
-  RootedObject libraryObj(cx,
-                          JS_NewObject(cx, &sLibraryClass, NullPtr(), NullPtr()));
+  RootedObject libraryObj(cx, JS_NewObject(cx, &sLibraryClass));
   if (!libraryObj)
     return nullptr;
 
   // initialize the library
   JS_SetReservedSlot(libraryObj, SLOT_LIBRARY, PRIVATE_TO_JSVAL(nullptr));
 
   // attach API functions
   if (!JS_DefineFunctions(cx, libraryObj, sLibraryFunctions))
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/ion/nursery-getter-setter.js
@@ -0,0 +1,17 @@
+var threshold = getJitCompilerOptions()["ion.warmup.trigger"] + 101;
+function bar(i) {
+    if (!i)
+        with (this) {}; // Don't inline.
+    if (i === threshold)
+        minorgc();
+}
+
+function f() {
+    var o2 = Object.create({get foo() { return this.x; }, set foo(x) { this.x = x + 1; }});
+    for (var i=0; i<2000; i++) {
+        o2.foo = i;
+        assertEq(o2.foo, i + 1);
+        bar(i);
+    }
+}
+f();
--- a/js/src/jit/BaselineIC.cpp
+++ b/js/src/jit/BaselineIC.cpp
@@ -3329,24 +3329,16 @@ IsCacheableGetPropCall(JSContext *cx, JS
 
     if (!shape->hasGetterValue())
         return false;
 
     if (!shape->getterValue().isObject() || !shape->getterObject()->is<JSFunction>())
         return false;
 
     JSFunction *func = &shape->getterObject()->as<JSFunction>();
-
-    // Information from get prop call ICs may be used directly from Ion code,
-    // and should not be nursery allocated.
-    if (IsInsideNursery(holder) || IsInsideNursery(func)) {
-        *isTemporarilyUnoptimizable = true;
-        return false;
-    }
-
     if (func->isNative()) {
         *isScripted = false;
         return true;
     }
 
     if (!func->hasJITCode()) {
         *isTemporarilyUnoptimizable = true;
         return false;
@@ -3452,23 +3444,16 @@ IsCacheableSetPropCall(JSContext *cx, JS
     if (!shape->hasSetterValue())
         return false;
 
     if (!shape->setterValue().isObject() || !shape->setterObject()->is<JSFunction>())
         return false;
 
     JSFunction *func = &shape->setterObject()->as<JSFunction>();
 
-    // Information from set prop call ICs may be used directly from Ion code,
-    // and should not be nursery allocated.
-    if (IsInsideNursery(holder) || IsInsideNursery(func)) {
-        *isTemporarilyUnoptimizable = true;
-        return false;
-    }
-
     if (func->isNative()) {
         *isScripted = false;
         return true;
     }
 
     if (!func->hasJITCode()) {
         *isTemporarilyUnoptimizable = true;
         return false;
--- a/js/src/jit/CodeGenerator.cpp
+++ b/js/src/jit/CodeGenerator.cpp
@@ -2150,16 +2150,29 @@ CodeGenerator::visitPointer(LPointer *li
 {
     if (lir->kind() == LPointer::GC_THING)
         masm.movePtr(ImmGCPtr(lir->gcptr()), ToRegister(lir->output()));
     else
         masm.movePtr(ImmPtr(lir->ptr()), ToRegister(lir->output()));
 }
 
 void
+CodeGenerator::visitNurseryObject(LNurseryObject *lir)
+{
+    Register output = ToRegister(lir->output());
+    uint32_t index = lir->mir()->index();
+
+    // Store a dummy JSObject pointer. We will fix it up on the main thread,
+    // in JitCode::fixupNurseryObjects. The low bit is set to distinguish
+    // it from a real JSObject pointer.
+    JSObject *ptr = reinterpret_cast<JSObject*>((uintptr_t(index) << 1) | 1);
+    masm.movePtr(ImmGCPtr(IonNurseryPtr(ptr)), output);
+}
+
+void
 CodeGenerator::visitSlots(LSlots *lir)
 {
     Address slots(ToRegister(lir->object()), NativeObject::offsetOfSlots());
     masm.loadPtr(slots, ToRegister(lir->output()));
 }
 
 void
 CodeGenerator::visitLoadSlotT(LLoadSlotT *lir)
@@ -7378,16 +7391,19 @@ CodeGenerator::link(JSContext *cx, types
             patchableTLScripts_[i].fixup(&masm);
             Assembler::PatchDataWithValueCheck(CodeLocationLabel(code, patchableTLScripts_[i]),
                                                ImmPtr((void *) uintptr_t(textId)),
                                                ImmPtr((void *)0));
         }
     }
 #endif
 
+    // Replace dummy JSObject pointers embedded by LNurseryObject.
+    code->fixupNurseryObjects(cx, gen->nurseryObjects());
+
     // The correct state for prebarriers is unknown until the end of compilation,
     // since a GC can occur during code generation. All barriers are emitted
     // off-by-default, and are toggled on here if necessary.
     if (cx->zone()->needsIncrementalBarrier())
         ionScript->toggleBarriers(true);
 
     // Attach any generated script counts to the script.
     if (IonScriptCounts *counts = extractScriptCounts())
--- a/js/src/jit/CodeGenerator.h
+++ b/js/src/jit/CodeGenerator.h
@@ -106,16 +106,17 @@ class CodeGenerator : public CodeGenerat
     void visitRegExpTest(LRegExpTest *lir);
     void visitOutOfLineRegExpTest(OutOfLineRegExpTest *ool);
     void visitRegExpReplace(LRegExpReplace *lir);
     void visitStringReplace(LStringReplace *lir);
     void visitLambda(LLambda *lir);
     void visitLambdaArrow(LLambdaArrow *lir);
     void visitLambdaForSingleton(LLambdaForSingleton *lir);
     void visitPointer(LPointer *lir);
+    void visitNurseryObject(LNurseryObject *lir);
     void visitSlots(LSlots *lir);
     void visitLoadSlotT(LLoadSlotT *lir);
     void visitLoadSlotV(LLoadSlotV *lir);
     void visitStoreSlotT(LStoreSlotT *lir);
     void visitStoreSlotV(LStoreSlotV *lir);
     void visitElements(LElements *lir);
     void visitConvertElementsToDoubles(LConvertElementsToDoubles *lir);
     void visitMaybeToDoubleElement(LMaybeToDoubleElement *lir);
--- a/js/src/jit/Ion.cpp
+++ b/js/src/jit/Ion.cpp
@@ -158,17 +158,18 @@ JitRuntime::JitRuntime()
     argumentsRectifierReturnAddr_(nullptr),
     invalidator_(nullptr),
     debugTrapHandler_(nullptr),
     baselineDebugModeOSRHandler_(nullptr),
     functionWrappers_(nullptr),
     osrTempData_(nullptr),
     mutatingBackedgeList_(false),
     ionReturnOverride_(MagicValue(JS_ARG_POISON)),
-    jitcodeGlobalTable_(nullptr)
+    jitcodeGlobalTable_(nullptr),
+    hasIonNurseryObjects_(false)
 {
 }
 
 JitRuntime::~JitRuntime()
 {
     js_delete(functionWrappers_);
     freeOsrTempData();
 
@@ -649,16 +650,27 @@ JitCode::trace(JSTracer *trc)
     if (dataRelocTableBytes_) {
         uint8_t *start = code_ + dataRelocTableOffset();
         CompactBufferReader reader(start, start + dataRelocTableBytes_);
         MacroAssembler::TraceDataRelocations(trc, this, reader);
     }
 }
 
 void
+JitCode::fixupNurseryObjects(JSContext *cx, const ObjectVector &nurseryObjects)
+{
+    if (nurseryObjects.empty() || !dataRelocTableBytes_)
+        return;
+
+    uint8_t *start = code_ + dataRelocTableOffset();
+    CompactBufferReader reader(start, start + dataRelocTableBytes_);
+    MacroAssembler::FixupNurseryObjects(cx, this, reader, nurseryObjects);
+}
+
+void
 JitCode::finalize(FreeOp *fop)
 {
     JSRuntime *rt = fop->runtime();
 
     // If this jitcode has a bytecode map, de-register it.
     if (hasBytecodeMap_) {
         MOZ_ASSERT(rt->jitRuntime()->hasJitcodeGlobalTable());
         rt->jitRuntime()->getJitcodeGlobalTable()->removeEntry(raw(), rt);
@@ -1666,16 +1678,72 @@ AttachFinishedCompilations(JSContext *cx
                 cx->clearPendingException();
             }
         }
 
         FinishOffThreadBuilder(cx, builder);
     }
 }
 
+void
+MIRGenerator::traceNurseryObjects(JSTracer *trc)
+{
+    MarkObjectRootRange(trc, nurseryObjects_.length(), nurseryObjects_.begin(), "ion-nursery-objects");
+}
+
+class MarkOffThreadNurseryObjects : public gc::BufferableRef
+{
+  public:
+    void mark(JSTracer *trc);
+};
+
+void
+MarkOffThreadNurseryObjects::mark(JSTracer *trc)
+{
+    JSRuntime *rt = trc->runtime();
+
+    MOZ_ASSERT(rt->jitRuntime()->hasIonNurseryObjects());
+    rt->jitRuntime()->setHasIonNurseryObjects(false);
+
+    AutoLockHelperThreadState lock;
+    if (!HelperThreadState().threads)
+        return;
+
+    // Trace nursery objects of any builders which haven't started yet.
+    GlobalHelperThreadState::IonBuilderVector &worklist = HelperThreadState().ionWorklist();
+    for (size_t i = 0; i < worklist.length(); i++) {
+        jit::IonBuilder *builder = worklist[i];
+        if (builder->script()->runtimeFromAnyThread() == rt)
+            builder->traceNurseryObjects(trc);
+    }
+
+    // Trace nursery objects of in-progress entries.
+    for (size_t i = 0; i < HelperThreadState().threadCount; i++) {
+        HelperThread &helper = HelperThreadState().threads[i];
+        if (helper.ionBuilder && helper.ionBuilder->script()->runtimeFromAnyThread() == rt)
+            helper.ionBuilder->traceNurseryObjects(trc);
+    }
+
+    // Trace nursery objects of any completed entries.
+    GlobalHelperThreadState::IonBuilderVector &finished = HelperThreadState().ionFinishedList();
+    for (size_t i = 0; i < finished.length(); i++) {
+        jit::IonBuilder *builder = finished[i];
+        if (builder->script()->runtimeFromAnyThread() == rt)
+            builder->traceNurseryObjects(trc);
+    }
+
+    // Trace nursery objects of lazy-linked builders.
+    jit::IonBuilder *builder = HelperThreadState().ionLazyLinkList().getFirst();
+    while (builder) {
+        if (builder->script()->runtimeFromAnyThread() == rt)
+            builder->traceNurseryObjects(trc);
+        builder = builder->getNext();
+    }
+}
+
 static inline bool
 OffThreadCompilationAvailable(JSContext *cx)
 {
     // Even if off thread compilation is enabled, compilation must still occur
     // on the main thread in some cases.
     //
     // Require cpuCount > 1 so that Ion compilation jobs and main-thread
     // execution are not competing for the same resources.
@@ -1861,16 +1929,25 @@ IonCompile(JSContext *cx, JSScript *scri
     // If possible, compile the script off thread.
     if (OffThreadCompilationAvailable(cx)) {
         if (!recompile)
             builderScript->setIonScript(cx, ION_COMPILING_SCRIPT);
 
         JitSpew(JitSpew_IonLogs, "Can't log script %s:%d. (Compiled on background thread.)",
                 builderScript->filename(), builderScript->lineno());
 
+        JSRuntime *rt = cx->runtime();
+        if (!builder->nurseryObjects().empty() && !rt->jitRuntime()->hasIonNurseryObjects()) {
+            // Ensure the builder's nursery objects are marked when a nursery
+            // GC happens on the main thread.
+            MarkOffThreadNurseryObjects mark;
+            rt->gc.storeBuffer.putGeneric(mark);
+            rt->jitRuntime()->setHasIonNurseryObjects(true);
+        }
+
         if (!StartOffThreadIonCompile(cx, builder)) {
             JitSpew(JitSpew_IonAbort, "Unable to start off-thread ion compilation.");
             return AbortReason_Alloc;
         }
 
         // The allocator and associated data will be destroyed after being
         // processed in the finishedOffThreadCompilations list.
         autoDelete.forget();
--- a/js/src/jit/IonBuilder.cpp
+++ b/js/src/jit/IonBuilder.cpp
@@ -211,16 +211,47 @@ void
 IonBuilder::spew(const char *message)
 {
     // Don't call PCToLineNumber in release builds.
 #ifdef DEBUG
     JitSpew(JitSpew_IonMIR, "%s @ %s:%d", message, script()->filename(), PCToLineNumber(script(), pc));
 #endif
 }
 
+MInstruction *
+IonBuilder::constantMaybeNursery(JSObject *obj)
+{
+    MOZ_ASSERT(obj);
+    if (!IsInsideNursery(obj))
+        return constant(ObjectValue(*obj));
+
+    // If |obj| is in the nursery, we have to add it to the list of nursery
+    // objects that get traced during off-thread compilation. We use
+    // MNurseryObject to ensure we will patch the code with the right
+    // pointer after codegen is done.
+
+    size_t index = UINT32_MAX;
+    for (size_t i = 0, len = nurseryObjects_.length(); i < len; i++) {
+        if (nurseryObjects_[i] == obj) {
+            index = i;
+            break;
+        }
+    }
+
+    if (index == UINT32_MAX) {
+        if (!nurseryObjects_.append(obj))
+            return nullptr;
+        index = nurseryObjects_.length() - 1;
+    }
+
+    MNurseryObject *ins = MNurseryObject::New(alloc(), obj, index, constraints());
+    current->add(ins);
+    return ins;
+}
+
 static inline int32_t
 GetJumpOffset(jsbytecode *pc)
 {
     MOZ_ASSERT(js_CodeSpec[JSOp(*pc)].type() == JOF_JUMP);
     return GET_JUMP_OFFSET(pc);
 }
 
 IonBuilder::CFGState
@@ -5833,16 +5864,19 @@ IonBuilder::makeCallsiteClone(JSFunction
     current->add(clone);
     return clone;
 }
 
 bool
 IonBuilder::testShouldDOMCall(types::TypeSet *inTypes,
                               JSFunction *func, JSJitInfo::OpType opType)
 {
+    if (IsInsideNursery(func))
+        return false;
+
     if (!func->isNative() || !func->jitInfo())
         return false;
 
     // If all the DOM objects flowing through are legal with this
     // property, we can bake in a call to the bottom half of the DOM
     // accessor
     DOMInstanceClassHasProtoAtDepth instanceChecker =
         compartment->runtime()->DOMcallbacks()->instanceClassMatchesProto;
@@ -9292,27 +9326,25 @@ IonBuilder::objectsHaveCommonPrototype(t
             }
             if (singleton) {
                 if (types::CanHaveEmptyPropertyTypesForOwnProperty(singleton)) {
                     MOZ_ASSERT(singleton->is<GlobalObject>());
                     *guardGlobal = true;
                 }
             }
 
-            if (!type->hasTenuredProto())
-                return false;
-            JSObject *proto = type->proto().toObjectOrNull();
+            JSObject *proto = type->protoMaybeInNursery().toObjectOrNull();
             if (proto == foundProto)
                 break;
             if (!proto) {
                 // The foundProto being searched for did not show up on the
                 // object's prototype chain.
                 return false;
             }
-            type = types::TypeObjectKey::get(type->proto().toObjectOrNull());
+            type = types::TypeObjectKey::get(proto);
         }
     }
 
     return true;
 }
 
 void
 IonBuilder::freezePropertiesForCommonPrototype(types::TemporaryTypeSet *types, PropertyName *name,
@@ -9331,24 +9363,24 @@ IonBuilder::freezePropertiesForCommonPro
 
         while (true) {
             types::HeapTypeSetKey property = type->property(NameToId(name));
             JS_ALWAYS_TRUE(!property.isOwnProperty(constraints(), allowEmptyTypesforGlobal));
 
             // Don't mark the proto. It will be held down by the shape
             // guard. This allows us to use properties found on prototypes
             // with properties unknown to TI.
-            if (type->proto() == TaggedProto(foundProto))
+            if (type->protoMaybeInNursery() == TaggedProto(foundProto))
                 break;
-            type = types::TypeObjectKey::get(type->proto().toObjectOrNull());
-        }
-    }
-}
-
-inline bool
+            type = types::TypeObjectKey::get(type->protoMaybeInNursery().toObjectOrNull());
+        }
+    }
+}
+
+bool
 IonBuilder::testCommonGetterSetter(types::TemporaryTypeSet *types, PropertyName *name,
                                    bool isGetter, JSObject *foundProto, Shape *lastProperty,
                                    MDefinition **guard,
                                    Shape *globalShape/* = nullptr*/,
                                    MDefinition **globalGuard/* = nullptr */)
 {
     MOZ_ASSERT_IF(globalShape, globalGuard);
     bool guardGlobal;
@@ -9380,17 +9412,17 @@ IonBuilder::testCommonGetterSetter(types
     }
 
     if (foundProto->isNative()) {
         Shape *propShape = foundProto->as<NativeObject>().lookupPure(name);
         if (propShape && !propShape->configurable())
             return true;
     }
 
-    MInstruction *wrapper = constant(ObjectValue(*foundProto));
+    MInstruction *wrapper = constantMaybeNursery(foundProto);
     *guard = addShapeGuard(wrapper, lastProperty, Bailout_ShapeGuard);
     return true;
 }
 
 void
 IonBuilder::replaceMaybeFallbackFunctionGetter(MGetPropertyCache *cache)
 {
     // Discard the last prior resume point of the previous MGetPropertyCache.
@@ -10044,17 +10076,17 @@ IonBuilder::getPropTryCommonGetter(bool 
         obj = guardObj;
     }
 
     // Spoof stack to expected state for call.
 
     // Make sure there's enough room
     if (!current->ensureHasSlots(2))
         return false;
-    pushConstant(ObjectValue(*commonGetter));
+    current->push(constantMaybeNursery(commonGetter));
 
     current->push(obj);
 
     CallInfo callInfo(alloc(), false);
     if (!callInfo.init(current, 0))
         return false;
 
     if (commonGetter->isNative()) {
@@ -10084,17 +10116,18 @@ IonBuilder::getPropTryCommonGetter(bool 
           case InliningDecision_Inline:
             if (!inlineScriptedCall(callInfo, commonGetter))
                 return false;
             *emitted = true;
             return true;
         }
     }
 
-    if (!makeCall(commonGetter, callInfo, false))
+    JSFunction *tenuredCommonGetter = IsInsideNursery(commonGetter) ? nullptr : commonGetter;
+    if (!makeCall(tenuredCommonGetter, callInfo, false))
         return false;
 
     // If the getter could have been inlined, don't track success. The call to
     // makeInliningDecision above would have tracked a specific reason why we
     // couldn't inline.
     if (!commonGetter->isInterpreted())
         trackOptimizationSuccess();
 
@@ -10492,18 +10525,17 @@ IonBuilder::setPropTryCommonSetter(bool 
         obj = guardObj;
     }
 
     // Dummy up the stack, as in getprop. We are pushing an extra value, so
     // ensure there is enough space.
     if (!current->ensureHasSlots(3))
         return false;
 
-    pushConstant(ObjectValue(*commonSetter));
-
+    current->push(constantMaybeNursery(commonSetter));
     current->push(obj);
     current->push(value);
 
     // Call the setter. Note that we have to push the original value, not
     // the setter's return value.
     CallInfo callInfo(alloc(), false);
     if (!callInfo.init(current, 1))
         return false;
@@ -10523,17 +10555,18 @@ IonBuilder::setPropTryCommonSetter(bool 
           case InliningDecision_Inline:
             if (!inlineScriptedCall(callInfo, commonSetter))
                 return false;
             *emitted = true;
             return true;
         }
     }
 
-    MCall *call = makeCallHelper(commonSetter, callInfo, false);
+    JSFunction *tenuredCommonSetter = IsInsideNursery(commonSetter) ? nullptr : commonSetter;
+    MCall *call = makeCallHelper(tenuredCommonSetter, callInfo, false);
     if (!call)
         return false;
 
     current->push(value);
     if (!resumeAfter(call))
         return false;
 
     // If the setter could have been inlined, don't track success. The call to
--- a/js/src/jit/IonBuilder.h
+++ b/js/src/jit/IonBuilder.h
@@ -233,16 +233,18 @@ class IonBuilder
     bool processIterators();
     bool inspectOpcode(JSOp op);
     uint32_t readIndex(jsbytecode *pc);
     JSAtom *readAtom(jsbytecode *pc);
     bool abort(const char *message, ...);
     void trackActionableAbort(const char *message);
     void spew(const char *message);
 
+    MInstruction *constantMaybeNursery(JSObject *obj);
+
     JSFunction *getSingleCallTarget(types::TemporaryTypeSet *calleeTypes);
     bool getPolyCallTargets(types::TemporaryTypeSet *calleeTypes, bool constructing,
                             ObjectVector &targets, uint32_t maxTargets);
 
     void popCfgStack();
     DeferredEdge *filterDeadDeferredEdges(DeferredEdge *edge);
     bool processDeferredContinues(CFGState &state);
     ControlStatus processControlEnd();
--- a/js/src/jit/IonCaches.cpp
+++ b/js/src/jit/IonCaches.cpp
@@ -1172,19 +1172,27 @@ CanAttachNativeGetProp(typename GetPropC
 {
     if (!obj || !obj->isNative())
         return GetPropertyIC::CanAttachNone;
 
     // The lookup needs to be universally pure, otherwise we risk calling hooks out
     // of turn. We don't mind doing this even when purity isn't required, because we
     // only miss out on shape hashification, which is only a temporary perf cost.
     // The limits were arbitrarily set, anyways.
-    if (!LookupPropertyPure(cx, obj, NameToId(name), holder.address(), shape.address()))
+    JSObject *baseHolder = nullptr;
+    if (!LookupPropertyPure(cx, obj, NameToId(name), &baseHolder, shape.address()))
         return GetPropertyIC::CanAttachNone;
 
+    MOZ_ASSERT(!holder);
+    if (baseHolder) {
+        if (!baseHolder->isNative())
+            return GetPropertyIC::CanAttachNone;
+        holder.set(&baseHolder->as<NativeObject>());
+    }
+
     RootedScript script(cx);
     jsbytecode *pc;
     cache.getScriptedLocation(&script, &pc);
     if (IsCacheableGetPropReadSlotForIon(obj, holder, shape) ||
         IsCacheableNoProperty(obj, holder, shape, pc, cache.output()))
     {
         return GetPropertyIC::CanAttachReadSlot;
     }
@@ -2640,17 +2648,17 @@ IsPropertyAddInlineable(NativeObject *ob
         return CanInlineSetPropTypeCheck(obj, id, val, checkTypeset);
 
     *checkTypeset = false;
     return true;
 }
 
 static SetPropertyIC::NativeSetPropCacheability
 CanAttachNativeSetProp(JSContext *cx, HandleObject obj, HandleId id, ConstantOrRegister val,
-                       bool needsTypeBarrier, MutableHandleNativeObject holder,
+                       bool needsTypeBarrier, MutableHandleObject holder,
                        MutableHandleShape shape, bool *checkTypeset)
 {
     if (!obj->isNative())
         return SetPropertyIC::CanAttachNone;
 
     // See if the property exists on the object.
     if (IsPropertySetInlineable(&obj->as<NativeObject>(), id, shape, val, needsTypeBarrier, checkTypeset))
         return SetPropertyIC::CanAttachSetSlot;
@@ -2718,17 +2726,17 @@ SetPropertyIC::update(JSContext *cx, siz
             if (!addedSetterStub && !cache.hasGenericProxyStub()) {
                 if (!cache.attachGenericProxy(cx, script, ion, returnAddr))
                     return false;
                 addedSetterStub = true;
             }
         }
 
         RootedShape shape(cx);
-        RootedNativeObject holder(cx);
+        RootedObject holder(cx);
         bool checkTypeset;
         canCache = CanAttachNativeSetProp(cx, obj, id, cache.value(), cache.needsTypeBarrier(),
                                           &holder, &shape, &checkTypeset);
 
         if (!addedSetterStub && canCache == CanAttachSetSlot) {
             RootedNativeObject nobj(cx, &obj->as<NativeObject>());
             if (!cache.attachSetSlot(cx, script, ion, nobj, shape, checkTypeset))
                 return false;
--- a/js/src/jit/IonCode.h
+++ b/js/src/jit/IonCode.h
@@ -27,16 +27,18 @@ class AsmJSModule;
 
 namespace jit {
 
 class MacroAssembler;
 class CodeOffsetLabel;
 class PatchableBackedge;
 class IonBuilder;
 
+typedef Vector<JSObject *, 4, JitAllocPolicy> ObjectVector;
+
 class JitCode : public gc::TenuredCell
 {
   protected:
     uint8_t *code_;
     ExecutablePool *pool_;
     uint32_t bufferSize_;             // Total buffer size. Does not include headerSize_.
     uint32_t insnSize_;               // Instruction stream size.
     uint32_t dataSize_;               // Size of the read-only data area.
@@ -107,16 +109,18 @@ class JitCode : public gc::TenuredCell
     }
     void trace(JSTracer *trc);
     void finalize(FreeOp *fop);
     void fixupAfterMovingGC() {}
     void setInvalidated() {
         invalidated_ = true;
     }
 
+    void fixupNurseryObjects(JSContext *cx, const ObjectVector &nurseryObjects);
+
     void setHasBytecodeMap() {
         hasBytecodeMap_ = true;
     }
 
     void togglePreBarriers(bool enabled);
 
     // If this JitCode object has been, effectively, corrupted due to
     // invalidation patching, then we have to remember this so we don't try and
--- a/js/src/jit/JitCompartment.h
+++ b/js/src/jit/JitCompartment.h
@@ -230,16 +230,18 @@ class JitRuntime
     // value that will be temporarily corrupt. This special override value is set
     // only in callVM() targets that are about to return *and* have invalidated
     // their callee.
     js::Value ionReturnOverride_;
 
     // Global table of jitcode native address => bytecode address mappings.
     JitcodeGlobalTable *jitcodeGlobalTable_;
 
+    bool hasIonNurseryObjects_;
+
   private:
     JitCode *generateLazyLinkStub(JSContext *cx);
     JitCode *generateProfilerExitFrameTailStub(JSContext *cx);
     JitCode *generateExceptionTailStub(JSContext *cx, void *handler);
     JitCode *generateBailoutTailStub(JSContext *cx);
     JitCode *generateEnterJIT(JSContext *cx, EnterJitType type);
     JitCode *generateArgumentsRectifier(JSContext *cx, void **returnAddrOut);
     JitCode *generateBailoutTable(JSContext *cx, uint32_t frameClass);
@@ -385,16 +387,23 @@ class JitRuntime
         return v;
     }
     void setIonReturnOverride(const js::Value &v) {
         MOZ_ASSERT(!hasIonReturnOverride());
         MOZ_ASSERT(!v.isMagic());
         ionReturnOverride_ = v;
     }
 
+    bool hasIonNurseryObjects() const {
+        return hasIonNurseryObjects_;
+    }
+    void setHasIonNurseryObjects(bool b)  {
+        hasIonNurseryObjects_ = b;
+    }
+
     bool hasJitcodeGlobalTable() const {
         return jitcodeGlobalTable_ != nullptr;
     }
 
     JitcodeGlobalTable *getJitcodeGlobalTable() {
         MOZ_ASSERT(hasJitcodeGlobalTable());
         return jitcodeGlobalTable_;
     }
--- a/js/src/jit/LIR-Common.h
+++ b/js/src/jit/LIR-Common.h
@@ -678,16 +678,26 @@ class LValue : public LInstructionHelper
       : v_(v)
     { }
 
     Value value() const {
         return v_;
     }
 };
 
+class LNurseryObject : public LInstructionHelper<1, 0, 0>
+{
+  public:
+    LIR_HEADER(NurseryObject);
+
+    MNurseryObject *mir() const {
+        return mir_->toNurseryObject();
+    }
+};
+
 // Clone an object literal such as we are not modifying the object contained in
 // the sources.
 class LCloneLiteral : public LCallInstructionHelper<1, 1, 0>
 {
   public:
     LIR_HEADER(CloneLiteral)
 
     explicit LCloneLiteral(const LAllocation &obj)
--- a/js/src/jit/LOpcodes.h
+++ b/js/src/jit/LOpcodes.h
@@ -330,16 +330,17 @@
     _(RecompileCheck)               \
     _(MemoryBarrier)                \
     _(AssertRangeI)                 \
     _(AssertRangeD)                 \
     _(AssertRangeF)                 \
     _(AssertRangeV)                 \
     _(LexicalCheck)                 \
     _(ThrowUninitializedLexical)    \
+    _(NurseryObject)                \
     _(Debugger)
 
 #if defined(JS_CODEGEN_X86)
 # include "jit/x86/LOpcodes-x86.h"
 #elif defined(JS_CODEGEN_X64)
 # include "jit/x64/LOpcodes-x64.h"
 #elif defined(JS_CODEGEN_ARM)
 # include "jit/arm/LOpcodes-arm.h"
--- a/js/src/jit/Lowering.cpp
+++ b/js/src/jit/Lowering.cpp
@@ -3998,16 +3998,22 @@ LIRGenerator::visitThrowUninitializedLex
 void
 LIRGenerator::visitDebugger(MDebugger *ins)
 {
     LDebugger *lir = new(alloc()) LDebugger(tempFixed(CallTempReg0), tempFixed(CallTempReg1));
     assignSnapshot(lir, Bailout_Debugger);
     add(lir, ins);
 }
 
+void
+LIRGenerator::visitNurseryObject(MNurseryObject *ins)
+{
+    define(new(alloc()) LNurseryObject(), ins);
+}
+
 static void
 SpewResumePoint(MBasicBlock *block, MInstruction *ins, MResumePoint *resumePoint)
 {
     fprintf(JitSpewFile, "Current resume point %p details:\n", (void *)resumePoint);
     fprintf(JitSpewFile, "    frame count: %u\n", resumePoint->frameCount());
 
     if (ins) {
         fprintf(JitSpewFile, "    taken after: ");
--- a/js/src/jit/Lowering.h
+++ b/js/src/jit/Lowering.h
@@ -282,14 +282,15 @@ class LIRGenerator : public LIRGenerator
     void visitPhi(MPhi *ins);
     void visitBeta(MBeta *ins);
     void visitObjectState(MObjectState *ins);
     void visitArrayState(MArrayState *ins);
     void visitUnknownValue(MUnknownValue *ins);
     void visitLexicalCheck(MLexicalCheck *ins);
     void visitThrowUninitializedLexical(MThrowUninitializedLexical *ins);
     void visitDebugger(MDebugger *ins);
+    void visitNurseryObject(MNurseryObject *ins);
 };
 
 } // namespace jit
 } // namespace js
 
 #endif /* jit_Lowering_h */
--- a/js/src/jit/MIR.cpp
+++ b/js/src/jit/MIR.cpp
@@ -671,16 +671,17 @@ MakeUnknownTypeSet()
 
 MConstant::MConstant(const js::Value &vp, types::CompilerConstraintList *constraints)
   : value_(vp)
 {
     setResultType(MIRTypeFromValue(vp));
     if (vp.isObject()) {
         // Create a singleton type set for the object. This isn't necessary for
         // other types as the result type encodes all needed information.
+        MOZ_ASSERT(!IsInsideNursery(&vp.toObject()));
         setResultTypeSet(MakeSingletonTypeSet(constraints, &vp.toObject()));
     }
     if (vp.isMagic() && vp.whyMagic() == JS_UNINITIALIZED_LEXICAL) {
         // JS_UNINITIALIZED_LEXICAL does not escape to script and is not
         // observed in type sets. However, it may flow around freely during
         // Ion compilation. Give it an unknown typeset to poison any type sets
         // it merges with.
         //
@@ -690,16 +691,17 @@ MConstant::MConstant(const js::Value &vp
     }
 
     setMovable();
 }
 
 MConstant::MConstant(JSObject *obj)
   : value_(ObjectValue(*obj))
 {
+    MOZ_ASSERT(!IsInsideNursery(obj));
     setResultType(MIRType_Object);
     setMovable();
 }
 
 HashNumber
 MConstant::valueHash() const
 {
     // Fold all 64 bits into the 32-bit result. It's tempting to just discard
@@ -799,16 +801,49 @@ MConstant::canProduceFloat32() const
 
     if (type() == MIRType_Int32)
         return IsFloat32Representable(static_cast<double>(value_.toInt32()));
     if (type() == MIRType_Double)
         return IsFloat32Representable(value_.toDouble());
     return true;
 }
 
+MNurseryObject::MNurseryObject(JSObject *obj, uint32_t index, types::CompilerConstraintList *constraints)
+  : index_(index)
+{
+    setResultType(MIRType_Object);
+
+    MOZ_ASSERT(IsInsideNursery(obj));
+    MOZ_ASSERT(!obj->hasSingletonType());
+    setResultTypeSet(MakeSingletonTypeSet(constraints, obj));
+
+    setMovable();
+}
+
+MNurseryObject *
+MNurseryObject::New(TempAllocator &alloc, JSObject *obj, uint32_t index,
+                    types::CompilerConstraintList *constraints)
+{
+    return new(alloc) MNurseryObject(obj, index, constraints);
+}
+
+HashNumber
+MNurseryObject::valueHash() const
+{
+    return HashNumber(index_);
+}
+
+bool
+MNurseryObject::congruentTo(const MDefinition *ins) const
+{
+    if (!ins->isNurseryObject())
+        return false;
+    return ins->toNurseryObject()->index_ == index_;
+}
+
 MDefinition*
 MSimdValueX4::foldsTo(TempAllocator &alloc)
 {
     DebugOnly<MIRType> scalarType = SimdTypeToScalarType(type());
     bool allConstants = true;
     bool allSame = true;
 
     for (size_t i = 0; i < 4; ++i) {
--- a/js/src/jit/MIR.h
+++ b/js/src/jit/MIR.h
@@ -1324,16 +1324,43 @@ class MConstant : public MNullaryInstruc
     bool needTruncation(TruncateKind kind) MOZ_OVERRIDE;
     void truncate() MOZ_OVERRIDE;
 
     bool canProduceFloat32() const MOZ_OVERRIDE;
 
     ALLOW_CLONE(MConstant)
 };
 
+class MNurseryObject : public MNullaryInstruction
+{
+    // Index in MIRGenerator::nurseryObjects_.
+    uint32_t index_;
+
+  protected:
+    MNurseryObject(JSObject *obj, uint32_t index, types::CompilerConstraintList *constraints);
+
+  public:
+    INSTRUCTION_HEADER(NurseryObject)
+    static MNurseryObject *New(TempAllocator &alloc, JSObject *obj, uint32_t index,
+                               types::CompilerConstraintList *constraints = nullptr);
+
+    HashNumber valueHash() const MOZ_OVERRIDE;
+    bool congruentTo(const MDefinition *ins) const MOZ_OVERRIDE;
+
+    uint32_t index() const {
+        return index_;
+    }
+
+    AliasSet getAliasSet() const MOZ_OVERRIDE {
+        return AliasSet::None();
+    }
+
+    ALLOW_CLONE(MNurseryObject)
+};
+
 // Generic constructor of SIMD valuesX4.
 class MSimdValueX4
   : public MQuaternaryInstruction,
     public Mix4Policy<SimdScalarPolicy<0>, SimdScalarPolicy<1>,
                       SimdScalarPolicy<2>, SimdScalarPolicy<3> >::Data
 {
   protected:
     MSimdValueX4(MIRType type, MDefinition *x, MDefinition *y, MDefinition *z, MDefinition *w)
@@ -9820,17 +9847,17 @@ class MGuardObjectType
     }
 };
 
 // Guard on an object's identity, inclusively or exclusively.
 class MGuardObjectIdentity
   : public MUnaryInstruction,
     public SingleObjectPolicy::Data
 {
-    AlwaysTenured<JSObject *> singleObject_;
+    AlwaysTenuredObject singleObject_;
     bool bailOnEquality_;
 
     MGuardObjectIdentity(MDefinition *obj, JSObject *singleObject, bool bailOnEquality)
       : MUnaryInstruction(obj),
         singleObject_(singleObject),
         bailOnEquality_(bailOnEquality)
     {
         setGuard();
--- a/js/src/jit/MIRGenerator.h
+++ b/js/src/jit/MIRGenerator.h
@@ -188,16 +188,22 @@ class MIRGenerator
     // Keep track of whether frame arguments are modified during execution.
     // RegAlloc needs to know this as spilling values back to their register
     // slots is not compatible with that.
     bool modifiesFrameArguments_;
 
     bool instrumentedProfiling_;
     bool instrumentedProfilingIsCached_;
 
+    // List of nursery objects used by this compilation. Can be traced by a
+    // minor GC while compilation happens off-thread. This Vector should only
+    // be accessed on the main thread (IonBuilder, nursery GC or
+    // CodeGenerator::link).
+    ObjectVector nurseryObjects_;
+
     void addAbortedNewScriptPropertiesType(types::TypeObject *type);
     void setForceAbort() {
         shouldForceAbort_ = true;
     }
     bool shouldForceAbort() {
         return shouldForceAbort_;
     }
 
@@ -205,14 +211,20 @@ class MIRGenerator
     AsmJSPerfSpewer asmJSPerfSpewer_;
 
   public:
     AsmJSPerfSpewer &perfSpewer() { return asmJSPerfSpewer_; }
 #endif
 
   public:
     const JitCompileOptions options;
+
+    void traceNurseryObjects(JSTracer *trc);
+
+    const ObjectVector &nurseryObjects() const {
+        return nurseryObjects_;
+    }
 };
 
 } // namespace jit
 } // namespace js
 
 #endif /* jit_MIRGenerator_h */
--- a/js/src/jit/MIRGraph.cpp
+++ b/js/src/jit/MIRGraph.cpp
@@ -34,16 +34,17 @@ MIRGenerator::MIRGenerator(CompileCompar
     maxAsmJSStackArgBytes_(0),
     performsCall_(false),
     usesSimd_(false),
     usesSimdCached_(false),
     minAsmJSHeapLength_(0),
     modifiesFrameArguments_(false),
     instrumentedProfiling_(false),
     instrumentedProfilingIsCached_(false),
+    nurseryObjects_(*alloc),
     options(options)
 { }
 
 bool
 MIRGenerator::usesSimd()
 {
     if (usesSimdCached_)
         return usesSimd_;
--- a/js/src/jit/MOpcodes.h
+++ b/js/src/jit/MOpcodes.h
@@ -7,16 +7,17 @@
 #ifndef jit_MOpcodes_h
 #define jit_MOpcodes_h
 
 namespace js {
 namespace jit {
 
 #define MIR_OPCODE_LIST(_)                                                  \
     _(Constant)                                                             \
+    _(NurseryObject)                                                        \
     _(SimdBox)                                                              \
     _(SimdUnbox)                                                            \
     _(SimdValueX4)                                                          \
     _(SimdSplatX4)                                                          \
     _(SimdConstant)                                                         \
     _(SimdConvert)                                                          \
     _(SimdReinterpretCast)                                                  \
     _(SimdExtractElement)                                                   \
--- a/js/src/jit/arm/Assembler-arm.cpp
+++ b/js/src/jit/arm/Assembler-arm.cpp
@@ -800,16 +800,22 @@ static void
 TraceOneDataRelocation(JSTracer *trc, Iter *iter, MacroAssemblerARM *masm)
 {
     Instruction *ins = iter->cur();
     Register dest;
     Assembler::RelocStyle rs;
     const void *prior = Assembler::GetPtr32Target(iter, &dest, &rs);
     void *ptr = const_cast<void *>(prior);
 
+    // The low bit shouldn't be set. If it is, we probably got a dummy
+    // pointer inserted by CodeGenerator::visitNurseryObject, but we
+    // shouldn't be able to trigger GC before those are patched to their
+    // real values.
+    MOZ_ASSERT(!(uintptr_t(ptr) & 0x1));
+
     // No barrier needed since these are constants.
     gc::MarkGCThingUnbarriered(trc, &ptr, "ion-masm-ptr");
 
     if (ptr != prior) {
         masm->ma_movPatchable(Imm32(int32_t(ptr)), dest, Assembler::Always, rs, ins);
         // L_LDR won't cause any instructions to be updated.
         if (rs != Assembler::L_LDR) {
             AutoFlushICache::flush(uintptr_t(ins), 4);
@@ -842,16 +848,61 @@ TraceDataRelocations(JSTracer *trc, ARMB
 
 void
 Assembler::TraceDataRelocations(JSTracer *trc, JitCode *code, CompactBufferReader &reader)
 {
     ::TraceDataRelocations(trc, code->raw(), reader, static_cast<MacroAssemblerARM *>(Dummy));
 }
 
 void
+Assembler::FixupNurseryObjects(JSContext *cx, JitCode *code, CompactBufferReader &reader,
+                               const ObjectVector &nurseryObjects)
+{
+    MOZ_ASSERT(!nurseryObjects.empty());
+
+    uint8_t *buffer = code->raw();
+    bool hasNurseryPointers = false;
+    MacroAssemblerARM *masm = static_cast<MacroAssemblerARM *>(Dummy);
+
+    while (reader.more()) {
+        size_t offset = reader.readUnsigned();
+        InstructionIterator iter((Instruction*)(buffer + offset));
+        Instruction *ins = iter.cur();
+        Register dest;
+        Assembler::RelocStyle rs;
+        const void *prior = Assembler::GetPtr32Target(&iter, &dest, &rs);
+        void *ptr = const_cast<void *>(prior);
+        uintptr_t word = reinterpret_cast<uintptr_t>(ptr);
+
+        if (!(word & 0x1))
+            continue;
+
+        uint32_t index = word >> 1;
+        JSObject *obj = nurseryObjects[index];
+        masm->ma_movPatchable(Imm32(int32_t(obj)), dest, Assembler::Always, rs, ins);
+
+        if (rs != Assembler::L_LDR) {
+            // L_LDR won't cause any instructions to be updated.
+            AutoFlushICache::flush(uintptr_t(ins), 4);
+            AutoFlushICache::flush(uintptr_t(ins->next()), 4);
+        }
+
+        // Either all objects are still in the nursery, or all objects are
+        // tenured.
+        MOZ_ASSERT_IF(hasNurseryPointers, IsInsideNursery(obj));
+
+        if (!hasNurseryPointers && IsInsideNursery(obj))
+            hasNurseryPointers = true;
+    }
+
+    if (hasNurseryPointers)
+        cx->runtime()->gc.storeBuffer.putWholeCellFromMainThread(code);
+}
+
+void
 Assembler::copyJumpRelocationTable(uint8_t *dest)
 {
     if (jumpRelocations_.length())
         memcpy(dest, jumpRelocations_.buffer(), jumpRelocations_.length());
 }
 
 void
 Assembler::copyDataRelocationTable(uint8_t *dest)
--- a/js/src/jit/arm/Assembler-arm.h
+++ b/js/src/jit/arm/Assembler-arm.h
@@ -1592,16 +1592,19 @@ class Assembler : public AssemblerShared
     void call(void *target);
 
     void as_bkpt();
 
   public:
     static void TraceJumpRelocations(JSTracer *trc, JitCode *code, CompactBufferReader &reader);
     static void TraceDataRelocations(JSTracer *trc, JitCode *code, CompactBufferReader &reader);
 
+    static void FixupNurseryObjects(JSContext *cx, JitCode *code, CompactBufferReader &reader,
+                                    const ObjectVector &nurseryObjects);
+
     static bool SupportsFloatingPoint() {
         return HasVFP();
     }
     static bool SupportsSimd() {
         return js::jit::SupportsSimd;
     }
 
   protected:
--- a/js/src/jit/mips/Assembler-mips.cpp
+++ b/js/src/jit/mips/Assembler-mips.cpp
@@ -283,16 +283,22 @@ Assembler::TraceJumpRelocations(JSTracer
 }
 
 static void
 TraceOneDataRelocation(JSTracer *trc, Instruction *inst)
 {
     void *ptr = (void *)Assembler::ExtractLuiOriValue(inst, inst->next());
     void *prior = ptr;
 
+    // The low bit shouldn't be set. If it is, we probably got a dummy
+    // pointer inserted by CodeGenerator::visitNurseryObject, but we
+    // shouldn't be able to trigger GC before those are patched to their
+    // real values.
+    MOZ_ASSERT(!(uintptr_t(ptr) & 0x1));
+
     // No barrier needed since these are constants.
     gc::MarkGCThingUnbarriered(trc, reinterpret_cast<void **>(&ptr), "ion-masm-ptr");
     if (ptr != prior) {
         Assembler::UpdateLuiOriValue(inst, inst->next(), uint32_t(ptr));
         AutoFlushICache::flush(uintptr_t(inst), 8);
     }
 }
 
@@ -318,16 +324,53 @@ TraceDataRelocations(JSTracer *trc, MIPS
 
 void
 Assembler::TraceDataRelocations(JSTracer *trc, JitCode *code, CompactBufferReader &reader)
 {
     ::TraceDataRelocations(trc, code->raw(), reader);
 }
 
 void
+Assembler::FixupNurseryObjects(JSContext *cx, JitCode *code, CompactBufferReader &reader,
+                               const ObjectVector &nurseryObjects)
+{
+    MOZ_ASSERT(!nurseryObjects.empty());
+
+    uint8_t *buffer = code->raw();
+    bool hasNurseryPointers = false;
+
+    while (reader.more()) {
+        size_t offset = reader.readUnsigned();
+        Instruction *inst = (Instruction*)(buffer + offset);
+
+        void *ptr = (void *)Assembler::ExtractLuiOriValue(inst, inst->next());
+        uintptr_t word = uintptr_t(ptr);
+
+        if (!(word & 0x1))
+            continue;
+
+        uint32_t index = word >> 1;
+        JSObject *obj = nurseryObjects[index];
+
+        Assembler::UpdateLuiOriValue(inst, inst->next(), uint32_t(obj));
+        AutoFlushICache::flush(uintptr_t(inst), 8);
+
+        // Either all objects are still in the nursery, or all objects are
+        // tenured.
+        MOZ_ASSERT_IF(hasNurseryPointers, IsInsideNursery(obj));
+
+        if (!hasNurseryPointers && IsInsideNursery(obj))
+            hasNurseryPointers = true;
+    }
+
+    if (hasNurseryPointers)
+        cx->runtime()->gc.storeBuffer.putWholeCellFromMainThread(code);
+}
+
+void
 Assembler::copyJumpRelocationTable(uint8_t *dest)
 {
     if (jumpRelocations_.length())
         memcpy(dest, jumpRelocations_.buffer(), jumpRelocations_.length());
 }
 
 void
 Assembler::copyDataRelocationTable(uint8_t *dest)
--- a/js/src/jit/mips/Assembler-mips.h
+++ b/js/src/jit/mips/Assembler-mips.h
@@ -1007,16 +1007,19 @@ class Assembler : public AssemblerShared
     void call(void *target);
 
     void as_break(uint32_t code);
 
   public:
     static void TraceJumpRelocations(JSTracer *trc, JitCode *code, CompactBufferReader &reader);
     static void TraceDataRelocations(JSTracer *trc, JitCode *code, CompactBufferReader &reader);
 
+    static void FixupNurseryObjects(JSContext *cx, JitCode *code, CompactBufferReader &reader,
+                                    const ObjectVector &nurseryObjects);
+
     static bool SupportsFloatingPoint() {
 #if (defined(__mips_hard_float) && !defined(__mips_single_float)) || defined(JS_MIPS_SIMULATOR)
         return true;
 #else
         return false;
 #endif
     }
     static bool SupportsSimd() {
--- a/js/src/jit/none/MacroAssembler-none.h
+++ b/js/src/jit/none/MacroAssembler-none.h
@@ -151,16 +151,22 @@ class MacroAssemblerNone : public Assemb
 
     size_t numCodeLabels() const { MOZ_CRASH(); }
     CodeLabel codeLabel(size_t) { MOZ_CRASH(); }
 
     void trace(JSTracer *) { MOZ_CRASH(); }
     static void TraceJumpRelocations(JSTracer *, JitCode *, CompactBufferReader &) { MOZ_CRASH(); }
     static void TraceDataRelocations(JSTracer *, JitCode *, CompactBufferReader &) { MOZ_CRASH(); }
 
+    static void FixupNurseryObjects(JSContext *, JitCode *, CompactBufferReader &,
+                                    const ObjectVector &)
+    {
+        MOZ_CRASH();
+    }
+
     static bool SupportsFloatingPoint() { return false; }
     static bool SupportsSimd() { return false; }
 
     void executableCopy(void *) { MOZ_CRASH(); }
     void copyJumpRelocationTable(uint8_t *) { MOZ_CRASH(); }
     void copyDataRelocationTable(uint8_t *) { MOZ_CRASH(); }
     void copyPreBarrierTable(uint8_t *) { MOZ_CRASH(); }
     void processCodeLabels(uint8_t *) { MOZ_CRASH(); }
--- a/js/src/jit/shared/Assembler-shared.h
+++ b/js/src/jit/shared/Assembler-shared.h
@@ -228,31 +228,56 @@ class ImmMaybeNurseryPtr
     {
         MOZ_ASSERT(!IsPoisonedPtr(ptr));
 
         // asm.js shouldn't be creating GC things
         MOZ_ASSERT(!IsCompilingAsmJS());
     }
 };
 
+// Dummy value used for nursery pointers during Ion compilation, see
+// LNurseryObject.
+class IonNurseryPtr
+{
+    const gc::Cell *ptr;
+
+  public:
+    friend class ImmGCPtr;
+
+    explicit IonNurseryPtr(const gc::Cell *ptr) : ptr(ptr)
+    {
+        MOZ_ASSERT(ptr);
+        MOZ_ASSERT(uintptr_t(ptr) & 0x1);
+    }
+};
+
 // Used for immediates which require relocation.
 class ImmGCPtr
 {
   public:
     const gc::Cell *value;
 
     explicit ImmGCPtr(const gc::Cell *ptr) : value(ptr)
     {
         MOZ_ASSERT(!IsPoisonedPtr(ptr));
         MOZ_ASSERT_IF(ptr, ptr->isTenured());
 
         // asm.js shouldn't be creating GC things
         MOZ_ASSERT(!IsCompilingAsmJS());
     }
 
+    explicit ImmGCPtr(IonNurseryPtr ptr) : value(ptr.ptr)
+    {
+        MOZ_ASSERT(!IsPoisonedPtr(value));
+        MOZ_ASSERT(value);
+
+        // asm.js shouldn't be creating GC things
+        MOZ_ASSERT(!IsCompilingAsmJS());
+    }
+
   private:
     ImmGCPtr() : value(0) {}
 
     friend class AssemblerShared;
     explicit ImmGCPtr(ImmMaybeNurseryPtr ptr) : value(ptr.value)
     {
         MOZ_ASSERT(!IsPoisonedPtr(ptr.value));
 
--- a/js/src/jit/shared/Assembler-x86-shared.cpp
+++ b/js/src/jit/shared/Assembler-x86-shared.cpp
@@ -62,29 +62,74 @@ TraceDataRelocations(JSTracer *trc, uint
             layout.asBits = *word;
             Value v = IMPL_TO_JSVAL(layout);
             gc::MarkValueUnbarriered(trc, &v, "ion-masm-value");
             *word = JSVAL_TO_IMPL(v).asBits;
             continue;
         }
 #endif
 
+        // The low bit shouldn't be set. If it is, we probably got a dummy
+        // pointer inserted by CodeGenerator::visitNurseryObject, but we
+        // shouldn't be able to trigger GC before those are patched to their
+        // real values.
+        MOZ_ASSERT(!(*reinterpret_cast<uintptr_t *>(ptr) & 0x1));
+
         // No barrier needed since these are constants.
         gc::MarkGCThingUnbarriered(trc, ptr, "ion-masm-ptr");
     }
 }
 
 
 void
 AssemblerX86Shared::TraceDataRelocations(JSTracer *trc, JitCode *code, CompactBufferReader &reader)
 {
     ::TraceDataRelocations(trc, code->raw(), reader);
 }
 
 void
+AssemblerX86Shared::FixupNurseryObjects(JSContext *cx, JitCode *code, CompactBufferReader &reader,
+                                        const ObjectVector &nurseryObjects)
+{
+    MOZ_ASSERT(!nurseryObjects.empty());
+
+    uint8_t *buffer = code->raw();
+    bool hasNurseryPointers = false;
+
+    while (reader.more()) {
+        size_t offset = reader.readUnsigned();
+        void **ptr = X86Encoding::GetPointerRef(buffer + offset);
+
+        uintptr_t *word = reinterpret_cast<uintptr_t *>(ptr);
+
+#ifdef JS_PUNBOX64
+        if (*word >> JSVAL_TAG_SHIFT)
+            continue; // This is a Value.
+#endif
+
+        if (!(*word & 0x1))
+            continue;
+
+        uint32_t index = *word >> 1;
+        JSObject *obj = nurseryObjects[index];
+        *word = uintptr_t(obj);
+
+        // Either all objects are still in the nursery, or all objects are
+        // tenured.
+        MOZ_ASSERT_IF(hasNurseryPointers, IsInsideNursery(obj));
+
+        if (!hasNurseryPointers && IsInsideNursery(obj))
+            hasNurseryPointers = true;
+    }
+
+    if (hasNurseryPointers)
+        cx->runtime()->gc.storeBuffer.putWholeCellFromMainThread(code);
+}
+
+void
 AssemblerX86Shared::trace(JSTracer *trc)
 {
     for (size_t i = 0; i < jumps_.length(); i++) {
         RelativePatch &rp = jumps_[i];
         if (rp.kind == Relocation::JITCODE) {
             JitCode *code = JitCode::FromExecutable((uint8_t *)rp.target);
             MarkJitCodeUnbarriered(trc, &code, "masmrel32");
             MOZ_ASSERT(code == JitCode::FromExecutable((uint8_t *)rp.target));
--- a/js/src/jit/shared/Assembler-x86-shared.h
+++ b/js/src/jit/shared/Assembler-x86-shared.h
@@ -322,16 +322,19 @@ class AssemblerX86Shared : public Assemb
     // handle NaNs properly and may therefore require a secondary condition.
     // Use NaNCondFromDoubleCondition to determine what else is needed.
     static inline Condition ConditionFromDoubleCondition(DoubleCondition cond) {
         return static_cast<Condition>(cond & ~DoubleConditionBits);
     }
 
     static void TraceDataRelocations(JSTracer *trc, JitCode *code, CompactBufferReader &reader);
 
+    static void FixupNurseryObjects(JSContext *cx, JitCode *code, CompactBufferReader &reader,
+                                    const ObjectVector &nurseryObjects);
+
     // MacroAssemblers hold onto gcthings, so they are traced by the GC.
     void trace(JSTracer *trc);
 
     bool oom() const {
         return AssemblerShared::oom() ||
                masm.oom() ||
                jumpRelocations_.oom() ||
                dataRelocations_.oom() ||
--- a/js/src/jsapi-tests/testAddPropertyPropcache.cpp
+++ b/js/src/jsapi-tests/testAddPropertyPropcache.cpp
@@ -41,17 +41,17 @@ BEGIN_TEST(testAddPropertyHook)
     JS::RootedValue arr(cx, OBJECT_TO_JSVAL(obj));
 
     CHECK(JS_DefineProperty(cx, global, "arr", arr,
                             JSPROP_ENUMERATE,
                             JS_STUBGETTER, JS_STUBSETTER));
 
     JS::RootedObject arrObj(cx, &arr.toObject());
     for (int i = 0; i < ExpectedCount; ++i) {
-        obj = JS_NewObject(cx, &AddPropertyClass, JS::NullPtr(), JS::NullPtr());
+        obj = JS_NewObject(cx, &AddPropertyClass);
         CHECK(obj);
         CHECK(JS_DefineElement(cx, arrObj, i, obj,
                                JSPROP_ENUMERATE,
                                JS_STUBGETTER, JS_STUBSETTER));
     }
 
     // Now add a prop to each of the objects, but make sure to do
     // so at the same bytecode location so we can hit the propcache.
--- a/js/src/jsapi-tests/testCallNonGenericMethodOnProxy.cpp
+++ b/js/src/jsapi-tests/testCallNonGenericMethodOnProxy.cpp
@@ -35,17 +35,17 @@ CustomMethod(JSContext *cx, unsigned arg
 }
 
 BEGIN_TEST(test_CallNonGenericMethodOnProxy)
 {
   // Create the first global object and compartment
   JS::RootedObject globalA(cx, JS_NewGlobalObject(cx, getGlobalClass(), nullptr, JS::FireOnNewGlobalHook));
   CHECK(globalA);
 
-  JS::RootedObject customA(cx, JS_NewObject(cx, &CustomClass, JS::NullPtr(), JS::NullPtr()));
+  JS::RootedObject customA(cx, JS_NewObject(cx, &CustomClass));
   CHECK(customA);
   JS_SetReservedSlot(customA, CUSTOM_SLOT, Int32Value(17));
 
   JS::RootedFunction customMethodA(cx, JS_NewFunction(cx, CustomMethod, 0, 0,
                                                       customA, "customMethodA"));
   CHECK(customMethodA);
 
   JS::RootedValue rval(cx);
@@ -55,17 +55,17 @@ BEGIN_TEST(test_CallNonGenericMethodOnPr
 
   // Now create the second global object and compartment...
   {
     JS::RootedObject globalB(cx, JS_NewGlobalObject(cx, getGlobalClass(), nullptr, JS::FireOnNewGlobalHook));
     CHECK(globalB);
 
     // ...and enter it.
     JSAutoCompartment enter(cx, globalB);
-    JS::RootedObject customB(cx, JS_NewObject(cx, &CustomClass, JS::NullPtr(), JS::NullPtr()));
+    JS::RootedObject customB(cx, JS_NewObject(cx, &CustomClass));
     CHECK(customB);
     JS_SetReservedSlot(customB, CUSTOM_SLOT, Int32Value(42));
 
     JS::RootedFunction customMethodB(cx, JS_NewFunction(cx, CustomMethod, 0, 0, customB, "customMethodB"));
     CHECK(customMethodB);
 
     JS::RootedValue rval(cx);
     CHECK(JS_CallFunction(cx, customB, customMethodB, JS::HandleValueArray::empty(),
--- a/js/src/jsapi-tests/testGCNursery.cpp
+++ b/js/src/jsapi-tests/testGCNursery.cpp
@@ -63,59 +63,59 @@ BEGIN_TEST(testGCNurseryFinalizer)
 #ifdef JS_GC_ZEAL
     // Running extra GCs during this test will make us get incorrect
     // finalization counts.
     AutoLeaveZeal nozeal(cx);
 #endif /* JS_GC_ZEAL */
 
     JS::RootedObject obj(cx);
 
-    obj = JS_NewObject(cx, Jsvalify(&TenuredClass), JS::NullPtr(), JS::NullPtr());
+    obj = JS_NewObject(cx, Jsvalify(&TenuredClass));
     CHECK(!js::gc::IsInsideNursery(obj));
 
     // Null finalization list with empty nursery.
     rt->gc.minorGC(JS::gcreason::EVICT_NURSERY);
     CHECK(ranFinalizer == 0);
 
     // Null finalization list with non-empty nursery.
     obj = JS_NewPlainObject(cx);
     obj = JS_NewPlainObject(cx);
     obj = JS_NewPlainObject(cx);
     CHECK(js::gc::IsInsideNursery(obj));
     obj = nullptr;
     rt->gc.minorGC(JS::gcreason::EVICT_NURSERY);
     CHECK(ranFinalizer == 0);
 
     // Single finalizable nursery thing.
-    obj = JS_NewObject(cx, Jsvalify(&NurseryClass), JS::NullPtr(), JS::NullPtr());
+    obj = JS_NewObject(cx, Jsvalify(&NurseryClass));
     CHECK(js::gc::IsInsideNursery(obj));
     obj = nullptr;
     rt->gc.minorGC(JS::gcreason::EVICT_NURSERY);
     CHECK(ranFinalizer == 1);
     ranFinalizer = 0;
 
     // Multiple finalizable nursery things.
-    obj = JS_NewObject(cx, Jsvalify(&NurseryClass), JS::NullPtr(), JS::NullPtr());
-    obj = JS_NewObject(cx, Jsvalify(&NurseryClass), JS::NullPtr(), JS::NullPtr());
-    obj = JS_NewObject(cx, Jsvalify(&NurseryClass), JS::NullPtr(), JS::NullPtr());
+    obj = JS_NewObject(cx, Jsvalify(&NurseryClass));
+    obj = JS_NewObject(cx, Jsvalify(&NurseryClass));
+    obj = JS_NewObject(cx, Jsvalify(&NurseryClass));
     CHECK(js::gc::IsInsideNursery(obj));
     obj = nullptr;
     rt->gc.minorGC(JS::gcreason::EVICT_NURSERY);
     CHECK(ranFinalizer == 3);
     ranFinalizer = 0;
 
     // Interleaved finalizable things in nursery.
     obj = JS_NewPlainObject(cx);
-    obj = JS_NewObject(cx, Jsvalify(&NurseryClass), JS::NullPtr(), JS::NullPtr());
+    obj = JS_NewObject(cx, Jsvalify(&NurseryClass));
     obj = JS_NewPlainObject(cx);
-    obj = JS_NewObject(cx, Jsvalify(&NurseryClass), JS::NullPtr(), JS::NullPtr());
+    obj = JS_NewObject(cx, Jsvalify(&NurseryClass));
     obj = JS_NewPlainObject(cx);
-    obj = JS_NewObject(cx, Jsvalify(&NurseryClass), JS::NullPtr(), JS::NullPtr());
+    obj = JS_NewObject(cx, Jsvalify(&NurseryClass));
     obj = JS_NewPlainObject(cx);
-    obj = JS_NewObject(cx, Jsvalify(&NurseryClass), JS::NullPtr(), JS::NullPtr());
+    obj = JS_NewObject(cx, Jsvalify(&NurseryClass));
     obj = JS_NewPlainObject(cx);
     CHECK(js::gc::IsInsideNursery(obj));
     obj = nullptr;
     rt->gc.minorGC(JS::gcreason::EVICT_NURSERY);
     CHECK(ranFinalizer == 4);
     ranFinalizer = 0;
 
     return true;
--- a/js/src/jsapi-tests/testLookup.cpp
+++ b/js/src/jsapi-tests/testLookup.cpp
@@ -51,18 +51,17 @@ document_resolve(JSContext *cx, JS::Hand
         return false;
 
     if (v.isString()) {
         JSString *str = v.toString();
         JSFlatString *flatStr = JS_FlattenString(cx, str);
         if (!flatStr)
             return false;
         if (JS_FlatStringEqualsAscii(flatStr, "all")) {
-            JS::Rooted<JSObject*> docAll(cx,
-                                         JS_NewObject(cx, &DocumentAllClass, JS::NullPtr(), JS::NullPtr()));
+            JS::Rooted<JSObject*> docAll(cx, JS_NewObject(cx, &DocumentAllClass));
             if (!docAll)
                 return false;
 
             JS::Rooted<JS::Value> allValue(cx, JS::ObjectValue(*docAll));
             if (!JS_DefinePropertyById(cx, obj, id, allValue, 0))
                 return false;
 
             *resolvedp = true;
@@ -77,17 +76,17 @@ document_resolve(JSContext *cx, JS::Hand
 static const JSClass document_class = {
     "document", 0,
     nullptr, nullptr, nullptr, nullptr,
     nullptr, document_resolve, nullptr
 };
 
 BEGIN_TEST(testLookup_bug570195)
 {
-    JS::RootedObject obj(cx, JS_NewObject(cx, &document_class, JS::NullPtr(), JS::NullPtr()));
+    JS::RootedObject obj(cx, JS_NewObject(cx, &document_class));
     CHECK(obj);
     CHECK(JS_DefineProperty(cx, global, "document", obj, 0));
     JS::RootedValue v(cx);
     EVAL("document.all ? true : false", &v);
     CHECK_SAME(v, JSVAL_FALSE);
     EVAL("document.hasOwnProperty('all')", &v);
     CHECK_SAME(v, JSVAL_TRUE);
     return true;
--- a/js/src/jsapi-tests/testNewObject.cpp
+++ b/js/src/jsapi-tests/testNewObject.cpp
@@ -95,17 +95,17 @@ BEGIN_TEST(testNewObject_1)
     // With JSClass.construct.
     static const JSClass cls = {
         "testNewObject_1",
         0,
         nullptr, nullptr, nullptr, nullptr,
         nullptr, nullptr, nullptr, nullptr,
         nullptr, nullptr, constructHook
     };
-    JS::RootedObject ctor(cx, JS_NewObject(cx, &cls, JS::NullPtr(), JS::NullPtr()));
+    JS::RootedObject ctor(cx, JS_NewObject(cx, &cls));
     CHECK(ctor);
     JS::RootedValue rt2(cx, OBJECT_TO_JSVAL(ctor));
     obj = JS_New(cx, ctor, JS::HandleValueArray::subarray(argv, 0, 3));
     CHECK(obj);
     CHECK(JS_GetElement(cx, ctor, 0, &v));
     CHECK_SAME(v, JSVAL_ZERO);
 
     return true;
--- a/js/src/jsapi-tests/testOps.cpp
+++ b/js/src/jsapi-tests/testOps.cpp
@@ -28,17 +28,17 @@ static const JSClass myClass = {
 
 static bool
 createMyObject(JSContext* context, unsigned argc, jsval *vp)
 {
     JS_BeginRequest(context);
 
     //JS_GC(context); //<- if we make GC here, all is ok
 
-    JSObject* myObject = JS_NewObject(context, &myClass, JS::NullPtr(), JS::NullPtr());
+    JSObject* myObject = JS_NewObject(context, &myClass);
     *vp = OBJECT_TO_JSVAL(myObject);
 
     JS_EndRequest(context);
 
     return true;
 }
 
 static const JSFunctionSpec s_functions[] =
--- a/js/src/jsapi-tests/testPersistentRooted.cpp
+++ b/js/src/jsapi-tests/testPersistentRooted.cpp
@@ -50,17 +50,17 @@ struct Kennel {
 };
 
 // A function for allocating a Kennel and a barker. Only allocating
 // PersistentRooteds on the heap, and in this function, helps ensure that the
 // conservative GC doesn't find stray references to the barker. Ugh.
 MOZ_NEVER_INLINE static Kennel *
 Allocate(JSContext *cx)
 {
-    RootedObject barker(cx, JS_NewObject(cx, &BarkWhenTracedClass::class_, JS::NullPtr(), JS::NullPtr()));
+    RootedObject barker(cx, JS_NewObject(cx, &BarkWhenTracedClass::class_));
     if (!barker)
         return nullptr;
 
     return new Kennel(cx, barker);
 }
 
 // Do a GC, expecting |n| barkers to be finalized.
 static bool
@@ -191,17 +191,17 @@ static PersistentRootedObject gGlobalRoo
 // PersistentRooted instances can initialized in a separate step to allow for global PersistentRooteds.
 BEGIN_TEST(test_GlobalPersistentRooted)
 {
     BarkWhenTracedClass::reset();
 
     CHECK(!gGlobalRoot.initialized());
 
     {
-        RootedObject barker(cx, JS_NewObject(cx, &BarkWhenTracedClass::class_, JS::NullPtr(), JS::NullPtr()));
+        RootedObject barker(cx, JS_NewObject(cx, &BarkWhenTracedClass::class_));
         CHECK(barker);
 
         gGlobalRoot.init(cx, barker);
     }
 
     CHECK(gGlobalRoot.initialized());
 
     // GC should be able to find our barker.
--- a/js/src/jsapi-tests/testResolveRecursion.cpp
+++ b/js/src/jsapi-tests/testResolveRecursion.cpp
@@ -20,19 +20,19 @@ BEGIN_TEST(testResolveRecursion)
         nullptr, // add
         nullptr, // delete
         nullptr, // get
         nullptr, // set
         nullptr, // enumerate
         my_resolve
     };
 
-    obj1.init(cx, JS_NewObject(cx, &my_resolve_class, JS::NullPtr(), JS::NullPtr()));
+    obj1.init(cx, JS_NewObject(cx, &my_resolve_class));
     CHECK(obj1);
-    obj2.init(cx, JS_NewObject(cx, &my_resolve_class, JS::NullPtr(), JS::NullPtr()));
+    obj2.init(cx, JS_NewObject(cx, &my_resolve_class));
     CHECK(obj2);
     JS_SetPrivate(obj1, this);
     JS_SetPrivate(obj2, this);
 
     JS::RootedValue obj1Val(cx, JS::ObjectValue(*obj1));
     JS::RootedValue obj2Val(cx, JS::ObjectValue(*obj2));
     CHECK(JS_DefineProperty(cx, global, "obj1", obj1Val, 0));
     CHECK(JS_DefineProperty(cx, global, "obj2", obj2Val, 0));
--- a/js/src/jsapi-tests/testWeakMap.cpp
+++ b/js/src/jsapi-tests/testWeakMap.cpp
@@ -159,21 +159,17 @@ JSObject *newKey()
             nullptr,
             nullptr,
             false,
             GetKeyDelegate
         },
         JS_NULL_OBJECT_OPS
     };
 
-    JS::RootedObject key(cx);
-    key = JS_NewObject(cx,
-                       Jsvalify(&keyClass),
-                       JS::NullPtr(),
-                       JS::NullPtr());
+    JS::RootedObject key(cx, JS_NewObject(cx, Jsvalify(&keyClass)));
     if (!key)
         return nullptr;
 
     return key;
 }
 
 JSObject *newCCW(JS::HandleObject sourceZone, JS::HandleObject destZone)
 {
--- a/js/src/jsapi.cpp
+++ b/js/src/jsapi.cpp
@@ -2027,31 +2027,31 @@ JS_FireOnNewGlobalObject(JSContext *cx, 
     // to be able to throw errors during delicate global creation routines.
     // This infallibility will eat OOM and slow script, but if that happens
     // we'll likely run up into them again soon in a fallible context.
     Rooted<js::GlobalObject*> globalObject(cx, &global->as<GlobalObject>());
     Debugger::onNewGlobalObject(cx, globalObject);
 }
 
 JS_PUBLIC_API(JSObject *)
-JS_NewObject(JSContext *cx, const JSClass *jsclasp, HandleObject proto, HandleObject parent)
+JS_NewObject(JSContext *cx, const JSClass *jsclasp, HandleObject parent)
 {
     MOZ_ASSERT(!cx->runtime()->isAtomsCompartment(cx->compartment()));
     AssertHeapIsIdle(cx);
     CHECK_REQUEST(cx);
-    assertSameCompartment(cx, proto, parent);
+    assertSameCompartment(cx, parent);
 
     const Class *clasp = Valueify(jsclasp);
     if (!clasp)
         clasp = &PlainObject::class_;    /* default class is Object */
 
     MOZ_ASSERT(clasp != &JSFunction::class_);
     MOZ_ASSERT(!(clasp->flags & JSCLASS_IS_GLOBAL));
 
-    JSObject *obj = NewObjectWithClassProto(cx, clasp, proto, parent);
+    JSObject *obj = NewObjectWithClassProto(cx, clasp, nullptr, parent);
     MOZ_ASSERT_IF(obj, obj->getParent());
     return obj;
 }
 
 JS_PUBLIC_API(JSObject *)
 JS_NewObjectWithGivenProto(JSContext *cx, const JSClass *jsclasp, HandleObject proto, HandleObject parent)
 {
     MOZ_ASSERT(!cx->runtime()->isAtomsCompartment(cx->compartment()));
@@ -2061,20 +2061,17 @@ JS_NewObjectWithGivenProto(JSContext *cx
 
     const Class *clasp = Valueify(jsclasp);
     if (!clasp)
         clasp = &PlainObject::class_;    /* default class is Object */
 
     MOZ_ASSERT(clasp != &JSFunction::class_);
     MOZ_ASSERT(!(clasp->flags & JSCLASS_IS_GLOBAL));
 
-    JSObject *obj = NewObjectWithGivenProto(cx, clasp, proto, parent);
-    if (obj)
-        MarkTypeObjectUnknownProperties(cx, obj->type());
-    return obj;
+    return NewObjectWithGivenProto(cx, clasp, proto, parent);
 }
 
 JS_PUBLIC_API(JSObject *)
 JS_NewPlainObject(JSContext *cx)
 {
     MOZ_ASSERT(!cx->runtime()->isAtomsCompartment(cx->compartment()));
     AssertHeapIsIdle(cx);
     CHECK_REQUEST(cx);
--- a/js/src/jsapi.h
+++ b/js/src/jsapi.h
@@ -2564,32 +2564,31 @@ JS_NewGlobalObject(JSContext *cx, const 
  */
 extern JS_PUBLIC_API(void)
 JS_GlobalObjectTraceHook(JSTracer *trc, JSObject *global);
 
 extern JS_PUBLIC_API(void)
 JS_FireOnNewGlobalObject(JSContext *cx, JS::HandleObject global);
 
 extern JS_PUBLIC_API(JSObject *)
-JS_NewObject(JSContext *cx, const JSClass *clasp, JS::Handle<JSObject*> proto,
-             JS::Handle<JSObject*> parent);
+JS_NewObject(JSContext *cx, const JSClass *clasp, JS::Handle<JSObject*> parent = JS::NullPtr());
 
 /* Queries the [[Extensible]] property of the object. */
 extern JS_PUBLIC_API(bool)
 JS_IsExtensible(JSContext *cx, JS::HandleObject obj, bool *extensible);
 
 extern JS_PUBLIC_API(bool)
 JS_IsNative(JSObject *obj);
 
 extern JS_PUBLIC_API(JSRuntime *)
 JS_GetObjectRuntime(JSObject *obj);
 
 /*
- * Unlike JS_NewObject, JS_NewObjectWithGivenProto does not compute a default
- * proto if proto's actual parameter value is null.
+ * Unlike JS_NewObject, JS_NewObjectWithGivenProto does not compute a default proto.
+ * If proto is JS::NullPtr, the JS object will have `null` as [[Prototype]].
  */
 extern JS_PUBLIC_API(JSObject *)
 JS_NewObjectWithGivenProto(JSContext *cx, const JSClass *clasp, JS::Handle<JSObject*> proto,
                            JS::Handle<JSObject*> parent);
 
 // Creates a new plain object, like `new Object()`, with Object.prototype as [[Prototype]].
 extern JS_PUBLIC_API(JSObject *)
 JS_NewPlainObject(JSContext *cx);
--- a/js/src/jsinfer.cpp
+++ b/js/src/jsinfer.cpp
@@ -1069,16 +1069,22 @@ TypeObjectKey::clasp()
 
 TaggedProto
 TypeObjectKey::proto()
 {
     MOZ_ASSERT(hasTenuredProto());
     return isTypeObject() ? asTypeObject()->proto() : asSingleObject()->getTaggedProto();
 }
 
+TaggedProto
+TypeObjectKey::protoMaybeInNursery()
+{
+    return isTypeObject() ? asTypeObject()->proto() : asSingleObject()->getTaggedProto();
+}
+
 bool
 JSObject::hasTenuredProto() const
 {
     return type_->hasTenuredProto();
 }
 
 bool
 TypeObjectKey::hasTenuredProto()
--- a/js/src/jsinfer.h
+++ b/js/src/jsinfer.h
@@ -1516,20 +1516,18 @@ typedef HashMap<AllocationSiteKey,
 class HeapTypeSetKey;
 
 // Type set entry for either a JSObject with singleton type or a non-singleton TypeObject.
 struct TypeObjectKey
 {
     static intptr_t keyBits(TypeObjectKey *obj) { return (intptr_t) obj; }
     static TypeObjectKey *getKey(TypeObjectKey *obj) { return obj; }
 
-    static TypeObjectKey *get(JSObject *obj) {
-        MOZ_ASSERT(obj);
-        return (TypeObjectKey *) (uintptr_t(obj) | 1);
-    }
+    static inline TypeObjectKey *get(JSObject *obj);
+
     static TypeObjectKey *get(TypeObject *obj) {
         MOZ_ASSERT(obj);
         return (TypeObjectKey *) obj;
     }
 
     bool isTypeObject() {
         return (uintptr_t(this) & 1) == 0;
     }
@@ -1540,16 +1538,17 @@ struct TypeObjectKey
     inline TypeObject *asTypeObject();
     inline JSObject *asSingleObject();
 
     inline TypeObject *asTypeObjectNoBarrier();
     inline JSObject *asSingleObjectNoBarrier();
 
     const Class *clasp();
     TaggedProto proto();
+    TaggedProto protoMaybeInNursery();
     bool hasTenuredProto();
     JSObject *singleton();
     TypeNewScript *newScript();
 
     bool unknownProperties();
     bool hasFlags(CompilerConstraintList *constraints, TypeObjectFlags flags);
     bool hasStableClassAndProto(CompilerConstraintList *constraints);
     void watchStateChangeForInlinedCall(CompilerConstraintList *constraints);
--- a/js/src/jsinferinlines.h
+++ b/js/src/jsinferinlines.h
@@ -117,16 +117,24 @@ TypeObjectKey::asTypeObject()
 inline JSObject *
 TypeObjectKey::asSingleObject()
 {
     JSObject *res = asSingleObjectNoBarrier();
     JSObject::readBarrier(res);
     return res;
 }
 
+/* static */ inline TypeObjectKey *
+TypeObjectKey::get(JSObject *obj)
+{
+    if (obj->hasSingletonType())
+        return (TypeObjectKey *) (uintptr_t(obj) | 1);
+    return TypeObjectKey::get(obj->type());
+}
+
 /* static */ inline Type
 Type::ObjectType(JSObject *obj)
 {
     if (obj->hasSingletonType())
         return Type(uintptr_t(obj) | 1);
     return Type(uintptr_t(obj->type()));
 }
 
--- a/js/src/jsobj.cpp
+++ b/js/src/jsobj.cpp
@@ -3042,90 +3042,84 @@ js::HasOwnProperty(JSContext *cx, Handle
 
     RootedShape shape(cx);
     if (!NativeLookupOwnProperty<CanGC>(cx, obj.as<NativeObject>(), id, &shape))
         return false;
     *result = (shape != nullptr);
     return true;
 }
 
-static MOZ_ALWAYS_INLINE bool
-LookupPropertyPureInline(ExclusiveContext *cx, JSObject *obj, jsid id, NativeObject **objp,
-                         Shape **propp)
+bool
+js::LookupPropertyPure(ExclusiveContext *cx, JSObject *obj, jsid id, JSObject **objp,
+                       Shape **propp)
 {
-    if (!obj->isNative())
-        return false;
-
-    NativeObject *current = &obj->as<NativeObject>();
-    while (true) {
-        /* Search for a native dense element, typed array element, or property. */
-
-        if (JSID_IS_INT(id) && current->containsDenseElement(JSID_TO_INT(id))) {
-            *objp = current;
-            MarkDenseOrTypedArrayElementFound<NoGC>(propp);
-            return true;
-        }
-
-        if (IsAnyTypedArray(current)) {
-            uint64_t index;
-            if (IsTypedArrayIndex(id, &index)) {
-                if (index < AnyTypedArrayLength(obj)) {
-                    *objp = current;
-                    MarkDenseOrTypedArrayElementFound<NoGC>(propp);
-                } else {
-                    *objp = nullptr;
-                    *propp = nullptr;
+    do {
+        if (obj->isNative()) {
+            /* Search for a native dense element, typed array element, or property. */
+
+            if (JSID_IS_INT(id) && obj->as<NativeObject>().containsDenseElement(JSID_TO_INT(id))) {
+                *objp = obj;
+                MarkDenseOrTypedArrayElementFound<NoGC>(propp);
+                return true;
+            }
+
+            if (IsAnyTypedArray(obj)) {
+                uint64_t index;
+                if (IsTypedArrayIndex(id, &index)) {
+                    if (index < AnyTypedArrayLength(obj)) {
+                        *objp = obj;
+                        MarkDenseOrTypedArrayElementFound<NoGC>(propp);
+                    } else {
+                        *objp = nullptr;
+                        *propp = nullptr;
+                    }
+                    return true;
                 }
+            }
+
+            if (Shape *shape = obj->as<NativeObject>().lookupPure(id)) {
+                *objp = obj;
+                *propp = shape;
+                return true;
+            }
+
+            // Fail if there's a resolve hook. We allow the JSFunction resolve hook
+            // if we know it will never add a property with this name or str_resolve
+            // with a non-integer property.
+            do {
+                const Class *clasp = obj->getClass();
+                if (!clasp->resolve)
+                break;
+                if (clasp->resolve == fun_resolve && !FunctionHasResolveHook(cx->names(), id))
+                    break;
+                if (clasp->resolve == str_resolve && !JSID_IS_INT(id))
+                    break;
+                return false;
+            } while (0);
+        } else {
+            // Search for a property on an unboxed object. Other non-native objects
+            // are not handled here.
+            if (!obj->is<UnboxedPlainObject>())
+                return false;
+            if (obj->as<UnboxedPlainObject>().layout().lookup(id)) {
+                *objp = obj;
+                MarkNonNativePropertyFound<NoGC>(propp);
                 return true;
             }
         }
 
-        if (Shape *shape = current->lookupPure(id)) {
-            *objp = current;
-            *propp = shape;
-            return true;
-        }
-
-        // Fail if there's a resolve hook. We allow the JSFunction resolve hook
-        // if we know it will never add a property with this name or str_resolve
-        // with a non-integer property.
-        do {
-            const Class *clasp = current->getClass();
-            if (!clasp->resolve)
-                break;
-            if (clasp->resolve == fun_resolve && !FunctionHasResolveHook(cx->names(), id))
-                break;
-            if (clasp->resolve == str_resolve && !JSID_IS_INT(id))
-                break;
-            return false;
-        } while (0);
-
-        JSObject *proto = current->getProto();
-
-        if (!proto)
-            break;
-        if (!proto->isNative())
-            return false;
-
-        current = &proto->as<NativeObject>();
-    }
+        obj = obj->getProto();
+    } while (obj);
 
     *objp = nullptr;
     *propp = nullptr;
     return true;
 }
 
 bool
-js::LookupPropertyPure(ExclusiveContext *cx, JSObject *obj, jsid id, NativeObject **objp,
-                       Shape **propp)
-{
-    return LookupPropertyPureInline(cx, obj, id, objp, propp);
-}
-
-bool
 JSObject::reportReadOnly(JSContext *cx, jsid id, unsigned report)
 {
     RootedValue val(cx, IdToValue(id));
     return js_ReportValueErrorFlags(cx, report, JSMSG_READ_ONLY,
                                     JSDVG_IGNORE_STACK, val, js::NullPtr(),
                                     nullptr, nullptr);
 }
 
--- a/js/src/jsobj.h
+++ b/js/src/jsobj.h
@@ -1221,17 +1221,17 @@ LookupNameUnqualified(JSContext *cx, Han
 
 extern JSObject *
 js_FindVariableScope(JSContext *cx, JSFunction **funp);
 
 
 namespace js {
 
 bool
-LookupPropertyPure(ExclusiveContext *cx, JSObject *obj, jsid id, NativeObject **objp,
+LookupPropertyPure(ExclusiveContext *cx, JSObject *obj, jsid id, JSObject **objp,
                    Shape **propp);
 
 bool
 GetOwnPropertyDescriptor(JSContext *cx, HandleObject obj, HandleId id,
                          MutableHandle<PropertyDescriptor> desc);
 
 bool
 GetOwnPropertyDescriptor(JSContext *cx, HandleObject obj, HandleId id, MutableHandleValue vp);
--- a/js/src/proxy/Proxy.cpp
+++ b/js/src/proxy/Proxy.cpp
@@ -554,17 +554,17 @@ bool
 js::proxy_LookupGeneric(JSContext *cx, HandleObject obj, HandleId id,
                         MutableHandleObject objp, MutableHandleShape propp)
 {
     bool found;
     if (!Proxy::has(cx, obj, id, &found))
         return false;
 
     if (found) {
-        MarkNonNativePropertyFound(propp);
+        MarkNonNativePropertyFound<CanGC>(propp);
         objp.set(obj);
     } else {
         objp.set(nullptr);
         propp.set(nullptr);
     }
     return true;
 }
 
--- a/js/src/shell/js.cpp
+++ b/js/src/shell/js.cpp
@@ -1030,17 +1030,17 @@ CacheEntry(JSContext* cx, unsigned argc,
 {
     CallArgs args = CallArgsFromVp(argc, vp);
 
     if (args.length() != 1 || !args[0].isString()) {
         JS_ReportErrorNumber(cx, my_GetErrorMessage, nullptr, JSSMSG_INVALID_ARGS, "CacheEntry");
         return false;
     }
 
-    RootedObject obj(cx, JS_NewObject(cx, &CacheEntry_class, JS::NullPtr(), JS::NullPtr()));
+    RootedObject obj(cx, JS_NewObject(cx, &CacheEntry_class));
     if (!obj)
         return false;
 
     SetReservedSlot(obj, CacheEntry_SOURCE, args[0]);
     SetReservedSlot(obj, CacheEntry_BYTECODE, UndefinedValue());
     args.rval().setObject(*obj);
     return true;
 }
@@ -4034,17 +4034,17 @@ ObjectEmulatingUndefined(JSContext *cx, 
 {
     CallArgs args = CallArgsFromVp(argc, vp);
 
     static const JSClass cls = {
         "ObjectEmulatingUndefined",
         JSCLASS_EMULATES_UNDEFINED
     };
 
-    RootedObject obj(cx, JS_NewObject(cx, &cls, JS::NullPtr(), JS::NullPtr()));
+    RootedObject obj(cx, JS_NewObject(cx, &cls));
     if (!obj)
         return false;
     args.rval().setObject(*obj);
     return true;
 }
 
 static bool
 GetSelfHostedValue(JSContext *cx, unsigned argc, jsval *vp)
@@ -5087,17 +5087,17 @@ dom_constructor(JSContext* cx, unsigned 
         return false;
 
     if (!protov.isObject()) {
         JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr, JSMSG_BAD_PROTOTYPE, "FakeDOMObject");
         return false;
     }
 
     RootedObject proto(cx, &protov.toObject());
-    RootedObject domObj(cx, JS_NewObject(cx, &dom_class, proto, JS::NullPtr()));
+    RootedObject domObj(cx, JS_NewObjectWithGivenProto(cx, &dom_class, proto, JS::NullPtr()));
     if (!domObj)
         return false;
 
     InitDOMObject(domObj);
 
     args.rval().setObject(*domObj);
     return true;
 }
--- a/js/src/vm/NativeObject.cpp
+++ b/js/src/vm/NativeObject.cpp
@@ -327,16 +327,17 @@ NativeObject::updateSlotsForSpan(Exclusi
 
 /* static */ bool
 NativeObject::setLastProperty(ExclusiveContext *cx, HandleNativeObject obj, HandleShape shape)
 {
     MOZ_ASSERT(!obj->inDictionaryMode());
     MOZ_ASSERT(!shape->inDictionary());
     MOZ_ASSERT(shape->compartment() == obj->compartment());
     MOZ_ASSERT(shape->numFixedSlots() == obj->numFixedSlots());
+    MOZ_ASSERT(shape->getObjectClass() == obj->getClass());
 
     size_t oldSpan = obj->lastProperty()->slotSpan();
     size_t newSpan = shape->slotSpan();
 
     if (oldSpan == newSpan) {
         obj->shape_ = shape;
         return true;
     }
@@ -350,16 +351,17 @@ NativeObject::setLastProperty(ExclusiveC
 
 void
 NativeObject::setLastPropertyShrinkFixedSlots(Shape *shape)
 {
     MOZ_ASSERT(!inDictionaryMode());
     MOZ_ASSERT(!shape->inDictionary());
     MOZ_ASSERT(shape->compartment() == compartment());
     MOZ_ASSERT(lastProperty()->slotSpan() == shape->slotSpan());
+    MOZ_ASSERT(shape->getObjectClass() == getClass());
 
     DebugOnly<size_t> oldFixed = numFixedSlots();
     DebugOnly<size_t> newFixed = shape->numFixedSlots();
     MOZ_ASSERT(newFixed < oldFixed);
     MOZ_ASSERT(shape->slotSpan() <= oldFixed);
     MOZ_ASSERT(shape->slotSpan() <= newFixed);
     MOZ_ASSERT(dynamicSlotsCount(oldFixed, shape->slotSpan(), getClass()) == 0);
     MOZ_ASSERT(dynamicSlotsCount(newFixed, shape->slotSpan(), getClass()) == 0);
@@ -376,16 +378,40 @@ NativeObject::setLastPropertyMakeNonNati
     MOZ_ASSERT(shape->slotSpan() == 0);
     MOZ_ASSERT(shape->numFixedSlots() == 0);
     MOZ_ASSERT(!hasDynamicElements());
     MOZ_ASSERT(!hasDynamicSlots());
 
     shape_ = shape;
 }
 
+/* static */ void
+NativeObject::setLastPropertyMakeNative(ExclusiveContext *cx, HandleNativeObject obj,
+                                        HandleShape shape)
+{
+    MOZ_ASSERT(obj->getClass()->isNative());
+    MOZ_ASSERT(!obj->lastProperty()->isNative());
+    MOZ_ASSERT(shape->isNative());
+    MOZ_ASSERT(!obj->inDictionaryMode());
+    MOZ_ASSERT(!shape->inDictionary());
+    MOZ_ASSERT(shape->compartment() == obj->compartment());
+
+    obj->shape_ = shape;
+    obj->slots_ = nullptr;
+    obj->elements_ = emptyObjectElements;
+
+    size_t oldSpan = shape->numFixedSlots();
+    size_t newSpan = shape->slotSpan();
+
+    // A failures at this point will leave the object as a mutant, and we
+    // can't recover.
+    if (oldSpan != newSpan && !updateSlotsForSpan(cx, obj, oldSpan, newSpan))
+        CrashAtUnhandlableOOM("NativeObject::setLastPropertyMakeNative");
+}
+
 /* static */ bool
 NativeObject::setSlotSpan(ExclusiveContext *cx, HandleNativeObject obj, uint32_t span)
 {
     MOZ_ASSERT(obj->inDictionaryMode());
 
     size_t oldSpan = obj->lastProperty()->base()->slotSpan();
     if (oldSpan == span)
         return true;
--- a/js/src/vm/NativeObject.h
+++ b/js/src/vm/NativeObject.h
@@ -412,16 +412,22 @@ class NativeObject : public JSObject
     // the new properties.
     void setLastPropertyShrinkFixedSlots(Shape *shape);
 
     // As for setLastProperty(), but changes the class associated with the
     // object to a non-native one. This leaves the object with a type and shape
     // that are (temporarily) inconsistent.
     void setLastPropertyMakeNonNative(Shape *shape);
 
+    // As for setLastProperty(), but changes the class associated with the
+    // object to a native one. The object's type has already been changed, and
+    // this brings the shape into sync with it.
+    static void setLastPropertyMakeNative(ExclusiveContext *cx, HandleNativeObject obj,
+                                          HandleShape shape);
+
   protected:
 #ifdef DEBUG
     void checkShapeConsistency();
 #else
     void checkShapeConsistency() { }
 #endif
 
     Shape *
--- a/js/src/vm/Shape.h
+++ b/js/src/vm/Shape.h
@@ -1490,18 +1490,19 @@ template<> struct RootKind<Shape *> : Sp
 template<> struct RootKind<BaseShape *> : SpecificRootKind<BaseShape *, THING_ROOT_BASE_SHAPE> {};
 
 // Property lookup hooks on objects are required to return a non-nullptr shape
 // to signify that the property has been found. For cases where the property is
 // not actually represented by a Shape, use a dummy value. This includes all
 // properties of non-native objects, and dense elements for native objects.
 // Use separate APIs for these two cases.
 
+template <AllowGC allowGC>
 static inline void
-MarkNonNativePropertyFound(MutableHandleShape propp)
+MarkNonNativePropertyFound(typename MaybeRooted<Shape*, allowGC>::MutableHandleType propp)
 {
     propp.set(reinterpret_cast<Shape*>(1));
 }
 
 template <AllowGC allowGC>
 static inline void
 MarkDenseOrTypedArrayElementFound(typename MaybeRooted<Shape*, allowGC>::MutableHandleType propp)
 {
--- a/js/src/vm/UnboxedObject.cpp
+++ b/js/src/vm/UnboxedObject.cpp
@@ -191,25 +191,21 @@ UnboxedPlainObject::convertToNative(JSCo
         shape = cx->compartment()->propertyTree.getChild(cx, shape, *child);
         if (!shape)
             return false;
     }
 
     if (!SetClassAndProto(cx, obj, &PlainObject::class_, proto))
         return false;
 
-    // Any failures after this point will leave the object as a mutant, and we
-    // can't recover.
-
-    RootedPlainObject nobj(cx, &obj->as<PlainObject>());
-    if (!nobj->setLastProperty(cx, nobj, shape))
-        CrashAtUnhandlableOOM("UnboxedPlainObject::convertToNative");
+    RootedNativeObject nobj(cx, &obj->as<PlainObject>());
+    NativeObject::setLastPropertyMakeNative(cx, nobj, shape);
 
     for (size_t i = 0; i < values.length(); i++)
-        nobj->initSlot(i, values[i]);
+        nobj->initSlotUnchecked(i, values[i]);
 
     return true;
 }
 
 /* static */
 UnboxedPlainObject *
 UnboxedPlainObject::create(JSContext *cx, HandleTypeObject type, NewObjectKind newKind)
 {
@@ -245,17 +241,17 @@ UnboxedPlainObject::create(JSContext *cx
 }
 
 /* static */ bool
 UnboxedPlainObject::obj_lookupGeneric(JSContext *cx, HandleObject obj,
                                       HandleId id, MutableHandleObject objp,
                                       MutableHandleShape propp)
 {
     if (obj->as<UnboxedPlainObject>().layout().lookup(id)) {
-        MarkNonNativePropertyFound(propp);
+        MarkNonNativePropertyFound<CanGC>(propp);
         objp.set(obj);
         return true;
     }
 
     RootedObject proto(cx, obj->getProto());
     if (!proto) {
         objp.set(nullptr);
         propp.set(nullptr);
--- a/js/src/vm/UnboxedObject.h
+++ b/js/src/vm/UnboxedObject.h
@@ -23,16 +23,22 @@ UnboxedTypeSize(JSValueType type)
       case JSVAL_TYPE_INT32:   return 4;
       case JSVAL_TYPE_DOUBLE:  return 8;
       case JSVAL_TYPE_STRING:  return sizeof(void *);
       case JSVAL_TYPE_OBJECT:  return sizeof(void *);
       default:                 return 0;
     }
 }
 
+static inline bool
+UnboxedTypeNeedsPreBarrier(JSValueType type)
+{
+    return type == JSVAL_TYPE_STRING || type == JSVAL_TYPE_OBJECT;
+}
+
 // Class describing the layout of an UnboxedPlainObject.
 class UnboxedLayout
 {
   public:
     struct Property {
         PropertyName *name;
         uint32_t offset;
         JSValueType type;
--- a/js/src/vm/make_opcode_doc.py
+++ b/js/src/vm/make_opcode_doc.py
@@ -307,39 +307,43 @@ def print_opcode(opcode):
         values = map(lambda code: values_template.format(name=escape(code.name),
                                                          value=code.value),
                     sorted([opcode] + opcode.group,
                            key=lambda opcode: opcode.name))
 
     print("""<dt>{names}</dt>
 <dd>
 <table class="standard-table">
+<tbody>
 <tr><th>Value</th><td><code>{values}</code></td></tr>
 <tr><th>Operands</th><td><code>{operands}</code></td></tr>
 <tr><th>Length</th><td><code>{length}</code></td></tr>
 <tr><th>Stack Uses</th><td><code>{stack_uses}</code></td></tr>
 <tr><th>Stack Defs</th><td><code>{stack_defs}</code></td></tr>
+</tbody>
 </table>
 
 {desc}
 </dd>
 """.format(names='<br>'.join(names),
            values='<br>'.join(values),
-           operands=escape(opcode.operands),
+           operands=escape(opcode.operands) or "&nbsp;",
            length=escape(override(opcode.length,
                                   opcode.length_override)),
-           stack_uses=escape(opcode.stack_uses),
-           stack_defs=escape(opcode.stack_defs),
+           stack_uses=escape(opcode.stack_uses) or "&nbsp;",
+           stack_defs=escape(opcode.stack_defs) or "&nbsp;",
            desc=opcode.desc)) # desc is already escaped
 
 def make_element_id(name):
     return name.replace(' ', '-')
 
 def print_doc(version, index):
-    print("""<h2 id="Bytecode_Listing">Bytecode Listing</h2>
+    print("""<div>{{{{SpiderMonkeySidebar("Internals")}}}}</div>
+
+<h2 id="Bytecode_Listing">Bytecode Listing</h2>
 
 <p>This document is automatically generated from
 <a href="{source_base}/js/src/vm/Opcodes.h">Opcodes.h</a> and
 <a href="{source_base}/js/src/vm/Xdr.h">Xdr.h</a> by
 <a href="{source_base}/js/src/vm/make_opcode_doc.py">make_opcode_doc.py</a>.</p>
 
 <p>Bytecode version: <code>{version}</code>
 (<code>0x{actual_version:08x}</code>).</p>
--- a/js/xpconnect/loader/mozJSComponentLoader.cpp
+++ b/js/xpconnect/loader/mozJSComponentLoader.cpp
@@ -583,17 +583,17 @@ mozJSComponentLoader::PrepareObjectForLo
     RootedObject obj(aCx, holder->GetJSObject());
     NS_ENSURE_TRUE(obj, nullptr);
 
     JSAutoCompartment ac(aCx, obj);
 
     if (aReuseLoaderGlobal) {
         // If we're reusing the loader global, we don't actually use the
         // global, but rather we use a different object as the 'this' object.
-        obj = JS_NewObject(aCx, &kFakeBackstagePassJSClass, NullPtr(), NullPtr());
+        obj = JS_NewObject(aCx, &kFakeBackstagePassJSClass);
         NS_ENSURE_TRUE(obj, nullptr);
     }
 
     *aRealFile = false;
 
     // need to be extra careful checking for URIs pointing to files
     // EnsureFile may not always get called, especially on resource URIs
     // so we need to call GetFile to make sure this is a valid file
--- a/js/xpconnect/src/ExportHelpers.cpp
+++ b/js/xpconnect/src/ExportHelpers.cpp
@@ -459,17 +459,17 @@ CreateObjectIn(JSContext *cx, HandleValu
     if (define && js::IsScriptedProxy(scope)) {
         JS_ReportError(cx, "Defining property on proxy object is not allowed");
         return false;
     }
 
     RootedObject obj(cx);
     {
         JSAutoCompartment ac(cx, scope);
-        obj = JS_NewObject(cx, nullptr, JS::NullPtr(), scope);
+        obj = JS_NewObject(cx, nullptr, scope);
         if (!obj)
             return false;
 
         if (define) {
             if (!JS_DefinePropertyById(cx, scope, options.defineAs, obj,
                                        JSPROP_ENUMERATE,
                                        JS_STUBGETTER, JS_STUBSETTER))
                 return false;
--- a/js/xpconnect/src/XPCWrappedJSClass.cpp
+++ b/js/xpconnect/src/XPCWrappedJSClass.cpp
@@ -1462,17 +1462,17 @@ xpc::IsOutObject(JSContext* cx, JSObject
 {
     return js::GetObjectJSClass(obj) == &XPCOutParamClass;
 }
 
 JSObject*
 xpc::NewOutObject(JSContext* cx, JSObject* scope)
 {
     RootedObject global(cx, JS_GetGlobalForObject(cx, scope));
-    return JS_NewObject(cx, nullptr, NullPtr(), global);
+    return JS_NewObject(cx, nullptr, global);
 }
 
 
 NS_IMETHODIMP
 nsXPCWrappedJSClass::DebugDump(int16_t depth)
 {
 #ifdef DEBUG
     depth-- ;
--- a/js/xpconnect/src/XPCWrappedNative.cpp
+++ b/js/xpconnect/src/XPCWrappedNative.cpp
@@ -803,17 +803,17 @@ XPCWrappedNative::Init(HandleObject pare
 
     RootedObject protoJSObject(cx, HasProto() ?
                                    GetProto()->GetJSProtoObject() :
                                    JS_GetObjectPrototype(cx, parent));
     if (!protoJSObject) {
         return false;
     }
 
-    mFlatJSObject = JS_NewObject(cx, jsclazz, protoJSObject, parent);
+    mFlatJSObject = JS_NewObjectWithGivenProto(cx, jsclazz, protoJSObject, parent);
     if (!mFlatJSObject) {
         mFlatJSObject.unsetFlags(FLAT_JS_OBJECT_VALID);
         return false;
     }
 
     mFlatJSObject.setFlags(FLAT_JS_OBJECT_VALID);
     JS_SetPrivate(mFlatJSObject, this);
 
@@ -1568,19 +1568,17 @@ XPCWrappedNative::InitTearOff(XPCWrapped
 }
 
 bool
 XPCWrappedNative::InitTearOffJSObject(XPCWrappedNativeTearOff* to)
 {
     AutoJSContext cx;
 
     RootedObject parent(cx, mFlatJSObject);
-    RootedObject proto(cx, JS_GetObjectPrototype(cx, parent));
-    JSObject* obj = JS_NewObject(cx, Jsvalify(&XPC_WN_Tearoff_JSClass),
-                                 proto, parent);
+    JSObject* obj = JS_NewObject(cx, Jsvalify(&XPC_WN_Tearoff_JSClass), parent);
     if (!obj)
         return false;
 
     JS_SetPrivate(obj, to);
     to->SetJSObject(obj);
     return true;
 }
 
--- a/layout/generic/crashtests/385526.html
+++ b/layout/generic/crashtests/385526.html
@@ -1,9 +1,9 @@
-<html><head>
+<html class="reftest-wait"><head>
 <style>
 *::first-line { font-size:310%; }
 </style>
 </head>
 <body style="display: inline; white-space: nowrap;">
 <span>mmmmmmmmmm mmmmmmmmmmm mmmmmmmmmmmmmmmmm mmmmmmmmmmmmmmmmm mmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmm mmmmmmmm mmmmmmmmmmmmmmm mmmmmmmmmmmmmmmmm mmmmmmmmmmmmmmmmm mmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmm mmmmmmmmmmmmmmmmmmmmmmmmmm•mmmmmmmmmmmmmmmmmmmmm mmmmmmmmmmm mmmmmmmmmmmmmmmmm mmmmmmmmmmmmmmmmm mmmmmmmmmmmmmmmmmmmm mmmmmmm mmmmmmmmmmmmmmm mmmmmmmmmmmmmmmmm mmmmmmmmmmmmmmmmm mmmmmmmmmmmmmmmmmmmm mmmmmmmmmmmmmmmmmmmmmm mmmmmmmmmmm mmmmmmmmmmmmmmmmmmmm mmmmmmmmmmmmmmmmm mmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmm mmmmmmm mmmmmmmmmmmmmmm mmmmmmmmmmmmmmmmmmmm mmmmmmmmmmmmmmmmm mmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmm mmmmmmmmmmmmmmmmmmmmmmmmmČmmmmmmmmmmmmŪmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmm mmmmmmmmmmmmmmmmm!mmmmmmm
 
 mmmmmmmm mmmmmmmmmmmmmmmm
@@ -99,15 +99,18 @@ mmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmm
 mmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmm mm
 mmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmm mm
 mmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmm mm
 mmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmm mm
 mmmmmmmmmmmmmmmmmmmmmmmmm mmmmmmmmmmm mmmmmmmmmmmmmmmmm mmmmmmmmmmmmmmmmm mmmmmmmmmmmmmmmmmmmm mmmm mmmmmmmmmmmmmmm mmmmmmmmmmmmmmmmm mmmmmmmmmmmmmmmmm mmmmmmmmmmmmmmmmmmmm mmmmmmmmmmmmmmmm mmmmmmmmmmm mmmmmmmmmmmmmmmmmmmm mmmmmmmmmmmmmmmmmm mmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmm mmmmmmmm mmmmmmmmmmmmmmm mmmmmmmmmmmmmmmmmmmm mmmmmmmmmmmmmmmmmm mmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmm mmmmmmmmmmmmmmmmmmm mmmmmmmmmmm mmmmmmmmmmmmmmmmm mmmmmmmmmmmmmmmmmm mmmmmmmmmmmmmmmmmmmmmmmmmmmmm mmmmmmm mmmmmmmmmmmmmmm mmmmmmmmmmmmmmmmm mmmmmmmmmmmmmmmmmm mmmmmmmmmmmmmmmmmmmmmmmmmmmmm mmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmm mmmmmmmmmmm mmmmmmmmmmmmmmmmm mmmmmmmmmmmmmmmmm mmmmmmmmmmmmmmmmmmmm mmmmmmmmm mmmmmmmmmmmmmmm mmmmmmmmmmmmmmmmm mmmmmmmmmmmmmmmmm mmmmmmmmmmmmmmmmmmmm mmmmmmmmmmmmmmmmmmmmmmmm mmmmmmmmmmm mmmmmmmmmmmmmmmmmmmm mmmmmmmmmmmmmmmmmm mmmmmmmmmmmmmmmmmmmm mmmmmmmmmmmmmm mmmmmmmmmmmmmmm mmmmmmmmmmmmmmmmmmmm mmmmmmmmmmmmmmmmmm mmmmmmmmmmmmmmmmmmmm mmmmmmmmmmmmmmmmmmmm mmmmmmmmm mmmmmmmmmmmmmmmm mmmmmmmmmmm mmmmmmmmmmmmmmmmmmmm mmmmmmmmmmmmmmmmm mmmmmmmmmmmmmmmmmmmmmmmmmmmmm mmmm mmmmmmmmmmmmmmm mmmmmmmmmmmmmmmmmmmm mmmmmmmmmmmmmmmmm mmmmmmmmmmmmmmmmmmmmmmmmmmmmm mmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmm mmmmmmmmmmm mmmmmmmmmmmmmmmmmmmm mmmmmmmmmmmmmmmmmm mmmmmmmmmmmmmmmmmmmmmmmmmmmmm mmmmmmmm mmmmmmmmmmmmmmm mmmmmmmmmmmmmmmmmmmm mmmmmmmmmmmmmmmmmm mmmmmmmmmmmmmmmmmmmmmmmmmmmmm mmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmm mmmmmmmmmmm mmmmmmmmmmmmmmmmmmmmmmm mmmmmmmmmmmmmmmmmmmm mmmmmmmmmmmmmmmmmmmmmmm mmmmmmmmmm mmmmmmmmmmmmmmm mmmmmmmmmm mmmmmmmmmm mmmm mmmmmmmmmmmmm mmmmmmmm mmmmmmmmmmmm mmmmmmmmmmmmmŌ°mŪmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmm mmmmmmmmmmm mmmmmmmmmmmmmmmmmmmm mmmmmmmmmmmmmmmmmmmm mmmmmmmmmm mmmmmmmmmmmmmmmmmmmmmmmm mmmmmmmmmm mmmmmmmmmmmmmmm mmmmmmm mmmmmmmmmm mmmm mmmmmmmmmmmmm mmmmmmmmmmmmmmmmm mmmmmmmmmmmm mmmmmmm mmmmmmmmm mmmmmmmmmmmm˜mmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmm
 mmmmmmmmmmmmmmmmmmmmmmmmmm
 </span>
 <script>
+function finish() {
+  document.documentElement.removeAttribute('class');
+}
 function doe(){
-document.body.removeAttribute('style');
+  document.body.removeAttribute('style');
+  setTimeout(finish, 100);
 }
 setTimeout(doe,300,0);
-setTimeout(function() {window.location.reload()}, 600);
 </script>
-</body></html>
\ No newline at end of file
+</body></html>
--- a/layout/generic/crashtests/crashtests.list
+++ b/layout/generic/crashtests/crashtests.list
@@ -120,17 +120,17 @@ load 382745-1.xhtml
 load 383089-1.html
 load 385265-1.xhtml
 load 385295-1.xhtml
 load 385344-1.html
 load 385344-2.html
 load 385414-1.html
 load 385414-2.html
 load 385426-1.html
-skip-if(B2G) skip-if(Android&&AndroidVersion==10) load 385526.html # Bug 891347
+load 385526.html
 load 385681.html
 load 385885-1.xul
 load 386799-1.html
 load 386807-1.html
 load 386812-1.html
 load 386827-1.html
 load 387058-1.html
 load 387058-2.html
--- a/layout/generic/nsFirstLetterFrame.cpp
+++ b/layout/generic/nsFirstLetterFrame.cpp
@@ -221,16 +221,25 @@ nsFirstLetterFrame::Reflow(nsPresContext
     kid->FinishAndStoreOverflow(&kidMetrics);
     kid->DidReflow(aPresContext, nullptr, nsDidReflowStatus::FINISHED);
 
     convertedSize.ISize(wm) += bp.IStartEnd(wm);
     convertedSize.BSize(wm) += bp.BStartEnd(wm);
     aMetrics.SetSize(wm, convertedSize);
     aMetrics.SetBlockStartAscent(kidMetrics.BlockStartAscent() +
                                  bp.BStart(wm));
+
+    // Ensure that the overflow rect contains the child textframe's
+    // overflow rect.
+    // Note that if this is floating, the overline/underline drawable
+    // area is in the overflow rect of the child textframe.
+    aMetrics.UnionOverflowAreasWithDesiredBounds();
+    ConsiderChildOverflow(aMetrics.mOverflowAreas, kid);
+
+    FinishAndStoreOverflow(&aMetrics);
   }
   else {
     // Pretend we are a span and reflow the child frame
     nsLineLayout* ll = aReflowState.mLineLayout;
     bool          pushedFrame;
 
     ll->SetInFirstLetter(
       mStyleContext->GetPseudo() == nsCSSPseudoElements::firstLetter);
@@ -242,22 +251,16 @@ nsFirstLetterFrame::Reflow(nsPresContext
                  "since we shouldn't have orthogonal writing modes within "
                  "a line.");
     aMetrics.ISize(lineWM) = ll->EndSpan(this) + bp.IStartEnd(wm);
     ll->SetInFirstLetter(false);
 
     nsLayoutUtils::SetBSizeFromFontMetrics(this, aMetrics, bp, lineWM, wm);
   }
 
-  // Ensure that the overflow rect contains the child textframe's overflow rect.
-  // Note that if this is floating, the overline/underline drawable area is in
-  // the overflow rect of the child textframe.
-  aMetrics.UnionOverflowAreasWithDesiredBounds();
-  ConsiderChildOverflow(aMetrics.mOverflowAreas, kid);
-
   if (!NS_INLINE_IS_BREAK_BEFORE(aReflowStatus)) {
     // Create a continuation or remove existing continuations based on
     // the reflow completion status.
     if (NS_FRAME_IS_COMPLETE(aReflowStatus)) {
       if (aReflowState.mLineLayout) {
         aReflowState.mLineLayout->SetFirstLetterStyleOK(false);
       }
       nsIFrame* kidNextInFlow = kid->GetNextInFlow();
@@ -282,18 +285,16 @@ nsFirstLetterFrame::Reflow(nsPresContext
         // text that the first letter frame was made out of.
         nsIFrame* continuation;
         CreateContinuationForFloatingParent(aPresContext, kid,
                                             &continuation, true);
       }
     }
   }
 
-  FinishAndStoreOverflow(&aMetrics);
-
   NS_FRAME_SET_TRUNCATION(aReflowStatus, aReflowState, aMetrics);
 }
 
 /* virtual */ bool
 nsFirstLetterFrame::CanContinueTextRun() const
 {
   // We can continue a text run through a first-letter frame.
   return true;
--- a/layout/reftests/bugs/reftest.list
+++ b/layout/reftests/bugs/reftest.list
@@ -911,17 +911,17 @@ fuzzy-if(Android&&AndroidVersion>=15,8,5
 == 405584-1.html 405584-1-ref.html
 # == 405952-1.html 405952-1-ref.html
 == 406484-1.html 406484-1-ref.html
 == 406568-1.html 406568-1-ref.html
 == 407016-1-a.html 407016-1-ref.html
 == 407016-1-b.html 407016-1-ref.html
 == 407078-1.html 407078-1-ref.html
 == 407095-1.html 407095-1-ref.html
-== 407111-1.html 407111-1-ref.html
+fuzzy-if(Android,13,9) == 407111-1.html 407111-1-ref.html  # Bug 1128229
 == 407227-1.html 407227-1-ref.html
 == 407243-1.html 407243-1-ref.html
 == 407419-1.html 407419-1-ref.html
 == 407937-1.html 407937-1-ref.html
 == 408493-1.html about:blank
 == 408493-2.html 408493-2-ref.html
 == 408656-1a.html 408656-1-ref.html
 == 408656-1b.html 408656-1-ref.html
new file mode 100644
--- /dev/null
+++ b/layout/reftests/first-letter/overflow-float-nooverflow-ref.html
@@ -0,0 +1,14 @@
+<title>::first-letter and overflow</title>
+<style>
+
+div {
+  height: 8em; width: 5em;
+  padding: 3px;
+  background: yellow; color: black;
+  line-height: 1.0;
+}
+div::first-letter { font-size: 1.2em; float: left; }
+
+</style>
+
+<div>Hello world, testing, testing, testing, testing</div>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/first-letter/overflow-float-nooverflow.html
@@ -0,0 +1,15 @@
+<title>::first-letter and overflow</title>
+<style>
+
+div {
+  height: 8em; width: 5em;
+  padding: 3px;
+  background: yellow; color: black;
+  overflow: auto;
+  line-height: 1.0;
+}
+div::first-letter { font-size: 1.2em; float: left; }
+
+</style>
+
+<div>Hello world, testing, testing, testing, testing</div>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/first-letter/overflow-float-overflow-notref.html
@@ -0,0 +1,14 @@
+<title>::first-letter and overflow</title>
+<style>
+
+div {
+  height: 3em; width: 8em;
+  padding: 3px;
+  background: yellow; color: black;
+  line-height: 1.0;
+}
+div::first-letter { font-size: 4em; float: left; }
+
+</style>
+
+<div>Hello</div>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/first-letter/overflow-float-overflow.html
@@ -0,0 +1,15 @@
+<title>::first-letter and overflow</title>
+<style>
+
+div {
+  height: 3em; width: 8em;
+  padding: 3px;
+  background: yellow; color: black;
+  overflow: auto;
+  line-height: 1.0;
+}
+div::first-letter { font-size: 4em; float: left; }
+
+</style>
+
+<div>Hello</div>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/first-letter/overflow-inline-nooverflow-ref.html
@@ -0,0 +1,14 @@
+<title>::first-letter and overflow</title>
+<style>
+
+div {
+  height: 8em; width: 5em;
+  padding: 3px;
+  background: yellow; color: black;
+  line-height: 1.0;
+}
+div::first-letter { font-size: 1.2em }
+
+</style>
+
+<div>Hello world, testing, testing, testing, testing</div>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/first-letter/overflow-inline-nooverflow.html
@@ -0,0 +1,15 @@
+<title>::first-letter and overflow</title>
+<style>
+
+div {
+  height: 8em; width: 5em;
+  padding: 3px;
+  background: yellow; color: black;
+  overflow: auto;
+  line-height: 1.0;
+}
+div::first-letter { font-size: 1.2em }
+
+</style>
+
+<div>Hello world, testing, testing, testing, testing</div>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/first-letter/overflow-inline-overflow-notref.html
@@ -0,0 +1,14 @@
+<title>::first-letter and overflow</title>
+<style>
+
+div {
+  height: 3em; width: 8em;
+  padding: 3px;
+  background: yellow; color: black;
+  line-height: 1.0;
+}
+div::first-letter { font-size: 4em }
+
+</style>
+
+<div>Hello</div>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/first-letter/overflow-inline-overflow-ref.html
@@ -0,0 +1,15 @@
+<title>::first-letter and overflow</title>
+<style>
+
+div {
+  height: 3em; width: 8em;
+  padding: 3px;
+  background: yellow; color: black;
+  overflow: auto;
+  line-height: 1.0;
+}
+span { font-size: 4em }
+
+</style>
+
+<div><span>H</span>ello</div>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/first-letter/overflow-inline-overflow.html
@@ -0,0 +1,15 @@
+<title>::first-letter and overflow</title>
+<style>
+
+div {
+  height: 3em; width: 8em;
+  padding: 3px;
+  background: yellow; color: black;
+  overflow: auto;
+  line-height: 1.0;
+}
+div::first-letter { font-size: 4em }
+
+</style>
+
+<div>Hello</div>
--- a/layout/reftests/first-letter/reftest.list
+++ b/layout/reftests/first-letter/reftest.list
@@ -62,8 +62,13 @@ HTTP(..) == 329069-5.html 329069-5-ref.h
 fails-if(winWidget||cocoaWidget) == 617869-1.html 617869-1-ref.html
 == 723509-1.html 723509-1-ref.html
 == 922550-1.html 922550-1-ref.html
 == 958249.html 958249-ref.html
 == font-text-styles.html font-text-styles-ref.html
 fails-if(gtk2Widget) random-if(winWidget&&!d2d) == font-text-styles-floater.html font-text-styles-floater-ref.html # bug 992846
 == inline-height-empty.html inline-height-empty-ref.html
 HTTP(..) == indic-clusters-1.html indic-clusters-1-ref.html
+== overflow-float-nooverflow.html overflow-float-nooverflow-ref.html
+== overflow-float-overflow.html overflow-float-overflow-notref.html
+== overflow-inline-nooverflow.html overflow-inline-nooverflow-ref.html
+!= overflow-inline-overflow.html overflow-inline-overflow-notref.html
+== overflow-inline-overflow.html overflow-inline-overflow-ref.html
--- a/layout/reftests/text-overflow/reftest.list
+++ b/layout/reftests/text-overflow/reftest.list
@@ -1,11 +1,11 @@
 skip-if(B2G) == ellipsis-font-fallback.html ellipsis-font-fallback-ref.html
 == line-clipping.html line-clipping-ref.html
-skip-if(B2G) HTTP(..) == marker-basic.html marker-basic-ref.html
+fuzzy-if(Android,16,244) skip-if(B2G) HTTP(..) == marker-basic.html marker-basic-ref.html  # Bug 1128229
 skip-if(B2G) HTTP(..) == marker-string.html marker-string-ref.html
 skip-if(Android||B2G) HTTP(..) == bidi-simple.html bidi-simple-ref.html # Fails on Android due to anti-aliasing
 skip-if(!gtk2Widget) fuzzy-if(gtk2Widget,1,104) HTTP(..) == bidi-simple-scrolled.html bidi-simple-scrolled-ref.html # Fails on Windows and OSX due to anti-aliasing
 skip-if(B2G) fuzzy-if(Android&&AndroidVersion<15,9,2545) fuzzy-if(Android&&AndroidVersion>=15,24,4000) fuzzy-if(cocoaWidget,1,40) HTTP(..) == scroll-rounding.html scroll-rounding-ref.html # bug 760264
 fuzzy-if(OSX==1008,1,1) HTTP(..) == anonymous-block.html anonymous-block-ref.html
 skip-if(B2G) HTTP(..) == false-marker-overlap.html false-marker-overlap-ref.html
 HTTP(..) == visibility-hidden.html visibility-hidden-ref.html
 skip-if(B2G) HTTP(..) == block-padding.html block-padding-ref.html
--- a/layout/reftests/w3c-css/submitted/ui3/reftest.list
+++ b/layout/reftests/w3c-css/submitted/ui3/reftest.list
@@ -4,10 +4,10 @@
 == box-sizing-border-box-004.xht box-sizing-border-box-004-ref.xht
 == box-sizing-content-box-001.xht box-sizing-content-box-001-ref.xht
 == box-sizing-content-box-002.xht box-sizing-content-box-002-ref.xht
 == box-sizing-content-box-003.xht box-sizing-content-box-003-ref.xht
 == box-sizing-padding-box-001.xht box-sizing-padding-box-001-ref.xht
 == box-sizing-padding-box-002.xht box-sizing-padding-box-002-ref.xht
 == box-sizing-padding-box-003.xht box-sizing-padding-box-003-ref.xht
 random-if(Android) skip-if(B2G&&browserIsRemote)  == box-sizing-replaced-001.xht box-sizing-replaced-001-ref.xht #bug 982547
-random-if(B2G&&browserIsRemote) == box-sizing-replaced-002.xht box-sizing-replaced-002-ref.xht
-random-if(B2G&&browserIsRemote) == box-sizing-replaced-003.xht box-sizing-replaced-003-ref.xht
+fuzzy-if(Android,14,112) random-if(B2G&&browserIsRemote) == box-sizing-replaced-002.xht box-sizing-replaced-002-ref.xht # Bug 1128229
+fuzzy-if(Android,14,813) random-if(B2G&&browserIsRemote) == box-sizing-replaced-003.xht box-sizing-replaced-003-ref.xht # Bug 1128229
--- a/media/gmp-clearkey/0.1/clearkey.info
+++ b/media/gmp-clearkey/0.1/clearkey.info
@@ -1,4 +1,4 @@
 Name: clearkey
 Description: ClearKey decrypt-only GMP plugin
 Version: 0.1
-APIs: eme-decrypt-v5[org.w3.clearkey]
+APIs: eme-decrypt-v6[org.w3.clearkey]
--- a/mobile/android/base/tests/StringHelper.java
+++ b/mobile/android/base/tests/StringHelper.java
@@ -143,17 +143,16 @@ public class StringHelper {
     public static final String ROBOCOP_BOXES_TITLE = "Browser Box test";
     public static final String ROBOCOP_GEOLOCATION_TITLE = "Geolocation Test Page";
     public static final String ROBOCOP_LOGIN_TITLE = "Robocop Login";
     public static final String ROBOCOP_OFFLINE_STORAGE_TITLE = "Robocop offline storage";
     public static final String ROBOCOP_PICTURE_LINK_TITLE = "Picture Link";
     public static final String ROBOCOP_SEARCH_TITLE = "Robocop Search Engine";
     public static final String ROBOCOP_TEXT_PAGE_TITLE = "Robocop Text Page";
     public static final String ROBOCOP_INPUT_TITLE = "Robocop Input";
-    public static final String ROBOCOP_SELECTION_HANDLER_TITLE = "Automated Text Selection tests for Mobile";
 
     // Distribution tile labels
     public static final String DISTRIBUTION1_LABEL = "Distribution 1";
     public static final String DISTRIBUTION2_LABEL = "Distribution 2";
 
     // Settings menu strings
     // Section labels - ordered as found in the settings menu
     public static final String CUSTOMIZE_SECTION_LABEL = "Customize";
--- a/netwerk/streamconv/converters/mozTXTToHTMLConv.cpp
+++ b/netwerk/streamconv/converters/mozTXTToHTMLConv.cpp
@@ -1218,53 +1218,83 @@ mozTXTToHTMLConv::ScanHTML(nsString& aIn
   int32_t lengthOfInString = aInString.Length();
   const char16_t * uniBuffer = aInString.get();
 
 #ifdef DEBUG_BenB_Perf
   PRTime parsing_start = PR_IntervalNow();
 #endif
 
   // Look for simple entities not included in a tags and scan them.
-  /* Skip all tags ("<[...]>") and content in an a tag ("<a[...]</a>")
-     or in a tag ("<!--[...]-->").
-     Unescape the rest (text between tags) and pass it to ScanTXT. */
+  // Skip all tags ("<[...]>") and content in an a link tag ("<a [...]</a>"),
+  // comment tag ("<!--[...]-->"), style tag, script tag or head tag.
+  // Unescape the rest (text between tags) and pass it to ScanTXT.
   for (int32_t i = 0; i < lengthOfInString;)
   {
     if (aInString[i] == '<')  // html tag
     {
-      uint32_t start = uint32_t(i);
-      if (nsCRT::ToLower((char)aInString[uint32_t(i) + 1]) == 'a')
-           // if a tag, skip until </a>
+      int32_t start = i;
+      if (Substring(aInString, i + 1, 2).LowerCaseEqualsASCII("a "))
+           // if a tag, skip until </a>.
+           // Make sure there's a space after, not to match "abbr".
       {
         i = aInString.Find("</a>", true, i);
         if (i == kNotFound)
           i = lengthOfInString;
         else
           i += 4;
       }
-      else if (aInString[uint32_t(i) + 1] == '!' && aInString[uint32_t(i) + 2] == '-' &&
-        aInString[uint32_t(i) + 3] == '-')
-          //if out-commended code, skip until -->
+      else if (Substring(aInString, i + 1, 3).LowerCaseEqualsASCII("!--"))
+          // if out-commended code, skip until -->
       {
         i = aInString.Find("-->", false, i);
         if (i == kNotFound)
           i = lengthOfInString;
         else
           i += 3;
-
+      }
+      else if (Substring(aInString, i + 1, 5).LowerCaseEqualsASCII("style") &&
+               (aInString.CharAt(i + 6) == ' ' || aInString.CharAt(i + 6) == '>'))
+           // if style tag, skip until </style>
+      {
+        i = aInString.Find("</style>", true, i);
+        if (i == kNotFound)
+          i = lengthOfInString;
+        else
+          i += 8;
+      }
+      else if (Substring(aInString, i + 1, 6).LowerCaseEqualsASCII("script") &&
+               (aInString.CharAt(i + 7) == ' ' || aInString.CharAt(i + 7) == '>'))
+           // if script tag, skip until </script>
+      {
+        i = aInString.Find("</script>", true, i);
+        if (i == kNotFound)
+          i = lengthOfInString;
+        else
+          i += 9;
+      }
+      else if (Substring(aInString, i + 1, 4).LowerCaseEqualsASCII("head") &&
+               (aInString.CharAt(i + 5) == ' ' || aInString.CharAt(i + 5) == '>'))
+           // if head tag, skip until </head>
+           // Make sure not to match <header>.
+      {
+        i = aInString.Find("</head>", true, i);
+        if (i == kNotFound)
+          i = lengthOfInString;
+        else
+          i += 7;
       }
       else  // just skip tag (attributes etc.)
       {
         i = aInString.FindChar('>', i);
         if (i == kNotFound)
           i = lengthOfInString;
         else
           i++;
       }
-      aOutString.Append(&uniBuffer[start], uint32_t(i) - start);
+      aOutString.Append(&uniBuffer[start], i - start);
     }
     else
     {
       uint32_t start = uint32_t(i);
       i = aInString.FindChar('<', i);
       if (i == kNotFound)
         i = lengthOfInString;
   
--- a/netwerk/test/unit/test_mozTXTToHTMLConv.js
+++ b/netwerk/test/unit/test_mozTXTToHTMLConv.js
@@ -8,17 +8,17 @@
 
 var Cc = Components.classes;
 var Ci = Components.interfaces;
 
 function run_test() {
   let converter = Cc["@mozilla.org/txttohtmlconv;1"]
                      .getService(Ci.mozITXTToHTMLConv);
 
-  const tests = [
+  const scanTXTtests = [
     // -- RFC1738
     {
       input: "RFC1738: <URL:http://mozilla.org> then",
       url: "http://mozilla.org"
     },
     // -- RFC2396E
     {
       input: "RFC2396E: <http://mozilla.org/> then",
@@ -108,20 +108,88 @@ function run_test() {
       url: "http://[::ffff:127.0.0.1]/#yay"
     },
     {
       input: "ipv6 parenthesis port: (http://[2001:db8::1]:80/) test",
       url: "http://[2001:db8::1]:80/"
     }
   ];
 
+  const scanHTMLtests = [
+    {
+      input: "http://foo.example.com",
+      shouldChange: true
+    },
+    {
+      input: " <a href='http://a.example.com/'>foo</a>",
+      shouldChange: false
+    },
+    {
+      input: "<abbr>see http://abbr.example.com</abbr>",
+      shouldChange: true
+    },
+    {
+      input: "<!-- see http://comment.example.com/ -->",
+      shouldChange: false
+    },
+    {
+      input: "<!-- greater > -->",
+      shouldChange: false
+    },
+    {
+      input: "<!-- lesser < -->",
+      shouldChange: false
+    },
+    {
+      input: "<style id='ex'>background-image: url(http://example.com/ex.png);</style>",
+      shouldChange: false
+    },
+    {
+      input: "<style>body > p, body > div { color:blue }</style>",
+      shouldChange: false
+    },
+    {
+      input: "<script>window.location='http://script.example.com/';</script>",
+      shouldChange: false
+    },
+    {
+      input: "<head><title>http://head.example.com/</title></head>",
+      shouldChange: false
+    },
+    {
+      input: "<header>see http://header.example.com</header>",
+      shouldChange: true
+    },
+    {
+      input: "<iframe src='http://iframe.example.com/' />",
+      shouldChange: false
+    },
+    {
+      input: "broken end <script",
+      shouldChange: false
+    },
+  ];
+
   function hrefLink(url) {
     return ' href="' + url + '"';
   }
 
-  for (let i = 0; i < tests.length; i++) {
-    let output = converter.scanTXT(tests[i].input, Ci.mozITXTToHTMLConv.kURLs);
-    let link = hrefLink(tests[i].url);
+  for (let i = 0; i < scanTXTtests.length; i++) {
+    let t = scanTXTtests[i];
+    let output = converter.scanTXT(t.input, Ci.mozITXTToHTMLConv.kURLs);
+    let link = hrefLink(t.url);
     if (output.indexOf(link) == -1)
-      do_throw("Unexpected conversion: input=" + tests[i].input +
+      do_throw("Unexpected conversion by scanTXT: input=" + t.input +
                ", output=" + output + ", link=" + link);
   }
+
+  for (let i = 0; i < scanHTMLtests.length; i++) {
+    let t = scanHTMLtests[i];
+    let output = converter.scanHTML(t.input, Ci.mozITXTToHTMLConv.kURLs);
+    let changed = (t.input != output);
+    if (changed != t.shouldChange) {
+      do_throw("Unexpected change by scanHTML: changed=" + changed +
+               ", shouldChange=" + t.shouldChange +
+               ", \ninput=" + t.input +
+               ", \noutput=" + output);
+    }
+  }
 }
--- a/security/manager/ssl/src/nsNSSIOLayer.cpp
+++ b/security/manager/ssl/src/nsNSSIOLayer.cpp
@@ -1185,16 +1185,17 @@ uint32_t tlsIntoleranceTelemetryBucket(P
     case SSL_ERROR_BAD_MAC_READ: return 2;
     case SSL_ERROR_HANDSHAKE_FAILURE_ALERT: return 3;
     case SSL_ERROR_HANDSHAKE_UNEXPECTED_ALERT: return 4;
     case SSL_ERROR_CLIENT_KEY_EXCHANGE_FAILURE: return 5;
     case SSL_ERROR_ILLEGAL_PARAMETER_ALERT: return 6;
     case SSL_ERROR_NO_CYPHER_OVERLAP: return 7;
     case SSL_ERROR_BAD_SERVER: return 8;
     case SSL_ERROR_BAD_BLOCK_PADDING: return 9;
+    case SSL_ERROR_UNSUPPORTED_VERSION: return 10;
     case SSL_ERROR_PROTOCOL_VERSION_ALERT: return 11;
     case SSL_ERROR_RX_MALFORMED_FINISHED: return 12;
     case SSL_ERROR_BAD_HANDSHAKE_HASH_VALUE: return 13;
     case SSL_ERROR_DECODE_ERROR_ALERT: return 14;
     case SSL_ERROR_RX_UNKNOWN_ALERT: return 15;
     case PR_CONNECT_RESET_ERROR: return 16;
     case PR_END_OF_FILE_ERROR: return 17;
     default: return 0;
--- a/toolkit/components/finalizationwitness/FinalizationWitnessService.cpp
+++ b/toolkit/components/finalizationwitness/FinalizationWitnessService.cpp
@@ -185,18 +185,17 @@ NS_IMPL_ISUPPORTS(FinalizationWitnessSer
  * @constructor
  */
 NS_IMETHODIMP
 FinalizationWitnessService::Make(const char* aTopic,
                                  const char16_t* aValue,
                                  JSContext* aCx,
                                  JS::MutableHandle<JS::Value> aRetval)
 {
-  JS::Rooted<JSObject*> objResult(aCx, JS_NewObject(aCx, &sWitnessClass, JS::NullPtr(),
-                                                    JS::NullPtr()));
+  JS::Rooted<JSObject*> objResult(aCx, JS_NewObject(aCx, &sWitnessClass));
   if (!objResult) {
     return NS_ERROR_OUT_OF_MEMORY;
   }
   if (!JS_DefineFunctions(aCx, objResult, sWitnessClassFunctions)) {
     return NS_ERROR_FAILURE;
   }
 
   nsRefPtr<FinalizationEvent> event = new FinalizationEvent(aTopic, aValue);
--- a/toolkit/components/passwordmgr/LoginManagerContent.jsm
+++ b/toolkit/components/passwordmgr/LoginManagerContent.jsm
@@ -1,9 +1,9 @@
-/* vim: set ts=4 sts=4 sw=4 et tw=80: */
+/* vim: set ts=2 sts=2 sw=2 et 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/. */
 
 "use strict";
 
 this.EXPORTED_SYMBOLS = [ "LoginManagerContent",
                           "UserAutoCompleteResult" ];
@@ -17,927 +17,927 @@ Cu.import("resource://gre/modules/XPCOMU
 Cu.import("resource://gre/modules/Services.jsm");
 Cu.import("resource://gre/modules/PrivateBrowsingUtils.jsm");
 Cu.import("resource://gre/modules/Promise.jsm");
 
 // These mirror signon.* prefs.
 var gEnabled, gDebug, gAutofillForms, gStoreWhenAutocompleteOff;
 
 function log(...pieces) {
-    function generateLogMessage(args) {
-        let strings = ['Login Manager (content):'];
+  function generateLogMessage(args) {
+    let strings = ['Login Manager (content):'];
 
-        args.forEach(function(arg) {
-            if (typeof arg === 'string') {
-                strings.push(arg);
-            } else if (typeof arg === 'undefined') {
-                strings.push('undefined');
-            } else if (arg === null) {
-                strings.push('null');
-            } else {
-                try {
-                  strings.push(JSON.stringify(arg, null, 2));
-                } catch(err) {
-                  strings.push("<<something>>");
-                }
-            }
-        });
-        return strings.join(' ');
-    }
+    args.forEach(function(arg) {
+      if (typeof arg === 'string') {
+        strings.push(arg);
+      } else if (typeof arg === 'undefined') {
+        strings.push('undefined');
+      } else if (arg === null) {
+        strings.push('null');
+      } else {
+        try {
+          strings.push(JSON.stringify(arg, null, 2));
+        } catch(err) {
+          strings.push("<<something>>");
+        }
+      }
+    });
+    return strings.join(' ');
+  }
 
-    if (!gDebug)
-        return;
+  if (!gDebug)
+    return;
 
-    let message = generateLogMessage(pieces);
-    dump(message + "\n");
-    Services.console.logStringMessage(message);
+  let message = generateLogMessage(pieces);
+  dump(message + "\n");
+  Services.console.logStringMessage(message);
 }
 
 
 var observer = {
-    QueryInterface : XPCOMUtils.generateQI([Ci.nsIObserver,
-                                            Ci.nsIFormSubmitObserver,
-                                            Ci.nsISupportsWeakReference]),
+  QueryInterface : XPCOMUtils.generateQI([Ci.nsIObserver,
+                                          Ci.nsIFormSubmitObserver,
+                                          Ci.nsISupportsWeakReference]),
 
-    // nsIFormSubmitObserver
-    notify : function (formElement, aWindow, actionURI) {
-        log("observer notified for form submission.");
+  // nsIFormSubmitObserver
+  notify : function (formElement, aWindow, actionURI) {
+    log("observer notified for form submission.");
 
-        // We're invoked before the content's |onsubmit| handlers, so we
-        // can grab form data before it might be modified (see bug 257781).
+    // We're invoked before the content's |onsubmit| handlers, so we
+    // can grab form data before it might be modified (see bug 257781).
 
-        try {
-            LoginManagerContent._onFormSubmit(formElement);
-        } catch (e) {
-            log("Caught error in onFormSubmit(", e.lineNumber, "):", e.message);
-        }
+    try {
+      LoginManagerContent._onFormSubmit(formElement);
+    } catch (e) {
+      log("Caught error in onFormSubmit(", e.lineNumber, "):", e.message);
+    }
 
-        return true; // Always return true, or form submit will be canceled.
-    },
+    return true; // Always return true, or form submit will be canceled.
+  },
 
-    onPrefChange : function() {
-        gDebug = Services.prefs.getBoolPref("signon.debug");
-        gEnabled = Services.prefs.getBoolPref("signon.rememberSignons");
-        gAutofillForms = Services.prefs.getBoolPref("signon.autofillForms");
-        gStoreWhenAutocompleteOff = Services.prefs.getBoolPref("signon.storeWhenAutocompleteOff");
-    },
+  onPrefChange : function() {
+    gDebug = Services.prefs.getBoolPref("signon.debug");
+    gEnabled = Services.prefs.getBoolPref("signon.rememberSignons");
+    gAutofillForms = Services.prefs.getBoolPref("signon.autofillForms");
+    gStoreWhenAutocompleteOff = Services.prefs.getBoolPref("signon.storeWhenAutocompleteOff");
+  },
 };
 
 Services.obs.addObserver(observer, "earlyformsubmit", false);
 var prefBranch = Services.prefs.getBranch("signon.");
 prefBranch.addObserver("", observer.onPrefChange, false);
 
 observer.onPrefChange(); // read initial values
 
 
 function messageManagerFromWindow(win) {
-    return win.QueryInterface(Ci.nsIInterfaceRequestor)
-              .getInterface(Ci.nsIWebNavigation)
-              .QueryInterface(Ci.nsIDocShell)
-              .QueryInterface(Ci.nsIInterfaceRequestor)
-              .getInterface(Ci.nsIContentFrameMessageManager)
+  return win.QueryInterface(Ci.nsIInterfaceRequestor)
+            .getInterface(Ci.nsIWebNavigation)
+            .QueryInterface(Ci.nsIDocShell)
+            .QueryInterface(Ci.nsIInterfaceRequestor)
+            .getInterface(Ci.nsIContentFrameMessageManager)
 }
 
 // This object maps to the "child" process (even in the single-process case).
 var LoginManagerContent = {
 
-    __formFillService : null, // FormFillController, for username autocompleting
-    get _formFillService() {
-        if (!this.__formFillService)
-            this.__formFillService =
-                            Cc["@mozilla.org/satchel/form-fill-controller;1"].
-                            getService(Ci.nsIFormFillController);
-        return this.__formFillService;
-    },
+  __formFillService : null, // FormFillController, for username autocompleting
+  get _formFillService() {
+    if (!this.__formFillService)
+      this.__formFillService =
+                      Cc["@mozilla.org/satchel/form-fill-controller;1"].
+                      getService(Ci.nsIFormFillController);
+    return this.__formFillService;
+  },
 
-    _getRandomId: function() {
-        return Cc["@mozilla.org/uuid-generator;1"]
-                 .getService(Ci.nsIUUIDGenerator).generateUUID().toString();
-    },
+  _getRandomId: function() {
+    return Cc["@mozilla.org/uuid-generator;1"]
+             .getService(Ci.nsIUUIDGenerator).generateUUID().toString();
+  },
 
-    _messages: [ "RemoteLogins:loginsFound",
-                 "RemoteLogins:loginsAutoCompleted" ],
+  _messages: [ "RemoteLogins:loginsFound",
+               "RemoteLogins:loginsAutoCompleted" ],
 
-    // Map from form login requests to information about that request.
-    _requests: new Map(),
+  // Map from form login requests to information about that request.
+  _requests: new Map(),
 
-    // Number of outstanding requests to each manager.
-    _managers: new Map(),
+  // Number of outstanding requests to each manager.
+  _managers: new Map(),
 
-    _takeRequest: function(msg) {
-        let data = msg.data;
-        let request = this._requests.get(data.requestId);
+  _takeRequest: function(msg) {
+    let data = msg.data;
+    let request = this._requests.get(data.requestId);
 
-        this._requests.delete(data.requestId);
+    this._requests.delete(data.requestId);
 
-        let count = this._managers.get(msg.target);
-        if (--count === 0) {
-            this._managers.delete(msg.target);
+    let count = this._managers.get(msg.target);
+    if (--count === 0) {
+      this._managers.delete(msg.target);
 
-            for (let message of this._messages)
-                msg.target.removeMessageListener(message, this);
-        } else {
-            this._managers.set(msg.target, count);
-        }
+      for (let message of this._messages)
+        msg.target.removeMessageListener(message, this);
+    } else {
+      this._managers.set(msg.target, count);
+    }
 
-        return request;
-    },
+    return request;
+  },
 
-    _sendRequest: function(messageManager, requestData,
-                           name, messageData) {
-        let count;
-        if (!(count = this._managers.get(messageManager))) {
-            this._managers.set(messageManager, 1);
+  _sendRequest: function(messageManager, requestData,
+                         name, messageData) {
+    let count;
+    if (!(count = this._managers.get(messageManager))) {
+      this._managers.set(messageManager, 1);
 
-            for (let message of this._messages)
-                messageManager.addMessageListener(message, this);
-        } else {
-            this._managers.set(messageManager, ++count);
-        }
+      for (let message of this._messages)
+        messageManager.addMessageListener(message, this);
+    } else {
+      this._managers.set(messageManager, ++count);
+    }
 
-        let requestId = this._getRandomId();
-        messageData.requestId = requestId;
+    let requestId = this._getRandomId();
+    messageData.requestId = requestId;
 
-        messageManager.sendAsyncMessage(name, messageData);
+    messageManager.sendAsyncMessage(name, messageData);
 
-        let deferred = Promise.defer();
-        requestData.promise = deferred;
-        this._requests.set(requestId, requestData);
-        return deferred.promise;
-    },
+    let deferred = Promise.defer();
+    requestData.promise = deferred;
+    this._requests.set(requestId, requestData);
+    return deferred.promise;
+  },
 
-    receiveMessage: function (msg) {
-        let request = this._takeRequest(msg);
-        switch (msg.name) {
-            case "RemoteLogins:loginsFound": {
-                request.promise.resolve({ form: request.form,
-                                          loginsFound: msg.data.logins });
-                break;
-            }
+  receiveMessage: function (msg) {
+    let request = this._takeRequest(msg);
+    switch (msg.name) {
+      case "RemoteLogins:loginsFound": {
+        request.promise.resolve({ form: request.form,
+                                  loginsFound: msg.data.logins });
+        break;
+      }
 
-            case "RemoteLogins:loginsAutoCompleted": {
-                request.promise.resolve(msg.data.logins);
-                break;
-            }
-        }
-    },
+      case "RemoteLogins:loginsAutoCompleted": {
+        request.promise.resolve(msg.data.logins);
+        break;
+      }
+    }
+  },
 
-    _asyncFindLogins: function(form, options) {
-      let doc = form.ownerDocument;
-      let win = doc.defaultView;
+  _asyncFindLogins: function(form, options) {
+    let doc = form.ownerDocument;
+    let win = doc.defaultView;
 
-      let formOrigin = LoginUtils._getPasswordOrigin(doc.documentURI);
-      let actionOrigin = LoginUtils._getActionOrigin(form);
+    let formOrigin = LoginUtils._getPasswordOrigin(doc.documentURI);
+    let actionOrigin = LoginUtils._getActionOrigin(form);
 
-      let messageManager = messageManagerFromWindow(win);
+    let messageManager = messageManagerFromWindow(win);
 
-      // XXX Weak??
-      let requestData = { form: form };
-      let messageData = { formOrigin: formOrigin,
-                          actionOrigin: actionOrigin,
-                          options: options };
+    // XXX Weak??
+    let requestData = { form: form };
+    let messageData = { formOrigin: formOrigin,
+                        actionOrigin: actionOrigin,
+                        options: options };
 
-      return this._sendRequest(messageManager, requestData,
-                               "RemoteLogins:findLogins",
-                               messageData);
-    },
+    return this._sendRequest(messageManager, requestData,
+                             "RemoteLogins:findLogins",
+                             messageData);
+  },
 
-    _autoCompleteSearchAsync: function(aSearchString, aPreviousResult,
-                                       aElement, aRect) {
-        let doc = aElement.ownerDocument;
-        let form = aElement.form;
-        let win = doc.defaultView;
+  _autoCompleteSearchAsync: function(aSearchString, aPreviousResult,
+                                     aElement, aRect) {
+    let doc = aElement.ownerDocument;
+    let form = aElement.form;
+    let win = doc.defaultView;
 
-        let formOrigin = LoginUtils._getPasswordOrigin(doc.documentURI);
-        let actionOrigin = LoginUtils._getActionOrigin(form);
+    let formOrigin = LoginUtils._getPasswordOrigin(doc.documentURI);
+    let actionOrigin = LoginUtils._getActionOrigin(form);
 
-        let messageManager = messageManagerFromWindow(win);
+    let messageManager = messageManagerFromWindow(win);
 
-        let remote = (Services.appinfo.processType ===
-                      Services.appinfo.PROCESS_TYPE_CONTENT);
+    let remote = (Services.appinfo.processType ===
+                  Services.appinfo.PROCESS_TYPE_CONTENT);
 
-        let requestData = {};
-        let messageData = { formOrigin: formOrigin,
-                            actionOrigin: actionOrigin,
-                            searchString: aSearchString,
-                            previousResult: aPreviousResult,
-                            rect: aRect,
-                            remote: remote };
+    let requestData = {};
+    let messageData = { formOrigin: formOrigin,
+                        actionOrigin: actionOrigin,
+                        searchString: aSearchString,
+                        previousResult: aPreviousResult,
+                        rect: aRect,
+                        remote: remote };
 
-        return this._sendRequest(messageManager, requestData,
-                                 "RemoteLogins:autoCompleteLogins",
-                                 messageData);
-    },
+    return this._sendRequest(messageManager, requestData,
+                             "RemoteLogins:autoCompleteLogins",
+                             messageData);
+  },
 
-    /*
-     * onFormPassword
-     *
-     * Called when an <input type="password"> element is added to the page
-     */
-    onFormPassword: function (event) {
-      if (!event.isTrusted)
-          return;
+  /*
+   * onFormPassword
+   *
+   * Called when an <input type="password"> element is added to the page
+   */
+  onFormPassword: function (event) {
+    if (!event.isTrusted)
+      return;
 
-      if (!gEnabled)
-          return;
+    if (!gEnabled)
+      return;
 
-      let form = event.target;
-      log("onFormPassword for", form.ownerDocument.documentURI);
-      this._asyncFindLogins(form, { showMasterPassword: true })
-          .then(this.loginsFound.bind(this))
-          .then(null, Cu.reportError);
-    },
+    let form = event.target;
+    log("onFormPassword for", form.ownerDocument.documentURI);
+    this._asyncFindLogins(form, { showMasterPassword: true })
+        .then(this.loginsFound.bind(this))
+        .then(null, Cu.reportError);
+  },
 
-    loginsFound: function({ form, loginsFound }) {
-        let doc = form.ownerDocument;
-        let autofillForm = gAutofillForms && !PrivateBrowsingUtils.isContentWindowPrivate(doc.defaultView);
+  loginsFound: function({ form, loginsFound }) {
+    let doc = form.ownerDocument;
+    let autofillForm = gAutofillForms && !PrivateBrowsingUtils.isContentWindowPrivate(doc.defaultView);
 
-        this._fillForm(form, autofillForm, false, false, false, loginsFound);
-    },
+    this._fillForm(form, autofillForm, false, false, false, loginsFound);
+  },
 
-    /*
-     * onUsernameInput
-     *
-     * Listens for DOMAutoComplete and blur events on an input field.
-     */
-    onUsernameInput : function(event) {
-        if (!event.isTrusted)
-            return;
+  /*
+   * onUsernameInput
+   *
+   * Listens for DOMAutoComplete and blur events on an input field.
+   */
+  onUsernameInput : function(event) {
+    if (!event.isTrusted)
+      return;
 
-        if (!gEnabled)
-            return;
+    if (!gEnabled)
+      return;
 
-        var acInputField = event.target;
+    var acInputField = event.target;
 
-        // This is probably a bit over-conservatative.
-        if (!(acInputField.ownerDocument instanceof Ci.nsIDOMHTMLDocument))
-            return;
+    // This is probably a bit over-conservatative.
+    if (!(acInputField.ownerDocument instanceof Ci.nsIDOMHTMLDocument))
+      return;
 
-        if (!this._isUsernameFieldType(acInputField))
-            return;
+    if (!this._isUsernameFieldType(acInputField))
+      return;
 
-        var acForm = acInputField.form;
-        if (!acForm)
-            return;
+    var acForm = acInputField.form;
+    if (!acForm)
+      return;
 
-        // If the username is blank, bail out now -- we don't want
-        // fillForm() to try filling in a login without a username
-        // to filter on (bug 471906).
-        if (!acInputField.value)
-            return;
+    // If the username is blank, bail out now -- we don't want
+    // fillForm() to try filling in a login without a username
+    // to filter on (bug 471906).
+    if (!acInputField.value)
+      return;
 
-        log("onUsernameInput from", event.type);
+    log("onUsernameInput from", event.type);
 
-        // Make sure the username field fillForm will use is the
-        // same field as the autocomplete was activated on.
-        var [usernameField, passwordField, ignored] =
-            this._getFormFields(acForm, false);
-        if (usernameField == acInputField && passwordField) {
-            this._asyncFindLogins(acForm, { showMasterPassword: false })
-                .then(({ form, loginsFound }) => {
-                    this._fillForm(form, true, true, true, true, loginsFound);
-                })
-                .then(null, Cu.reportError);
-        } else {
-            // Ignore the event, it's for some input we don't care about.
-        }
-    },
+    // Make sure the username field fillForm will use is the
+    // same field as the autocomplete was activated on.
+    var [usernameField, passwordField, ignored] =
+        this._getFormFields(acForm, false);
+    if (usernameField == acInputField && passwordField) {
+      this._asyncFindLogins(acForm, { showMasterPassword: false })
+          .then(({ form, loginsFound }) => {
+              this._fillForm(form, true, true, true, true, loginsFound);
+          })
+          .then(null, Cu.reportError);
+    } else {
+      // Ignore the event, it's for some input we don't care about.
+    }
+  },
 
 
-    /*
-     * _getPasswordFields
-     *
-     * Returns an array of password field elements for the specified form.
-     * If no pw fields are found, or if more than 3 are found, then null
-     * is returned.
-     *
-     * skipEmptyFields can be set to ignore password fields with no value.
-     */
-    _getPasswordFields : function (form, skipEmptyFields) {
-        // Locate the password fields in the form.
-        var pwFields = [];
-        for (var i = 0; i < form.elements.length; i++) {
-            var element = form.elements[i];
-            if (!(element instanceof Ci.nsIDOMHTMLInputElement) ||
-                element.type != "password")
-                continue;
+  /*
+   * _getPasswordFields
+   *
+   * Returns an array of password field elements for the specified form.
+   * If no pw fields are found, or if more than 3 are found, then null
+   * is returned.
+   *
+   * skipEmptyFields can be set to ignore password fields with no value.
+   */
+  _getPasswordFields : function (form, skipEmptyFields) {
+    // Locate the password fields in the form.
+    var pwFields = [];
+    for (var i = 0; i < form.elements.length; i++) {
+      var element = form.elements[i];
+      if (!(element instanceof Ci.nsIDOMHTMLInputElement) ||
+          element.type != "password")
+        continue;
 
-            if (skipEmptyFields && !element.value)
-                continue;
+      if (skipEmptyFields && !element.value)
+        continue;
 
-            pwFields[pwFields.length] = {
-                                            index   : i,
-                                            element : element
-                                        };
-        }
+      pwFields[pwFields.length] = {
+                                    index   : i,
+                                    element : element
+                                  };
+    }
 
-        // If too few or too many fields, bail out.
-        if (pwFields.length == 0) {
-            log("(form ignored -- no password fields.)");
-            return null;
-        } else if (pwFields.length > 3) {
-            log("(form ignored -- too many password fields. [ got ",
-                        pwFields.length, "])");
-            return null;
-        }
+    // If too few or too many fields, bail out.
+    if (pwFields.length == 0) {
+      log("(form ignored -- no password fields.)");
+      return null;
+    } else if (pwFields.length > 3) {
+      log("(form ignored -- too many password fields. [ got ",
+                  pwFields.length, "])");
+      return null;
+    }
 
-        return pwFields;
-    },
+    return pwFields;
+  },
 
 
-    _isUsernameFieldType: function(element) {
-        if (!(element instanceof Ci.nsIDOMHTMLInputElement))
-            return false;
+  _isUsernameFieldType: function(element) {
+    if (!(element instanceof Ci.nsIDOMHTMLInputElement))
+      return false;
 
-        let fieldType = (element.hasAttribute("type") ?
-                         element.getAttribute("type").toLowerCase() :
-                         element.type);
-        if (fieldType == "text"  ||
-            fieldType == "email" ||
-            fieldType == "url"   ||
-            fieldType == "tel"   ||
-            fieldType == "number") {
-            return true;
-        }
-        return false;
-    },
+    let fieldType = (element.hasAttribute("type") ?
+                     element.getAttribute("type").toLowerCase() :
+                     element.type);
+    if (fieldType == "text"  ||
+        fieldType == "email" ||
+        fieldType == "url"   ||
+        fieldType == "tel"   ||
+        fieldType == "number") {
+      return true;
+    }
+    return false;
+  },
 
 
-    /*
-     * _getFormFields
-     *
-     * Returns the username and password fields found in the form.
-     * Can handle complex forms by trying to figure out what the
-     * relevant fields are.
-     *
-     * Returns: [usernameField, newPasswordField, oldPasswordField]
-     *
-     * usernameField may be null.
-     * newPasswordField will always be non-null.
-     * oldPasswordField may be null. If null, newPasswordField is just
-     * "theLoginField". If not null, the form is apparently a
-     * change-password field, with oldPasswordField containing the password
-     * that is being changed.
-     */
-    _getFormFields : function (form, isSubmission) {
-        var usernameField = null;
+  /*
+   * _getFormFields
+   *
+   * Returns the username and password fields found in the form.
+   * Can handle complex forms by trying to figure out what the
+   * relevant fields are.
+   *
+   * Returns: [usernameField, newPasswordField, oldPasswordField]
+   *
+   * usernameField may be null.
+   * newPasswordField will always be non-null.
+   * oldPasswordField may be null. If null, newPasswordField is just
+   * "theLoginField". If not null, the form is apparently a
+   * change-password field, with oldPasswordField containing the password
+   * that is being changed.
+   */
+  _getFormFields : function (form, isSubmission) {
+    var usernameField = null;
 
-        // Locate the password field(s) in the form. Up to 3 supported.
-        // If there's no password field, there's nothing for us to do.
-        var pwFields = this._getPasswordFields(form, isSubmission);
-        if (!pwFields)
-            return [null, null, null];
+    // Locate the password field(s) in the form. Up to 3 supported.
+    // If there's no password field, there's nothing for us to do.
+    var pwFields = this._getPasswordFields(form, isSubmission);
+    if (!pwFields)
+      return [null, null, null];
 
 
-        // Locate the username field in the form by searching backwards
-        // from the first passwordfield, assume the first text field is the
-        // username. We might not find a username field if the user is
-        // already logged in to the site.
-        for (var i = pwFields[0].index - 1; i >= 0; i--) {
-            var element = form.elements[i];
-            if (this._isUsernameFieldType(element)) {
-                usernameField = element;
-                break;
-            }
-        }
+    // Locate the username field in the form by searching backwards
+    // from the first passwordfield, assume the first text field is the
+    // username. We might not find a username field if the user is
+    // already logged in to the site.
+    for (var i = pwFields[0].index - 1; i >= 0; i--) {
+      var element = form.elements[i];
+      if (this._isUsernameFieldType(element)) {
+        usernameField = element;
+        break;
+      }
+    }
 
-        if (!usernameField)
-            log("(form -- no username field found)");
+    if (!usernameField)
+      log("(form -- no username field found)");
 
 
-        // If we're not submitting a form (it's a page load), there are no
-        // password field values for us to use for identifying fields. So,
-        // just assume the first password field is the one to be filled in.
-        if (!isSubmission || pwFields.length == 1)
-            return [usernameField, pwFields[0].element, null];
+    // If we're not submitting a form (it's a page load), there are no
+    // password field values for us to use for identifying fields. So,
+    // just assume the first password field is the one to be filled in.
+    if (!isSubmission || pwFields.length == 1)
+      return [usernameField, pwFields[0].element, null];
 
 
-        // Try to figure out WTF is in the form based on the password values.
-        var oldPasswordField, newPasswordField;
-        var pw1 = pwFields[0].element.value;
-        var pw2 = pwFields[1].element.value;
-        var pw3 = (pwFields[2] ? pwFields[2].element.value : null);
+    // Try to figure out WTF is in the form based on the password values.
+    var oldPasswordField, newPasswordField;
+    var pw1 = pwFields[0].element.value;
+    var pw2 = pwFields[1].element.value;
+    var pw3 = (pwFields[2] ? pwFields[2].element.value : null);
 
-        if (pwFields.length == 3) {
-            // Look for two identical passwords, that's the new password
+    if (pwFields.length == 3) {
+      // Look for two identical passwords, that's the new password
 
-            if (pw1 == pw2 && pw2 == pw3) {
-                // All 3 passwords the same? Weird! Treat as if 1 pw field.
-                newPasswordField = pwFields[0].element;
-                oldPasswordField = null;
-            } else if (pw1 == pw2) {
-                newPasswordField = pwFields[0].element;
-                oldPasswordField = pwFields[2].element;
-            } else if (pw2 == pw3) {
-                oldPasswordField = pwFields[0].element;
-                newPasswordField = pwFields[2].element;
-            } else  if (pw1 == pw3) {
-                // A bit odd, but could make sense with the right page layout.
-                newPasswordField = pwFields[0].element;
-                oldPasswordField = pwFields[1].element;
-            } else {
-                // We can't tell which of the 3 passwords should be saved.
-                log("(form ignored -- all 3 pw fields differ)");
-                return [null, null, null];
-            }
-        } else { // pwFields.length == 2
-            if (pw1 == pw2) {
-                // Treat as if 1 pw field
-                newPasswordField = pwFields[0].element;
-                oldPasswordField = null;
-            } else {
-                // Just assume that the 2nd password is the new password
-                oldPasswordField = pwFields[0].element;
-                newPasswordField = pwFields[1].element;
-            }
-        }
+      if (pw1 == pw2 && pw2 == pw3) {
+        // All 3 passwords the same? Weird! Treat as if 1 pw field.
+        newPasswordField = pwFields[0].element;
+        oldPasswordField = null;
+      } else if (pw1 == pw2) {
+        newPasswordField = pwFields[0].element;
+        oldPasswordField = pwFields[2].element;
+      } else if (pw2 == pw3) {
+        oldPasswordField = pwFields[0].element;
+        newPasswordField = pwFields[2].element;
+      } else  if (pw1 == pw3) {
+        // A bit odd, but could make sense with the right page layout.
+        newPasswordField = pwFields[0].element;
+        oldPasswordField = pwFields[1].element;
+      } else {
+        // We can't tell which of the 3 passwords should be saved.
+        log("(form ignored -- all 3 pw fields differ)");
+        return [null, null, null];
+      }
+    } else { // pwFields.length == 2
+      if (pw1 == pw2) {
+        // Treat as if 1 pw field
+        newPasswordField = pwFields[0].element;
+        oldPasswordField = null;
+      } else {
+        // Just assume that the 2nd password is the new password
+        oldPasswordField = pwFields[0].element;
+        newPasswordField = pwFields[1].element;
+      }
+    }
 
-        return [usernameField, newPasswordField, oldPasswordField];
-    },
+    return [usernameField, newPasswordField, oldPasswordField];
+  },
 
 
-    /*
-     * _isAutoCompleteDisabled
-     *
-     * Returns true if the page requests autocomplete be disabled for the
-     * specified form input.
-     */
-    _isAutocompleteDisabled :  function (element) {
-        if (element && element.hasAttribute("autocomplete") &&
-            element.getAttribute("autocomplete").toLowerCase() == "off")
-            return true;
-        
-        return false;
-    },
+  /*
+   * _isAutoCompleteDisabled
+   *
+   * Returns true if the page requests autocomplete be disabled for the
+   * specified form input.
+   */
+  _isAutocompleteDisabled :  function (element) {
+    if (element && element.hasAttribute("autocomplete") &&
+        element.getAttribute("autocomplete").toLowerCase() == "off")
+      return true;
+
+    return false;
+  },
 
 
-    /*
-     * _onFormSubmit
-     *
-     * Called by the our observer when notified of a form submission.
-     * [Note that this happens before any DOM onsubmit handlers are invoked.]
-     * Looks for a password change in the submitted form, so we can update
-     * our stored password.
-     */
-    _onFormSubmit : function (form) {
-        var doc = form.ownerDocument;
-        var win = doc.defaultView;
+  /*
+   * _onFormSubmit
+   *
+   * Called by the our observer when notified of a form submission.
+   * [Note that this happens before any DOM onsubmit handlers are invoked.]
+   * Looks for a password change in the submitted form, so we can update
+   * our stored password.
+   */
+  _onFormSubmit : function (form) {
+    var doc = form.ownerDocument;
+    var win = doc.defaultView;
 
-        if (PrivateBrowsingUtils.isContentWindowPrivate(win)) {
-            // We won't do anything in private browsing mode anyway,
-            // so there's no need to perform further checks.
-            log("(form submission ignored in private browsing mode)");
-            return;
-        }
+    if (PrivateBrowsingUtils.isContentWindowPrivate(win)) {
+      // We won't do anything in private browsing mode anyway,
+      // so there's no need to perform further checks.
+      log("(form submission ignored in private browsing mode)");
+      return;
+    }
 
-        // If password saving is disabled (globally or for host), bail out now.
-        if (!gEnabled)
-            return;
+    // If password saving is disabled (globally or for host), bail out now.
+    if (!gEnabled)
+      return;
 
-        var hostname = LoginUtils._getPasswordOrigin(doc.documentURI);
-        if (!hostname) {
-            log("(form submission ignored -- invalid hostname)");
-            return;
-        }
+    var hostname = LoginUtils._getPasswordOrigin(doc.documentURI);
+    if (!hostname) {
+      log("(form submission ignored -- invalid hostname)");
+      return;
+    }
 
-        // Somewhat gross hack - we don't want to show the "remember password"
-        // notification on about:accounts for Firefox.
-        let topWin = win.top;
-        if (/^about:accounts($|\?)/i.test(topWin.document.documentURI)) {
-            log("(form submission ignored -- about:accounts)");
-            return;
-        }
+    // Somewhat gross hack - we don't want to show the "remember password"
+    // notification on about:accounts for Firefox.
+    let topWin = win.top;
+    if (/^about:accounts($|\?)/i.test(topWin.document.documentURI)) {
+      log("(form submission ignored -- about:accounts)");
+      return;
+    }
 
-        var formSubmitURL = LoginUtils._getActionOrigin(form)
+    var formSubmitURL = LoginUtils._getActionOrigin(form)
 
-        // Get the appropriate fields from the form.
-        var [usernameField, newPasswordField, oldPasswordField] =
-            this._getFormFields(form, true);
+    // Get the appropriate fields from the form.
+    var [usernameField, newPasswordField, oldPasswordField] =
+        this._getFormFields(form, true);
 
-        // Need at least 1 valid password field to do anything.
-        if (newPasswordField == null)
-            return;
+    // Need at least 1 valid password field to do anything.
+    if (newPasswordField == null)
+      return;
 
-        // Check for autocomplete=off attribute. We don't use it to prevent
-        // autofilling (for existing logins), but won't save logins when it's
-        // present and the storeWhenAutocompleteOff pref is false.
-        // XXX spin out a bug that we don't update timeLastUsed in this case?
-        if ((this._isAutocompleteDisabled(form) ||
-             this._isAutocompleteDisabled(usernameField) ||
-             this._isAutocompleteDisabled(newPasswordField) ||
-             this._isAutocompleteDisabled(oldPasswordField)) &&
-            !gStoreWhenAutocompleteOff) {
-                log("(form submission ignored -- autocomplete=off found)");
-                return;
-        }
+    // Check for autocomplete=off attribute. We don't use it to prevent
+    // autofilling (for existing logins), but won't save logins when it's
+    // present and the storeWhenAutocompleteOff pref is false.
+    // XXX spin out a bug that we don't update timeLastUsed in this case?
+    if ((this._isAutocompleteDisabled(form) ||
+         this._isAutocompleteDisabled(usernameField) ||
+         this._isAutocompleteDisabled(newPasswordField) ||
+         this._isAutocompleteDisabled(oldPasswordField)) &&
+        !gStoreWhenAutocompleteOff) {
+      log("(form submission ignored -- autocomplete=off found)");
+      return;
+    }
 
-        // Don't try to send DOM nodes over IPC.
-        let mockUsername = usernameField ?
-                             { name: usernameField.name,
-                               value: usernameField.value } :
-                             null;
-        let mockPassword = { name: newPasswordField.name,
-                             value: newPasswordField.value };
-        let mockOldPassword = oldPasswordField ?
-                                { name: oldPasswordField.name,
-                                  value: oldPasswordField.value } :
-                                null;
+    // Don't try to send DOM nodes over IPC.
+    let mockUsername = usernameField ?
+                         { name: usernameField.name,
+                           value: usernameField.value } :
+                         null;
+    let mockPassword = { name: newPasswordField.name,
+                         value: newPasswordField.value };
+    let mockOldPassword = oldPasswordField ?
+                            { name: oldPasswordField.name,
+                              value: oldPasswordField.value } :
+                            null;
 
-        // Make sure to pass the opener's top in case it was in a frame.
-        let opener = win.opener ? win.opener.top : null;
+    // Make sure to pass the opener's top in case it was in a frame.
+    let opener = win.opener ? win.opener.top : null;
 
-        let messageManager = messageManagerFromWindow(win);
-        messageManager.sendAsyncMessage("RemoteLogins:onFormSubmit",
-                                        { hostname: hostname,
-                                          formSubmitURL: formSubmitURL,
-                                          usernameField: mockUsername,
-                                          newPasswordField: mockPassword,
-                                          oldPasswordField: mockOldPassword },
-                                        { openerWin: opener });
-    },
+    let messageManager = messageManagerFromWindow(win);
+    messageManager.sendAsyncMessage("RemoteLogins:onFormSubmit",
+                                    { hostname: hostname,
+                                      formSubmitURL: formSubmitURL,
+                                      usernameField: mockUsername,
+                                      newPasswordField: mockPassword,
+                                      oldPasswordField: mockOldPassword },
+                                    { openerWin: opener });
+  },
 
-    /*
-     * _fillform
-     *
-     * Fill the form with login information if we can find it. This will find
-     * an array of logins if not given any, otherwise it will use the logins
-     * passed in. The logins are returned so they can be reused for
-     * optimization. Success of action is also returned in format
-     * [success, foundLogins].
-     *
-     * - autofillForm denotes if we should fill the form in automatically
-     * - ignoreAutocomplete denotes if we should ignore autocomplete=off
-     *     attributes
-     * - userTriggered is an indication of whether this filling was triggered by
-     *     the user
-     * - foundLogins is an array of nsILoginInfo for optimization
-     */
-    _fillForm : function (form, autofillForm, ignoreAutocomplete,
-                          clobberPassword, userTriggered, foundLogins) {
-        // Heuristically determine what the user/pass fields are
-        // We do this before checking to see if logins are stored,
-        // so that the user isn't prompted for a master password
-        // without need.
-        var [usernameField, passwordField, ignored] =
-            this._getFormFields(form, false);
+  /*
+   * _fillform
+   *
+   * Fill the form with login information if we can find it. This will find
+   * an array of logins if not given any, otherwise it will use the logins
+   * passed in. The logins are returned so they can be reused for
+   * optimization. Success of action is also returned in format
+   * [success, foundLogins].
+   *
+   * - autofillForm denotes if we should fill the form in automatically
+   * - ignoreAutocomplete denotes if we should ignore autocomplete=off
+   *     attributes
+   * - userTriggered is an indication of whether this filling was triggered by
+   *     the user
+   * - foundLogins is an array of nsILoginInfo for optimization
+   */
+  _fillForm : function (form, autofillForm, ignoreAutocomplete,
+                        clobberPassword, userTriggered, foundLogins) {
+    // Heuristically determine what the user/pass fields are
+    // We do this before checking to see if logins are stored,
+    // so that the user isn't prompted for a master password
+    // without need.
+    var [usernameField, passwordField, ignored] =
+        this._getFormFields(form, false);
 
-        // Need a valid password field to do anything.
-        if (passwordField == null)
-            return [false, foundLogins];
+    // Need a valid password field to do anything.
+    if (passwordField == null)
+      return [false, foundLogins];
 
-        // If the password field is disabled or read-only, there's nothing to do.
-        if (passwordField.disabled || passwordField.readOnly) {
-            log("not filling form, password field disabled or read-only");
-            return [false, foundLogins];
-        }
+    // If the password field is disabled or read-only, there's nothing to do.
+    if (passwordField.disabled || passwordField.readOnly) {
+      log("not filling form, password field disabled or read-only");
+      return [false, foundLogins];
+    }
 
-        // Discard logins which have username/password values that don't
-        // fit into the fields (as specified by the maxlength attribute).
-        // The user couldn't enter these values anyway, and it helps
-        // with sites that have an extra PIN to be entered (bug 391514)
-        var maxUsernameLen = Number.MAX_VALUE;
-        var maxPasswordLen = Number.MAX_VALUE;
+    // Discard logins which have username/password values that don't
+    // fit into the fields (as specified by the maxlength attribute).
+    // The user couldn't enter these values anyway, and it helps
+    // with sites that have an extra PIN to be entered (bug 391514)
+    var maxUsernameLen = Number.MAX_VALUE;
+    var maxPasswordLen = Number.MAX_VALUE;
 
-        // If attribute wasn't set, default is -1.
-        if (usernameField && usernameField.maxLength >= 0)
-            maxUsernameLen = usernameField.maxLength;
-        if (passwordField.maxLength >= 0)
-            maxPasswordLen = passwordField.maxLength;
+    // If attribute wasn't set, default is -1.
+    if (usernameField && usernameField.maxLength >= 0)
+      maxUsernameLen = usernameField.maxLength;
+    if (passwordField.maxLength >= 0)
+      maxPasswordLen = passwordField.maxLength;
 
-        foundLogins = foundLogins.map(login => {
-            var formLogin = Cc["@mozilla.org/login-manager/loginInfo;1"].
-                            createInstance(Ci.nsILoginInfo);
-            formLogin.init(login.hostname, login.formSubmitURL,
-                           login.httpRealm, login.username,
-                           login.password, login.usernameField,
-                           login.passwordField);
-            return formLogin;
-        });
-        var logins = foundLogins.filter(function (l) {
-                var fit = (l.username.length <= maxUsernameLen &&
-                           l.password.length <= maxPasswordLen);
-                if (!fit)
-                    log("Ignored", l.username, "login: won't fit");
+    foundLogins = foundLogins.map(login => {
+      var formLogin = Cc["@mozilla.org/login-manager/loginInfo;1"].
+                      createInstance(Ci.nsILoginInfo);
+      formLogin.init(login.hostname, login.formSubmitURL,
+                     login.httpRealm, login.username,
+                     login.password, login.usernameField,
+                     login.passwordField);
+      return formLogin;
+    });
+    var logins = foundLogins.filter(function (l) {
+      var fit = (l.username.length <= maxUsernameLen &&
+                 l.password.length <= maxPasswordLen);
+      if (!fit)
+        log("Ignored", l.username, "login: won't fit");
 
-                return fit;
-            }, this);
+      return fit;
+    }, this);
 
 
-        // Nothing to do if we have no matching logins available.
-        if (logins.length == 0)
-            return [false, foundLogins];
+    // Nothing to do if we have no matching logins available.
+    if (logins.length == 0)
+      return [false, foundLogins];
 
 
-        // The reason we didn't end up filling the form, if any.  We include
-        // this in the formInfo object we send with the passwordmgr-found-logins
-        // notification.  See the _notifyFoundLogins docs for possible values.
-        var didntFillReason = null;
+    // The reason we didn't end up filling the form, if any.  We include
+    // this in the formInfo object we send with the passwordmgr-found-logins
+    // notification.  See the _notifyFoundLogins docs for possible values.
+    var didntFillReason = null;
 
-        // Attach autocomplete stuff to the username field, if we have
-        // one. This is normally used to select from multiple accounts,
-        // but even with one account we should refill if the user edits.
-        if (usernameField)
-            this._formFillService.markAsLoginManagerField(usernameField);
+    // Attach autocomplete stuff to the username field, if we have
+    // one. This is normally used to select from multiple accounts,
+    // but even with one account we should refill if the user edits.
+    if (usernameField)
+      this._formFillService.markAsLoginManagerField(usernameField);
 
-        // Don't clobber an existing password.
-        if (passwordField.value && !clobberPassword) {
-            didntFillReason = "existingPassword";
-            this._notifyFoundLogins(didntFillReason, usernameField,
-                                    passwordField, foundLogins, null);
-            return [false, foundLogins];
-        }
+    // Don't clobber an existing password.
+    if (passwordField.value && !clobberPassword) {
+      didntFillReason = "existingPassword";
+      this._notifyFoundLogins(didntFillReason, usernameField,
+                              passwordField, foundLogins, null);
+      return [false, foundLogins];
+    }
 
-        // If the form has an autocomplete=off attribute in play, don't
-        // fill in the login automatically. We check this after attaching
-        // the autocomplete stuff to the username field, so the user can
-        // still manually select a login to be filled in.
-        var isFormDisabled = false;
-        if (!ignoreAutocomplete &&
-            (this._isAutocompleteDisabled(form) ||
-             this._isAutocompleteDisabled(usernameField) ||
-             this._isAutocompleteDisabled(passwordField))) {
+    // If the form has an autocomplete=off attribute in play, don't
+    // fill in the login automatically. We check this after attaching
+    // the autocomplete stuff to the username field, so the user can
+    // still manually select a login to be filled in.
+    var isFormDisabled = false;
+    if (!ignoreAutocomplete &&
+        (this._isAutocompleteDisabled(form) ||
+         this._isAutocompleteDisabled(usernameField) ||
+         this._isAutocompleteDisabled(passwordField))) {
 
-            isFormDisabled = true;
-            log("form not filled, has autocomplete=off");
-        }
+      isFormDisabled = true;
+      log("form not filled, has autocomplete=off");
+    }
 
-        // Variable such that we reduce code duplication and can be sure we
-        // should be firing notifications if and only if we can fill the form.
-        var selectedLogin = null;
+    // Variable such that we reduce code duplication and can be sure we
+    // should be firing notifications if and only if we can fill the form.
+    var selectedLogin = null;
 
-        if (usernameField && (usernameField.value || usernameField.disabled || usernameField.readOnly)) {
-            // If username was specified in the field, it's disabled or it's readOnly, only fill in the
-            // password if we find a matching login.
-            var username = usernameField.value.toLowerCase();
+    if (usernameField && (usernameField.value || usernameField.disabled || usernameField.readOnly)) {
+      // If username was specified in the field, it's disabled or it's readOnly, only fill in the
+      // password if we find a matching login.
+      var username = usernameField.value.toLowerCase();
 
-            let matchingLogins = logins.filter(function(l)
-                                     l.username.toLowerCase() == username);
-            if (matchingLogins.length) {
-                // If there are multiple, and one matches case, use it
-                for (let l of matchingLogins) {
-                    if (l.username == usernameField.value) {
-                        selectedLogin = l;
-                    }
-                }
-                // Otherwise just use the first
-                if (!selectedLogin) {
-                  selectedLogin = matchingLogins[0];
-                }
-            } else {
-                didntFillReason = "existingUsername";
-                log("Password not filled. None of the stored logins match the username already present.");
-            }
-        } else if (logins.length == 1) {
-            selectedLogin = logins[0];
-        } else {
-            // We have multiple logins. Handle a special case here, for sites
-            // which have a normal user+pass login *and* a password-only login
-            // (eg, a PIN). Prefer the login that matches the type of the form
-            // (user+pass or pass-only) when there's exactly one that matches.
-            let matchingLogins;
-            if (usernameField)
-                matchingLogins = logins.filter(function(l) l.username);
-            else
-                matchingLogins = logins.filter(function(l) !l.username);
-            if (matchingLogins.length == 1) {
-                selectedLogin = matchingLogins[0];
-            } else {
-                didntFillReason = "multipleLogins";
-                log("Multiple logins for form, so not filling any.");
-            }
+      let matchingLogins = logins.filter(function(l)
+                                         l.username.toLowerCase() == username);
+      if (matchingLogins.length) {
+        // If there are multiple, and one matches case, use it
+        for (let l of matchingLogins) {
+          if (l.username == usernameField.value) {
+            selectedLogin = l;
+          }
+        }
+        // Otherwise just use the first
+        if (!selectedLogin) {
+          selectedLogin = matchingLogins[0];
         }
+      } else {
+        didntFillReason = "existingUsername";
+        log("Password not filled. None of the stored logins match the username already present.");
+      }
+    } else if (logins.length == 1) {
+      selectedLogin = logins[0];
+    } else {
+      // We have multiple logins. Handle a special case here, for sites
+      // which have a normal user+pass login *and* a password-only login
+      // (eg, a PIN). Prefer the login that matches the type of the form
+      // (user+pass or pass-only) when there's exactly one that matches.
+      let matchingLogins;
+      if (usernameField)
+        matchingLogins = logins.filter(function(l) l.username);
+      else
+        matchingLogins = logins.filter(function(l) !l.username);
+      if (matchingLogins.length == 1) {
+        selectedLogin = matchingLogins[0];
+      } else {
+        didntFillReason = "multipleLogins";
+        log("Multiple logins for form, so not filling any.");
+      }
+    }
 
-        var didFillForm = false;
-        if (selectedLogin && autofillForm && !isFormDisabled) {
-            // Fill the form
+    var didFillForm = false;
+    if (selectedLogin && autofillForm && !isFormDisabled) {
+      // Fill the form
 
-            if (usernameField) {
-                // Don't modify the username field if it's disabled or readOnly so we preserve its case.
-                let disabledOrReadOnly = usernameField.disabled || usernameField.readOnly;
+      if (usernameField) {
+        // Don't modify the username field if it's disabled or readOnly so we preserve its case.
+        let disabledOrReadOnly = usernameField.disabled || usernameField.readOnly;
 
-                let userNameDiffers = selectedLogin.username != usernameField.value;
-                // Don't replace the username if it differs only in case, and the user triggered
-                // this autocomplete. We assume that if it was user-triggered the entered text
-                // is desired.
-                let userEnteredDifferentCase = userTriggered && userNameDiffers &&
-                       usernameField.value.toLowerCase() == selectedLogin.username.toLowerCase();
+        let userNameDiffers = selectedLogin.username != usernameField.value;
+        // Don't replace the username if it differs only in case, and the user triggered
+        // this autocomplete. We assume that if it was user-triggered the entered text
+        // is desired.
+        let userEnteredDifferentCase = userTriggered && userNameDiffers &&
+               usernameField.value.toLowerCase() == selectedLogin.username.toLowerCase();
 
-                if (!disabledOrReadOnly && !userEnteredDifferentCase && userNameDiffers) {
-                    usernameField.setUserInput(selectedLogin.username);
-                }
-            }
-            if (passwordField.value != selectedLogin.password) {
-                passwordField.setUserInput(selectedLogin.password);
-            }
-            didFillForm = true;
-        } else if (selectedLogin && !autofillForm) {
-            // For when autofillForm is false, but we still have the information
-            // to fill a form, we notify observers.
-            didntFillReason = "noAutofillForms";
-            Services.obs.notifyObservers(form, "passwordmgr-found-form", didntFillReason);
-            log("autofillForms=false but form can be filled; notified observers");
-        } else if (selectedLogin && isFormDisabled) {
-            // For when autocomplete is off, but we still have the information
-            // to fill a form, we notify observers.
-            didntFillReason = "autocompleteOff";
-            Services.obs.notifyObservers(form, "passwordmgr-found-form", didntFillReason);
-            log("autocomplete=off but form can be filled; notified observers");
+        if (!disabledOrReadOnly && !userEnteredDifferentCase && userNameDiffers) {
+          usernameField.setUserInput(selectedLogin.username);
         }
+      }
+      if (passwordField.value != selectedLogin.password) {
+        passwordField.setUserInput(selectedLogin.password);
+      }
+      didFillForm = true;
+    } else if (selectedLogin && !autofillForm) {
+      // For when autofillForm is false, but we still have the information
+      // to fill a form, we notify observers.
+      didntFillReason = "noAutofillForms";
+      Services.obs.notifyObservers(form, "passwordmgr-found-form", didntFillReason);
+      log("autofillForms=false but form can be filled; notified observers");
+    } else if (selectedLogin && isFormDisabled) {
+      // For when autocomplete is off, but we still have the information
+      // to fill a form, we notify observers.
+      didntFillReason = "autocompleteOff";
+      Services.obs.notifyObservers(form, "passwordmgr-found-form", didntFillReason);
+      log("autocomplete=off but form can be filled; notified observers");
+    }
 
-        this._notifyFoundLogins(didntFillReason, usernameField, passwordField,
-                                foundLogins, selectedLogin);
+    this._notifyFoundLogins(didntFillReason, usernameField, passwordField,
+                            foundLogins, selectedLogin);
 
-        return [didFillForm, foundLogins];
-    },
+    return [didFillForm, foundLogins];
+  },
 
 
-    /**
-     * Notify observers about an attempt to fill a form that resulted in some
-     * saved logins being found for the form.
-     *
-     * This does not get called if the login manager attempts to fill a form
-     * but does not find any saved logins.  It does, however, get called when
-     * the login manager does find saved logins whether or not it actually
-     * fills the form with one of them.
-     *
-     * @param didntFillReason {String}
-     *        the reason the login manager didn't fill the form, if any;
-     *        if the value of this parameter is null, then the form was filled;
-     *        otherwise, this parameter will be one of these values:
-     *          existingUsername: the username field already contains a username
-     *                            that doesn't match any stored usernames
-     *          existingPassword: the password field already contains a password
-     *          autocompleteOff:  autocomplete has been disabled for the form
-     *                            or its username or password fields
-     *          multipleLogins:   we have multiple logins for the form
-     *          noAutofillForms:  the autofillForms pref is set to false
-     *
-     * @param usernameField   {HTMLInputElement}
-     *        the username field detected by the login manager, if any;
-     *        otherwise null
-     *
-     * @param passwordField   {HTMLInputElement}
-     *        the password field detected by the login manager
-     *
-     * @param foundLogins     {Array}
-     *        an array of nsILoginInfos that can be used to fill the form
-     *
-     * @param selectedLogin   {nsILoginInfo}
-     *        the nsILoginInfo that was/would be used to fill the form, if any;
-     *        otherwise null; whether or not it was actually used depends on
-     *        the value of the didntFillReason parameter
-     */
-    _notifyFoundLogins : function (didntFillReason, usernameField,
-                                   passwordField, foundLogins, selectedLogin) {
-        // We need .setProperty(), which is a method on the original
-        // nsIWritablePropertyBag. Strangley enough, nsIWritablePropertyBag2
-        // doesn't inherit from that, so the additional QI is needed.
-        let formInfo = Cc["@mozilla.org/hash-property-bag;1"].
-                       createInstance(Ci.nsIWritablePropertyBag2).
-                       QueryInterface(Ci.nsIWritablePropertyBag);
+  /**
+   * Notify observers about an attempt to fill a form that resulted in some
+   * saved logins being found for the form.
+   *
+   * This does not get called if the login manager attempts to fill a form
+   * but does not find any saved logins.  It does, however, get called when
+   * the login manager does find saved logins whether or not it actually
+   * fills the form with one of them.
+   *
+   * @param didntFillReason {String}
+   *        the reason the login manager didn't fill the form, if any;
+   *        if the value of this parameter is null, then the form was filled;
+   *        otherwise, this parameter will be one of these values:
+   *          existingUsername: the username field already contains a username
+   *                            that doesn't match any stored usernames
+   *          existingPassword: the password field already contains a password
+   *          autocompleteOff:  autocomplete has been disabled for the form
+   *                            or its username or password fields
+   *          multipleLogins:   we have multiple logins for the form
+   *          noAutofillForms:  the autofillForms pref is set to false
+   *
+   * @param usernameField   {HTMLInputElement}
+   *        the username field detected by the login manager, if any;
+   *        otherwise null
+   *
+   * @param passwordField   {HTMLInputElement}
+   *        the password field detected by the login manager
+   *
+   * @param foundLogins     {Array}
+   *        an array of nsILoginInfos that can be used to fill the form
+   *
+   * @param selectedLogin   {nsILoginInfo}
+   *        the nsILoginInfo that was/would be used to fill the form, if any;
+   *        otherwise null; whether or not it was actually used depends on
+   *        the value of the didntFillReason parameter
+   */
+  _notifyFoundLogins : function (didntFillReason, usernameField,
+                                 passwordField, foundLogins, selectedLogin) {
+    // We need .setProperty(), which is a method on the original
+    // nsIWritablePropertyBag. Strangley enough, nsIWritablePropertyBag2
+    // doesn't inherit from that, so the additional QI is needed.
+    let formInfo = Cc["@mozilla.org/hash-property-bag;1"].
+                   createInstance(Ci.nsIWritablePropertyBag2).
+                   QueryInterface(Ci.nsIWritablePropertyBag);
 
-        formInfo.setPropertyAsACString("didntFillReason", didntFillReason);
-        formInfo.setPropertyAsInterface("usernameField", usernameField);
-        formInfo.setPropertyAsInterface("passwordField", passwordField);
-        formInfo.setProperty("foundLogins", foundLogins.concat());
-        formInfo.setPropertyAsInterface("selectedLogin", selectedLogin);
+    formInfo.setPropertyAsACString("didntFillReason", didntFillReason);
+    formInfo.setPropertyAsInterface("usernameField", usernameField);
+    formInfo.setPropertyAsInterface("passwordField", passwordField);
+    formInfo.setProperty("foundLogins", foundLogins.concat());
+    formInfo.setPropertyAsInterface("selectedLogin", selectedLogin);
 
-        Services.obs.notifyObservers(formInfo, "passwordmgr-found-logins", null);
-    },
+    Services.obs.notifyObservers(formInfo, "passwordmgr-found-logins", null);
+  },
 
 };
 
 var LoginUtils = {
-    /*
-     * _getPasswordOrigin
-     *
-     * Get the parts of the URL we want for identification.
-     */
-    _getPasswordOrigin : function (uriString, allowJS) {
-        var realm = "";
-        try {
-            var uri = Services.io.newURI(uriString, null, null);
+  /*
+   * _getPasswordOrigin
+   *
+   * Get the parts of the URL we want for identification.
+   */
+  _getPasswordOrigin : function (uriString, allowJS) {
+    var realm = "";
+    try {
+      var uri = Services.io.newURI(uriString, null, null);
 
-            if (allowJS && uri.scheme == "javascript")
-                return "javascript:"
+      if (allowJS && uri.scheme == "javascript")
+        return "javascript:"
 
-            realm = uri.scheme + "://" + uri.host;
+      realm = uri.scheme + "://" + uri.host;
 
-            // If the URI explicitly specified a port, only include it when
-            // it's not the default. (We never want "http://foo.com:80")
-            var port = uri.port;
-            if (port != -1) {
-                var handler = Services.io.getProtocolHandler(uri.scheme);
-                if (port != handler.defaultPort)
-                    realm += ":" + port;
-            }
+      // If the URI explicitly specified a port, only include it when
+      // it's not the default. (We never want "http://foo.com:80")
+      var port = uri.port;
+      if (port != -1) {
+        var handler = Services.io.getProtocolHandler(uri.scheme);
+        if (port != handler.defaultPort)
+          realm += ":" + port;
+      }
 
-        } catch (e) {
-            // bug 159484 - disallow url types that don't support a hostPort.
-            // (although we handle "javascript:..." as a special case above.)
-            log("Couldn't parse origin for", uriString);
-            realm = null;
-        }
+    } catch (e) {
+      // bug 159484 - disallow url types that don't support a hostPort.
+      // (although we handle "javascript:..." as a special case above.)
+      log("Couldn't parse origin for", uriString);
+      realm = null;
+    }
 
-        return realm;
-    },
+    return realm;
+  },
 
-    _getActionOrigin : function (form) {
-        var uriString = form.action;
+  _getActionOrigin : function (form) {
+    var uriString = form.action;
 
-        // A blank or missing action submits to where it came from.
-        if (uriString == "")
-            uriString = form.baseURI; // ala bug 297761
+    // A blank or missing action submits to where it came from.
+    if (uriString == "")
+      uriString = form.baseURI; // ala bug 297761
 
-        return this._getPasswordOrigin(uriString, true);
-    },
+    return this._getPasswordOrigin(uriString, true);
+  },
 
 };
 
 // nsIAutoCompleteResult implementation
 function UserAutoCompleteResult (aSearchString, matchingLogins) {
-    function loginSort(a,b) {
-        var userA = a.username.toLowerCase();
-        var userB = b.username.toLowerCase();
+  function loginSort(a,b) {
+    var userA = a.username.toLowerCase();
+    var userB = b.username.toLowerCase();
 
-        if (userA < userB)
-            return -1;
+    if (userA < userB)
+      return -1;
 
-        if (userB > userA)
-            return  1;
+    if (userB > userA)
+      return  1;
 
-        return 0;
-    };
+    return 0;
+  };
 
-    this.searchString = aSearchString;
-    this.logins = matchingLogins.sort(loginSort);
-    this.matchCount = matchingLogins.length;
+  this.searchString = aSearchString;
+  this.logins = matchingLogins.sort(loginSort);
+  this.matchCount = matchingLogins.length;
 
-    if (this.matchCount > 0) {
-        this.searchResult = Ci.nsIAutoCompleteResult.RESULT_SUCCESS;
-        this.defaultIndex = 0;
-    }
+  if (this.matchCount > 0) {
+    this.searchResult = Ci.nsIAutoCompleteResult.RESULT_SUCCESS;
+    this.defaultIndex = 0;
+  }
 }
 
 UserAutoCompleteResult.prototype = {
-    QueryInterface : XPCOMUtils.generateQI([Ci.nsIAutoCompleteResult,
-                                            Ci.nsISupportsWeakReference]),
+  QueryInterface : XPCOMUtils.generateQI([Ci.nsIAutoCompleteResult,
+                                          Ci.nsISupportsWeakReference]),
 
-    // private
-    logins : null,
+  // private
+  logins : null,
 
-    // Allow autoCompleteSearch to get at the JS object so it can
-    // modify some readonly properties for internal use.
-    get wrappedJSObject() {
-        return this;
-    },
+  // Allow autoCompleteSearch to get at the JS object so it can
+  // modify some readonly properties for internal use.
+  get wrappedJSObject() {
+    return this;
+  },
 
-    // Interfaces from idl...
-    searchString : null,
-    searchResult : Ci.nsIAutoCompleteResult.RESULT_NOMATCH,
-    defaultIndex : -1,
-    errorDescription : "",
-    matchCount : 0,
+  // Interfaces from idl...
+  searchString : null,
+  searchResult : Ci.nsIAutoCompleteResult.RESULT_NOMATCH,
+  defaultIndex : -1,
+  errorDescription : "",
+  matchCount : 0,
 
-    getValueAt : function (index) {
-        if (index < 0 || index >= this.logins.length)
-            throw "Index out of range.";
+  getValueAt : function (index) {
+    if (index < 0 || index >= this.logins.length)
+      throw "Index out of range.";
 
-        return this.logins[index].username;
-    },
+    return this.logins[index].username;
+  },
 
-    getLabelAt: function(index) {
-        return this.getValueAt(index);
-    },
+  getLabelAt: function(index) {
+    return this.getValueAt(index);
+  },
 
-    getCommentAt : function (index) {
-        return "";
-    },
+  getCommentAt : function (index) {
+    return "";
+  },
 
-    getStyleAt : function (index) {
-        return "";
-    },
+  getStyleAt : function (index) {
+    return "";
+  },
 
-    getImageAt : function (index) {
-        return "";
-    },
+  getImageAt : function (index) {
+    return "";
+  },
 
-    getFinalCompleteValueAt : function (index) {
-        return this.getValueAt(index);
-    },
+  getFinalCompleteValueAt : function (index) {
+    return this.getValueAt(index);
+  },
 
-    removeValueAt : function (index, removeFromDB) {
-        if (index < 0 || index >= this.logins.length)
-            throw "Index out of range.";
+  removeValueAt : function (index, removeFromDB) {
+    if (index < 0 || index >= this.logins.length)
+        throw "Index out of range.";
 
-        var [removedLogin] = this.logins.splice(index, 1);
+    var [removedLogin] = this.logins.splice(index, 1);
 
-        this.matchCount--;
-        if (this.defaultIndex > this.logins.length)
-            this.defaultIndex--;
+    this.matchCount--;
+    if (this.defaultIndex > this.logins.length)
+      this.defaultIndex--;
 
-        if (removeFromDB) {
-            var pwmgr = Cc["@mozilla.org/login-manager;1"].
-                        getService(Ci.nsILoginManager);
-            pwmgr.removeLogin(removedLogin);
-        }
+    if (removeFromDB) {
+      var pwmgr = Cc["@mozilla.org/login-manager;1"].
+                  getService(Ci.nsILoginManager);
+      pwmgr.removeLogin(removedLogin);
     }
+  }
 };
--- a/toolkit/components/passwordmgr/LoginManagerParent.jsm
+++ b/toolkit/components/passwordmgr/LoginManagerParent.jsm
@@ -1,9 +1,9 @@
-/* vim: set ts=4 sts=4 sw=4 et tw=80: */
+/* vim: set ts=2 sts=2 sw=2 et 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/. */
 
 "use strict";
 
 const Cu = Components.utils;
 const Ci = Components.interfaces;
@@ -17,306 +17,306 @@ XPCOMUtils.defineLazyModuleGetter(this, 
 XPCOMUtils.defineLazyModuleGetter(this, "AutoCompleteE10S",
                                   "resource://gre/modules/AutoCompleteE10S.jsm");
 
 this.EXPORTED_SYMBOLS = [ "LoginManagerParent" ];
 
 var gDebug;
 
 function log(...pieces) {
-    function generateLogMessage(args) {
-        let strings = ['Login Manager (parent):'];
+  function generateLogMessage(args) {
+    let strings = ['Login Manager (parent):'];
 
-        args.forEach(function(arg) {
-            if (typeof arg === 'string') {
-                strings.push(arg);
-            } else if (typeof arg === 'undefined') {
-                strings.push('undefined');
-            } else if (arg === null) {
-                strings.push('null');
-            } else {
-                try {
-                  strings.push(JSON.stringify(arg, null, 2));
-                } catch(err) {
-                  strings.push("<<something>>");
-                }
-            }
-        });
-        return strings.join(' ');
-    }
+    args.forEach(function(arg) {
+      if (typeof arg === 'string') {
+        strings.push(arg);
+      } else if (typeof arg === 'undefined') {
+        strings.push('undefined');
+      } else if (arg === null) {
+        strings.push('null');
+      } else {
+        try {
+          strings.push(JSON.stringify(arg, null, 2));
+        } catch(err) {
+          strings.push("<<something>>");
+        }
+      }
+    });
+    return strings.join(' ');
+  }
 
-    if (!gDebug)
-        return;
+  if (!gDebug)
+    return;
 
-    let message = generateLogMessage(pieces);
-    dump(message + "\n");
-    Services.console.logStringMessage(message);
+  let message = generateLogMessage(pieces);
+  dump(message + "\n");
+  Services.console.logStringMessage(message);
 }
 
 function prefChanged() {
-    gDebug = Services.prefs.getBoolPref("signon.debug");
+  gDebug = Services.prefs.getBoolPref("signon.debug");
 }
 
 Services.prefs.addObserver("signon.debug", prefChanged, false);
 prefChanged();
 
 var LoginManagerParent = {
-    init: function() {
-        let mm = Cc["@mozilla.org/globalmessagemanager;1"]
-                   .getService(Ci.nsIMessageListenerManager);
-        mm.addMessageListener("RemoteLogins:findLogins", this);
-        mm.addMessageListener("RemoteLogins:onFormSubmit", this);
-        mm.addMessageListener("RemoteLogins:autoCompleteLogins", this);
-    },
+  init: function() {
+    let mm = Cc["@mozilla.org/globalmessagemanager;1"]
+               .getService(Ci.nsIMessageListenerManager);
+    mm.addMessageListener("RemoteLogins:findLogins", this);
+    mm.addMessageListener("RemoteLogins:onFormSubmit", this);
+    mm.addMessageListener("RemoteLogins:autoCompleteLogins", this);
+  },
 
-    receiveMessage: function (msg) {
-        let data = msg.data;
-        switch (msg.name) {
-            case "RemoteLogins:findLogins": {
-                // TODO Verify msg.target's principals against the formOrigin?
-                this.findLogins(data.options.showMasterPassword,
-                                data.formOrigin,
-                                data.actionOrigin,
-                                data.requestId,
-                                msg.target.messageManager);
-                break;
-            }
+  receiveMessage: function (msg) {
+    let data = msg.data;
+    switch (msg.name) {
+      case "RemoteLogins:findLogins": {
+        // TODO Verify msg.target's principals against the formOrigin?
+        this.findLogins(data.options.showMasterPassword,
+                        data.formOrigin,
+                        data.actionOrigin,
+                        data.requestId,
+                        msg.target.messageManager);
+        break;
+      }
+
+      case "RemoteLogins:onFormSubmit": {
+        // TODO Verify msg.target's principals against the formOrigin?
+        this.onFormSubmit(data.hostname,
+                          data.formSubmitURL,
+                          data.usernameField,
+                          data.newPasswordField,
+                          data.oldPasswordField,
+                          msg.objects.openerWin,
+                          msg.target);
+        break;
+      }
 
-            case "RemoteLogins:onFormSubmit": {
-                // TODO Verify msg.target's principals against the formOrigin?
-                this.onFormSubmit(data.hostname,
-                                  data.formSubmitURL,
-                                  data.usernameField,
-                                  data.newPasswordField,
-                                  data.oldPasswordField,
-                                  msg.objects.openerWin,
-                                  msg.target);
-                break;
-            }
+      case "RemoteLogins:autoCompleteLogins": {
+        this.doAutocompleteSearch(data, msg.target);
+        break;
+      }
+    }
+  },
+
+  findLogins: function(showMasterPassword, formOrigin, actionOrigin,
+                       requestId, target) {
+    if (!showMasterPassword && !Services.logins.isLoggedIn) {
+      target.sendAsyncMessage("RemoteLogins:loginsFound",
+                              { requestId: requestId, logins: [] });
+      return;
+    }
 
-            case "RemoteLogins:autoCompleteLogins": {
-                this.doAutocompleteSearch(data, msg.target);
-                break;
-            }
-        }
-    },
+    // If there are no logins for this site, bail out now.
+    if (!Services.logins.countLogins(formOrigin, "", null)) {
+      target.sendAsyncMessage("RemoteLogins:loginsFound",
+                              { requestId: requestId, logins: [] });
+      return;
+    }
 
-    findLogins: function(showMasterPassword, formOrigin, actionOrigin,
-                         requestId, target) {
-        if (!showMasterPassword && !Services.logins.isLoggedIn) {
-            target.sendAsyncMessage("RemoteLogins:loginsFound",
-                                    { requestId: requestId, logins: [] });
-            return;
-        }
+    // If we're currently displaying a master password prompt, defer
+    // processing this form until the user handles the prompt.
+    if (Services.logins.uiBusy) {
+      log("deferring onFormPassword for", formOrigin);
+      let self = this;
+      let observer = {
+        QueryInterface: XPCOMUtils.generateQI([Ci.nsIObserver,
+                                               Ci.nsISupportsWeakReference]),
 
-        // If there are no logins for this site, bail out now.
-        if (!Services.logins.countLogins(formOrigin, "", null)) {
+        observe: function (subject, topic, data) {
+          log("Got deferred onFormPassword notification:", topic);
+          // Only run observer once.
+          Services.obs.removeObserver(this, "passwordmgr-crypto-login");
+          Services.obs.removeObserver(this, "passwordmgr-crypto-loginCanceled");
+          if (topic == "passwordmgr-crypto-loginCanceled") {
             target.sendAsyncMessage("RemoteLogins:loginsFound",
                                     { requestId: requestId, logins: [] });
             return;
-        }
+          }
 
-        // If we're currently displaying a master password prompt, defer
-        // processing this form until the user handles the prompt.
-        if (Services.logins.uiBusy) {
-            log("deferring onFormPassword for", formOrigin);
-            let self = this;
-            let observer = {
-                QueryInterface: XPCOMUtils.generateQI([Ci.nsIObserver,
-                                                       Ci.nsISupportsWeakReference]),
+          self.findLogins(showMasterPassword, formOrigin, actionOrigin,
+                          requestId, target);
+        },
+      };
 
-                observe: function (subject, topic, data) {
-                    log("Got deferred onFormPassword notification:", topic);
-                    // Only run observer once.
-                    Services.obs.removeObserver(this, "passwordmgr-crypto-login");
-                    Services.obs.removeObserver(this, "passwordmgr-crypto-loginCanceled");
-                    if (topic == "passwordmgr-crypto-loginCanceled") {
-                        target.sendAsyncMessage("RemoteLogins:loginsFound",
-                                                { requestId: requestId, logins: [] });
-                        return;
-                    }
+      // Possible leak: it's possible that neither of these notifications
+      // will fire, and if that happens, we'll leak the observer (and
+      // never return). We should guarantee that at least one of these
+      // will fire.
+      // See bug XXX.
+      Services.obs.addObserver(observer, "passwordmgr-crypto-login", false);
+      Services.obs.addObserver(observer, "passwordmgr-crypto-loginCanceled", false);
+      return;
+    }
 
-                    self.findLogins(showMasterPassword, formOrigin, actionOrigin,
-                                    requestId, target);
-                },
-            };
+    var logins = Services.logins.findLogins({}, formOrigin, actionOrigin, null);
+    target.sendAsyncMessage("RemoteLogins:loginsFound",
+                            { requestId: requestId, logins: logins });
+  },
+
+  doAutocompleteSearch: function({ formOrigin, actionOrigin,
+                                   searchString, previousResult,
+                                   rect, requestId, remote }, target) {
+    // Note: previousResult is a regular object, not an
+    // nsIAutoCompleteResult.
+    var result;
 
-            // Possible leak: it's possible that neither of these notifications
-            // will fire, and if that happens, we'll leak the observer (and
-            // never return). We should guarantee that at least one of these
-            // will fire.
-            // See bug XXX.
-            Services.obs.addObserver(observer, "passwordmgr-crypto-login", false);
-            Services.obs.addObserver(observer, "passwordmgr-crypto-loginCanceled", false);
-            return;
-        }
+    let searchStringLower = searchString.toLowerCase();
+    let logins;
+    if (previousResult &&
+        searchStringLower.startsWith(previousResult.searchString.toLowerCase())) {
+      log("Using previous autocomplete result");
 
-        var logins = Services.logins.findLogins({}, formOrigin, actionOrigin, null);
-        target.sendAsyncMessage("RemoteLogins:loginsFound",
-                                { requestId: requestId, logins: logins });
-    },
+      // We have a list of results for a shorter search string, so just
+      // filter them further based on the new search string.
+      logins = previousResult.logins;
+    } else {
+      log("Creating new autocomplete search result.");
 
-    doAutocompleteSearch: function({ formOrigin, actionOrigin,
-                                     searchString, previousResult,
-                                     rect, requestId, remote }, target) {
-        // Note: previousResult is a regular object, not an
-        // nsIAutoCompleteResult.
-        var result;
+      // Grab the logins from the database.
+      logins = Services.logins.findLogins({}, formOrigin, actionOrigin, null);
+    }
 
-        let searchStringLower = searchString.toLowerCase();
-        let logins;
-        if (previousResult &&
-            searchStringLower.startsWith(previousResult.searchString.toLowerCase())) {
-            log("Using previous autocomplete result");
+    let matchingLogins = logins.filter(function(fullMatch) {
+      let match = fullMatch.username;
 
-            // We have a list of results for a shorter search string, so just
-            // filter them further based on the new search string.
-            logins = previousResult.logins;
-        } else {
-            log("Creating new autocomplete search result.");
+      // Remove results that are too short, or have different prefix.
+      // Also don't offer empty usernames as possible results.
+      return match && match.toLowerCase().startsWith(searchStringLower);
+    });
 
-            // Grab the logins from the database.
-            logins = Services.logins.findLogins({}, formOrigin, actionOrigin, null);
-        }
-
-        let matchingLogins = logins.filter(function(fullMatch) {
-            let match = fullMatch.username;
-
-            // Remove results that are too short, or have different prefix.
-            // Also don't offer empty usernames as possible results.
-            return match && match.toLowerCase().startsWith(searchStringLower);
-        });
+    // XXX In the E10S case, we're responsible for showing our own
+    // autocomplete popup here because the autocomplete protocol hasn't
+    // been e10s-ized yet. In the non-e10s case, our caller is responsible
+    // for showing the autocomplete popup (via the regular
+    // nsAutoCompleteController).
+    if (remote) {
+      result = new UserAutoCompleteResult(searchString, matchingLogins);
+      AutoCompleteE10S.showPopupWithResults(target.ownerDocument.defaultView, rect, result);
+    }
 
-        // XXX In the E10S case, we're responsible for showing our own
-        // autocomplete popup here because the autocomplete protocol hasn't
-        // been e10s-ized yet. In the non-e10s case, our caller is responsible
-        // for showing the autocomplete popup (via the regular
-        // nsAutoCompleteController).
-        if (remote) {
-            result = new UserAutoCompleteResult(searchString, matchingLogins);
-            AutoCompleteE10S.showPopupWithResults(target.ownerDocument.defaultView, rect, result);
-        }
-
-        target.messageManager.sendAsyncMessage("RemoteLogins:loginsAutoCompleted",
-                                               { requestId: requestId,
-                                                 logins: matchingLogins });
-    },
+    target.messageManager.sendAsyncMessage("RemoteLogins:loginsAutoCompleted",
+                                           { requestId: requestId,
+                                             logins: matchingLogins });
+  },
 
-    onFormSubmit: function(hostname, formSubmitURL,
-                           usernameField, newPasswordField,
-                           oldPasswordField, opener,
-                           target) {
-        function getPrompter() {
-            var prompterSvc = Cc["@mozilla.org/login-manager/prompter;1"].
-                              createInstance(Ci.nsILoginManagerPrompter);
-            // XXX For E10S, we don't want to use the browser's contentWindow
-            // because it's in another process, so we use our chrome window as
-            // the window parent (the content process is responsible for
-            // making sure that its window is not in private browsing mode).
-            // In the same-process case, we can simply use the content window.
-            prompterSvc.init(target.isRemoteBrowser ?
-                                target.ownerDocument.defaultView :
-                                target.contentWindow);
-            if (target.isRemoteBrowser)
-                prompterSvc.setE10sData(target, opener);
-            return prompterSvc;
-        }
+  onFormSubmit: function(hostname, formSubmitURL,
+                         usernameField, newPasswordField,
+                         oldPasswordField, opener,
+                         target) {
+    function getPrompter() {
+      var prompterSvc = Cc["@mozilla.org/login-manager/prompter;1"].
+                        createInstance(Ci.nsILoginManagerPrompter);
+      // XXX For E10S, we don't want to use the browser's contentWindow
+      // because it's in another process, so we use our chrome window as
+      // the window parent (the content process is responsible for
+      // making sure that its window is not in private browsing mode).
+      // In the same-process case, we can simply use the content window.
+      prompterSvc.init(target.isRemoteBrowser ?
+                          target.ownerDocument.defaultView :
+                          target.contentWindow);
+      if (target.isRemoteBrowser)
+        prompterSvc.setE10sData(target, opener);
+      return prompterSvc;
+    }
+
+    if (!Services.logins.getLoginSavingEnabled(hostname)) {
+      log("(form submission ignored -- saving is disabled for:", hostname, ")");
+      return;
+    }
 
-        if (!Services.logins.getLoginSavingEnabled(hostname)) {
-            log("(form submission ignored -- saving is disabled for:", hostname, ")");
-            return;
-        }
+    var formLogin = Cc["@mozilla.org/login-manager/loginInfo;1"].
+                    createInstance(Ci.nsILoginInfo);
+    formLogin.init(hostname, formSubmitURL, null,
+                   (usernameField ? usernameField.value : ""),
+                   newPasswordField.value,
+                   (usernameField ? usernameField.name  : ""),
+                   newPasswordField.name);
 
-        var formLogin = Cc["@mozilla.org/login-manager/loginInfo;1"].
-                        createInstance(Ci.nsILoginInfo);
-        formLogin.init(hostname, formSubmitURL, null,
-                    (usernameField ? usernameField.value : ""),
-                    newPasswordField.value,
-                    (usernameField ? usernameField.name  : ""),
-                    newPasswordField.name);
+    // If we didn't find a username field, but seem to be changing a
+    // password, allow the user to select from a list of applicable
+    // logins to update the password for.
+    if (!usernameField && oldPasswordField) {
 
-        // If we didn't find a username field, but seem to be changing a
-        // password, allow the user to select from a list of applicable
-        // logins to update the password for.
-        if (!usernameField && oldPasswordField) {
-
-            var logins = Services.logins.findLogins({}, hostname, formSubmitURL, null);
+      var logins = Services.logins.findLogins({}, hostname, formSubmitURL, null);
 
-            if (logins.length == 0) {
-                // Could prompt to save this as a new password-only login.
-                // This seems uncommon, and might be wrong, so ignore.
-                log("(no logins for this host -- pwchange ignored)");
-                return;
-            }
+      if (logins.length == 0) {
+        // Could prompt to save this as a new password-only login.
+        // This seems uncommon, and might be wrong, so ignore.
+        log("(no logins for this host -- pwchange ignored)");
+        return;
+      }
 
-            var prompter = getPrompter();
+      var prompter = getPrompter();
 
-            if (logins.length == 1) {
-                var oldLogin = logins[0];
-                formLogin.username      = oldLogin.username;
-                formLogin.usernameField = oldLogin.usernameField;
+      if (logins.length == 1) {
+        var oldLogin = logins[0];
+        formLogin.username      = oldLogin.username;
+        formLogin.usernameField = oldLogin.usernameField;
 
-                prompter.promptToChangePassword(oldLogin, formLogin);
-            } else {
-                prompter.promptToChangePasswordWithUsernames(
-                                    logins, logins.length, formLogin);
-            }
+        prompter.promptToChangePassword(oldLogin, formLogin);
+      } else {
+        prompter.promptToChangePasswordWithUsernames(
+                            logins, logins.length, formLogin);
+      }
 
-            return;
-        }
+      return;
+    }
 
 
-        // Look for an existing login that matches the form login.
-        var existingLogin = null;
-        var logins = Services.logins.findLogins({}, hostname, formSubmitURL, null);
+    // Look for an existing login that matches the form login.
+    var existingLogin = null;
+    var logins = Services.logins.findLogins({}, hostname, formSubmitURL, null);
 
-        for (var i = 0; i < logins.length; i++) {
-            var same, login = logins[i];
+    for (var i = 0; i < logins.length; i++) {
+      var same, login = logins[i];
 
-            // If one login has a username but the other doesn't, ignore
-            // the username when comparing and only match if they have the
-            // same password. Otherwise, compare the logins and match even
-            // if the passwords differ.
-            if (!login.username && formLogin.username) {
-                var restoreMe = formLogin.username;
-                formLogin.username = "";
-                same = formLogin.matches(login, false);
-                formLogin.username = restoreMe;
-            } else if (!formLogin.username && login.username) {
-                formLogin.username = login.username;
-                same = formLogin.matches(login, false);
-                formLogin.username = ""; // we know it's always blank.
-            } else {
-                same = formLogin.matches(login, true);
-            }
+      // If one login has a username but the other doesn't, ignore
+      // the username when comparing and only match if they have the
+      // same password. Otherwise, compare the logins and match even
+      // if the passwords differ.
+      if (!login.username && formLogin.username) {
+        var restoreMe = formLogin.username;
+        formLogin.username = "";
+        same = formLogin.matches(login, false);
+        formLogin.username = restoreMe;
+      } else if (!formLogin.username && login.username) {
+        formLogin.username = login.username;
+        same = formLogin.matches(login, false);
+        formLogin.username = ""; // we know it's always blank.
+      } else {
+        same = formLogin.matches(login, true);
+      }
 
-            if (same) {
-                existingLogin = login;
-                break;
-            }
-        }
+      if (same) {
+        existingLogin = login;
+        break;
+      }
+    }
 
-        if (existingLogin) {
-            log("Found an existing login matching this form submission");
+    if (existingLogin) {
+      log("Found an existing login matching this form submission");
 
-            // Change password if needed.
-            if (existingLogin.password != formLogin.password) {
-                log("...passwords differ, prompting to change.");
-                prompter = getPrompter();
-                prompter.promptToChangePassword(existingLogin, formLogin);
-            } else {
-                // Update the lastUsed timestamp.
-                var propBag = Cc["@mozilla.org/hash-property-bag;1"].
-                              createInstance(Ci.nsIWritablePropertyBag);
-                propBag.setProperty("timeLastUsed", Date.now());
-                propBag.setProperty("timesUsedIncrement", 1);
-                Services.logins.modifyLogin(existingLogin, propBag);
-            }
+      // Change password if needed.
+      if (existingLogin.password != formLogin.password) {
+        log("...passwords differ, prompting to change.");
+        prompter = getPrompter();
+        prompter.promptToChangePassword(existingLogin, formLogin);
+      } else {
+        // Update the lastUsed timestamp.
+        var propBag = Cc["@mozilla.org/hash-property-bag;1"].
+                      createInstance(Ci.nsIWritablePropertyBag);
+        propBag.setProperty("timeLastUsed", Date.now());
+        propBag.setProperty("timesUsedIncrement", 1);
+        Services.logins.modifyLogin(existingLogin, propBag);
+      }
 
-            return;
-        }
+      return;
+    }
 
 
-        // Prompt user to save login (via dialog or notification bar)
-        prompter = getPrompter();
-        prompter.promptToSavePassword(formLogin);
-    }
+    // Prompt user to save login (via dialog or notification bar)
+    prompter = getPrompter();
+    prompter.promptToSavePassword(formLogin);
+  }
 };
--- a/toolkit/components/passwordmgr/crypto-SDR.js
+++ b/toolkit/components/passwordmgr/crypto-SDR.js
@@ -6,216 +6,216 @@
 const Cc = Components.classes;
 const Ci = Components.interfaces;
 const Cr = Components.results;
 
 Components.utils.import("resource://gre/modules/XPCOMUtils.jsm");
 Components.utils.import("resource://gre/modules/Services.jsm");
 
 function LoginManagerCrypto_SDR() {
-    this.init();
+  this.init();
 };
 
 LoginManagerCrypto_SDR.prototype = {
 
-    classID : Components.ID("{dc6c2976-0f73-4f1f-b9ff-3d72b4e28309}"),
-    QueryInterface : XPCOMUtils.generateQI([Ci.nsILoginManagerCrypto]),
+  classID : Components.ID("{dc6c2976-0f73-4f1f-b9ff-3d72b4e28309}"),
+  QueryInterface : XPCOMUtils.generateQI([Ci.nsILoginManagerCrypto]),
 
-    __sdrSlot : null, // PKCS#11 slot being used by the SDR.
-    get _sdrSlot() {
-        if (!this.__sdrSlot) {
-            let modules = Cc["@mozilla.org/security/pkcs11moduledb;1"].
-                          getService(Ci.nsIPKCS11ModuleDB);
-            this.__sdrSlot = modules.findSlotByName("");
-        }
-        return this.__sdrSlot;
-    },
+  __sdrSlot : null, // PKCS#11 slot being used by the SDR.
+  get _sdrSlot() {
+    if (!this.__sdrSlot) {
+      let modules = Cc["@mozilla.org/security/pkcs11moduledb;1"].
+                    getService(Ci.nsIPKCS11ModuleDB);
+      this.__sdrSlot = modules.findSlotByName("");
+    }
+    return this.__sdrSlot;
+  },
 
-    __decoderRing : null,  // nsSecretDecoderRing service
-    get _decoderRing() {
-        if (!this.__decoderRing)
-            this.__decoderRing = Cc["@mozilla.org/security/sdr;1"].
-                                 getService(Ci.nsISecretDecoderRing);
-        return this.__decoderRing;
-    },
+  __decoderRing : null,  // nsSecretDecoderRing service
+  get _decoderRing() {
+    if (!this.__decoderRing)
+      this.__decoderRing = Cc["@mozilla.org/security/sdr;1"].
+                           getService(Ci.nsISecretDecoderRing);
+    return this.__decoderRing;
+  },
 
-    __utfConverter : null, // UCS2 <--> UTF8 string conversion
-    get _utfConverter() {
-        if (!this.__utfConverter) {
-            this.__utfConverter = Cc["@mozilla.org/intl/scriptableunicodeconverter"].
-                                  createInstance(Ci.nsIScriptableUnicodeConverter);
-            this.__utfConverter.charset = "UTF-8";
-        }
-        return this.__utfConverter;
-    },
+  __utfConverter : null, // UCS2 <--> UTF8 string conversion
+  get _utfConverter() {
+    if (!this.__utfConverter) {
+      this.__utfConverter = Cc["@mozilla.org/intl/scriptableunicodeconverter"].
+                            createInstance(Ci.nsIScriptableUnicodeConverter);
+      this.__utfConverter.charset = "UTF-8";
+    }
+    return this.__utfConverter;
+  },
 
-    _utfConverterReset : function() {
-        this.__utfConverter = null;
-    },
+  _utfConverterReset : function() {
+    this.__utfConverter = null;
+  },
 
-    _debug  : false, // mirrors signon.debug
-    _uiBusy : false,
+  _debug  : false, // mirrors signon.debug
+  _uiBusy : false,
 
 
-    /*
-     * log
-     *
-     * Internal function for logging debug messages to the Error Console.
-     */
-    log : function (message) {
-        if (!this._debug)
-            return;
-        dump("PwMgr cryptoSDR: " + message + "\n");
-        Services.console.logStringMessage("PwMgr cryptoSDR: " + message);
-    },
+  /*
+   * log
+   *
+   * Internal function for logging debug messages to the Error Console.
+   */
+  log : function (message) {
+    if (!this._debug)
+      return;
+    dump("PwMgr cryptoSDR: " + message + "\n");
+    Services.console.logStringMessage("PwMgr cryptoSDR: " + message);
+  },
 
 
-    init : function () {
-        // Connect to the correct preferences branch.
-        this._prefBranch = Services.prefs.getBranch("signon.");
+  init : function () {
+    // Connect to the correct preferences branch.
+    this._prefBranch = Services.prefs.getBranch("signon.");
 
-        this._debug = this._prefBranch.getBoolPref("debug");
+    this._debug = this._prefBranch.getBoolPref("debug");
 
-        // Check to see if the internal PKCS#11 token has been initialized.
-        // If not, set a blank password.
-        let tokenDB = Cc["@mozilla.org/security/pk11tokendb;1"].
-                      getService(Ci.nsIPK11TokenDB);
+    // Check to see if the internal PKCS#11 token has been initialized.
+    // If not, set a blank password.
+    let tokenDB = Cc["@mozilla.org/security/pk11tokendb;1"].
+                  getService(Ci.nsIPK11TokenDB);
 
-        let token = tokenDB.getInternalKeyToken();
-        if (token.needsUserInit) {
-            this.log("Initializing key3.db with default blank password.");
-            token.initPassword("");
-        }
-    },
+    let token = tokenDB.getInternalKeyToken();
+    if (token.needsUserInit) {
+      this.log("Initializing key3.db with default blank password.");
+      token.initPassword("");
+    }
+  },
 
 
-    /*
-     * encrypt
-     *
-     * Encrypts the specified string, using the SecretDecoderRing.
-     *
-     * Returns the encrypted string, or throws an exception if there was a
-     * problem.
-     */
-    encrypt : function (plainText) {
-        let cipherText = null;
+  /*
+   * encrypt
+   *
+   * Encrypts the specified string, using the SecretDecoderRing.
+   *
+   * Returns the encrypted string, or throws an exception if there was a
+   * problem.
+   */
+  encrypt : function (plainText) {
+    let cipherText = null;
 
-        let wasLoggedIn = this.isLoggedIn;
-        let canceledMP = false;
+    let wasLoggedIn = this.isLoggedIn;
+    let canceledMP = false;
 
-        this._uiBusy = true;
-        try {
-            let plainOctet = this._utfConverter.ConvertFromUnicode(plainText);
-            plainOctet += this._utfConverter.Finish();
-            cipherText = this._decoderRing.encryptString(plainOctet);
-        } catch (e) {
-            this.log("Failed to encrypt string. (" + e.name + ")");
-            // If the user clicks Cancel, we get NS_ERROR_FAILURE.
-            // (unlike decrypting, which gets NS_ERROR_NOT_AVAILABLE).
-            if (e.result == Cr.NS_ERROR_FAILURE) {
-                canceledMP = true;
-                throw Components.Exception("User canceled master password entry", Cr.NS_ERROR_ABORT);
-            } else {
-                throw Components.Exception("Couldn't encrypt string", Cr.NS_ERROR_FAILURE);
-            }
-        } finally {
-            this._uiBusy = false;
-            // If we triggered a master password prompt, notify observers.
-            if (!wasLoggedIn && this.isLoggedIn)
-                this._notifyObservers("passwordmgr-crypto-login");
-            else if (canceledMP)
-                this._notifyObservers("passwordmgr-crypto-loginCanceled");
-        }
-        return cipherText;
-    },
+    this._uiBusy = true;
+    try {
+      let plainOctet = this._utfConverter.ConvertFromUnicode(plainText);
+      plainOctet += this._utfConverter.Finish();
+      cipherText = this._decoderRing.encryptString(plainOctet);
+    } catch (e) {
+      this.log("Failed to encrypt string. (" + e.name + ")");
+      // If the user clicks Cancel, we get NS_ERROR_FAILURE.
+      // (unlike decrypting, which gets NS_ERROR_NOT_AVAILABLE).
+      if (e.result == Cr.NS_ERROR_FAILURE) {
+        canceledMP = true;
+        throw Components.Exception("User canceled master password entry", Cr.NS_ERROR_ABORT);
+      } else {
+        throw Components.Exception("Couldn't encrypt string", Cr.NS_ERROR_FAILURE);
+      }
+    } finally {
+      this._uiBusy = false;
+      // If we triggered a master password prompt, notify observers.
+      if (!wasLoggedIn && this.isLoggedIn)
+        this._notifyObservers("passwordmgr-crypto-login");
+      else if (canceledMP)
+        this._notifyObservers("passwordmgr-crypto-loginCanceled");
+    }
+    return cipherText;
+  },
 
 
-    /*
-     * decrypt
-     *
-     * Decrypts the specified string, using the SecretDecoderRing.
-     *
-     * Returns the decrypted string, or throws an exception if there was a
-     * problem.
-     */
-    decrypt : function (cipherText) {
-        let plainText = null;
+  /*
+   * decrypt
+   *
+   * Decrypts the specified string, using the SecretDecoderRing.
+   *
+   * Returns the decrypted string, or throws an exception if there was a
+   * problem.
+   */
+  decrypt : function (cipherText) {
+    let plainText = null;
 
-        let wasLoggedIn = this.isLoggedIn;
-        let canceledMP = false;
+    let wasLoggedIn = this.isLoggedIn;
+    let canceledMP = false;
 
-        this._uiBusy = true;
-        try {
-            let plainOctet;
-            plainOctet = this._decoderRing.decryptString(cipherText);
-            plainText = this._utfConverter.ConvertToUnicode(plainOctet);
-        } catch (e) {
-            this.log("Failed to decrypt string: " + cipherText +
-                " (" + e.name + ")");
+    this._uiBusy = true;
+    try {
+      let plainOctet;
+      plainOctet = this._decoderRing.decryptString(cipherText);
+      plainText = this._utfConverter.ConvertToUnicode(plainOctet);
+    } catch (e) {
+      this.log("Failed to decrypt string: " + cipherText +
+          " (" + e.name + ")");
 
-            // In the unlikely event the converter threw, reset it.
-            this._utfConverterReset();
+      // In the unlikely event the converter threw, reset it.
+      this._utfConverterReset();
 
-            // If the user clicks Cancel, we get NS_ERROR_NOT_AVAILABLE.
-            // If the cipherText is bad / wrong key, we get NS_ERROR_FAILURE
-            // Wrong passwords are handled by the decoderRing reprompting;
-            // we get no notification.
-            if (e.result == Cr.NS_ERROR_NOT_AVAILABLE) {
-                canceledMP = true;
-                throw Components.Exception("User canceled master password entry", Cr.NS_ERROR_ABORT);
-            } else {
-                throw Components.Exception("Couldn't decrypt string", Cr.NS_ERROR_FAILURE);
-            }
-        } finally {
-            this._uiBusy = false;
-            // If we triggered a master password prompt, notify observers.
-            if (!wasLoggedIn && this.isLoggedIn)
-                this._notifyObservers("passwordmgr-crypto-login");
-            else if (canceledMP)
-                this._notifyObservers("passwordmgr-crypto-loginCanceled");
-        }
+      // If the user clicks Cancel, we get NS_ERROR_NOT_AVAILABLE.
+      // If the cipherText is bad / wrong key, we get NS_ERROR_FAILURE
+      // Wrong passwords are handled by the decoderRing reprompting;
+      // we get no notification.
+      if (e.result == Cr.NS_ERROR_NOT_AVAILABLE) {
+        canceledMP = true;
+        throw Components.Exception("User canceled master password entry", Cr.NS_ERROR_ABORT);
+      } else {
+        throw Components.Exception("Couldn't decrypt string", Cr.NS_ERROR_FAILURE);
+      }
+    } finally {
+      this._uiBusy = false;
+      // If we triggered a master password prompt, notify observers.
+      if (!wasLoggedIn && this.isLoggedIn)
+        this._notifyObservers("passwordmgr-crypto-login");
+      else if (canceledMP)
+        this._notifyObservers("passwordmgr-crypto-loginCanceled");
+    }
 
-        return plainText;
-    },
+    return plainText;
+  },
 
 
-    /*
-     * uiBusy
-     */
-    get uiBusy() {
-        return this._uiBusy;
-    },
+  /*
+   * uiBusy
+   */
+  get uiBusy() {
+    return this._uiBusy;
+  },
 
 
-    /*
-     * isLoggedIn
-     */
-    get isLoggedIn() {
-        let status = this._sdrSlot.status;
-        this.log("SDR slot status is " + status);
-        if (status == Ci.nsIPKCS11Slot.SLOT_READY ||
-            status == Ci.nsIPKCS11Slot.SLOT_LOGGED_IN)
-            return true;
-        if (status == Ci.nsIPKCS11Slot.SLOT_NOT_LOGGED_IN)
-            return false;
-        throw Components.Exception("unexpected slot status: " + status, Cr.NS_ERROR_FAILURE);
-    },
+  /*
+   * isLoggedIn
+   */
+  get isLoggedIn() {
+    let status = this._sdrSlot.status;
+    this.log("SDR slot status is " + status);
+    if (status == Ci.nsIPKCS11Slot.SLOT_READY ||
+        status == Ci.nsIPKCS11Slot.SLOT_LOGGED_IN)
+      return true;
+    if (status == Ci.nsIPKCS11Slot.SLOT_NOT_LOGGED_IN)
+      return false;
+    throw Components.Exception("unexpected slot status: " + status, Cr.NS_ERROR_FAILURE);
+  },
 
 
-    /*
-     * defaultEncType
-     */
-    get defaultEncType() {
-        return Ci.nsILoginManagerCrypto.ENCTYPE_SDR;
-    },
+  /*
+   * defaultEncType
+   */
+  get defaultEncType() {
+    return Ci.nsILoginManagerCrypto.ENCTYPE_SDR;
+  },
 
 
-    /*
-     * _notifyObservers
-     */
-    _notifyObservers : function(topic) {
-        this.log("Prompted for a master password, notifying for " + topic);
-        Services.obs.notifyObservers(null, topic, null);
-     },
+  /*
+   * _notifyObservers
+   */
+  _notifyObservers : function(topic) {
+    this.log("Prompted for a master password, notifying for " + topic);
+    Services.obs.notifyObservers(null, topic, null);
+  },
 }; // end of nsLoginManagerCrypto_SDR implementation
 
 let component = [LoginManagerCrypto_SDR];
 this.NSGetFactory = XPCOMUtils.generateNSGetFactory(component);
--- a/toolkit/components/passwordmgr/nsILoginInfo.idl
+++ b/toolkit/components/passwordmgr/nsILoginInfo.idl
@@ -7,114 +7,114 @@
 
 [scriptable, uuid(c41b7dff-6b9b-42fe-b78d-113051facb05)]
 
 /**
  * An object containing information for a login stored by the
  * password manager.
  */
 interface nsILoginInfo : nsISupports {
-    /**
-     * The hostname the login applies to.
-     *
-     * The hostname should be formatted as an URL. For example,
-     * "https://site.com", "http://site.com:1234", "ftp://ftp.site.com".
-     */
-    attribute AString hostname;
+  /**
+   * The hostname the login applies to.
+   *
+   * The hostname should be formatted as an URL. For example,
+   * "https://site.com", "http://site.com:1234", "ftp://ftp.site.com".
+   */
+  attribute AString hostname;
 
-    /**
-     * The URL a form-based login was submitted to.
-     *
-     * For logins obtained from HTML forms, this field is the |action|
-     * attribute from the |form| element, with the path removed. For
-     * example "http://www.site.com". [Forms with no |action| attribute
-     * default to submitting to their origin URL, so we store that.]
-     *
-     * For logins obtained from a HTTP or FTP protocol authentication,
-     * this field is NULL.
-     */
-    attribute AString formSubmitURL;
+  /**
+   * The URL a form-based login was submitted to.
+   *
+   * For logins obtained from HTML forms, this field is the |action|
+   * attribute from the |form| element, with the path removed. For
+   * example "http://www.site.com". [Forms with no |action| attribute
+   * default to submitting to their origin URL, so we store that.]
+   *
+   * For logins obtained from a HTTP or FTP protocol authentication,
+   * this field is NULL.
+   */
+  attribute AString formSubmitURL;
 
-    /**
-     * The HTTP Realm a login was requested for.
-     *
-     * When an HTTP server sends a 401 result, the WWW-Authenticate
-     * header includes a realm to identify the "protection space." See
-     * RFC2617. If the response sent has a missing or blank realm, the
-     * hostname is used instead.
-     *
-     * For logins obtained from HTML forms, this field is NULL.
-     */
-    attribute AString httpRealm;
+  /**
+   * The HTTP Realm a login was requested for.
+   *
+   * When an HTTP server sends a 401 result, the WWW-Authenticate
+   * header includes a realm to identify the "protection space." See
+   * RFC2617. If the response sent has a missing or blank realm, the
+   * hostname is used instead.
+   *
+   * For logins obtained from HTML forms, this field is NULL.
+   */
+  attribute AString httpRealm;
 
-    /**
-     * The username for the login.
-     */
-    attribute AString username;
+  /**
+   * The username for the login.
+   */
+  attribute AString username;
 
-    /**
-     * The |name| attribute for the username input field.
-     *
-     * For logins obtained from a HTTP or FTP protocol authentication,
-     * this field is an empty string.
-     */
-    attribute AString usernameField;
+  /**
+   * The |name| attribute for the username input field.
+   *
+   * For logins obtained from a HTTP or FTP protocol authentication,
+   * this field is an empty string.
+   */
+  attribute AString usernameField;
 
-    /**
-     * The password for the login.
-     */
-    attribute AString password;
+  /**
+   * The password for the login.
+   */
+  attribute AString password;
 
-    /**
-     * The |name| attribute for the password input field.
-     *
-     * For logins obtained from a HTTP or FTP protocol authentication,
-     * this field is an empty string.
-     */
-    attribute AString passwordField;
+  /**
+   * The |name| attribute for the password input field.
+   *
+   * For logins obtained from a HTTP or FTP protocol authentication,
+   * this field is an empty string.
+   */
+  attribute AString passwordField;
 
-    /**
-     * Initialize a newly created nsLoginInfo object.
-     *
-     * The arguments are the fields for the new object.
-     */
-    void init(in AString aHostname,
-              in AString aFormSubmitURL, in AString aHttpRealm,
-              in AString aUsername,      in AString aPassword,
-              in AString aUsernameField, in AString aPasswordField);
+  /**
+   * Initialize a newly created nsLoginInfo object.
+   *
+   * The arguments are the fields for the new object.
+   */
+  void init(in AString aHostname,
+            in AString aFormSubmitURL, in AString aHttpRealm,
+            in AString aUsername,      in AString aPassword,
+            in AString aUsernameField, in AString aPasswordField);
 
-    /**
-     * Test for strict equality with another nsILoginInfo object.
-     *
-     * @param aLoginInfo
-     *        The other object to test.
-     */
-    boolean equals(in nsILoginInfo aLoginInfo);
+  /**
+   * Test for strict equality with another nsILoginInfo object.
+   *
+   * @param aLoginInfo
+   *        The other object to test.
+   */
+  boolean equals(in nsILoginInfo aLoginInfo);
 
-    /**
-     * Test for loose equivalency with another nsILoginInfo object. The
-     * passwordField and usernameField values are ignored, and the password
-     * values may be optionally ignored. If one login's formSubmitURL is an
-     * empty string (but not null), it will be treated as a wildcard. [The
-     * blank value indicates the login was stored before bug 360493 was fixed.]
-     *
-     * @param aLoginInfo
-     *        The other object to test.
-     * @param ignorePassword
-     *        If true, ignore the password when checking for match.
-     */
-    boolean matches(in nsILoginInfo aLoginInfo, in boolean ignorePassword);
+  /**
+   * Test for loose equivalency with another nsILoginInfo object. The
+   * passwordField and usernameField values are ignored, and the password
+   * values may be optionally ignored. If one login's formSubmitURL is an
+   * empty string (but not null), it will be treated as a wildcard. [The
+   * blank value indicates the login was stored before bug 360493 was fixed.]
+   *
+   * @param aLoginInfo
+   *        The other object to test.
+   * @param ignorePassword
+   *        If true, ignore the password when checking for match.
+   */
+  boolean matches(in nsILoginInfo aLoginInfo, in boolean ignorePassword);
 
-    /**
-     * Create an identical copy of the login, duplicating all of the login's
-     * nsILoginInfo and nsILoginMetaInfo properties.
-     *
-     * This allows code to be forwards-compatible, when additional properties
-     * are added to nsILoginMetaInfo (or nsILoginInfo) in the future.
-     */
-    nsILoginInfo clone();
+  /**
+   * Create an identical copy of the login, duplicating all of the login's
+   * nsILoginInfo and nsILoginMetaInfo properties.
+   *
+   * This allows code to be forwards-compatible, when additional properties
+   * are added to nsILoginMetaInfo (or nsILoginInfo) in the future.
+   */
+  nsILoginInfo clone();
 };
 
 %{C++
 
 #define NS_LOGININFO_CONTRACTID "@mozilla.org/login-manager/loginInfo;1"
 
 %}
--- a/toolkit/components/passwordmgr/nsILoginManager.idl
+++ b/toolkit/components/passwordmgr/nsILoginManager.idl
@@ -10,257 +10,257 @@ interface nsILoginInfo;
 interface nsIAutoCompleteResult;
 interface nsIFormAutoCompleteObserver;
 interface nsIDOMHTMLInputElement;
 interface nsIDOMHTMLFormElement;
 interface nsIPropertyBag;
 
 [scriptable, uuid(f0c5ca21-db71-4b32-993e-ab63054cc6f5)]
 interface nsILoginManager : nsISupports {
-    /**
-     * This promise is resolved when initialization is complete, and is rejected
-     * in case initialization failed.  This includes the initial loading of the
-     * login data as well as any migration from previous versions.
-     *
-     * Calling any method of nsILoginManager before this promise is resolved
-     * might trigger the synchronous initialization fallback.
-     */
-    readonly attribute jsval initializationPromise;
-
-
-    /**
-     * Store a new login in the login manager.
-     *
-     * @param aLogin
-     *        The login to be added.
-     *
-     * Default values for the login's nsILoginMetaInfo properties will be
-     * created. However, if the caller specifies non-default values, they will
-     * be used instead.
-     */
-    void addLogin(in nsILoginInfo aLogin);
+  /**
+   * This promise is resolved when initialization is complete, and is rejected
+   * in case initialization failed.  This includes the initial loading of the
+   * login data as well as any migration from previous versions.
+   *
+   * Calling any method of nsILoginManager before this promise is resolved
+   * might trigger the synchronous initialization fallback.
+   */
+  readonly attribute jsval initializationPromise;
 
 
-    /**
-     * Remove a login from the login manager.
-     *
-     * @param aLogin
-     *        The login to be removed.
-     *
-     * The specified login must exactly match a stored login. However, the
-     * values of any nsILoginMetaInfo properties are ignored.
-     */
-    void removeLogin(in nsILoginInfo aLogin);
+  /**
+   * Store a new login in the login manager.
+   *
+   * @param aLogin
+   *        The login to be added.
+   *
+   * Default values for the login's nsILoginMetaInfo properties will be
+   * created. However, if the caller specifies non-default values, they will
+   * be used instead.
+   */
+  void addLogin(in nsILoginInfo aLogin);
 
 
-    /**
-     * Modify an existing login in the login manager.
-     *
-     * @param oldLogin
-     *        The login to be modified.
-     * @param newLoginData
-     *        The new login values (either a nsILoginInfo or nsIProperyBag)
-     *
-     * If newLoginData is a nsILoginInfo, all of the old login's nsILoginInfo
-     * properties are changed to the values from newLoginData (but the old
-     * login's nsILoginMetaInfo properties are unmodified).
-     *
-     * If newLoginData is a nsIPropertyBag, only the specified properties
-     * will be changed. The nsILoginMetaInfo properties of oldLogin can be
-     * changed in this manner.
-     *
-     * If the propertybag contains an item named "timesUsedIncrement", the
-     * login's timesUsed property will be incremented by the item's value.
-     */
-    void modifyLogin(in nsILoginInfo oldLogin, in nsISupports newLoginData);
-
-
-    /**
-     * Remove all logins known to login manager.
-     *
-     * The browser sanitization feature allows the user to clear any stored
-     * passwords. This interface allows that to be done without getting each
-     * login first (which might require knowing the master password).
-     *
-     */
-    void removeAllLogins();
+  /**
+   * Remove a login from the login manager.
+   *
+   * @param aLogin
+   *        The login to be removed.
+   *
+   * The specified login must exactly match a stored login. However, the
+   * values of any nsILoginMetaInfo properties are ignored.
+   */
+  void removeLogin(in nsILoginInfo aLogin);
 
 
-    /**
-     * Fetch all logins in the login manager. An array is always returned;
-     * if there are no logins the array is empty.
-     *
-     * @param count
-     *        The number of elements in the array. JS callers can simply use
-     *        the array's .length property and omit this param.
-     * @param logins
-     *        An array of nsILoginInfo objects.
-     *
-     * NOTE: This can be called from JS as:
-     *       var logins = pwmgr.getAllLogins();
-     *       (|logins| is an array).
-     */
-    void getAllLogins([optional] out unsigned long count,
-                      [retval, array, size_is(count)] out nsILoginInfo logins);
-
-
-    /**
-     * Obtain a list of all hosts for which password saving is disabled.
-     *
-     * @param count
-     *        The number of elements in the array. JS callers can simply use
-     *        the array's .length property and omit this param.
-     * @param hostnames
-     *        An array of hostname strings, in origin URL format without a
-     *        pathname. For example: "https://www.site.com".
-     *
-     * NOTE: This can be called from JS as:
-     *       var logins = pwmgr.getDisabledAllLogins();
-     */
-    void getAllDisabledHosts([optional] out unsigned long count,
-                      [retval, array, size_is(count)] out wstring hostnames);
-
-
-    /**
-     * Check to see if saving logins has been disabled for a host.
-     *
-     * @param aHost
-     *        The hostname to check. This argument should be in the origin
-     *        URL format, without a pathname. For example: "http://foo.com".
-     */
-    boolean getLoginSavingEnabled(in AString aHost);
+  /**
+   * Modify an existing login in the login manager.
+   *
+   * @param oldLogin
+   *        The login to be modified.
+   * @param newLoginData
+   *        The new login values (either a nsILoginInfo or nsIProperyBag)
+   *
+   * If newLoginData is a nsILoginInfo, all of the old login's nsILoginInfo
+   * properties are changed to the values from newLoginData (but the old
+   * login's nsILoginMetaInfo properties are unmodified).
+   *
+   * If newLoginData is a nsIPropertyBag, only the specified properties
+   * will be changed. The nsILoginMetaInfo properties of oldLogin can be
+   * changed in this manner.
+   *
+   * If the propertybag contains an item named "timesUsedIncrement", the
+   * login's timesUsed property will be incremented by the item's value.
+   */
+  void modifyLogin(in nsILoginInfo oldLogin, in nsISupports newLoginData);
 
 
-    /**
-     * Disable (or enable) storing logins for the specified host. When
-     * disabled, the login manager will not prompt to store logins for
-     * that host. Existing logins are not affected.
-     *
-     * @param aHost
-     *        The hostname to set. This argument should be in the origin
-     *        URL format, without a pathname. For example: "http://foo.com".
-     * @param isEnabled
-     *        Specify if saving logins should be enabled (true) or
-     *        disabled (false)
-     */
-    void setLoginSavingEnabled(in AString aHost, in boolean isEnabled);
+  /**
+   * Remove all logins known to login manager.
+   *
+   * The browser sanitization feature allows the user to clear any stored
+   * passwords. This interface allows that to be done without getting each
+   * login first (which might require knowing the master password).
+   *
+   */
+  void removeAllLogins();
 
 
-    /**
-     * Search for logins matching the specified criteria. Called when looking
-     * for logins that might be applicable to a form or authentication request.
-     *
-     * @param count
-     *        The number of elements in the array. JS callers can simply use
-     *        the array's .length property, and supply an dummy object for
-     *        this out param. For example: |findLogins({}, hostname, ...)|
-     * @param aHostname
-     *        The hostname to restrict searches to, in URL format. For
-     *        example: "http://www.site.com".
-     *        To find logins for a given nsIURI, you would typically pass in
-     *        its prePath.
-     * @param aActionURL
-     *        For form logins, this argument should be the URL to which the
-     *        form will be submitted. For protocol logins, specify null.
-     *        An empty string ("") will match any value (except null).
-     * @param aHttpRealm
-     *        For protocol logins, this argument should be the HTTP Realm
-     *        for which the login applies. This is obtained from the
-     *        WWW-Authenticate header. See RFC2617. For form logins,
-     *        specify null.
-     *        An empty string ("") will match any value (except null).
-     * @param logins
-     *        An array of nsILoginInfo objects.
-     *
-     * NOTE: This can be called from JS as:
-     *       var logins = pwmgr.findLogins({}, hostname, ...);
-     *
-     */
-    void findLogins(out unsigned long count, in AString aHostname,
-                    in AString aActionURL,   in AString aHttpRealm,
+  /**
+   * Fetch all logins in the login manager. An array is always returned;
+   * if there are no logins the array is empty.
+   *
+   * @param count
+   *        The number of elements in the array. JS callers can simply use
+   *        the array's .length property and omit this param.
+   * @param logins
+   *        An array of nsILoginInfo objects.
+   *
+   * NOTE: This can be called from JS as:
+   *       var logins = pwmgr.getAllLogins();
+   *       (|logins| is an array).
+   */
+  void getAllLogins([optional] out unsigned long count,
                     [retval, array, size_is(count)] out nsILoginInfo logins);
 
 
-   /**
-    * Search for logins matching the specified criteria, as with
-    * findLogins(). This interface only returns the number of matching
-    * logins (and not the logins themselves), which allows a caller to
-    * check for logins without causing the user to be prompted for a master
-    * password to decrypt the logins.
-    *
-    * @param aHostname
-    *        The hostname to restrict searches to. Specify an empty string
-    *        to match all hosts. A null value will not match any logins, and
-    *        will thus always return a count of 0.
-    * @param aActionURL
-    *        The URL to which a form login will be submitted. To match any
-    *        form login, specify an empty string. To not match any form
-    *        login, specify null.
-    * @param aHttpRealm
-    *        The HTTP Realm for which the login applies. To match logins for
-    *        any realm, specify an empty string. To not match logins for any
-    *        realm, specify null.
-    */
-   unsigned long countLogins(in AString aHostname, in AString aActionURL,
-                             in AString aHttpRealm);
+  /**
+   * Obtain a list of all hosts for which password saving is disabled.
+   *
+   * @param count
+   *        The number of elements in the array. JS callers can simply use
+   *        the array's .length property and omit this param.
+   * @param hostnames
+   *        An array of hostname strings, in origin URL format without a
+   *        pathname. For example: "https://www.site.com".
+   *
+   * NOTE: This can be called from JS as:
+   *       var logins = pwmgr.getDisabledAllLogins();
+   */
+  void getAllDisabledHosts([optional] out unsigned long count,
+                    [retval, array, size_is(count)] out wstring hostnames);
+
+
+  /**
+   * Check to see if saving logins has been disabled for a host.
+   *
+   * @param aHost
+   *        The hostname to check. This argument should be in the origin
+   *        URL format, without a pathname. For example: "http://foo.com".
+   */
+  boolean getLoginSavingEnabled(in AString aHost);
+
+
+  /**
+   * Disable (or enable) storing logins for the specified host. When
+   * disabled, the login manager will not prompt to store logins for
+   * that host. Existing logins are not affected.
+   *
+   * @param aHost
+   *        The hostname to set. This argument should be in the origin
+   *        URL format, without a pathname. For example: "http://foo.com".
+   * @param isEnabled
+   *        Specify if saving logins should be enabled (true) or
+   *        disabled (false)
+   */
+  void setLoginSavingEnabled(in AString aHost, in boolean isEnabled);
+
+
+  /**
+   * Search for logins matching the specified criteria. Called when looking
+   * for logins that might be applicable to a form or authentication request.
+   *
+   * @param count
+   *        The number of elements in the array. JS callers can simply use
+   *        the array's .length property, and supply an dummy object for
+   *        this out param. For example: |findLogins({}, hostname, ...)|
+   * @param aHostname
+   *        The hostname to restrict searches to, in URL format. For
+   *        example: "http://www.site.com".
+   *        To find logins for a given nsIURI, you would typically pass in
+   *        its prePath.
+   * @param aActionURL
+   *        For form logins, this argument should be the URL to which the
+   *        form will be submitted. For protocol logins, specify null.
+   *        An empty string ("") will match any value (except null).
+   * @param aHttpRealm
+   *        For protocol logins, this argument should be the HTTP Realm
+   *        for which the login applies. This is obtained from the
+   *        WWW-Authenticate header. See RFC2617. For form logins,
+   *        specify null.
+   *        An empty string ("") will match any value (except null).
+   * @param logins
+   *        An array of nsILoginInfo objects.
+   *
+   * NOTE: This can be called from JS as:
+   *       var logins = pwmgr.findLogins({}, hostname, ...);
+   *
+   */
+  void findLogins(out unsigned long count, in AString aHostname,
+                  in AString aActionURL,   in AString aHttpRealm,
+                  [retval, array, size_is(count)] out nsILoginInfo logins);
 
 
-    /**
-     * Generate results for a userfield autocomplete menu.
-     *
-     * NOTE: This interface is provided for use only by the FormFillController,
-     *       which calls it directly. This isn't really ideal, it should
-     *       probably be callback registered through the FFC.
-     */
-    void autoCompleteSearchAsync(in AString aSearchString,
-                                 in nsIAutoCompleteResult aPreviousResult,
-                                 in nsIDOMHTMLInputElement aElement,
-                                 in nsIFormAutoCompleteObserver aListener);
+  /**
+   * Search for logins matching the specified criteria, as with
+   * findLogins(). This interface only returns the number of matching
+   * logins (and not the logins themselves), which allows a caller to
+   * check for logins without causing the user to be prompted for a master
+   * password to decrypt the logins.
+   *
+   * @param aHostname
+   *        The hostname to restrict searches to. Specify an empty string
+   *        to match all hosts. A null value will not match any logins, and
+   *        will thus always return a count of 0.
+   * @param aActionURL
+   *        The URL to which a form login will be submitted. To match any
+   *        form login, specify an empty string. To not match any form
+   *        login, specify null.
+   * @param aHttpRealm
+   *        The HTTP Realm for which the login applies. To match logins for
+   *        any realm, specify an empty string. To not match logins for any
+   *        realm, specify null.
+   */
+  unsigned long countLogins(in AString aHostname, in AString aActionURL,
+                            in AString aHttpRealm);
 
-    /**
-     * Fill a form with login information if we have it. This method will fill
-     * aForm regardless of the signon.autofillForms preference.
-     *
-     * @param aForm
-     *        The form to fill
-     * @return Promise that is resolved with whether or not the form was filled.
-     */
-    jsval fillForm(in nsIDOMHTMLFormElement aForm);
+
+  /**
+   * Generate results for a userfield autocomplete menu.
+   *
+   * NOTE: This interface is provided for use only by the FormFillController,
+   *       which calls it directly. This isn't really ideal, it should
+   *       probably be callback registered through the FFC.
+   */
+  void autoCompleteSearchAsync(in AString aSearchString,
+                               in nsIAutoCompleteResult aPreviousResult,
+                               in nsIDOMHTMLInputElement aElement,
+                               in nsIFormAutoCompleteObserver aListener);
 
-    /**
-     * Search for logins in the login manager. An array is always returned;
-     * if there are no logins the array is empty.
-     *
-     * @param count
-     *        The number of elements in the array. JS callers can simply use
-     *        the array's .length property, and supply an dummy object for
-     *        this out param. For example: |searchLogins({}, matchData)|
-     * @param matchData
-     *        The data used to search. This does not follow the same
-     *        requirements as findLogins for those fields. Wildcard matches are
-     *        simply not specified.
-     * @param logins
-     *        An array of nsILoginInfo objects.
-     *
-     * NOTE: This can be called from JS as:
-     *       var logins = pwmgr.searchLogins({}, matchData);
-     *       (|logins| is an array).
-     */
-    void searchLogins(out unsigned long count, in nsIPropertyBag matchData,
-                      [retval, array, size_is(count)] out nsILoginInfo logins);
+  /**
+   * Fill a form with login information if we have it. This method will fill
+   * aForm regardless of the signon.autofillForms preference.
+   *
+   * @param aForm
+   *        The form to fill
+   * @return Promise that is resolved with whether or not the form was filled.
+   */
+  jsval fillForm(in nsIDOMHTMLFormElement aForm);
 
-   /**
-    * True when a master password prompt is being displayed.
-    */
-    readonly attribute boolean uiBusy;
+  /**
+   * Search for logins in the login manager. An array is always returned;
+   * if there are no logins the array is empty.
+   *
+   * @param count
+   *        The number of elements in the array. JS callers can simply use
+   *        the array's .length property, and supply an dummy object for
+   *        this out param. For example: |searchLogins({}, matchData)|
+   * @param matchData
+   *        The data used to search. This does not follow the same
+   *        requirements as findLogins for those fields. Wildcard matches are
+   *        simply not specified.
+   * @param logins
+   *        An array of nsILoginInfo objects.
+   *
+   * NOTE: This can be called from JS as:
+   *       var logins = pwmgr.searchLogins({}, matchData);
+   *       (|logins| is an array).
+   */
+  void searchLogins(out unsigned long count, in nsIPropertyBag matchData,
+                    [retval, array, size_is(count)] out nsILoginInfo logins);
 
-   /**
-    * True when the master password has already been entered, and so a caller
-    * can ask for decrypted logins without triggering a prompt.
-    */
-    readonly attribute boolean isLoggedIn;
+ /**
+  * True when a master password prompt is being displayed.
+  */
+  readonly attribute boolean uiBusy;
+
+ /**
+  * True when the master password has already been entered, and so a caller
+  * can ask for decrypted logins without triggering a prompt.
+  */
+  readonly attribute boolean isLoggedIn;
 };
 
 %{C++
 
 #define NS_LOGINMANAGER_CONTRACTID "@mozilla.org/login-manager;1"
 
 %}
--- a/toolkit/components/passwordmgr/nsILoginManagerCrypto.idl
+++ b/toolkit/components/passwordmgr/nsILoginManagerCrypto.idl
@@ -4,64 +4,64 @@
 
 
 #include "nsISupports.idl"
 
 [scriptable, uuid(2030770e-542e-40cd-8061-cd9d4ad4227f)]
 
 interface nsILoginManagerCrypto : nsISupports {
 
-    const unsigned long ENCTYPE_BASE64 = 0; // obsolete
-    const unsigned long ENCTYPE_SDR = 1;
+  const unsigned long ENCTYPE_BASE64 = 0; // obsolete
+  const unsigned long ENCTYPE_SDR = 1;
 
-    /**
-     * encrypt
-     *
-     * @param plainText
-     *        The string to be encrypted.
-     *
-     * Encrypts the specified string, returning the ciphertext value.
-     *
-     * NOTE: The current implemention of this inferface simply uses NSS/PSM's
-     * "Secret Decoder Ring" service. It is not recommended for general
-     * purpose encryption/decryption.
-     *
-     * Can throw if the user cancels entry of their master password.
-     */
-    AString encrypt(in AString plainText);
+  /**
+   * encrypt
+   *
+   * @param plainText
+   *        The string to be encrypted.
+   *
+   * Encrypts the specified string, returning the ciphertext value.
+   *
+   * NOTE: The current implemention of this inferface simply uses NSS/PSM's
+   * "Secret Decoder Ring" service. It is not recommended for general
+   * purpose encryption/decryption.
+   *
+   * Can throw if the user cancels entry of their master password.
+   */
+  AString encrypt(in AString plainText);
 
-    /**
-     * decrypt
-     *
-     * @param cipherText
-     *        The string to be decrypted.
-     *
-     * Decrypts the specified string, returning the plaintext value.
-     *
-     * Can throw if the user cancels entry of their master password, or if the
-     * cipherText value can not be successfully decrypted (eg, if it was
-     * encrypted with some other key).
-     */
-    AString decrypt(in AString cipherText);
+  /**
+   * decrypt
+   *
+   * @param cipherText
+   *        The string to be decrypted.
+   *
+   * Decrypts the specified string, returning the plaintext value.
+   *
+   * Can throw if the user cancels entry of their master password, or if the
+   * cipherText value can not be successfully decrypted (eg, if it was
+   * encrypted with some other key).
+   */
+  AString decrypt(in AString cipherText);
 
-    /**
-     * uiBusy
-     *
-     * True when a master password prompt is being displayed.
-     */
-    readonly attribute boolean uiBusy;
+  /**
+   * uiBusy
+   *
+   * True when a master password prompt is being displayed.
+   */
+  readonly attribute boolean uiBusy;
 
-    /**
-     * isLoggedIn
-     *
-     * Current login state of the token used for encryption. If the user is
-     * not logged in, performing a crypto operation will result in a master
-     * password prompt.
-     */
-    readonly attribute boolean isLoggedIn;
+  /**
+   * isLoggedIn
+   *
+   * Current login state of the token used for encryption. If the user is
+   * not logged in, performing a crypto operation will result in a master
+   * password prompt.
+   */
+  readonly attribute boolean isLoggedIn;
 
-    /**
-     * defaultEncType
-     *
-     * Default encryption type used by an implementation of this interface.
-     */
-    readonly attribute unsigned long defaultEncType;
+  /**
+   * defaultEncType
+   *
+   * Default encryption type used by an implementation of this interface.
+   */
+  readonly attribute unsigned long defaultEncType;
 };
--- a/toolkit/components/passwordmgr/nsILoginManagerPrompter.idl
+++ b/toolkit/components/passwordmgr/nsILoginManagerPrompter.idl
@@ -6,77 +6,77 @@
 #include "nsISupports.idl"
 
 interface nsILoginInfo;
 interface nsIDOMElement;
 interface nsIDOMWindow;
 
 [scriptable, uuid(425f73b9-b2db-4e8a-88c5-9ac2512934ce)]
 interface nsILoginManagerPrompter : nsISupports {
-    /**
-     * Initialize the prompter. Must be called before using other interfaces.
-     *
-     * @param aWindow
-     *        The in which the user is doing some login-related action that's
-     *        resulting in a need to prompt them for something. The prompt
-     *        will be associated with this window (or, if a notification bar
-     *        is being used, topmost opener in some cases).
-     */
-    void init(in nsIDOMWindow aWindow);
+  /**
+   * Initialize the prompter. Must be called before using other interfaces.
+   *
+   * @param aWindow
+   *        The in which the user is doing some login-related action that's
+   *        resulting in a need to prompt them for something. The prompt
+   *        will be associated with this window (or, if a notification bar
+   *        is being used, topmost opener in some cases).
+   */
+  void init(in nsIDOMWindow aWindow);
 
-    /**
-     * If the caller knows which browser this prompter is being created for,
-     * they can call this function to avoid having to calculate it from the
-     * window passed to init.
-     *
-     * @param aBrowser the <browser> to use for this prompter.
-     * @param aOpener the opener to use for this prompter.
-     */
-    void setE10sData(in nsIDOMElement aBrowser, in nsIDOMWindow aOpener);
+  /**
+   * If the caller knows which browser this prompter is being created for,
+   * they can call this function to avoid having to calculate it from the
+   * window passed to init.
+   *
+   * @param aBrowser the <browser> to use for this prompter.
+   * @param aOpener the opener to use for this prompter.
+   */
+  void setE10sData(in nsIDOMElement aBrowser, in nsIDOMWindow aOpener);
 
-    /**
-     * Ask the user if they want to save a login (Yes, Never, Not Now)
-     *
-     * @param aLogin
-     *        The login to be saved.
-     */
-    void promptToSavePassword(in nsILoginInfo aLogin);
+  /**
+   * Ask the user if they want to save a login (Yes, Never, Not Now)
+   *
+   * @param aLogin
+   *        The login to be saved.
+   */
+  void promptToSavePassword(in nsILoginInfo aLogin);
 
-    /**
-     * Ask the user if they want to change a login's password. If the
-     * user consents, modifyLogin() will be called.
-     *
-     * @param aOldLogin
-     *        The existing login (with the old password).
-     * @param aNewLogin
-     *        The new login.
-     */
-    void promptToChangePassword(in nsILoginInfo aOldLogin,
-                                in nsILoginInfo aNewLogin);
+  /**
+   * Ask the user if they want to change a login's password. If the
+   * user consents, modifyLogin() will be called.
+   *
+   * @param aOldLogin
+   *        The existing login (with the old password).
+   * @param aNewLogin
+   *        The new login.
+   */
+  void promptToChangePassword(in nsILoginInfo aOldLogin,
+                              in nsILoginInfo aNewLogin);
 
-    /**
-     * Ask the user if they want to change the password for one of
-     * multiple logins, when the caller can't determine exactly which
-     * login should be changed. If the user consents, modifyLogin() will
-     * be called.
-     *
-     * @param logins
-     *        An array of existing logins.
-     * @param count
-     *        (length of the array)
-     * @param aNewLogin
-     *        The new login.
-     *
-     * Note: Because the caller does not know the username of the login
-     *       to be changed, aNewLogin.username and aNewLogin.usernameField
-     *       will be set (using the user's selection) before modifyLogin()
-     *       is called.
-     */
-    void promptToChangePasswordWithUsernames(
-            [array, size_is(count)] in nsILoginInfo logins,
-            in uint32_t count,
-            in nsILoginInfo aNewLogin);
+  /**
+   * Ask the user if they want to change the password for one of
+   * multiple logins, when the caller can't determine exactly which
+   * login should be changed. If the user consents, modifyLogin() will
+   * be called.
+   *
+   * @param logins
+   *        An array of existing logins.
+   * @param count
+   *        (length of the array)
+   * @param aNewLogin
+   *        The new login.
+   *
+   * Note: Because the caller does not know the username of the login
+   *       to be changed, aNewLogin.username and aNewLogin.usernameField
+   *       will be set (using the user's selection) before modifyLogin()
+   *       is called.
+   */
+  void promptToChangePasswordWithUsernames(
+          [array, size_is(count)] in nsILoginInfo logins,
+          in uint32_t count,
+          in nsILoginInfo aNewLogin);
 };
 %{C++
 
 #define NS_LOGINMANAGERPROMPTER_CONTRACTID "@mozilla.org/login-manager/prompter/;1"
 
 %}
--- a/toolkit/components/passwordmgr/nsILoginManagerStorage.idl
+++ b/toolkit/components/passwordmgr/nsILoginManagerStorage.idl
@@ -14,239 +14,239 @@ interface nsIPropertyBag;
 /*
  * NOTE: This interface is intended to be implemented by modules
  *       providing storage mechanisms for the login manager.
  *       Other code should use the login manager's interfaces
  *       (nsILoginManager), and should not call storage modules
  *       directly.
  */
 interface nsILoginManagerStorage : nsISupports {
-    /**
-     * Initialize the component.
-     *
-     * At present, other methods of this interface may be called before the
-     * returned promise is resolved or rejected.
-     *
-     * @return {Promise}
-     * @resolves When initialization is complete.
-     * @rejects JavaScript exception.
-     */
-    jsval initialize();
-
-
-    /**
-     * Ensures that all data has been written to disk and all files are closed.
-     *
-     * At present, this method is called by regression tests only.  Finalization
-     * on shutdown is done by observers within the component.
-     *
-     * @return {Promise}
-     * @resolves When finalization is complete.
-     * @rejects JavaScript exception.
-     */
-    jsval terminate();
-
-
-    /**
-     * Store a new login in the storage module.
-     *
-     * @param aLogin
-     *        The login to be added.
-     *
-     * Default values for the login's nsILoginMetaInfo properties will be
-     * created. However, if the caller specifies non-default values, they will
-     * be used instead.
-     */
-    void addLogin(in nsILoginInfo aLogin);
+  /**
+   * Initialize the component.
+   *
+   * At present, other methods of this interface may be called before the
+   * returned promise is resolved or rejected.
+   *
+   * @return {Promise}
+   * @resolves When initialization is complete.
+   * @rejects JavaScript exception.
+   */
+  jsval initialize();
 
 
-    /**
-     * Remove a login from the storage module.
-     *
-     * @param aLogin
-     *        The login to be removed.
-     *
-     * The specified login must exactly match a stored login. However, the
-     * values of any nsILoginMetaInfo properties are ignored.
-     */
-    void removeLogin(in nsILoginInfo aLogin);
+  /**
+   * Ensures that all data has been written to disk and all files are closed.
+   *
+   * At present, this method is called by regression tests only.  Finalization
+   * on shutdown is done by observers within the component.
+   *
+   * @return {Promise}
+   * @resolves When finalization is complete.
+   * @rejects JavaScript exception.
+   */
+  jsval terminate();
 
 
-    /**
-     * Modify an existing login in the storage module.
-     *
-     * @param oldLogin
-     *        The login to be modified.
-     * @param newLoginData
-     *        The new login values (either a nsILoginInfo or nsIProperyBag)
-     *
-     * If newLoginData is a nsILoginInfo, all of the old login's nsILoginInfo
-     * properties are changed to the values from newLoginData (but the old
-     * login's nsILoginMetaInfo properties are unmodified).
-     *
-     * If newLoginData is a nsIPropertyBag, only the specified properties
-     * will be changed. The nsILoginMetaInfo properties of oldLogin can be
-     * changed in this manner.
-     *
-     * If the propertybag contains an item named "timesUsedIncrement", the
-     * login's timesUsed property will be incremented by the item's value.
-     */
-    void modifyLogin(in nsILoginInfo oldLogin, in nsISupports newLoginData);
-
-
-    /**
-     * Remove all stored logins.
-     *
-     * The browser sanitization feature allows the user to clear any stored
-     * passwords. This interface allows that to be done without getting each
-     * login first (which might require knowing the master password).
-     *
-     */
-    void removeAllLogins();
+  /**
+   * Store a new login in the storage module.
+   *
+   * @param aLogin
+   *        The login to be added.
+   *
+   * Default values for the login's nsILoginMetaInfo properties will be
+   * created. However, if the caller specifies non-default values, they will
+   * be used instead.
+   */
+  void addLogin(in nsILoginInfo aLogin);
 
 
-    /**
-     * Fetch all logins in the login manager. An array is always returned;
-     * if there are no logins the array is empty.
-     *
-     * @param count
-     *        The number of elements in the array. JS callers can simply use
-     *        the array's .length property and omit this param.
-     * @param logins
-     *        An array of nsILoginInfo objects.
-     *
-     * NOTE: This can be called from JS as:
-     *       var logins = pwmgr.getAllLogins();
-     *       (|logins| is an array).
-     */
-    void getAllLogins([optional] out unsigned long count,
-                      [retval, array, size_is(count)] out nsILoginInfo logins);
-
-
-    /**
-     * Search for logins in the login manager. An array is always returned;
-     * if there are no logins the array is empty.
-     *
-     * @param count
-     *        The number of elements in the array. JS callers can simply use
-     *        the array's .length property, and supply an dummy object for
-     *        this out param. For example: |searchLogins({}, matchData)|
-     * @param matchData
-     *        The data used to search. This does not follow the same
-     *        requirements as findLogins for those fields. Wildcard matches are
-     *        simply not specified.
-     * @param logins
-     *        An array of nsILoginInfo objects.
-     *
-     * NOTE: This can be called from JS as:
-     *       var logins = pwmgr.searchLogins({}, matchData);
-     *       (|logins| is an array).
-     */
-    void searchLogins(out unsigned long count, in nsIPropertyBag matchData,
-                      [retval, array, size_is(count)] out nsILoginInfo logins);
+  /**
+   * Remove a login from the storage module.
+   *
+   * @param aLogin
+   *        The login to be removed.
+   *
+   * The specified login must exactly match a stored login. However, the
+   * values of any nsILoginMetaInfo properties are ignored.
+   */
+  void removeLogin(in nsILoginInfo aLogin);
 
 
-    /**
-     * Obtain a list of all hosts for which password saving is disabled.
-     *
-     * @param count
-     *        The number of elements in the array. JS callers can simply use
-     *        the array's .length property and omit this param.
-     * @param hostnames
-     *        An array of hostname strings, in origin URL format without a
-     *        pathname. For example: "https://www.site.com".
-     *
-     * NOTE: This can be called from JS as:
-     *       var logins = pwmgr.getAllDisabledHosts();
-     */
-    void getAllDisabledHosts([optional] out unsigned long count,
-                      [retval, array, size_is(count)] out wstring hostnames);
-
-
-    /**
-     * Check to see if saving logins has been disabled for a host.
-     *
-     * @param aHost
-     *        The hostname to check. This argument should be in the origin
-     *        URL format, without a pathname. For example: "http://foo.com".
-     */
-    boolean getLoginSavingEnabled(in AString aHost);
+  /**
+   * Modify an existing login in the storage module.
+   *
+   * @param oldLogin
+   *        The login to be modified.
+   * @param newLoginData
+   *        The new login values (either a nsILoginInfo or nsIProperyBag)
+   *
+   * If newLoginData is a nsILoginInfo, all of the old login's nsILoginInfo
+   * properties are changed to the values from newLoginData (but the old
+   * login's nsILoginMetaInfo properties are unmodified).
+   *
+   * If newLoginData is a nsIPropertyBag, only the specified properties
+   * will be changed. The nsILoginMetaInfo properties of oldLogin can be
+   * changed in this manner.
+   *
+   * If the propertybag contains an item named "timesUsedIncrement", the
+   * login's timesUsed property will be incremented by the item's value.
+   */
+  void modifyLogin(in nsILoginInfo oldLogin, in nsISupports newLoginData);
 
 
-    /**
-     * Disable (or enable) storing logins for the specified host. When
-     * disabled, the login manager will not prompt to store logins for
-     * that host. Existing logins are not affected.
-     *
-     * @param aHost
-     *        The hostname to set. This argument should be in the origin
-     *        URL format, without a pathname. For example: "http://foo.com".
-     * @param isEnabled
-     *        Specify if saving logins should be enabled (true) or
-     *        disabled (false)
-     */
-    void setLoginSavingEnabled(in AString aHost, in boolean isEnabled);
+  /**
+   * Remove all stored logins.
+   *
+   * The browser sanitization feature allows the user to clear any stored
+   * passwords. This interface allows that to be done without getting each
+   * login first (which might require knowing the master password).
+   *
+   */
+  void removeAllLogins();
 
 
-    /**
-     * Search for logins matching the specified criteria. Called when looking
-     * for logins that might be applicable to a form or authentication request.
-     *
-     * @param count
-     *        The number of elements in the array. JS callers can simply use
-     *        the array's .length property, and supply an dummy object for
-     *        this out param. For example: |findLogins({}, hostname, ...)|
-     * @param aHostname
-     *        The hostname to restrict searches to, in URL format. For
-     *        example: "http://www.site.com".
-     * @param aActionURL
-     *        For form logins, this argument should be the URL to which the
-     *        form will be submitted. For protocol logins, specify null.
-     * @param aHttpRealm
-     *        For protocol logins, this argument should be the HTTP Realm
-     *        for which the login applies. This is obtained from the
-     *        WWW-Authenticate header. See RFC2617. For form logins,
-     *        specify null.
-     * @param logins
-     *        An array of nsILoginInfo objects.
-     *
-     * NOTE: This can be called from JS as:
-     *       var logins = pwmgr.findLogins({}, hostname, ...);
-     *
-     */
-    void findLogins(out unsigned long count, in AString aHostname,
-                    in AString aActionURL,   in AString aHttpRealm,
+  /**
+   * Fetch all logins in the login manager. An array is always returned;
+   * if there are no logins the array is empty.
+   *
+   * @param count
+   *        The number of elements in the array. JS callers can simply use
+   *        the array's .length property and omit this param.
+   * @param logins
+   *        An array of nsILoginInfo objects.
+   *
+   * NOTE: This can be called from JS as:
+   *       var logins = pwmgr.getAllLogins();
+   *       (|logins| is an array).
+   */
+  void getAllLogins([optional] out unsigned long count,
                     [retval, array, size_is(count)] out nsILoginInfo logins);
 
 
-   /**
-    * Search for logins matching the specified criteria, as with
-    * findLogins(). This interface only returns the number of matching
-    * logins (and not the logins themselves), which allows a caller to
-    * check for logins without causing the user to be prompted for a master
-    * password to decrypt the logins.
-    *
-    * @param aHostname
-    *        The hostname to restrict searches to. Specify an empty string
-    *        to match all hosts. A null value will not match any logins, and
-    *        will thus always return a count of 0.
-    * @param aActionURL
-    *        The URL to which a form login will be submitted. To match any
-    *        form login, specify an empty string. To not match any form
-    *        login, specify null.
-    * @param aHttpRealm
-    *        The HTTP Realm for which the login applies. To match logins for
-    *        any realm, specify an empty string. To not match logins for any
-    *        realm, specify null.
-    */
-   unsigned long countLogins(in AString aHostname, in AString aActionURL,
-                             in AString aHttpRealm);
-   /**
-    * True when a master password prompt is being shown.
-    */
-    readonly attribute boolean uiBusy;
+  /**
+   * Search for logins in the login manager. An array is always returned;
+   * if there are no logins the array is empty.
+   *
+   * @param count
+   *        The number of elements in the array. JS callers can simply use
+   *        the array's .length property, and supply an dummy object for
+   *        this out param. For example: |searchLogins({}, matchData)|
+   * @param matchData
+   *        The data used to search. This does not follow the same
+   *        requirements as findLogins for those fields. Wildcard matches are
+   *        simply not specified.
+   * @param logins
+   *        An array of nsILoginInfo objects.
+   *
+   * NOTE: This can be called from JS as:
+   *       var logins = pwmgr.searchLogins({}, matchData);
+   *       (|logins| is an array).
+   */
+  void searchLogins(out unsigned long count, in nsIPropertyBag matchData,
+                    [retval, array, size_is(count)] out nsILoginInfo logins);
+
+
+  /**
+   * Obtain a list of all hosts for which password saving is disabled.
+   *
+   * @param count
+   *        The number of elements in the array. JS callers can simply use
+   *        the array's .length property and omit this param.
+   * @param hostnames
+   *        An array of hostname strings, in origin URL format without a
+   *        pathname. For example: "https://www.site.com".
+   *
+   * NOTE: This can be called from JS as:
+   *       var logins = pwmgr.getAllDisabledHosts();
+   */
+  void getAllDisabledHosts([optional] out unsigned long count,
+                    [retval, array, size_is(count)] out wstring hostnames);
+
+
+  /**
+   * Check to see if saving logins has been disabled for a host.
+   *
+   * @param aHost
+   *        The hostname to check. This argument should be in the origin
+   *        URL format, without a pathname. For example: "http://foo.com".
+   */
+  boolean getLoginSavingEnabled(in AString aHost);
+
+
+  /**
+   * Disable (or enable) storing logins for the specified host. When
+   * disabled, the login manager will not prompt to store logins for
+   * that host. Existing logins are not affected.
+   *
+   * @param aHost
+   *        The hostname to set. This argument should be in the origin
+   *        URL format, without a pathname. For example: "http://foo.com".
+   * @param isEnabled
+   *        Specify if saving logins should be enabled (true) or
+   *        disabled (false)
+   */
+  void setLoginSavingEnabled(in AString aHost, in boolean isEnabled);
+
 
-   /**
-    * True when the master password has already been entered, and so a caller
-    * can ask for decrypted logins without triggering a prompt.
-    */
-    readonly attribute boolean isLoggedIn;
+  /**
+   * Search for logins matching the specified criteria. Called when looking
+   * for logins that might be applicable to a form or authentication request.
+   *
+   * @param count
+   *        The number of elements in the array. JS callers can simply use
+   *        the array's .length property, and supply an dummy object for
+   *        this out param. For example: |findLogins({}, hostname, ...)|
+   * @param aHostname
+   *        The hostname to restrict searches to, in URL format. For
+   *        example: "http://www.site.com".
+   * @param aActionURL
+   *        For form logins, this argument should be the URL to which the
+   *        form will be submitted. For protocol logins, specify null.
+   * @param aHttpRealm
+   *        For protocol logins, this argument should be the HTTP Realm
+   *        for which the login applies. This is obtained from the
+   *        WWW-Authenticate header. See RFC2617. For form logins,
+   *        specify null.
+   * @param logins
+   *        An array of nsILoginInfo objects.
+   *
+   * NOTE: This can be called from JS as:
+   *       var logins = pwmgr.findLogins({}, hostname, ...);
+   *
+   */
+  void findLogins(out unsigned long count, in AString aHostname,
+                  in AString aActionURL,   in AString aHttpRealm,
+                  [retval, array, size_is(count)] out nsILoginInfo logins);
+
+
+  /**
+   * Search for logins matching the specified criteria, as with
+   * findLogins(). This interface only returns the number of matching
+   * logins (and not the logins themselves), which allows a caller to
+   * check for logins without causing the user to be prompted for a master
+   * password to decrypt the logins.
+   *
+   * @param aHostname
+   *        The hostname to restrict searches to. Specify an empty string
+   *        to match all hosts. A null value will not match any logins, and
+   *        will thus always return a count of 0.
+   * @param aActionURL
+   *        The URL to which a form login will be submitted. To match any
+   *        form login, specify an empty string. To not match any form
+   *        login, specify null.
+   * @param aHttpRealm
+   *        The HTTP Realm for which the login applies. To match logins for
+   *        any realm, specify an empty string. To not match logins for any
+   *        realm, specify null.
+   */
+  unsigned long countLogins(in AString aHostname, in AString aActionURL,
+                            in AString aHttpRealm);
+  /**
+   * True when a master password prompt is being shown.
+   */
+  readonly attribute boolean uiBusy;
+
+  /**
+   * True when the master password has already been entered, and so a caller
+   * can ask for decrypted logins without triggering a prompt.
+   */
+  readonly attribute boolean isLoggedIn;
 };
--- a/toolkit/components/passwordmgr/nsILoginMetaInfo.idl
+++ b/toolkit/components/passwordmgr/nsILoginMetaInfo.idl
@@ -12,42 +12,42 @@
  *
  * Code using login manager can generally ignore this interface. When adding
  * logins, default value will be created. When modifying logins, these
  * properties will be unchanged unless a change is explicitly requested [by
  * using modifyLogin() with a nsIPropertyBag]. When deleting a login or
  * comparing logins, these properties are ignored.
  */
 interface nsILoginMetaInfo : nsISupports {
-    /**
-     * The GUID to uniquely identify the login. This can be any arbitrary
-     * string, but a format as created by nsIUUIDGenerator is recommended.
-     * For example, "{d4e1a1f6-5ea0-40ee-bff5-da57982f21cf}"
-     *
-     * addLogin will generate a random value unless a value is provided.
-     *
-     * addLogin and modifyLogin will throw if the GUID already exists.
-     */
-    attribute AString guid;
+  /**
+   * The GUID to uniquely identify the login. This can be any arbitrary
+   * string, but a format as created by nsIUUIDGenerator is recommended.
+   * For example, "{d4e1a1f6-5ea0-40ee-bff5-da57982f21cf}"
+   *
+   * addLogin will generate a random value unless a value is provided.
+   *
+   * addLogin and modifyLogin will throw if the GUID already exists.
+   */
+  attribute AString guid;
 
-    /**
-     * The time, in Unix Epoch milliseconds, when the login was first created.
-     */
-    attribute unsigned long long timeCreated;
+  /**
+   * The time, in Unix Epoch milliseconds, when the login was first created.
+   */
+  attribute unsigned long long timeCreated;
 
-    /**
-     * The time, in Unix Epoch milliseconds, when the login was last submitted
-     * in a form or used to begin an HTTP auth session.
-     */
-    attribute unsigned long long timeLastUsed;
+  /**
+   * The time, in Unix Epoch milliseconds, when the login was last submitted
+   * in a form or used to begin an HTTP auth session.
+   */
+  attribute unsigned long long timeLastUsed;
 
-    /**
-     * The time, in Unix Epoch milliseconds, when the login's password was
-     * last modified.
-     */
-    attribute unsigned long long timePasswordChanged;
+  /**
+   * The time, in Unix Epoch milliseconds, when the login's password was
+   * last modified.
+   */
+  attribute unsigned long long timePasswordChanged;
 
-    /**
-     * The number of times the login was submitted in a form or used to begin
-     * an HTTP auth session.
-     */
-    attribute unsigned long timesUsed;
+  /**
+   * The number of times the login was submitted in a form or used to begin
+   * an HTTP auth session.
+   */
+  attribute unsigned long timesUsed;
 };
--- a/toolkit/components/passwordmgr/nsLoginInfo.js
+++ b/toolkit/components/passwordmgr/nsLoginInfo.js
@@ -7,98 +7,98 @@ const Cc = Components.classes;
 const Ci = Components.interfaces;
 
 Components.utils.import("resource://gre/modules/XPCOMUtils.jsm");
 
 function nsLoginInfo() {}
 
 nsLoginInfo.prototype = {
 
-    classID : Components.ID("{0f2f347c-1e4f-40cc-8efd-792dea70a85e}"),
-    QueryInterface: XPCOMUtils.generateQI([Ci.nsILoginInfo, Ci.nsILoginMetaInfo]),
+  classID : Components.ID("{0f2f347c-1e4f-40cc-8efd-792dea70a85e}"),
+  QueryInterface: XPCOMUtils.generateQI([Ci.nsILoginInfo, Ci.nsILoginMetaInfo]),
 
-    //
-    // nsILoginInfo interfaces...
-    //
+  //
+  // nsILoginInfo interfaces...
+  //
 
-    hostname      : null,
-    formSubmitURL : null,
-    httpRealm     : null,
-    username      : null,
-    password      : null,
-    usernameField : null,
-    passwordField : null,
+  hostname      : null,
+  formSubmitURL : null,
+  httpRealm     : null,
+  username      : null,
+  password      : null,
+  usernameField : null,
+  passwordField : null,
 
-    init : function (aHostname, aFormSubmitURL, aHttpRealm,
-                     aUsername,      aPassword,
-                     aUsernameField, aPasswordField) {
-        this.hostname      = aHostname;
-        this.formSubmitURL = aFormSubmitURL;
-        this.httpRealm     = aHttpRealm;
-        this.username      = aUsername;
-        this.password      = aPassword;
-        this.usernameField = aUsernameField;
-        this.passwordField = aPasswordField;
-    },
+  init : function (aHostname, aFormSubmitURL, aHttpRealm,
+                   aUsername,      aPassword,
+                   aUsernameField, aPasswordField) {
+    this.hostname      = aHostname;
+    this.formSubmitURL = aFormSubmitURL;
+    this.httpRealm     = aHttpRealm;
+    this.username      = aUsername;
+    this.password      = aPassword;
+    this.usernameField = aUsernameField;
+    this.passwordField = aPasswordField;
+  },
 
-    matches : function (aLogin, ignorePassword) {
-        if (this.hostname      != aLogin.hostname      ||
-            this.httpRealm     != aLogin.httpRealm     ||
-            this.username      != aLogin.username)
-            return false;
+  matches : function (aLogin, ignorePassword) {
+    if (this.hostname      != aLogin.hostname      ||
+        this.httpRealm     != aLogin.httpRealm     ||
+        this.username      != aLogin.username)
+      return false;
 
-        if (!ignorePassword && this.password != aLogin.password)
-            return false;
+    if (!ignorePassword && this.password != aLogin.password)
+      return false;
 
-        // If either formSubmitURL is blank (but not null), then match.
-        if (this.formSubmitURL != "" && aLogin.formSubmitURL != "" &&
-            this.formSubmitURL != aLogin.formSubmitURL)
-            return false;
+    // If either formSubmitURL is blank (but not null), then match.
+    if (this.formSubmitURL != "" && aLogin.formSubmitURL != "" &&
+        this.formSubmitURL != aLogin.formSubmitURL)
+      return false;
 
-        // The .usernameField and .passwordField values are ignored.
+    // The .usernameField and .passwordField values are ignored.
 
-        return true;
-    },
+    return true;
+  },
 
-    equals : function (aLogin) {
-        if (this.hostname      != aLogin.hostname      ||
-            this.formSubmitURL != aLogin.formSubmitURL ||
-            this.httpRealm     != aLogin.httpRealm     ||
-            this.username      != aLogin.username      ||
-            this.password      != aLogin.password      ||
-            this.usernameField != aLogin.usernameField ||
-            this.passwordField != aLogin.passwordField)
-            return false;
+  equals : function (aLogin) {
+    if (this.hostname      != aLogin.hostname      ||
+        this.formSubmitURL != aLogin.formSubmitURL ||
+        this.httpRealm     != aLogin.httpRealm     ||
+        this.username      != aLogin.username      ||
+        this.password      != aLogin.password      ||
+        this.usernameField != aLogin.usernameField ||
+        this.passwordField != aLogin.passwordField)
+      return false;
 
-        return true;
-    },
+    return true;
+  },
 
-    clone : function() {
-        let clone = Cc["@mozilla.org/login-manager/loginInfo;1"].
-                    createInstance(Ci.nsILoginInfo);
-        clone.init(this.hostname, this.formSubmitURL, this.httpRealm,
-                   this.username, this.password,
-                   this.usernameField, this.passwordField);
+  clone : function() {
+    let clone = Cc["@mozilla.org/login-manager/loginInfo;1"].
+                createInstance(Ci.nsILoginInfo);
+    clone.init(this.hostname, this.formSubmitURL, this.httpRealm,
+               this.username, this.password,
+               this.usernameField, this.passwordField);
 
-        // Copy nsILoginMetaInfo props
-        clone.QueryInterface(Ci.nsILoginMetaInfo);
-        clone.guid = this.guid;
-        clone.timeCreated = this.timeCreated;
-        clone.timeLastUsed = this.timeLastUsed;
-        clone.timePasswordChanged = this.timePasswordChanged;
-        clone.timesUsed = this.timesUsed;
+    // Copy nsILoginMetaInfo props
+    clone.QueryInterface(Ci.nsILoginMetaInfo);
+    clone.guid = this.guid;
+    clone.timeCreated = this.timeCreated;
+    clone.timeLastUsed = this.timeLastUsed;
+    clone.timePasswordChanged = this.timePasswordChanged;
+    clone.timesUsed = this.timesUsed;
 
-        return clone;
-    },
+    return clone;
+  },
 
-    //
-    // nsILoginMetaInfo interfaces...
-    //
+  //
+  // nsILoginMetaInfo interfaces...
+  //
 
-    guid : null,
-    timeCreated : null,
-    timeLastUsed : null,
-    timePasswordChanged : null,
-    timesUsed : null
+  guid : null,
+  timeCreated : null,
+  timeLastUsed : null,
+  timePasswordChanged : null,
+  timesUsed : null
 
 }; // end of nsLoginInfo implementation
 
 this.NSGetFactory = XPCOMUtils.generateNSGetFactory([nsLoginInfo]);
--- a/toolkit/components/passwordmgr/nsLoginManager.js
+++ b/toolkit/components/passwordmgr/nsLoginManager.js
@@ -17,539 +17,539 @@ XPCOMUtils.defineLazyModuleGetter(this, 
                                   "resource://gre/modules/Promise.jsm");
 XPCOMUtils.defineLazyModuleGetter(this, "Task",
                                   "resource://gre/modules/Task.jsm");
 XPCOMUtils.defineLazyModuleGetter(this, "BrowserUtils",
                                   "resource://gre/modules/BrowserUtils.jsm");
 
 var debug = false;
 function log(...pieces) {
-    function generateLogMessage(args) {
-        let strings = ['Login Manager:'];
+  function generateLogMessage(args) {
+    let strings = ['Login Manager:'];
 
-        args.forEach(function(arg) {
-            if (typeof arg === 'string') {
-                strings.push(arg);
-            } else if (typeof arg === 'undefined') {
-                strings.push('undefined');
-            } else if (arg === null) {
-                strings.push('null');
-            } else {
-                try {
-                  strings.push(JSON.stringify(arg, null, 2));
-                } catch(err) {
-                  strings.push("<<something>>");
-                }
-            }
-        });
-        return strings.join(' ');
-    }
+    args.forEach(function(arg) {
+      if (typeof arg === 'string') {
+        strings.push(arg);
+      } else if (typeof arg === 'undefined') {
+        strings.push('undefined');
+      } else if (arg === null) {
+        strings.push('null');
+      } else {
+        try {
+          strings.push(JSON.stringify(arg, null, 2));
+        } catch(err) {
+          strings.push("<<something>>");
+        }
+      }
+    });
+    return strings.join(' ');
+  }
 
-    if (!debug)
-        return;
+  if (!debug)
+    return;
 
-    let message = generateLogMessage(pieces);
-    dump(message + "\n");
-    Services.console.logStringMessage(message);
+  let message = generateLogMessage(pieces);
+  dump(message + "\n");
+  Services.console.logStringMessage(message);
 }
 
 function LoginManager() {
-    this.init();
+  this.init();
 }
 
 LoginManager.prototype = {
 
-    classID: Components.ID("{cb9e0de8-3598-4ed7-857b-827f011ad5d8}"),
-    QueryInterface : XPCOMUtils.generateQI([Ci.nsILoginManager,
-                                            Ci.nsISupportsWeakReference,
-                                            Ci.nsIInterfaceRequestor]),
-    getInterface : function(aIID) {
-        if (aIID.equals(Ci.mozIStorageConnection) && this._storage) {
-          let ir = this._storage.QueryInterface(Ci.nsIInterfaceRequestor);
-          return ir.getInterface(aIID);
-        }
+  classID: Components.ID("{cb9e0de8-3598-4ed7-857b-827f011ad5d8}"),
+  QueryInterface : XPCOMUtils.generateQI([Ci.nsILoginManager,
+                                          Ci.nsISupportsWeakReference,
+                                          Ci.nsIInterfaceRequestor]),
+  getInterface : function(aIID) {
+    if (aIID.equals(Ci.mozIStorageConnection) && this._storage) {
+      let ir = this._storage.QueryInterface(Ci.nsIInterfaceRequestor);
+      return ir.getInterface(aIID);
+    }
 
-        if (aIID.equals(Ci.nsIVariant)) {
-            // Allows unwrapping the JavaScript object for regression tests.
-            return this;
-        }
+    if (aIID.equals(Ci.nsIVariant)) {
+      // Allows unwrapping the JavaScript object for regression tests.
+      return this;
+    }
 
-        throw Cr.NS_ERROR_NO_INTERFACE;
-    },
+    throw Cr.NS_ERROR_NO_INTERFACE;
+  },
 
 
-    /* ---------- private members ---------- */
+  /* ---------- private members ---------- */
 
 
-    __formFillService : null, // FormFillController, for username autocompleting
-    get _formFillService() {
-        if (!this.__formFillService)
-            this.__formFillService =
-                            Cc["@mozilla.org/satchel/form-fill-controller;1"].
-                            getService(Ci.nsIFormFillController);
-        return this.__formFillService;
-    },
+  __formFillService : null, // FormFillController, for username autocompleting
+  get _formFillService() {
+    if (!this.__formFillService)
+      this.__formFillService =
+                      Cc["@mozilla.org/satchel/form-fill-controller;1"].
+                      getService(Ci.nsIFormFillController);
+    return this.__formFillService;
+  },
 
 
-    _storage : null, // Storage component which contains the saved logins
-    _prefBranch  : null, // Preferences service
-    _remember : true,  // mirrors signon.rememberSignons preference
+  _storage : null, // Storage component which contains the saved logins
+  _prefBranch  : null, // Preferences service
+  _remember : true,  // mirrors signon.rememberSignons preference
 
 
-    /*
-     * init
-     *
-     * Initialize the Login Manager. Automatically called when service
-     * is created.
-     *
-     * Note: Service created in /browser/base/content/browser.js,
-     *       delayedStartup()
-     */
-    init : function () {
+  /*
+   * init
+   *
+   * Initialize the Login Manager. Automatically called when service
+   * is created.
+   *
+   * Note: Service created in /browser/base/content/browser.js,
+   *       delayedStartup()
+   */
+  init : function () {
 
-        // Cache references to current |this| in utility objects
-        this._observer._pwmgr            = this;
+    // Cache references to current |this| in utility objects
+    this._observer._pwmgr            = this;
 
-        // Preferences. Add observer so we get notified of changes.
-        this._prefBranch = Services.prefs.getBranch("signon.");
-        this._prefBranch.addObserver("", this._observer, false);
+    // Preferences. Add observer so we get notified of changes.
+    this._prefBranch = Services.prefs.getBranch("signon.");
+    this._prefBranch.addObserver("", this._observer, false);
 
-        // Get current preference values.
-        debug = this._prefBranch.getBoolPref("debug");
+    // Get current preference values.
+    debug = this._prefBranch.getBoolPref("debug");
 
-        this._remember = this._prefBranch.getBoolPref("rememberSignons");
+    this._remember = this._prefBranch.getBoolPref("rememberSignons");
 
-        // Form submit observer checks forms for new logins and pw changes.
-        Services.obs.addObserver(this._observer, "xpcom-shutdown", false);
+    // Form submit observer checks forms for new logins and pw changes.
+    Services.obs.addObserver(this._observer, "xpcom-shutdown", false);
 
-        // TODO: Make this class useful in the child process (in addition to
-        // autoCompleteSearchAsync and fillForm).
-        if (Services.appinfo.processType ===
-            Services.appinfo.PROCESS_TYPE_DEFAULT) {
-            Services.obs.addObserver(this._observer, "passwordmgr-storage-replace",
-                                     false);
+    // TODO: Make this class useful in the child process (in addition to
+    // autoCompleteSearchAsync and fillForm).
+    if (Services.appinfo.processType ===
+        Services.appinfo.PROCESS_TYPE_DEFAULT) {
+      Services.obs.addObserver(this._observer, "passwordmgr-storage-replace",
+                               false);
 
-            // Initialize storage so that asynchronous data loading can start.
-            this._initStorage();
-        }
+      // Initialize storage so that asynchronous data loading can start.
+      this._initStorage();
+    }
 
-        Services.obs.addObserver(this._observer, "gather-telemetry", false);
-    },
+    Services.obs.addObserver(this._observer, "gather-telemetry", false);
+  },
 
 
-    _initStorage : function () {
+  _initStorage : function () {
 #ifdef ANDROID
-        var contractID = "@mozilla.org/login-manager/storage/mozStorage;1";
+    var contractID = "@mozilla.org/login-manager/storage/mozStorage;1";
 #else
-        var contractID = "@mozilla.org/login-manager/storage/json;1";
+    var contractID = "@mozilla.org/login-manager/storage/json;1";
 #endif
-        try {
-            var catMan = Cc["@mozilla.org/categorymanager;1"].
-                         getService(Ci.nsICategoryManager);
-            contractID = catMan.getCategoryEntry("login-manager-storage",
-                                                 "nsILoginManagerStorage");
-            log("Found alternate nsILoginManagerStorage with contract ID:", contractID);
-        } catch (e) {
-            log("No alternate nsILoginManagerStorage registered");
-        }
+    try {
+      var catMan = Cc["@mozilla.org/categorymanager;1"].
+                   getService(Ci.nsICategoryManager);
+      contractID = catMan.getCategoryEntry("login-manager-storage",
+                                           "nsILoginManagerStorage");
+      log("Found alternate nsILoginManagerStorage with contract ID:", contractID);
+    } catch (e) {
+      log("No alternate nsILoginManagerStorage registered");
+    }
 
-        this._storage = Cc[contractID].
-                        createInstance(Ci.nsILoginManagerStorage);
-        this.initializationPromise = this._storage.initialize();
-    },
+    this._storage = Cc[contractID].
+                    createInstance(Ci.nsILoginManagerStorage);
+    this.initializationPromise = this._storage.initialize();
+  },
 
 
-    /* ---------- Utility objects ---------- */
+  /* ---------- Utility objects ---------- */
 
 
-    /*
-     * _observer object
-     *
-     * Internal utility object, implements the nsIObserver interface.
-     * Used to receive notification for: form submission, preference changes.
-     */
-    _observer : {
-        _pwmgr : null,
+  /*
+   * _observer object
+   *
+   * Internal utility object, implements the nsIObserver interface.
+   * Used to receive notification for: form submission, preference changes.
+   */
+  _observer : {
+    _pwmgr : null,
 
-        QueryInterface : XPCOMUtils.generateQI([Ci.nsIObserver,
-                                                Ci.nsISupportsWeakReference]),
+    QueryInterface : XPCOMUtils.generateQI([Ci.nsIObserver,
+                                            Ci.nsISupportsWeakReference]),
 
-        // nsObserver
-        observe : function (subject, topic, data) {
+    // nsObserver
+    observe : function (subject, topic, data) {
 
-            if (topic == "nsPref:changed") {
-                var prefName = data;
-                log("got change to", prefName, "preference");
+      if (topic == "nsPref:changed") {
+        var prefName = data;
+        log("got change to", prefName, "preference");
 
-                if (prefName == "debug") {
-                    debug = this._pwmgr._prefBranch.getBoolPref("debug");
-                } else if (prefName == "rememberSignons") {
-                    this._pwmgr._remember =
-                        this._pwmgr._prefBranch.getBoolPref("rememberSignons");
-                } else {
-                    log("Oops! Pref not handled, change ignored.");
-                }
-            } else if (topic == "xpcom-shutdown") {
-                delete this._pwmgr.__formFillService;
-                delete this._pwmgr._storage;
-                delete this._pwmgr._prefBranch;
-                this._pwmgr = null;
-            } else if (topic == "passwordmgr-storage-replace") {
-                Task.spawn(function () {
-                  yield this._pwmgr._storage.terminate();
-                  this._pwmgr._initStorage();
-                  yield this._pwmgr.initializationPromise;
-                  Services.obs.notifyObservers(null,
-                               "passwordmgr-storage-replace-complete", null);
-                }.bind(this));
-            } else if (topic == "gather-telemetry") {
-                this._pwmgr._gatherTelemetry();
-            } else {
-                log("Oops! Unexpected notification:", topic);
-            }
+        if (prefName == "debug") {
+          debug = this._pwmgr._prefBranch.getBoolPref("debug");
+        } else if (prefName == "rememberSignons") {
+          this._pwmgr._remember =
+              this._pwmgr._prefBranch.getBoolPref("rememberSignons");
+        } else {
+          log("Oops! Pref not handled, change ignored.");
         }
-    },
-
-    _gatherTelemetry : function() {
-      let numPasswordsBlocklist = Services.telemetry.getHistogramById("PWMGR_BLOCKLIST_NUM_SITES");
-      numPasswordsBlocklist.clear();
-      numPasswordsBlocklist.add(this.getAllDisabledHosts({}).length);
-
-      let numPasswordsHist = Services.telemetry.getHistogramById("PWMGR_NUM_SAVED_PASSWORDS");
-      numPasswordsHist.clear();
-      numPasswordsHist.add(this.countLogins("", "", ""));
+      } else if (topic == "xpcom-shutdown") {
+        delete this._pwmgr.__formFillService;
+        delete this._pwmgr._storage;
+        delete this._pwmgr._prefBranch;
+        this._pwmgr = null;
+      } else if (topic == "passwordmgr-storage-replace") {
+        Task.spawn(function () {
+          yield this._pwmgr._storage.terminate();
+          this._pwmgr._initStorage();
+          yield this._pwmgr.initializationPromise;
+          Services.obs.notifyObservers(null,
+                       "passwordmgr-storage-replace-complete", null);
+        }.bind(this));
+      } else if (topic == "gather-telemetry") {
+        this._pwmgr._gatherTelemetry();
+      } else {
+        log("Oops! Unexpected notification:", topic);
+      }
+    }
+  },
 
-      let isPwdSavedEnabledHist = Services.telemetry.getHistogramById("PWMGR_SAVING_ENABLED");
-      isPwdSavedEnabledHist.clear();
-      isPwdSavedEnabledHist.add(this._remember);
+  _gatherTelemetry : function() {
+    let numPasswordsBlocklist = Services.telemetry.getHistogramById("PWMGR_BLOCKLIST_NUM_SITES");
+    numPasswordsBlocklist.clear();
+    numPasswordsBlocklist.add(this.getAllDisabledHosts({}).length);
 
-      // Don't try to get logins if MP is enabled, since we don't want to show a MP prompt.
-      if (this.isLoggedIn) {
-        let logins = this.getAllLogins({});
+    let numPasswordsHist = Services.telemetry.getHistogramById("PWMGR_NUM_SAVED_PASSWORDS");
+    numPasswordsHist.clear();
+    numPasswordsHist.add(this.countLogins("", "", ""));
 
-        let usernameHist = Services.telemetry.getHistogramById("PWMGR_USERNAME_PRESENT");
-        usernameHist.clear();
-        for (let login of logins) {
-          usernameHist.add(!!login.username);
-        }
+    let isPwdSavedEnabledHist = Services.telemetry.getHistogramById("PWMGR_SAVING_ENABLED");
+    isPwdSavedEnabledHist.clear();
+    isPwdSavedEnabledHist.add(this._remember);
+
+    // Don't try to get logins if MP is enabled, since we don't want to show a MP prompt.
+    if (this.isLoggedIn) {
+      let logins = this.getAllLogins({});
+
+      let usernameHist = Services.telemetry.getHistogramById("PWMGR_USERNAME_PRESENT");
+      usernameHist.clear();
+      for (let login of logins) {
+        usernameHist.add(!!login.username);
       }
-    },
+    }
+  },
 
 
 
 
 
-    /* ---------- Primary Public interfaces ---------- */
+  /* ---------- Primary Public interfaces ---------- */
 
 
 
 
-    /*
-     * initializationPromise
-     *
-     * This promise is resolved when initialization is complete, and is rejected
-     * in case the asynchronous part of initialization failed.
-     */
-    initializationPromise : null,
+  /*
+   * initializationPromise
+   *
+   * This promise is resolved when initialization is complete, and is rejected
+   * in case the asynchronous part of initialization failed.
+   */
+  initializationPromise : null,
 
 
-    /*
-     * addLogin
-     *
-     * Add a new login to login storage.
-     */
-    addLogin : function (login) {
-        // Sanity check the login
-        if (login.hostname == null || login.hostname.length == 0)
-            throw "Can't add a login with a null or empty hostname.";
+  /*
+   * addLogin
+   *
+   * Add a new login to login storage.
+   */
+  addLogin : function (login) {
+    // Sanity check the login
+    if (login.hostname == null || login.hostname.length == 0)
+      throw "Can't add a login with a null or empty hostname.";
 
-        // For logins w/o a username, set to "", not null.
-        if (login.username == null)
-            throw "Can't add a login with a null username.";
+    // For logins w/o a username, set to "", not null.
+    if (login.username == null)
+      throw "Can't add a login with a null username.";
 
-        if (login.password == null || login.password.length == 0)
-            throw "Can't add a login with a null or empty password.";
+    if (login.password == null || login.password.length == 0)
+      throw "Can't add a login with a null or empty password.";
 
-        if (login.formSubmitURL || login.formSubmitURL == "") {
-            // We have a form submit URL. Can't have a HTTP realm.
-            if (login.httpRealm != null)
-                throw "Can't add a login with both a httpRealm and formSubmitURL.";
-        } else if (login.httpRealm) {
-            // We have a HTTP realm. Can't have a form submit URL.
-            if (login.formSubmitURL != null)
-                throw "Can't add a login with both a httpRealm and formSubmitURL.";
-        } else {
-            // Need one or the other!
-            throw "Can't add a login without a httpRealm or formSubmitURL.";
-        }
+    if (login.formSubmitURL || login.formSubmitURL == "") {
+      // We have a form submit URL. Can't have a HTTP realm.
+      if (login.httpRealm != null)
+        throw "Can't add a login with both a httpRealm and formSubmitURL.";
+    } else if (login.httpRealm) {
+      // We have a HTTP realm. Can't have a form submit URL.
+      if (login.formSubmitURL != null)
+        throw "Can't add a login with both a httpRealm and formSubmitURL.";
+    } else {
+      // Need one or the other!
+      throw "Can't add a login without a httpRealm or formSubmitURL.";
+    }
 
 
-        // Look for an existing entry.
-        var logins = this.findLogins({}, login.hostname, login.formSubmitURL,
-                                     login.httpRealm);
+    // Look for an existing entry.
+    var logins = this.findLogins({}, login.hostname, login.formSubmitURL,
+                                 login.httpRealm);
 
-        if (logins.some(function(l) login.matches(l, true)))
-            throw "This login already exists.";
+    if (logins.some(function(l) login.matches(l, true)))
+      throw "This login already exists.";
 
-        log("Adding login");
-        return this._storage.addLogin(login);
-    },
+    log("Adding login");
+    return this._storage.addLogin(login);
+  },
 
 
-    /*
-     * removeLogin
-     *
-     * Remove the specified login from the stored logins.
-     */
-    removeLogin : function (login) {
-        log("Removing login");
-        return this._storage.removeLogin(login);
-    },
+  /*
+   * removeLogin
+   *
+   * Remove the specified login from the stored logins.
+   */
+  removeLogin : function (login) {
+    log("Removing login");
+    return this._storage.removeLogin(login);
+  },
 
 
-    /*
-     * modifyLogin
-     *
-     * Change the specified login to match the new login.
-     */
-    modifyLogin : function (oldLogin, newLogin) {
-        log("Modifying login");
-        return this._storage.modifyLogin(oldLogin, newLogin);
-    },
+  /*
+   * modifyLogin
+   *
+   * Change the specified login to match the new login.
+   */
+  modifyLogin : function (oldLogin, newLogin) {
+    log("Modifying login");
+    return this._storage.modifyLogin(oldLogin, newLogin);
+  },
 
 
-    /*
-     * getAllLogins
-     *
-     * Get a dump of all stored logins. Used by the login manager UI.
-     *
-     * |count| is only needed for XPCOM.
-     *
-     * Returns an array of logins. If there are no logins, the array is empty.
-     */
-    getAllLogins : function (count) {
-        log("Getting a list of all logins");
-        return this._storage.getAllLogins(count);
-    },
+  /*
+   * getAllLogins
+   *
+   * Get a dump of all stored logins. Used by the login manager UI.
+   *
+   * |count| is only needed for XPCOM.
+   *
+   * Returns an array of logins. If there are no logins, the array is empty.
+   */
+  getAllLogins : function (count) {
+    log("Getting a list of all logins");
+    return this._storage.getAllLogins(count);
+  },
 
 
-    /*
-     * removeAllLogins
-     *
-     * Remove all stored logins.
-     */
-    removeAllLogins : function () {
-        log("Removing all logins");
-        this._storage.removeAllLogins();
-    },
+  /*
+   * removeAllLogins
+   *
+   * Remove all stored logins.
+   */
+  removeAllLogins : function () {
+    log("Removing all logins");
+    this._storage.removeAllLogins();
+  },
 
-    /*
-     * getAllDisabledHosts
-     *
-     * Get a list of all hosts for which logins are disabled.
-     *
-     * |count| is only needed for XPCOM.
-     *
-     * Returns an array of disabled logins. If there are no disabled logins,
-     * the array is empty.
-     */
-    getAllDisabledHosts : function (count) {
-        log("Getting a list of all disabled hosts");
-        return this._storage.getAllDisabledHosts(count);
-    },
+  /*
+   * getAllDisabledHosts
+   *
+   * Get a list of all hosts for which logins are disabled.
+   *
+   * |count| is only needed for XPCOM.
+   *
+   * Returns an array of disabled logins. If there are no disabled logins,
+   * the array is empty.
+   */
+  getAllDisabledHosts : function (count) {
+    log("Getting a list of all disabled hosts");
+    return this._storage.getAllDisabledHosts(count);
+  },
 
 
-    /*
-     * findLogins
-     *
-     * Search for the known logins for entries matching the specified criteria.
-     */
-    findLogins : function (count, hostname, formSubmitURL, httpRealm) {
-        log("Searching for logins matching host:", hostname,
-            "formSubmitURL:", formSubmitURL, "httpRealm:", httpRealm);
+  /*
+   * findLogins
+   *
+   * Search for the known logins for entries matching the specified criteria.
+   */
+  findLogins : function (count, hostname, formSubmitURL, httpRealm) {
+    log("Searching for logins matching host:", hostname,
+        "formSubmitURL:", formSubmitURL, "httpRealm:", httpRealm);
 
-        return this._storage.findLogins(count, hostname, formSubmitURL,
-                                        httpRealm);
-    },
+    return this._storage.findLogins(count, hostname, formSubmitURL,
+                                    httpRealm);
+  },
 
 
-    /*
-     * searchLogins
-     *
-     * Public wrapper around _searchLogins to convert the nsIPropertyBag to a
-     * JavaScript object and decrypt the results.
-     *
-     * Returns an array of decrypted nsILoginInfo.
-     */
-    searchLogins : function(count, matchData) {
-       log("Searching for logins");
+  /*
+   * searchLogins
+   *
+   * Public wrapper around _searchLogins to convert the nsIPropertyBag to a
+   * JavaScript object and decrypt the results.
+   *
+   * Returns an array of decrypted nsILoginInfo.
+   */
+  searchLogins : function(count, matchData) {
+   log("Searching for logins");
 
-        return this._storage.searchLogins(count, matchData);
-    },
+    return this._storage.searchLogins(count, matchData);
+  },
 
 
-    /*
-     * countLogins
-     *
-     * Search for the known logins for entries matching the specified criteria,
-     * returns only the count.
-     */
-    countLogins : function (hostname, formSubmitURL, httpRealm) {
-        log("Counting logins matching host:", hostname,
-            "formSubmitURL:", formSubmitURL, "httpRealm:", httpRealm);
+  /*
+   * countLogins
+   *
+   * Search for the known logins for entries matching the specified criteria,
+   * returns only the count.
+   */
+  countLogins : function (hostname, formSubmitURL, httpRealm) {
+    log("Counting logins matching host:", hostname,
+        "formSubmitURL:", formSubmitURL, "httpRealm:", httpRealm);
 
-        return this._storage.countLogins(hostname, formSubmitURL, httpRealm);
-    },
+    return this._storage.countLogins(hostname, formSubmitURL, httpRealm);
+  },
 
 
-    /*
-     * uiBusy
-     */
-    get uiBusy() {
-        return this._storage.uiBusy;
-    },
+  /*
+   * uiBusy
+   */
+  get uiBusy() {
+    return this._storage.uiBusy;
+  },
 
 
-    /*
-     * isLoggedIn
-     */
-    get isLoggedIn() {
-        return this._storage.isLoggedIn;
-    },
+  /*
+   * isLoggedIn
+   */
+  get isLoggedIn() {
+    return this._storage.isLoggedIn;
+  },
 
 
-    /*
-     * getLoginSavingEnabled
-     *
-     * Check to see if user has disabled saving logins for the host.
-     */
-    getLoginSavingEnabled : function (host) {
-        log("Checking if logins to", host, "can be saved.");
-        if (!this._remember)
-            return false;
+  /*
+   * getLoginSavingEnabled
+   *
+   * Check to see if user has disabled saving logins for the host.
+   */
+  getLoginSavingEnabled : function (host) {
+    log("Checking if logins to", host, "can be saved.");
+    if (!this._remember)
+      return false;
 
-        return this._storage.getLoginSavingEnabled(host);
-    },
+    return this._storage.getLoginSavingEnabled(host);
+  },
 
 
-    /*
-     * setLoginSavingEnabled
-     *
-     * Enable or disable storing logins for the specified host.
-     */
-    setLoginSavingEnabled : function (hostname, enabled) {
-        // Nulls won't round-trip with getAllDisabledHosts().
-        if (hostname.indexOf("\0") != -1)
-            throw "Invalid hostname";
+  /*
+   * setLoginSavingEnabled
+   *
+   * Enable or disable storing logins for the specified host.
+   */
+  setLoginSavingEnabled : function (hostname, enabled) {
+    // Nulls won't round-trip with getAllDisabledHosts().
+    if (hostname.indexOf("\0") != -1)
+      throw "Invalid hostname";
 
-        log("Login saving for", hostname, "now enabled?", enabled);
-        return this._storage.setLoginSavingEnabled(hostname, enabled);
-    },
+    log("Login saving for", hostname, "now enabled?", enabled);
+    return this._storage.setLoginSavingEnabled(hostname, enabled);
+  },
 
-    /*
-     * autoCompleteSearchAsync
-     *
-     * Yuck. This is called directly by satchel:
-     * nsFormFillController::StartSearch()
-     * [toolkit/components/satchel/nsFormFillController.cpp]
-     *
-     * We really ought to have a simple way for code to register an
-     * auto-complete provider, and not have satchel calling pwmgr directly.
-     */
-    autoCompleteSearchAsync : function (aSearchString, aPreviousResult,
-                                        aElement, aCallback) {
-        // aPreviousResult is an nsIAutoCompleteResult, aElement is
-        // nsIDOMHTMLInputElement
+  /*
+   * autoCompleteSearchAsync
+   *
+   * Yuck. This is called directly by satchel:
+   * nsFormFillController::StartSearch()
+   * [toolkit/components/satchel/nsFormFillController.cpp]
+   *
+   * We really ought to have a simple way for code to register an
+   * auto-complete provider, and not have satchel calling pwmgr directly.
+   */
+  autoCompleteSearchAsync : function (aSearchString, aPreviousResult,
+                                      aElement, aCallback) {
+    // aPreviousResult is an nsIAutoCompleteResult, aElement is
+    // nsIDOMHTMLInputElement
 
-        if (!this._remember) {
-            setTimeout(function() {
-                aCallback.onSearchCompletion(new UserAutoCompleteResult(aSearchString, []));
-            }, 0);
-            return;
-        }
+    if (!this._remember) {
+      setTimeout(function() {
+        aCallback.onSearchCompletion(new UserAutoCompleteResult(aSearchString, []));
+      }, 0);
+      return;
+    }
 
-        log("AutoCompleteSearch invoked. Search is:", aSearchString);
+    log("AutoCompleteSearch invoked. Search is:", aSearchString);
 
-        var previousResult;
-        if (aPreviousResult) {
-            previousResult = { searchString: aPreviousResult.searchString,
-                               logins: aPreviousResult.wrappedJSObject.logins };
-        } else {
-            previousResult = null;
-        }
+    var previousResult;
+    if (aPreviousResult) {
+      previousResult = { searchString: aPreviousResult.searchString,
+                         logins: aPreviousResult.wrappedJSObject.logins };
+    } else {
+      previousResult = null;
+    }
 
-        let rect = BrowserUtils.getElementBoundingScreenRect(aElement);
-        LoginManagerContent._autoCompleteSearchAsync(aSearchString, previousResult,
-                                                     aElement, rect)
-                           .then(function(logins) {
-                               let results =
-                                   new UserAutoCompleteResult(aSearchString, logins);
-                               aCallback.onSearchCompletion(results);
-                           })
-                           .then(null, Cu.reportError);
-    },
+    let rect = BrowserUtils.getElementBoundingScreenRect(aElement);
+    LoginManagerContent._autoCompleteSearchAsync(aSearchString, previousResult,