Merge inbound to m-c a=merge
authorWes Kocher <wkocher@mozilla.com>
Mon, 13 Oct 2014 18:50:20 -0700
changeset 210208 54217864bae9ce772dabcb68d9a9cb0654431d34
parent 210163 155b84a1d18a94370a8642ded512434bf270b73b (current diff)
parent 210207 c782a908f89c5d5a8f6c120113ca2d08bdcd2a90 (diff)
child 210209 c2f0f3847dbc4f204c0bc2318f36abb7a8db3996
child 210225 e997cbe0c5b6ec69fb837fc62125eb1c63ca91e9
child 210276 3e08f81eed80e0152bec5050efc79ea66fa96d25
push id1
push userroot
push dateMon, 20 Oct 2014 17:29:22 +0000
reviewersmerge
milestone36.0a1
Merge inbound to m-c a=merge
--- a/accessible/interfaces/nsIAccessiblePivot.idl
+++ b/accessible/interfaces/nsIAccessiblePivot.idl
@@ -186,17 +186,17 @@ interface nsIAccessiblePivot : nsISuppor
    * @param aObserver [in] the observer object to remove from being notified.
    */
   void removeObserver(in nsIAccessiblePivotObserver aObserver);
 };
 
 /**
  * An observer interface for pivot changes.
  */
-[scriptable, uuid(b6508c5e-c081-467d-835c-613eedf9ee9b)]
+[scriptable, uuid(6006e502-3861-49bd-aba1-fa6d2e74e237)]
 interface nsIAccessiblePivotObserver : nsISupports
 {
   /**
    * Called when the pivot changes.
    *
    * @param aPivot           [in] the pivot that has changed.
    * @param aOldAccessible   [in] the old pivot position before the change,
    *                           or null.
--- a/b2g/chrome/content/shell.js
+++ b/b2g/chrome/content/shell.js
@@ -328,16 +328,17 @@ var shell = {
     window.addEventListener('MozApplicationManifest', this);
     window.addEventListener('mozfullscreenchange', this);
     window.addEventListener('MozAfterPaint', this);
     window.addEventListener('sizemodechange', this);
     window.addEventListener('unload', this);
     this.contentBrowser.addEventListener('mozbrowserloadstart', this, true);
     this.contentBrowser.addEventListener('mozbrowserselectionchange', this, true);
     this.contentBrowser.addEventListener('mozbrowserscrollviewchange', this, true);
+    this.contentBrowser.addEventListener('mozbrowsertouchcarettap', this, true);
 
     CustomEventManager.init();
     WebappsHelper.init();
     UserAgentOverrides.init();
     IndexedDBPromptHelper.init();
     CaptivePortalLoginHelper.init();
 
     this.contentBrowser.src = homeURL;
@@ -356,16 +357,17 @@ var shell = {
     window.removeEventListener('keypress', this, true);
     window.removeEventListener('keyup', this, true);
     window.removeEventListener('MozApplicationManifest', this);
     window.removeEventListener('mozfullscreenchange', this);
     window.removeEventListener('sizemodechange', this);
     this.contentBrowser.removeEventListener('mozbrowserloadstart', this, true);
     this.contentBrowser.removeEventListener('mozbrowserselectionchange', this, true);
     this.contentBrowser.removeEventListener('mozbrowserscrollviewchange', this, true);
+    this.contentBrowser.removeEventListener('mozbrowsertouchcarettap', this, true);
     ppmm.removeMessageListener("content-handler", this);
 
     UserAgentOverrides.uninit();
     IndexedDBPromptHelper.uninit();
   },
 
   // If this key event actually represents a hardware button, filter it here
   // and send a mozChromeEvent with detail.type set to xxx-button-press or
@@ -503,16 +505,22 @@ var shell = {
         this.notifyContentStart();
        break;
       case 'mozbrowserscrollviewchange':
         this.sendChromeEvent({
           type: 'scrollviewchange',
           detail: evt.detail,
         });
         break;
+      case 'mozbrowsertouchcarettap':
+        this.sendChromeEvent({
+          type: 'touchcarettap',
+          detail: evt.detail,
+        });
+        break;
       case 'mozbrowserselectionchange':
         // The mozbrowserselectionchange event, may have crossed the chrome-content boundary.
         // This event always dispatch to shell.js. But the offset we got from this event is
         // based on tab's coordinate. So get the actual offsets between shell and evt.target.
         let elt = evt.target;
         let win = elt.ownerDocument.defaultView;
         let offsetX = win.mozInnerScreenX - window.mozInnerScreenX;
         let offsetY = win.mozInnerScreenY - window.mozInnerScreenY;
--- a/content/base/public/nsIDOMParser.idl
+++ b/content/base/public/nsIDOMParser.idl
@@ -14,17 +14,17 @@ interface nsIGlobalObject;
 /**
  * The nsIDOMParser interface is a non-SAX interface that can be used
  * to parse a string or byte stream containing XML or HTML content
  * to a DOM document. Parsing is always synchronous - a document is always
  * returned from the parsing methods. This is as opposed to loading and
  * parsing with the XMLHttpRequest interface, which can be used for
  * asynchronous (callback-based) loading.
  */
-[uuid(5677f36e-1842-4c6f-a39c-2e5576ab8b40)]
+[uuid(70b9600e-8622-4c93-9ad8-22c28058dc44)]
 interface nsIDOMParser : nsISupports
 {
   /**
    * The string passed in is parsed into a DOM document.
    *
    * @param str The UTF16 string to be parsed
    * @param contentType The content type of the string (see parseFromStream)
    * @returns The DOM document created as a result of parsing the 
--- a/content/html/content/src/HTMLInputElement.cpp
+++ b/content/html/content/src/HTMLInputElement.cpp
@@ -1828,23 +1828,16 @@ HTMLInputElement::SetValue(const nsAStri
       //
       // NOTE: this is currently quite expensive work (too much string
       // manipulation). We should probably optimize that.
       nsAutoString currentValue;
       GetValue(currentValue);
 
       SetValueInternal(aValue, false, true);
 
-      if (mType == NS_FORM_INPUT_RANGE) {
-        nsRangeFrame* frame = do_QueryFrame(GetPrimaryFrame());
-        if (frame) {
-          frame->UpdateForValueChange();
-        }
-      }
-
       if (mFocusedValue.Equals(currentValue)) {
         GetValue(mFocusedValue);
       }
     } else {
       SetValueInternal(aValue, false, true);
     }
   }
 }
@@ -2843,16 +2836,21 @@ HTMLInputElement::SetValueInternal(const
         if (mType == NS_FORM_INPUT_NUMBER) {
           // This has to happen before OnValueChanged is called because that
           // method needs the new value of our frame's anon text control.
           nsNumberControlFrame* numberControlFrame =
             do_QueryFrame(GetPrimaryFrame());
           if (numberControlFrame) {
             numberControlFrame->SetValueOfAnonTextControl(value);
           }
+        } else if (mType == NS_FORM_INPUT_RANGE) {
+          nsRangeFrame* frame = do_QueryFrame(GetPrimaryFrame());
+          if (frame) {
+            frame->UpdateForValueChange();
+          }
         }
         if (!mParserCreating) {
           OnValueChanged(true);
         }
         // else DoneCreatingElement calls us again once mParserCreating is false
       }
 
       if (mType == NS_FORM_INPUT_COLOR) {
--- a/dom/browser-element/BrowserElementChildPreload.js
+++ b/dom/browser-element/BrowserElementChildPreload.js
@@ -221,16 +221,22 @@ BrowserElementChild.prototype = {
                      /* useCapture = */ false,
                      /* wantsUntrusted = */ false);
 
     addEventListener('scrollviewchange',
                      this._ScrollViewChangeHandler.bind(this),
                      /* useCapture = */ false,
                      /* wantsUntrusted = */ false);
 
+    addEventListener('touchcarettap',
+                     this._touchCaretTapHandler.bind(this),
+                     /* useCapture = */ false,
+                     /* wantsUntrusted = */ false);
+
+
     // This listens to unload events from our message manager, but /not/ from
     // the |content| window.  That's because the window's unload event doesn't
     // bubble, and we're not using a capturing listener.  If we'd used
     // useCapture == true, we /would/ hear unload events from the window, which
     // is not what we want!
     addEventListener('unload',
                      this._unloadHandler.bind(this),
                      /* useCapture = */ false,
@@ -626,16 +632,21 @@ BrowserElementChild.prototype = {
 
     if (lang) {
       meta.lang = lang;
     }
 
     sendAsyncMsg('metachange', meta);
   },
 
+  _touchCaretTapHandler: function(e) {
+    e.stopPropagation();
+    sendAsyncMsg('touchcarettap');
+  },
+
   _ScrollViewChangeHandler: function(e) {
     e.stopPropagation();
     let detail = {
       state: e.state,
       scrollX: e.scrollX,
       scrollY: e.scrollY,
     };
     sendAsyncMsg('scrollviewchange', detail);
--- a/dom/browser-element/BrowserElementParent.jsm
+++ b/dom/browser-element/BrowserElementParent.jsm
@@ -253,17 +253,18 @@ BrowserElementParent.prototype = {
       "got-can-go-forward": this._gotDOMRequestResult,
       "fullscreen-origin-change": this._remoteFullscreenOriginChange,
       "rollback-fullscreen": this._remoteFrameFullscreenReverted,
       "exit-fullscreen": this._exitFullscreen,
       "got-visible": this._gotDOMRequestResult,
       "visibilitychange": this._childVisibilityChange,
       "got-set-input-method-active": this._gotDOMRequestResult,
       "selectionchange": this._handleSelectionChange,
-      "scrollviewchange": this._handleScrollViewChange
+      "scrollviewchange": this._handleScrollViewChange,
+      "touchcarettap": this._handleTouchCaretTap
     };
 
     let mmSecuritySensitiveCalls = {
       "showmodalprompt": this._handleShowModalPrompt,
       "contextmenu": this._fireCtxMenuEvent,
       "securitychange": this._fireEventFromMsg,
       "locationchange": this._fireEventFromMsg,
       "iconchange": this._fireEventFromMsg,
@@ -501,16 +502,22 @@ BrowserElementParent.prototype = {
   },
 
   _handleScrollViewChange: function(data) {
     let evt = this._createEvent("scrollviewchange", data.json,
                                 /* cancelable = */ false);
     this._frameElement.dispatchEvent(evt);
   },
 
+  _handleTouchCaretTap: function(data) {
+    let evt = this._createEvent("touchcarettap", data.json,
+                                /* cancelable = */ false);
+    this._frameElement.dispatchEvent(evt);
+  },
+
   _createEvent: function(evtName, detail, cancelable) {
     // This will have to change if we ever want to send a CustomEvent with null
     // detail.  For now, it's OK.
     if (detail !== undefined && detail !== null) {
       detail = Cu.cloneInto(detail, this._window);
       return new this._window.CustomEvent('mozbrowser' + evtName,
                                           { bubbles: true,
                                             cancelable: cancelable,
--- a/dom/indexedDB/ActorsParent.cpp
+++ b/dom/indexedDB/ActorsParent.cpp
@@ -148,16 +148,18 @@ const int32_t kStorageProgressGranularit
 const char kSavepointClause[] = "SAVEPOINT sp;";
 
 const fallible_t fallible = fallible_t();
 
 const uint32_t kFileCopyBufferSize = 32768;
 
 const char kJournalDirectoryName[] = "journals";
 
+const char kFileManagerDirectoryNameSuffix[] = ".files";
+
 const char kPrefIndexedDBEnabled[] = "dom.indexedDB.enabled";
 
 #define IDB_PREFIX "indexedDB"
 
 #ifdef MOZ_CHILD_PERMISSIONS
 const char kPermissionString[] = IDB_PREFIX;
 #endif // MOZ_CHILD_PERMISSIONS
 
@@ -5414,29 +5416,33 @@ ConvertFileIdsToArray(const nsAString& a
     aResult.AppendElement(id);
   }
 
   return NS_OK;
 }
 
 bool
 GetDatabaseBaseFilename(const nsAString& aFilename,
-                        nsAString& aDatabaseBaseFilename)
+                        nsDependentSubstring& aDatabaseBaseFilename)
 {
   MOZ_ASSERT(!aFilename.IsEmpty());
+  MOZ_ASSERT(aDatabaseBaseFilename.IsEmpty());
 
   NS_NAMED_LITERAL_STRING(sqlite, ".sqlite");
 
-  if (!StringEndsWith(aFilename, sqlite)) {
+  if (!StringEndsWith(aFilename, sqlite) ||
+      aFilename.Length() == sqlite.Length()) {
     return false;
   }
 
-  aDatabaseBaseFilename =
-    Substring(aFilename, 0, aFilename.Length() - sqlite.Length());
-
+  MOZ_ASSERT(aFilename.Length() > sqlite.Length());
+
+  aDatabaseBaseFilename.Rebind(aFilename,
+                               0,
+                               aFilename.Length() - sqlite.Length());
   return true;
 }
 
 nsresult
 ConvertBlobsToActors(PBackgroundParent* aBackgroundActor,
                      FileManager* aFileManager,
                      const nsTArray<StructuredCloneFile>& aFiles,
                      FallibleTArray<PBlobParent*>& aActors,
@@ -9145,16 +9151,22 @@ QuotaClient::NoteBackgroundThread(nsIEve
 }
 
 mozilla::dom::quota::Client::Type
 QuotaClient::GetType()
 {
   return QuotaClient::IDB;
 }
 
+struct FileManagerInitInfo
+{
+  nsCOMPtr<nsIFile> mDirectory;
+  nsCOMPtr<nsIFile> mDatabaseFile;
+};
+
 nsresult
 QuotaClient::InitOrigin(PersistenceType aPersistenceType,
                         const nsACString& aGroup,
                         const nsACString& aOrigin,
                         UsageInfo* aUsageInfo)
 {
   AssertIsOnIOThread();
 
@@ -9165,141 +9177,222 @@ QuotaClient::InitOrigin(PersistenceType 
     return rv;
   }
 
   // We need to see if there are any files in the directory already. If they
   // are database files then we need to cleanup stored files (if it's needed)
   // and also get the usage.
 
   nsAutoTArray<nsString, 20> subdirsToProcess;
-  nsAutoTArray<nsCOMPtr<nsIFile> , 20> unknownFiles;
+  nsTArray<nsCOMPtr<nsIFile>> unknownFiles;
   nsTHashtable<nsStringHashKey> validSubdirs(20);
+  nsAutoTArray<FileManagerInitInfo, 20> initInfos;
 
   nsCOMPtr<nsISimpleEnumerator> entries;
   rv = directory->GetDirectoryEntries(getter_AddRefs(entries));
   if (NS_WARN_IF(NS_FAILED(rv))) {
     return rv;
   }
 
+  const NS_ConvertASCIItoUTF16 filesSuffix(kFileManagerDirectoryNameSuffix);
+
   bool hasMore;
   while (NS_SUCCEEDED((rv = entries->HasMoreElements(&hasMore))) &&
-         hasMore && (!aUsageInfo || !aUsageInfo->Canceled())) {
+         hasMore &&
+         (!aUsageInfo || !aUsageInfo->Canceled())) {
     nsCOMPtr<nsISupports> entry;
     rv = entries->GetNext(getter_AddRefs(entry));
     if (NS_WARN_IF(NS_FAILED(rv))) {
       return rv;
     }
 
     nsCOMPtr<nsIFile> file = do_QueryInterface(entry);
     MOZ_ASSERT(file);
 
     nsString leafName;
     rv = file->GetLeafName(leafName);
     if (NS_WARN_IF(NS_FAILED(rv))) {
       return rv;
     }
 
-    if (StringEndsWith(leafName, NS_LITERAL_STRING(".sqlite-journal"))) {
-      continue;
-    }
-
-    if (leafName.EqualsLiteral(DSSTORE_FILE_NAME)) {
-      continue;
-    }
 
     bool isDirectory;
     rv = file->IsDirectory(&isDirectory);
     if (NS_WARN_IF(NS_FAILED(rv))) {
       return rv;
     }
 
     if (isDirectory) {
-      if (!validSubdirs.GetEntry(leafName)) {
+      if (!StringEndsWith(leafName, filesSuffix) ||
+          !validSubdirs.GetEntry(leafName)) {
         subdirsToProcess.AppendElement(leafName);
       }
       continue;
     }
 
-    nsString dbBaseFilename;
+    // Skip SQLite and Desktop Service Store (.DS_Store) files.
+    // Desktop Service Store file is only used on Mac OS X, but the profile
+    // can be shared across different operating systems, so we check it on
+    // all platforms.
+    if (StringEndsWith(leafName, NS_LITERAL_STRING(".sqlite-journal")) ||
+        leafName.EqualsLiteral(DSSTORE_FILE_NAME)) {
+      continue;
+    }
+
+    nsDependentSubstring dbBaseFilename;
     if (!GetDatabaseBaseFilename(leafName, dbBaseFilename)) {
       unknownFiles.AppendElement(file);
       continue;
     }
 
+    nsString fmDirectoryBaseName = dbBaseFilename + filesSuffix;
+
     nsCOMPtr<nsIFile> fmDirectory;
     rv = directory->Clone(getter_AddRefs(fmDirectory));
     if (NS_WARN_IF(NS_FAILED(rv))) {
       return rv;
     }
 
-    rv = fmDirectory->Append(dbBaseFilename);
-    if (NS_WARN_IF(NS_FAILED(rv))) {
-      return rv;
-    }
-
-    rv = FileManager::InitDirectory(fmDirectory, file, aPersistenceType, aGroup,
+    rv = fmDirectory->Append(fmDirectoryBaseName);
+    if (NS_WARN_IF(NS_FAILED(rv))) {
+      return rv;
+    }
+
+    FileManagerInitInfo* initInfo = initInfos.AppendElement();
+    initInfo->mDirectory.swap(fmDirectory);
+    initInfo->mDatabaseFile.swap(file);
+
+    validSubdirs.PutEntry(fmDirectoryBaseName);
+  }
+
+  if (NS_WARN_IF(NS_FAILED(rv))) {
+    return rv;
+  }
+
+  for (uint32_t count = subdirsToProcess.Length(), i = 0; i < count; i++) {
+    const nsString& subdirName = subdirsToProcess[i];
+
+    // If the directory has the correct suffix then it must exist in
+    // validSubdirs.
+    if (StringEndsWith(subdirName, filesSuffix)) {
+      if (NS_WARN_IF(!validSubdirs.GetEntry(subdirName))) {
+        return NS_ERROR_UNEXPECTED;
+      }
+
+      continue;
+    }
+
+    // The directory didn't have the right suffix but we might need to rename
+    // it. Check to see if we have a database that references this directory.
+    nsString subdirNameWithSuffix = subdirName + filesSuffix;
+    if (!validSubdirs.GetEntry(subdirNameWithSuffix)) {
+      // Windows doesn't allow a directory to end with a dot ('.'), so we have
+      // to check that possibility here too.
+      // We do this on all platforms, because the origin directory may have
+      // been created on Windows and now accessed on different OS.
+      subdirNameWithSuffix = subdirName + NS_LITERAL_STRING(".") + filesSuffix;
+      if (NS_WARN_IF(!validSubdirs.GetEntry(subdirNameWithSuffix))) {
+        return NS_ERROR_UNEXPECTED;
+      }
+    }
+
+    // We do have a database that uses this directory so we should rename it
+    // now. However, first check to make sure that we're not overwriting
+    // something else.
+    nsCOMPtr<nsIFile> subdir;
+    rv = directory->Clone(getter_AddRefs(subdir));
+    if (NS_WARN_IF(NS_FAILED(rv))) {
+      return rv;
+    }
+
+    rv = subdir->Append(subdirNameWithSuffix);
+    if (NS_WARN_IF(NS_FAILED(rv))) {
+      return rv;
+    }
+
+    bool exists;
+    rv = subdir->Exists(&exists);
+    if (NS_WARN_IF(NS_FAILED(rv))) {
+      return rv;
+    }
+
+    if (exists) {
+      IDB_REPORT_INTERNAL_ERR();
+      return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
+    }
+
+    rv = directory->Clone(getter_AddRefs(subdir));
+    if (NS_WARN_IF(NS_FAILED(rv))) {
+      return rv;
+    }
+
+    rv = subdir->Append(subdirName);
+    if (NS_WARN_IF(NS_FAILED(rv))) {
+      return rv;
+    }
+
+    DebugOnly<bool> isDirectory;
+    MOZ_ASSERT(NS_SUCCEEDED(subdir->IsDirectory(&isDirectory)));
+    MOZ_ASSERT(isDirectory);
+
+    rv = subdir->RenameTo(nullptr, subdirNameWithSuffix);
+    if (NS_WARN_IF(NS_FAILED(rv))) {
+      return rv;
+    }
+  }
+
+  for (uint32_t count = initInfos.Length(), i = 0; i < count; i++) {
+    FileManagerInitInfo& initInfo = initInfos[i];
+    MOZ_ASSERT(initInfo.mDirectory);
+    MOZ_ASSERT(initInfo.mDatabaseFile);
+
+    rv = FileManager::InitDirectory(initInfo.mDirectory,
+                                    initInfo.mDatabaseFile,
+                                    aPersistenceType,
+                                    aGroup,
                                     aOrigin);
     if (NS_WARN_IF(NS_FAILED(rv))) {
       return rv;
     }
 
-    if (aUsageInfo) {
+    if (aUsageInfo && !aUsageInfo->Canceled()) {
       int64_t fileSize;
-      rv = file->GetFileSize(&fileSize);
+      rv = initInfo.mDatabaseFile->GetFileSize(&fileSize);
       if (NS_WARN_IF(NS_FAILED(rv))) {
         return rv;
       }
 
       MOZ_ASSERT(fileSize >= 0);
 
       aUsageInfo->AppendToDatabaseUsage(uint64_t(fileSize));
 
       uint64_t usage;
-      rv = FileManager::GetUsage(fmDirectory, &usage);
+      rv = FileManager::GetUsage(initInfo.mDirectory, &usage);
       if (NS_WARN_IF(NS_FAILED(rv))) {
         return rv;
       }
 
       aUsageInfo->AppendToFileUsage(usage);
     }
-
-    validSubdirs.PutEntry(dbBaseFilename);
-  }
-
-  if (NS_WARN_IF(NS_FAILED(rv))) {
-    return rv;
-  }
-
-  for (uint32_t i = 0; i < subdirsToProcess.Length(); i++) {
-    const nsString& subdir = subdirsToProcess[i];
-    if (NS_WARN_IF(!validSubdirs.GetEntry(subdir))) {
-      return NS_ERROR_UNEXPECTED;
-    }
-  }
-
-  for (uint32_t i = 0; i < unknownFiles.Length(); i++) {
+  }
+
+  // We have to do this after file manager initialization.
+  for (uint32_t count = unknownFiles.Length(), i = 0; i < count; i++) {
     nsCOMPtr<nsIFile>& unknownFile = unknownFiles[i];
 
-    // Some temporary SQLite files could disappear, so we have to check if the
-    // unknown file still exists.
+    // Some temporary SQLite files could disappear during file manager
+    // initialization, so we have to check if the unknown file still exists.
     bool exists;
     rv = unknownFile->Exists(&exists);
     if (NS_WARN_IF(NS_FAILED(rv))) {
       return rv;
     }
 
     if (exists) {
-      nsString leafName;
-      unknownFile->GetLeafName(leafName);
-
-      // The journal file may exists even after db has been correctly opened.
-      if (NS_WARN_IF(!StringEndsWith(leafName,
-                                     NS_LITERAL_STRING(".sqlite-journal")))) {
-        return NS_ERROR_UNEXPECTED;
-      }
+      return NS_ERROR_UNEXPECTED;
     }
   }
 
   return NS_OK;
 }
 
 nsresult
 QuotaClient::GetUsageForOrigin(PersistenceType aPersistenceType,
@@ -11169,17 +11262,19 @@ OpenDatabaseOp::DoDatabaseWork()
   }
 
   nsCOMPtr<nsIFile> fmDirectory;
   rv = dbDirectory->Clone(getter_AddRefs(fmDirectory));
   if (NS_WARN_IF(NS_FAILED(rv))) {
     return rv;
   }
 
-  rv = fmDirectory->Append(filename);
+  const NS_ConvertASCIItoUTF16 filesSuffix(kFileManagerDirectoryNameSuffix);
+
+  rv = fmDirectory->Append(filename + filesSuffix);
   if (NS_WARN_IF(NS_FAILED(rv))) {
     return rv;
   }
 
   nsCOMPtr<mozIStorageConnection> connection;
   rv = CreateDatabaseConnection(dbFile,
                                 fmDirectory,
                                 databaseName,
@@ -12655,17 +12750,20 @@ VersionChangeOp::RunOnIOThread()
   }
 
   nsCOMPtr<nsIFile> fmDirectory;
   rv = directory->Clone(getter_AddRefs(fmDirectory));
   if (NS_WARN_IF(NS_FAILED(rv))) {
     return rv;
   }
 
-  rv = fmDirectory->Append(mDeleteDatabaseOp->mDatabaseFilenameBase);
+  const NS_ConvertASCIItoUTF16 filesSuffix(kFileManagerDirectoryNameSuffix);
+
+  rv = fmDirectory->Append(mDeleteDatabaseOp->mDatabaseFilenameBase +
+                           filesSuffix);
   if (NS_WARN_IF(NS_FAILED(rv))) {
     return rv;
   }
 
   rv = fmDirectory->Exists(&exists);
   if (NS_WARN_IF(NS_FAILED(rv))) {
     return rv;
   }
--- a/dom/indexedDB/test/mochitest.ini
+++ b/dom/indexedDB/test/mochitest.ini
@@ -111,17 +111,17 @@ skip-if = (buildapp == 'b2g' && toolkit 
 skip-if = (buildapp == 'b2g' && toolkit != 'gonk') # Bug 931116
 [test_blob_archive.html]
 skip-if = (buildapp == 'b2g' && toolkit != 'gonk') # Bug 931116
 [test_blob_simple.html]
 skip-if = (buildapp == 'b2g' && toolkit != 'gonk') # Bug 931116
 [test_blob_worker_crash.html]
 skip-if = (buildapp == 'b2g' && toolkit != 'gonk') # Bug 931116
 [test_blob_worker_xhr_post.html]
-skip-if = (buildapp == 'b2g' && toolkit != 'gonk') # Bug 931116
+skip-if = ((buildapp == 'b2g' && toolkit != 'gonk') || (e10s && toolkit == 'windows')) # Bug 931116
 [test_blocked_order.html]
 skip-if = (buildapp == 'b2g' && toolkit != 'gonk') # Bug 931116
 [test_bug937006.html]
 skip-if = (buildapp == 'b2g' && toolkit != 'gonk') # Bug 931116
 [test_clear.html]
 skip-if = (buildapp == 'b2g' && toolkit != 'gonk') # Bug 931116
 [test_complex_keyPaths.html]
 skip-if = (buildapp == 'b2g' && toolkit != 'gonk') # Bug 931116
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..db3cfe62464e8f50d11664578c879c8af7c45014
GIT binary patch
literal 8029
zc$}?S2{@E%8`dIi(y1hkOr1JZgtCmuc63N~NrYii82dJsImVFVrzEK+lx-{t*%CvR
z8QGF$X0m6UjGZRS*rzc+=`SZ8=I=W1T<>+wb$##L&->i(H{bny&#j}rY4dirrO|#7
ztjxAzY-QtPgS$Gqn87SWFY9e%+r%Iq)e|Kh)pJAaVB4^HY6BbF=6#FnbiN`Ce21`i
z1%i`>3)~v+YT@9z4E76Y9Wdi4C8d>M2Y(E9-O9z${>ui5XU28^FU+HBVv5*XxSE-p
zxte_i-?J9@=y%!kuL*8#er<WvN7f^v{ySXBb#c!~fWRQ|X|R}-o2wHXX5r#$1~vb}
z(a1j^;=a#^z7$U9UFm(&mgSp3<|o66z@6=^T`j%_U7FtorMA>L8XNGkITcbV&5<po
zdUIwc3oh&Jvu!QV*?rDxqhNkjnkBLSm}|Fht-XUxrgc47%TVG<v>md4!}y(YOnLE*
zasVY%<)hn&^1D<iA!UPGWbN@G0(c;X9zE*SVs9XCWRnyBenE?N5y#z8og?0A*B`EU
zugaWQff0JV*MAlsH#%eYsX;-$I={Bv2XkDO@kf7fKU7?sIopK6EDX<#qNawzedarh
zr<vn@g7jcA@gs9As90{U2JMd{85Ot6-AUTO_RnJs>NYkF$Ok!^;1G!PCOcWgZpl$l
zZhSDVGIB~kr>;fPU`I`=*>j^*VUYmr)$+91qUQ%g(ooVE4M>K2|K=Sv*u%mk9I!EL
zbhAenSE{095lu_Hz{e5hSjb((Qv|3D2nw|k1B&>Mqjq5XxbA+uBiK?Jo5f2qG>z~{
z%9^7cP9p--d=zFZ|D2$7d(LFZcqjyY#7a>v3<DzT^j-Jpkl&;XR+1Y!l|YXWdr_BE
zKK!;V4SoA{zk`n9wr4e|if;DSDTPU)h{yR&v5`q#Pm|_HBR<xOx=p(yhLF)X6eIf=
zBtT=jb$YsXlhM|@M}5Xouf@@{Pa*KPdFNA*M1$8D_;n=6CKqokvSoCrKVH{ln{6tI
z%nYKQetg=-u^1mEWQvQBJDxl2kr!_+JO>$KhsKy}4>9#kc{wlC)Fjqga}!(5(bwkb
zBm=?hx=Y4%S&7Ehmtb4q6;qL|eo%>AP=e@mE&wxH5u%k5G9h*kO$e^b7V)^AqBl?$
z;+K8ufw{AlrI@5Nc5;f#l)&xSRqIWEo;?=_2smpBxKMM8gU@8f;#qjm(0f&st>|{k
z@GuztEPa#b0jh#6qBkDJ;XE<+F*`tCRFlKDsanOh`)woQSVs2q7gr8JQuZ~L`p-sY
zp5@7y)Ni+^N)$%Ms96dFeN2d<2L08v?)SP$y7Jdb%&jKX5?##VU%HD&4$0cj(9+LC
z>ZWkb#EV{KiDL<I87(!LsJ!1S0}8ftw0dPA=$_M8Uo^}`)ywdDyTv+@bh1dto60JA
z;1we+*<^gvi6-=8L4)uuw`o2pC!wZP&Ej%Op__I5O9TqiHyK`A<+d<}4um*c3eX94
z2Gvd-WpeqxZ~#A$Nsy8DXjHXp0V<c+%#PbYp;5Hp%Bkk0BszVEPq}W$bgogbRbf*H
z@bo*nDVV$NB3qL7Y~zzG4!M3vzsueV8Sx&Xg|rVqybQ&|l_b)88;x#tyv-PR$Y)0G
z6H3r}N>{^;-9I)oiX7=L^PgzbbsU==o$9rF>PO7h!lABTLKTgv6KAwdA0O8jz@SGH
zc;ZIG1O0%Q8g9pqH~e_XNr6cy258LaK}X5T$yXu?gBK+z<U^HU)XYxNSE}b^5{>4E
z<^m~H0PI<YZ$ZIsCbO@!%q{~#HJXlXY;}1MP&n1uqd?-c!?qwN-#46=4~!@bj;6vs
zr0d<nJVMQrG(K%w<6pZpn4%&u68UA$%&cNIp4UDnzEl6mkbM##_d36OB8-usKJ;5>
z)s2VT51vN5>|STty%%2fIhS^ATxXfC{)GtlYQ=R{{a!tx+MosAy3Vo-hDWU1PH?RC
zR9hM+Y6LZ9`VOzN>afM!6YC_t&Fd_Cl6H?J()!T<B57gTERnXICDK}pH+<93^e9bb
zzO-<p&?1SO7Wc7hQA4l0SeUt5K+Ug-Sh?EUeU`;$PFX$T;`~k){qJ8?FB9A6Po@iH
zpxRzZjRaKN899A0{KWA<z{CEDrkbaWeg)H^ei&W7vAYxu)q1n7SoOiy_f;B)?G?Z#
zpv|6a{%Y!q$v1>`{Kn4cr-wP^M86f7QaKpEaR2m>&OP~r91|Gfo{>Sew`J3v7ap!*
z7DEBbs=DWk;xafl`JY5>7t}lzb~7u$4(?G*rXKMH?^WEkC-lI*Z1&q56)q$pH%530
zUn|{_1#;dW6oIMZY>W6+9Z0$7eK7c#=nVkDhU(8%TvFV)bMrIL{f8`dewUrb?%fXE
z#&Melt(6ihX?Uuo-K<~AP^4~jGt@8GsZDq!wOus%?#;$&D}6GEd@h&BoXIoz)EUC$
z^)ypw#~&kxxg0e$l=PKM=YDo;VEe?&Ug0-8K+FoBZ<M<{I<Ne=`4a5ym$F4}{jx<0
zBqniMQt~v|b@6E6*IXT~9UUxTA}b3QtC}-<OY=vCOVd)}a?06O>|tCrS8_voyjIrM
zQ-+`;5^)4ohrgQM-$3h>ZYr_wxE3K$;e7U2so~9tuCkl~RXTcFRHF?ritNDMMMEmx
z0R>v$*Dc}l5UX53NoRVqpQp^r`$Oh0T5ExS9Y$A01<Lb?S8lHxfKX=aCeeJrevN*D
zPY5?Z^EaB&2<CC652JrHL}8v*NcLKoA}>s0I)V5FyS%x|p-w1jDpQ4tkjSGc(;KJ^
ztAlIZ&rAcPBR&ktc%4Y2hqtHq<B-A4o&D#p+YfYm;ySOWyAm2pCtMB)x16NW%uXFR
zBXpc}O68~!u=e#{p43ioNyoKQTWiEe*|8PICFwJzHaeV+Cbp6vyIR{??KnoaII=f%
zdnF#M4cKAkN`}~vGyG%{s<2{K87lDoJeHY~Ej~Q|X==qaL3>R_Loj40RnC26nkQI>
ziaq{dzRmM`f-|4awO*ykgwY}Ucpi<M!1Bf;$iPh_Pvi6PhxEe!8m74Dm>6Ceq*|Xa
zva|#b_6<2T?5!#kD5R-(;;2vrwlL3;%=;p5!5rh@s4W|t|Ni&{j0}?ymnSj79D$N*
zI5=K<J}NS@Jy@S!*%!}@F%>!4l=wXN(<DQooxg{-Y<jv%D4&w3-io_c=#5PHC8Poq
zbh9KpiKo=h;Oei>7S!CpcV;FO(<i+1a}RdxG!XPlm>F=I6pO9z>I;WgG>x?4$RJP)
z07|u!D((p6KLiE##)%4!*p|U?^+Acc(VPmqwDK-QRro$GQDQdM=M{UMHYoCzqca#E
z`#BsA3?foQPyNB~<P`m;(M&|ZPh~1N`n(wKxpefP#unG&Ec%n~xFCUDl-X_^j5EzN
zVyFJIP%eW~-;}xwdN4B!d|R>ZiDZ9x9SG_s067b>FT^zs+k5^RlZBXc179+YI6(?v
zs7GIzyT{%W*DVxU?Vm-dp0ayN&!LKfA}%Voc(fUFjB|#SW^xpmiWE=wggrVqc=Ce<
zEuTUVYQ>E^3|vwhMa)*<OXZX+<m2>afH5TQOh}bC^L(CO2#g<UGAKmE=w6mDZj1D~
zTj9}Ddc}F6I=NaktajYZo0**jake>0?<_H>zS`j@myd@7_<#&TyMo6%Rl8=O#9w`5
zJ$*{hhcxWXsp$bhI@({sJcUCBK()M{-Pv~N3}P1N@@u>wn^w$Npz2XB&+`1*-q*MD
zo}Q1cxw_E&bPJt0svT9sU0In;=0*?f1Da7L{LKU#kclyK7bug0T?MU98AUIgq!E)d
zo?cRD#Ti4vF8uuzd81kI06kCi4!2N`cGXNt(7jm;yHOC#r6ScJo9?)?Xj|1t_R&-y
z*9SdGDg%h5CdAtV6Qg$%qVR6FdEQIMb?TnNq1@9DwBeLzshJr>Wu_0<Lm^Vg6d%<o
z<d(;m)a{O<50b=D#&RFz5MxybfRaY-gmi-7Qr!~s2=(a?f%$cG`3B~uK{iaCr!AQ3
z4ySct3yqEQM$*r9kX6AV>uH#wyu(=*gkPv!Q;-$me>wDo1>xTfie^Rld!C|M5dL!=
zuDUD;e@LVjE7g*7gDNZ45=*4jRQ`*k2?JRojhn&}Y0Qn^nhnTB8C`i5^wToB+-~@D
zQ9S=#Eui0YTP<2sc^>auT*<O-i=Ppb0!v6pNS;Bg9Dmd8PrGFGmgZ{R);4ZA#CBCi
z)tS<4UvP5bkI<p>$M@=6>xOAwmb@J4y90Yp(>C@5>iBOZ)}6aA1Xul4AQ_NLLOz<7
zwf3oB@K;5S(D^+w?cX14-$poNa+x9DUDg)`C(T8Z!804xfg%z{Q|~{z(-u61Uf#Ec
z{Xn+|>?T9){-)cszw7q+XWhmv>2~IL<q!@kH{Vj`BOBGucri6ZRBYs2>&%&{3=p&i
z=iO63=U0<%*+V0Z5DJ3{^KBpff~WLRr!Gof+EG(u_8gL0OS*}@dLc7bHjfXR<|PL3
zfTX$4Z-xgg^&5(K8uvT0=XLE^>NmKh8x|vBNRL$RB0v$h#!XtNjTk`WKXoWLwqmBx
z<9xKO+1q!w=7mLSO>ONyiEK^Hrl%Ia!I|<a_&jfmbf-^;PsyY&>h=^ic;1pB9jjCm
zIH*EyFjf+MWc5p6#vjdlIGR<JuU{8T7G`g%=!-3Q@%*iEgRVqvt;^e*hVFR52OgU4
z^WkT0WnPZi!0gF*adUe{m3(Jg%u7Xh$;Dn0o|p_P!Z6{x_FRAHN%wM|ln3Ry4-=Y0
zYLuCBIEdaebu;_9p%I^4$=7lL=~T3VONDy)3wlNKJeA<tvEN68e+x9mbZcSAD<#)?
zp{71D(;5zJHNCIR#z`C!z4LAirmVT_h8jH_O5`@kgw6Pn-?b$xv~}8eVF8+lpdPfh
z;pkv&H_mjZLN|pN0OUvl93xVGCtZy%wjFAR;vWf_7RN9aOkv}jKs)t{8pFem>~+oD
z`}k~ah548h3ZBQWAu6mTcoMy#Gj&uh<<G&`z+mZ^B2de#!NjVoiAHlyzwr$o#3~I4
zr_~zJRZg;FokToomtm!eWp(b0`p^|GNZ}7s$*g%iQLpi*)Cb_OQuWQ92SA*_6g`nU
z+y)si@#t1}e4Cw;peHI1+ZpUQcKnlP>~P<Nx`M;46yIm1-clH$uA&E>z)?N<zQIGF
z;&&cS+RoQ7PI_GYQUBBJfn@#}S$x4;4{0B@q=~s`T-5+#)&X)rhzR9%b9tcBKYP|^
zto2HUv}7nFgRaJV2l-r}CC|~1nm{gMpl(vjo97vx&-uKIqLPDL@Y7duQx#S7y(Pdi
zjf_r$egeM9<|C)ItXF2#tz^KfszdU1*1hLL-i1HzxH8_{n2h4BCAT$R?VR%qgy&Oc
z5z~d&TriYV8W6mg9n3SNQQT2AYN7lR2tW)q*uM)9;+<KE6z6sAKRZ4dtT9#hiUcMX
zqs-E-@cO9X3%SlwZe}saQB~ZTrUd??(__buWs>g7G7`{yBz|g7v?aqE^@e;%1&kWm
z$MwqjoQw)~a=JB(LP$+IYl0dWhD<VR@{z5O@rk|<-YMC=(wuoM9(VDWA>&~)dk+fw
zw0s)K<6yh7_7&rl-GpV`UPqPwr`!B)CL`WL<x|v$J?s5qQ554@c^f_lVd-r+B#5QA
zVdpwlS_twYth5k>%9UAaA-uF=p@kp}<YB4rLSczCuYZ%Y3D!tE!V+n8(Qk5nc~L!A
zUX=P-_55PWaLMW|%~fi>VI%*he{zWqeEGJUjry61Z=MnRvS+jg+G@vWCEB?aXn*sM
z*q8mIHGo&UM=OCtehmE8OJZNPd;SmnqhIkC??m68HSt&YO6vz&?JBKI<o6A01zPr)
z*q1$~HDauGm{!Jkv~G-l^qbh1t)Cx;{wKF-C662%e=hXbQgHnZtZvmUZ(!+fc*9qH
z8{4YJ9s6?QZVk-Uy{K<V-SEY4UpJ}sI#cY+ovAgBbafs7?MPoKvhVrXEi51E4=eg_
z`LC|&SLW}&Zt!(0eD>uEe~tWCKNwf$pTql;Tln(q`Ozbi{d2NA7e7bY+1QSK?ymh8
DhVkiI
new file mode 100644
--- /dev/null
+++ b/dom/indexedDB/test/unit/test_bug1056939.js
@@ -0,0 +1,131 @@
+/**
+ * Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+var testGenerator = testSteps();
+
+function testSteps()
+{
+  const dbName1 = "upgrade_test";
+  const dbName2 = "testing.foobar";
+  const dbName3 = "xxxxxxx.xxxxxx";
+
+  clearAllDatabases(continueToNextStepSync);
+  yield undefined;
+
+  installPackagedProfile("bug1056939");
+
+  let request = indexedDB.open(dbName1, 1);
+  request.onerror = errorHandler;
+  request.onupgradeneeded = unexpectedSuccessHandler;
+  request.onsuccess = grabEventAndContinueHandler;
+  let event = yield undefined;
+
+  is(event.type, "success", "Correct event type");
+
+  request = indexedDB.open(dbName2, 1);
+  request.onerror = errorHandler;
+  request.onupgradeneeded = unexpectedSuccessHandler;
+  request.onsuccess = grabEventAndContinueHandler;
+  event = yield undefined;
+
+  is(event.type, "success", "Got correct event type");
+
+  request = indexedDB.open(dbName3, 1);
+  request.onerror = errorHandler;
+  request.onupgradeneeded = unexpectedSuccessHandler;
+  request.onsuccess = grabEventAndContinueHandler;
+  event = yield undefined;
+
+  is(event.type, "success", "Got correct event type");
+
+  clearAllDatabases(continueToNextStepSync);
+  yield undefined;
+
+  request = indexedDB.open(dbName3, 1);
+  request.onerror = errorHandler;
+  request.onupgradeneeded = grabEventAndContinueHandler;
+  request.onsuccess = unexpectedSuccessHandler;
+  event = yield undefined;
+
+  is(event.type, "upgradeneeded", "Got correct event type");
+
+  request.onupgradeneeded = unexpectedSuccessHandler;
+  request.onsuccess = grabEventAndContinueHandler;
+  event = yield undefined;
+
+  is(event.type, "success", "Got correct event type");
+
+  resetAllDatabases(continueToNextStepSync);
+  yield undefined;
+
+  request = indexedDB.open(dbName3, 1);
+  request.onerror = errorHandler;
+  request.onupgradeneeded = unexpectedSuccessHandler;
+  request.onsuccess = grabEventAndContinueHandler;
+  event = yield undefined;
+
+  is(event.type, "success", "Got correct event type");
+
+  finishTest();
+  yield undefined;
+}
+
+function installPackagedProfile(packageName)
+{
+  let directoryService = Cc["@mozilla.org/file/directory_service;1"]
+                         .getService(Ci.nsIProperties);
+
+  let profileDir = directoryService.get("ProfD", Ci.nsIFile);
+
+  let currentDir = directoryService.get("CurWorkD", Ci.nsIFile);
+
+  let packageFile = currentDir.clone();
+  packageFile.append(packageName + ".zip");
+
+  let zipReader = Cc["@mozilla.org/libjar/zip-reader;1"]
+                  .createInstance(Ci.nsIZipReader);
+  zipReader.open(packageFile);
+
+  let entryNames = [];
+  let entries = zipReader.findEntries(null);
+  while (entries.hasMore()) {
+    let entry = entries.getNext();
+    if (entry != "create_db.html") {
+      entryNames.push(entry);
+    }
+  }
+  entryNames.sort();
+
+  for (let entryName of entryNames) {
+    let zipentry = zipReader.getEntry(entryName);
+
+    let file = profileDir.clone();
+    let split = entryName.split("/");
+    for(let i = 0; i < split.length; i++) {
+      file.append(split[i]);
+    }
+
+    if (zipentry.isDirectory) {
+      file.create(Ci.nsIFile.DIRECTORY_TYPE, parseInt("0755", 8));
+    } else {
+      let istream = zipReader.getInputStream(entryName);
+
+      var ostream = Cc["@mozilla.org/network/file-output-stream;1"]
+                    .createInstance(Ci.nsIFileOutputStream);
+      ostream.init(file, -1, parseInt("0644", 8), 0);
+
+      let bostream = Cc['@mozilla.org/network/buffered-output-stream;1']
+                     .createInstance(Ci.nsIBufferedOutputStream);
+      bostream.init(ostream, 32768);
+
+      bostream.writeFrom(istream, istream.available());
+
+      istream.close();
+      bostream.close();
+    }
+  }
+
+  zipReader.close();
+}
--- a/dom/indexedDB/test/unit/xpcshell-head-parent-process.js
+++ b/dom/indexedDB/test/unit/xpcshell-head-parent-process.js
@@ -225,17 +225,17 @@ function setTimeout(fun, timeout) {
       fun();
     }
   };
   timer.initWithCallback(event, timeout,
                          Components.interfaces.nsITimer.TYPE_ONE_SHOT);
   return timer;
 }
 
-function clearAllDatabases(callback) {
+function resetOrClearAllDatabases(callback, clear) {
   if (!SpecialPowers.isMainProcess()) {
     throw new Error("clearAllDatabases not implemented for child processes!");
   }
 
   let quotaManager = Cc["@mozilla.org/dom/quota/manager;1"]
                        .getService(Ci.nsIQuotaManager);
 
   const quotaPref = "dom.quotaManager.testing";
@@ -243,17 +243,21 @@ function clearAllDatabases(callback) {
   let oldPrefValue;
   if (SpecialPowers._getPrefs().prefHasUserValue(quotaPref)) {
     oldPrefValue = SpecialPowers.getBoolPref(quotaPref);
   }
 
   SpecialPowers.setBoolPref(quotaPref, true);
 
   try {
-    quotaManager.clear();
+    if (clear) {
+      quotaManager.clear();
+    } else {
+      quotaManager.reset();
+    }
   } catch(e) {
     if (oldPrefValue !== undefined) {
       SpecialPowers.setBoolPref(quotaPref, oldPrefValue);
     } else {
       SpecialPowers.clearUserPref(quotaPref);
     }
     throw e;
   }
@@ -261,16 +265,24 @@ function clearAllDatabases(callback) {
   let uri = Cc["@mozilla.org/network/io-service;1"]
               .getService(Ci.nsIIOService)
               .newURI("http://foo.com", null, null);
   quotaManager.getUsageForURI(uri, function(usage, fileUsage) {
     callback();
   });
 }
 
+function resetAllDatabases(callback) {
+  resetOrClearAllDatabases(callback, false);
+}
+
+function clearAllDatabases(callback) {
+  resetOrClearAllDatabases(callback, true);
+}
+
 var SpecialPowers = {
   isMainProcess: function() {
     return Components.classes["@mozilla.org/xre/app-info;1"]
                      .getService(Components.interfaces.nsIXULRuntime)
                      .processType == Ci.nsIXULRuntime.PROCESS_TYPE_DEFAULT;
   },
   notifyObservers: function(subject, topic, data) {
     var obsvc = Cc['@mozilla.org/observer-service;1']
--- a/dom/indexedDB/test/unit/xpcshell-parent-process.ini
+++ b/dom/indexedDB/test/unit/xpcshell-parent-process.ini
@@ -3,25 +3,27 @@
 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
 
 [DEFAULT]
 dupe-manifest =
 head = xpcshell-head-parent-process.js
 tail =
 skip-if = toolkit == 'android' || toolkit == 'gonk'
 support-files =
+  bug1056939.zip
   GlobalObjectsChild.js
   GlobalObjectsComponent.js
   GlobalObjectsComponent.manifest
   GlobalObjectsModule.jsm
   GlobalObjectsSandbox.js
   xpcshell-shared.ini
 
 [include:xpcshell-shared.ini]
 
+[test_bug1056939.js]
 [test_globalObjects_ipc.js]
 [test_invalidate.js]
 # disabled for the moment.
 skip-if = true
 [test_lowDiskSpace.js]
 [test_temporary_storage.js]
 # bug 951017: intermittent failure on Android x86 emulator
 skip-if = os == "android" && processor == "x86"
--- a/dom/ipc/Blob.cpp
+++ b/dom/ipc/Blob.cpp
@@ -1092,16 +1092,36 @@ public:
   NoteDyingActor()
   {
     MOZ_ASSERT(mActor);
     mActor->AssertIsOnOwningThread();
 
     mActor = nullptr;
   }
 
+  BlobChild*
+  GetActor() const
+  {
+    AssertActorEventTargetIsOnCurrentThread();
+
+    return mActor;
+  }
+
+  nsIEventTarget*
+  GetActorEventTarget() const
+  {
+    return mActorTarget;
+  }
+
+  void
+  AssertActorEventTargetIsOnCurrentThread() const
+  {
+    MOZ_ASSERT(EventTargetIsOnCurrentThread(mActorTarget));
+  }
+
   NS_DECL_ISUPPORTS_INHERITED
 
   virtual void
   GetMozFullPathInternal(nsAString& aFileName, ErrorResult& aRv) MOZ_OVERRIDE;
 
   virtual already_AddRefed<FileImpl>
   CreateSlice(uint64_t aStart, uint64_t aLength,
               const nsAString& aContentType, ErrorResult& aRv) MOZ_OVERRIDE;
@@ -1163,46 +1183,43 @@ private:
     }
   }
 };
 
 class BlobChild::RemoteBlobImpl::StreamHelper MOZ_FINAL
   : public nsRunnable
 {
   Monitor mMonitor;
-  BlobChild* mActor;
-  nsRefPtr<FileImpl> mBlobImpl;
+  nsRefPtr<RemoteBlobImpl> mRemoteBlobImpl;
   nsRefPtr<RemoteInputStream> mInputStream;
   bool mDone;
 
 public:
-  StreamHelper(BlobChild* aActor, FileImpl* aBlobImpl)
+  StreamHelper(RemoteBlobImpl* aRemoteBlobImpl)
     : mMonitor("BlobChild::RemoteBlobImpl::StreamHelper::mMonitor")
-    , mActor(aActor)
-    , mBlobImpl(aBlobImpl)
+    , mRemoteBlobImpl(aRemoteBlobImpl)
     , mDone(false)
   {
     // This may be created on any thread.
-    MOZ_ASSERT(aActor);
-    MOZ_ASSERT(aBlobImpl);
+    MOZ_ASSERT(aRemoteBlobImpl);
   }
 
   nsresult
   GetStream(nsIInputStream** aInputStream)
   {
     // This may be called on any thread.
     MOZ_ASSERT(aInputStream);
-    MOZ_ASSERT(mActor);
+    MOZ_ASSERT(mRemoteBlobImpl);
     MOZ_ASSERT(!mInputStream);
     MOZ_ASSERT(!mDone);
 
-    if (mActor->IsOnOwningThread()) {
+    if (EventTargetIsOnCurrentThread(mRemoteBlobImpl->GetActorEventTarget())) {
       RunInternal(false);
     } else {
-      nsCOMPtr<nsIEventTarget> target = mActor->EventTarget();
+      nsCOMPtr<nsIEventTarget> target = mRemoteBlobImpl->GetActorEventTarget();
       if (!target) {
         target = do_GetMainThread();
       }
 
       MOZ_ASSERT(target);
 
       nsresult rv = target->Dispatch(this, NS_DISPATCH_NORMAL);
       NS_ENSURE_SUCCESS(rv, rv);
@@ -1210,108 +1227,109 @@ public:
       {
         MonitorAutoLock lock(mMonitor);
         while (!mDone) {
           lock.Wait();
         }
       }
     }
 
-    MOZ_ASSERT(!mActor);
+    MOZ_ASSERT(!mRemoteBlobImpl);
     MOZ_ASSERT(mDone);
 
     if (!mInputStream) {
       return NS_ERROR_UNEXPECTED;
     }
 
     mInputStream.forget(aInputStream);
     return NS_OK;
   }
 
   NS_IMETHOD
   Run() MOZ_OVERRIDE
   {
-    MOZ_ASSERT(mActor);
-    mActor->AssertIsOnOwningThread();
+    MOZ_ASSERT(mRemoteBlobImpl);
+    mRemoteBlobImpl->AssertActorEventTargetIsOnCurrentThread();
 
     RunInternal(true);
     return NS_OK;
   }
 
 private:
   void
   RunInternal(bool aNotify)
   {
-    MOZ_ASSERT(mActor);
-    mActor->AssertIsOnOwningThread();
+    MOZ_ASSERT(mRemoteBlobImpl);
+    mRemoteBlobImpl->AssertActorEventTargetIsOnCurrentThread();
     MOZ_ASSERT(!mInputStream);
     MOZ_ASSERT(!mDone);
 
-    nsRefPtr<RemoteInputStream> stream = new RemoteInputStream(mBlobImpl);
-
-    InputStreamChild* streamActor = new InputStreamChild(stream);
-    if (mActor->SendPBlobStreamConstructor(streamActor)) {
-      stream.swap(mInputStream);
+    if (BlobChild* actor = mRemoteBlobImpl->GetActor()) {
+      nsRefPtr<RemoteInputStream> stream =
+        new RemoteInputStream(mRemoteBlobImpl);
+
+      InputStreamChild* streamActor = new InputStreamChild(stream);
+      if (actor->SendPBlobStreamConstructor(streamActor)) {
+        stream.swap(mInputStream);
+      }
     }
 
-    mActor = nullptr;
+    mRemoteBlobImpl = nullptr;
 
     if (aNotify) {
       MonitorAutoLock lock(mMonitor);
       mDone = true;
       lock.Notify();
     }
     else {
       mDone = true;
     }
   }
 };
 
 class BlobChild::RemoteBlobImpl::SliceHelper MOZ_FINAL
   : public nsRunnable
 {
   Monitor mMonitor;
-  BlobChild* mActor;
+  nsRefPtr<RemoteBlobImpl> mRemoteBlobImpl;
   nsRefPtr<FileImpl> mSlice;
   uint64_t mStart;
   uint64_t mLength;
   nsString mContentType;
   bool mDone;
 
 public:
   explicit
-  SliceHelper(BlobChild* aActor)
+  SliceHelper(RemoteBlobImpl* aRemoteBlobImpl)
     : mMonitor("BlobChild::RemoteBlobImpl::SliceHelper::mMonitor")
-    , mActor(aActor)
+    , mRemoteBlobImpl(aRemoteBlobImpl)
     , mStart(0)
     , mLength(0)
     , mDone(false)
   {
     // This may be created on any thread.
-    MOZ_ASSERT(aActor);
+    MOZ_ASSERT(aRemoteBlobImpl);
   }
 
-  FileImpl*
-  GetSlice(uint64_t aStart,
-           uint64_t aLength,
-           const nsAString& aContentType)
+  already_AddRefed<FileImpl>
+  GetSlice(uint64_t aStart, uint64_t aLength, const nsAString& aContentType)
   {
     // This may be called on any thread.
-    MOZ_ASSERT(mActor);
+    MOZ_ASSERT(mRemoteBlobImpl);
     MOZ_ASSERT(!mSlice);
     MOZ_ASSERT(!mDone);
 
     mStart = aStart;
     mLength = aLength;
     mContentType = aContentType;
 
-    if (mActor->IsOnOwningThread()) {
+    if (EventTargetIsOnCurrentThread(mRemoteBlobImpl->GetActorEventTarget())) {
       RunInternal(false);
     } else {
-      nsCOMPtr<nsIEventTarget> target = mActor->EventTarget();
+      nsCOMPtr<nsIEventTarget> target = mRemoteBlobImpl->GetActorEventTarget();
       if (!target) {
         target = do_GetMainThread();
       }
 
       MOZ_ASSERT(target);
 
       nsresult rv = target->Dispatch(this, NS_DISPATCH_NORMAL);
       if (NS_WARN_IF(NS_FAILED(rv))) {
@@ -1321,78 +1339,82 @@ public:
       {
         MonitorAutoLock lock(mMonitor);
         while (!mDone) {
           lock.Wait();
         }
       }
     }
 
-    MOZ_ASSERT(!mActor);
+    MOZ_ASSERT(!mRemoteBlobImpl);
     MOZ_ASSERT(mDone);
 
     if (NS_WARN_IF(!mSlice)) {
       return nullptr;
     }
 
-    return mSlice;
+    return mSlice.forget();
   }
 
   NS_IMETHOD
   Run() MOZ_OVERRIDE
   {
-    MOZ_ASSERT(mActor);
-    mActor->AssertIsOnOwningThread();
+    MOZ_ASSERT(mRemoteBlobImpl);
+    mRemoteBlobImpl->AssertActorEventTargetIsOnCurrentThread();
 
     RunInternal(true);
     return NS_OK;
   }
 
 private:
   void
   RunInternal(bool aNotify)
   {
-    MOZ_ASSERT(mActor);
-    mActor->AssertIsOnOwningThread();
+    MOZ_ASSERT(mRemoteBlobImpl);
+    mRemoteBlobImpl->AssertActorEventTargetIsOnCurrentThread();
     MOZ_ASSERT(!mSlice);
     MOZ_ASSERT(!mDone);
 
-    NS_ENSURE_TRUE_VOID(mActor->HasManager());
-
-    nsID id;
-    MOZ_ALWAYS_TRUE(NS_SUCCEEDED(gUUIDGenerator->GenerateUUIDInPlace(&id)));
-
-    ChildBlobConstructorParams params(
-      id,
-      NormalBlobConstructorParams(mContentType /* contentType */,
-                                  mLength /* length */));
-
-    ParentBlobConstructorParams otherSideParams(
-      SlicedBlobConstructorParams(nullptr /* sourceParent */,
-                                  mActor /* sourceChild */,
-                                  id /* optionalID */,
-                                  mStart /* begin */,
-                                  mStart + mLength /* end */,
-                                  mContentType /* contentType */),
-      void_t() /* optionalInputStream */);
-
-    BlobChild* newActor;
-    if (nsIContentChild* contentManager = mActor->GetContentManager()) {
-      newActor = SendSliceConstructor(contentManager, params, otherSideParams);
-    } else {
-      newActor = SendSliceConstructor(mActor->GetBackgroundManager(),
-                                      params,
-                                      otherSideParams);
+    if (BlobChild* actor = mRemoteBlobImpl->GetActor()) {
+      MOZ_ASSERT(actor->HasManager());
+
+      nsID id;
+      MOZ_ALWAYS_TRUE(NS_SUCCEEDED(gUUIDGenerator->GenerateUUIDInPlace(&id)));
+
+      ChildBlobConstructorParams params(
+        id,
+        NormalBlobConstructorParams(mContentType /* contentType */,
+                                    mLength /* length */));
+
+      ParentBlobConstructorParams otherSideParams(
+        SlicedBlobConstructorParams(nullptr /* sourceParent */,
+                                    actor /* sourceChild */,
+                                    id /* optionalID */,
+                                    mStart /* begin */,
+                                    mStart + mLength /* end */,
+                                    mContentType /* contentType */),
+        void_t() /* optionalInputStream */);
+
+      BlobChild* newActor;
+      if (nsIContentChild* contentManager = actor->GetContentManager()) {
+        newActor = SendSliceConstructor(contentManager,
+                                        params,
+                                        otherSideParams);
+      } else {
+        newActor = SendSliceConstructor(actor->GetBackgroundManager(),
+                                        params,
+                                        otherSideParams);
+      }
+
+      if (newActor) {
+        mSlice = newActor->GetBlobImpl();
+      }
     }
 
-    if (newActor) {
-      mSlice = newActor->GetBlobImpl();
-    }
-
-    mActor = nullptr;
+    mRemoteBlobImpl = nullptr;
 
     if (aNotify) {
       MonitorAutoLock lock(mMonitor);
       mDone = true;
       lock.Notify();
     }
     else {
       mDone = true;
@@ -1410,16 +1432,20 @@ NS_IMPL_QUERY_INTERFACE_INHERITED(BlobCh
                                   FileImpl,
                                   nsIRemoteBlob)
 
 void
 BlobChild::
 RemoteBlobImpl::GetMozFullPathInternal(nsAString& aFilePath,
                                        ErrorResult& aRv)
 {
+  if (!EventTargetIsOnCurrentThread(mActorTarget)) {
+    MOZ_CRASH("Not implemented!");
+  }
+
   if (!mActor) {
     aRv.Throw(NS_ERROR_UNEXPECTED);
     return;
   }
 
   nsString filePath;
   if (!mActor->SendGetFilePath(&filePath)) {
     aRv.Throw(NS_ERROR_FAILURE);
@@ -1429,48 +1455,43 @@ RemoteBlobImpl::GetMozFullPathInternal(n
   aFilePath = filePath;
 }
 
 already_AddRefed<FileImpl>
 BlobChild::
 RemoteBlobImpl::CreateSlice(uint64_t aStart, uint64_t aLength,
                             const nsAString& aContentType, ErrorResult& aRv)
 {
-  if (!mActor) {
-    aRv.Throw(NS_ERROR_FAILURE);
-    return nullptr;
-  }
-
-  nsRefPtr<SliceHelper> helper = new SliceHelper(mActor);
+  nsRefPtr<SliceHelper> helper = new SliceHelper(this);
 
   nsRefPtr<FileImpl> impl = helper->GetSlice(aStart, aLength, aContentType);
   if (NS_WARN_IF(!impl)) {
     aRv.Throw(NS_ERROR_FAILURE);
     return nullptr;
   }
 
   return impl.forget();
 }
 
 nsresult
 BlobChild::
 RemoteBlobImpl::GetInternalStream(nsIInputStream** aStream)
 {
-  if (!mActor) {
-    return NS_ERROR_UNEXPECTED;
-  }
-
-  nsRefPtr<StreamHelper> helper = new StreamHelper(mActor, this);
+  nsRefPtr<StreamHelper> helper = new StreamHelper(this);
   return helper->GetStream(aStream);
 }
 
 int64_t
 BlobChild::
 RemoteBlobImpl::GetFileId()
 {
+  if (!EventTargetIsOnCurrentThread(mActorTarget)) {
+    MOZ_CRASH("Not implemented!");
+  }
+
   int64_t fileId;
   if (mActor && mActor->SendGetFileId(&fileId)) {
     return fileId;
   }
 
   return -1;
 }
 
--- a/dom/ipc/ContentProcess.h
+++ b/dom/ipc/ContentProcess.h
@@ -6,19 +6,16 @@
 
 #ifndef dom_tabs_ContentThread_h
 #define dom_tabs_ContentThread_h 1
 
 #include "mozilla/ipc/ProcessChild.h"
 #include "mozilla/ipc/ScopedXREEmbed.h"
 #include "ContentChild.h"
 
-#undef _MOZ_LOG
-#define _MOZ_LOG(s)  printf("[ContentProcess] %s", s)
-
 namespace mozilla {
 namespace dom {
 
 /**
  * ContentProcess is a singleton on the content process which represents
  * the main thread where tab instances live.
  */
 class ContentProcess : public mozilla::ipc::ProcessChild
--- a/dom/quota/QuotaManager.cpp
+++ b/dom/quota/QuotaManager.cpp
@@ -377,18 +377,17 @@ public:
     }
   }
 
   static void
   InvalidateOpenedStorages(nsTArray<nsCOMPtr<nsIOfflineStorage> >& aStorages,
                            void* aClosure);
 
   void
-  DeleteFiles(QuotaManager* aQuotaManager,
-              PersistenceType aPersistenceType);
+  DeleteFiles(QuotaManager* aQuotaManager);
 
 private:
   ~ResetOrClearRunnable() {}
 
   CallbackState mCallbackState;
   bool mClear;
 };
 
@@ -988,16 +987,19 @@ QuotaManager::Init()
     NS_ENSURE_SUCCESS(rv, rv);
 
     rv = indexedDBDir->GetPath(mIndexedDBPath);
     NS_ENSURE_SUCCESS(rv, rv);
 
     rv = baseDir->Append(NS_LITERAL_STRING("storage"));
     NS_ENSURE_SUCCESS(rv, rv);
 
+    rv = baseDir->GetPath(mStoragePath);
+    NS_ENSURE_SUCCESS(rv, rv);
+
     nsCOMPtr<nsIFile> persistentStorageDir;
     rv = baseDir->Clone(getter_AddRefs(persistentStorageDir));
     NS_ENSURE_SUCCESS(rv, rv);
 
     rv = persistentStorageDir->Append(NS_LITERAL_STRING("persistent"));
     NS_ENSURE_SUCCESS(rv, rv);
 
     rv = persistentStorageDir->GetPath(mPersistentStoragePath);
@@ -1972,16 +1974,17 @@ QuotaManager::OriginClearCompleted(
 
 void
 QuotaManager::ResetOrClearCompleted()
 {
   AssertIsOnIOThread();
 
   mInitializedOrigins.Clear();
   mTemporaryStorageInitialized = false;
+  mStorageAreaInitialized = false;
 
   ReleaseIOThreadObjects();
 }
 
 already_AddRefed<mozilla::dom::quota::Client>
 QuotaManager::GetClient(Client::Type aClientType)
 {
   nsRefPtr<Client> client = mClients.SafeElementAt(aClientType);
@@ -3923,29 +3926,28 @@ ResetOrClearRunnable::InvalidateOpenedSt
   storages.SwapElements(aStorages);
 
   for (uint32_t index = 0; index < storages.Length(); index++) {
     storages[index]->Invalidate();
   }
 }
 
 void
-ResetOrClearRunnable::DeleteFiles(QuotaManager* aQuotaManager,
-                                  PersistenceType aPersistenceType)
+ResetOrClearRunnable::DeleteFiles(QuotaManager* aQuotaManager)
 {
   AssertIsOnIOThread();
   NS_ASSERTION(aQuotaManager, "Don't pass me null!");
 
   nsresult rv;
 
   nsCOMPtr<nsIFile> directory =
     do_CreateInstance(NS_LOCAL_FILE_CONTRACTID, &rv);
   NS_ENSURE_SUCCESS_VOID(rv);
 
-  rv = directory->InitWithPath(aQuotaManager->GetStoragePath(aPersistenceType));
+  rv = directory->InitWithPath(aQuotaManager->GetStoragePath());
   NS_ENSURE_SUCCESS_VOID(rv);
 
   rv = directory->Remove(true);
   if (rv != NS_ERROR_FILE_TARGET_DOES_NOT_EXIST &&
       rv != NS_ERROR_FILE_NOT_FOUND && NS_FAILED(rv)) {
     // This should never fail if we've closed all storage connections
     // correctly...
     NS_ERROR("Failed to remove directory!");
@@ -3983,18 +3985,17 @@ ResetOrClearRunnable::Run()
     }
 
     case IO: {
       AssertIsOnIOThread();
 
       AdvanceState();
 
       if (mClear) {
-        DeleteFiles(quotaManager, PERSISTENCE_TYPE_PERSISTENT);
-        DeleteFiles(quotaManager, PERSISTENCE_TYPE_TEMPORARY);
+        DeleteFiles(quotaManager);
       }
 
       quotaManager->RemoveQuota();
       quotaManager->ResetOrClearCompleted();
 
       // Now dispatch back to the main thread.
       if (NS_FAILED(NS_DispatchToMainThread(this, NS_DISPATCH_NORMAL))) {
         NS_WARNING("Failed to dispatch to main thread!");
--- a/dom/quota/QuotaManager.h
+++ b/dom/quota/QuotaManager.h
@@ -275,16 +275,22 @@ public:
     NS_ASSERTION(mIOThread, "This should never be null!");
     return mIOThread;
   }
 
   already_AddRefed<Client>
   GetClient(Client::Type aClientType);
 
   const nsString&
+  GetStoragePath() const
+  {
+    return mStoragePath;
+  }
+
+  const nsString&
   GetStoragePath(PersistenceType aPersistenceType) const
   {
     if (aPersistenceType == PERSISTENCE_TYPE_PERSISTENT) {
       return mPersistentStoragePath;
     }
 
     NS_ASSERTION(aPersistenceType == PERSISTENCE_TYPE_TEMPORARY, "Huh?");
 
@@ -515,16 +521,17 @@ private:
 
   // A list of all successfully initialized origins. This list isn't protected
   // by any mutex but it is only ever touched on the IO thread.
   nsTArray<nsCString> mInitializedOrigins;
 
   nsAutoTArray<nsRefPtr<Client>, Client::TYPE_MAX> mClients;
 
   nsString mIndexedDBPath;
+  nsString mStoragePath;
   nsString mPersistentStoragePath;
   nsString mTemporaryStoragePath;
 
   uint64_t mTemporaryStorageLimit;
   uint64_t mTemporaryStorageUsage;
   bool mTemporaryStorageInitialized;
 
   bool mStorageAreaInitialized;
--- a/gfx/layers/ipc/CompositorChild.cpp
+++ b/gfx/layers/ipc/CompositorChild.cpp
@@ -45,19 +45,21 @@ CompositorChild::~CompositorChild()
   MOZ_COUNT_DTOR(CompositorChild);
 }
 
 void
 CompositorChild::Destroy()
 {
   mLayerManager->Destroy();
   mLayerManager = nullptr;
-  while (size_t len = ManagedPLayerTransactionChild().Length()) {
+  // start from the end of the array because Destroy() can cause the
+  // LayerTransactionChild to be removed from the array.
+  for (int i = ManagedPLayerTransactionChild().Length() - 1; i >= 0; --i) {
     RefPtr<LayerTransactionChild> layers =
-      static_cast<LayerTransactionChild*>(ManagedPLayerTransactionChild()[len - 1]);
+      static_cast<LayerTransactionChild*>(ManagedPLayerTransactionChild()[i]);
     layers->Destroy();
   }
   SendStop();
 }
 
 bool
 CompositorChild::LookupCompositorFrameMetrics(const FrameMetrics::ViewID aId,
                                               FrameMetrics& aFrame)
--- a/gfx/layers/ipc/LayerTransactionChild.cpp
+++ b/gfx/layers/ipc/LayerTransactionChild.cpp
@@ -17,29 +17,37 @@
 
 namespace mozilla {
 namespace layers {
 
 
 void
 LayerTransactionChild::Destroy()
 {
-  if (!IPCOpen() || mDestroyed) {
+  if (!IPCOpen()) {
     return;
   }
   // mDestroyed is used to prevent calling Send__delete__() twice.
   // When this function is called from CompositorChild::Destroy(),
   // under Send__delete__() call, this function is called from
   // ShadowLayerForwarder's destructor.
   // When it happens, IPCOpen() is still true.
   // See bug 1004191.
   mDestroyed = true;
   NS_ABORT_IF_FALSE(0 == ManagedPLayerChild().Length(),
                     "layers should have been cleaned up by now");
-  PLayerTransactionChild::Send__delete__(this);
+
+  for (size_t i = 0; i < ManagedPTextureChild().Length(); ++i) {
+    TextureClient* texture = TextureClient::AsTextureClient(ManagedPTextureChild()[i]);
+    if (texture) {
+      texture->ForceRemove();
+    }
+  }
+
+  SendShutdown();
 }
 
 
 PLayerChild*
 LayerTransactionChild::AllocPLayerChild()
 {
   // we always use the "power-user" ctor
   NS_RUNTIMEABORT("not reached");
@@ -51,16 +59,17 @@ LayerTransactionChild::DeallocPLayerChil
 {
   delete actor;
   return true;
 }
 
 PCompositableChild*
 LayerTransactionChild::AllocPCompositableChild(const TextureInfo& aInfo)
 {
+  MOZ_ASSERT(!mDestroyed);
   return CompositableClient::CreateIPDLActor();
 }
 
 bool
 LayerTransactionChild::DeallocPCompositableChild(PCompositableChild* actor)
 {
   return CompositableClient::DestroyIPDLActor(actor);
 }
@@ -131,16 +140,17 @@ LayerTransactionChild::ActorDestroy(Acto
   }
 #endif
 }
 
 PTextureChild*
 LayerTransactionChild::AllocPTextureChild(const SurfaceDescriptor&,
                                           const TextureFlags&)
 {
+  MOZ_ASSERT(!mDestroyed);
   return TextureClient::CreateIPDLActor();
 }
 
 bool
 LayerTransactionChild::DeallocPTextureChild(PTextureChild* actor)
 {
   return TextureClient::DestroyIPDLActor(actor);
 }
--- a/gfx/layers/ipc/LayerTransactionChild.h
+++ b/gfx/layers/ipc/LayerTransactionChild.h
@@ -26,25 +26,26 @@ namespace layers {
 
 class LayerTransactionChild : public PLayerTransactionChild
                             , public AsyncTransactionTrackersHolder
 {
   typedef InfallibleTArray<AsyncParentMessageData> AsyncParentMessageArray;
 public:
   NS_INLINE_DECL_THREADSAFE_REFCOUNTING(LayerTransactionChild)
   /**
-   * Clean this up, finishing with Send__delete__().
+   * Clean this up, finishing with SendShutDown() which will cause __delete__
+   * to be sent from the parent side.
    *
    * It is expected (checked with an assert) that all shadow layers
    * created by this have already been destroyed and
    * Send__delete__()d by the time this method is called.
    */
   void Destroy();
 
-  bool IPCOpen() const { return mIPCOpen; }
+  bool IPCOpen() const { return mIPCOpen && !mDestroyed; }
 
   void SetForwarder(ShadowLayerForwarder* aForwarder)
   {
     mForwarder = aForwarder;
   }
 
   virtual void SendFenceHandle(AsyncTransactionTracker* aTracker,
                                PTextureChild* aTexture,
--- a/gfx/layers/ipc/LayerTransactionParent.cpp
+++ b/gfx/layers/ipc/LayerTransactionParent.cpp
@@ -156,16 +156,23 @@ LayerTransactionParent::LayerTransaction
   MOZ_COUNT_CTOR(LayerTransactionParent);
 }
 
 LayerTransactionParent::~LayerTransactionParent()
 {
   MOZ_COUNT_DTOR(LayerTransactionParent);
 }
 
+bool
+LayerTransactionParent::RecvShutdown()
+{
+  Destroy();
+  return Send__delete__(this);
+}
+
 void
 LayerTransactionParent::Destroy()
 {
   mDestroyed = true;
   for (size_t i = 0; i < ManagedPLayerParent().Length(); ++i) {
     ShadowLayerParent* slp =
       static_cast<ShadowLayerParent*>(ManagedPLayerParent()[i]);
     slp->Destroy();
--- a/gfx/layers/ipc/LayerTransactionParent.h
+++ b/gfx/layers/ipc/LayerTransactionParent.h
@@ -96,16 +96,18 @@ public:
   virtual void SendAsyncMessage(const InfallibleTArray<AsyncParentMessageData>& aMessage) MOZ_OVERRIDE;
 
   virtual base::ProcessId GetChildProcessId() MOZ_OVERRIDE
   {
     return mChildProcessId;
   }
 
 protected:
+  virtual bool RecvShutdown() MOZ_OVERRIDE;
+
   virtual bool RecvUpdate(const EditArray& cset,
                           const uint64_t& aTransactionId,
                           const TargetConfig& targetConfig,
                           const bool& isFirstPaint,
                           const bool& scheduleComposite,
                           const uint32_t& paintSequenceNumber,
                           const bool& isRepeatTransaction,
                           const mozilla::TimeStamp& aTransactionStart,
--- a/gfx/layers/ipc/PLayerTransaction.ipdl
+++ b/gfx/layers/ipc/PLayerTransaction.ipdl
@@ -97,13 +97,15 @@ parent:
   // layers id.
   sync GetAPZTestData() returns (APZTestData data);
 
   // Query a named property from the last frame
   sync RequestProperty(nsString property) returns (float value);
 
   async ChildAsyncMessages(AsyncChildMessageData[] aMessages);
 
+  async Shutdown();
+child:
   async __delete__();
 };
 
 } // namespace layers
 } // namespace mozilla
--- a/js/src/irregexp/RegExpEngine.cpp
+++ b/js/src/irregexp/RegExpEngine.cpp
@@ -1645,17 +1645,17 @@ IsNativeRegExpEnabled(JSContext *cx)
 #else
     return cx->runtime()->options().nativeRegExp();
 #endif
 }
 
 RegExpCode
 irregexp::CompilePattern(JSContext *cx, RegExpShared *shared, RegExpCompileData *data,
                          HandleLinearString sample, bool is_global, bool ignore_case,
-                         bool is_ascii, bool match_only)
+                         bool is_ascii, bool match_only, bool force_bytecode)
 {
     if ((data->capture_count + 1) * 2 - 1 > RegExpMacroAssembler::kMaxRegister) {
         JS_ReportError(cx, "regexp too big");
         return RegExpCode();
     }
 
     LifoAlloc &alloc = cx->tempLifoAlloc();
     RegExpCompiler compiler(cx, &alloc, data->capture_count, ignore_case, is_ascii, match_only);
@@ -1722,17 +1722,17 @@ irregexp::CompilePattern(JSContext *cx, 
         return RegExpCode();
     }
 
     Maybe<jit::IonContext> ctx;
     Maybe<NativeRegExpMacroAssembler> native_assembler;
     Maybe<InterpretedRegExpMacroAssembler> interpreted_assembler;
 
     RegExpMacroAssembler *assembler;
-    if (IsNativeRegExpEnabled(cx)) {
+    if (IsNativeRegExpEnabled(cx) && !force_bytecode) {
         NativeRegExpMacroAssembler::Mode mode =
             is_ascii ? NativeRegExpMacroAssembler::ASCII
                      : NativeRegExpMacroAssembler::CHAR16;
 
         ctx.emplace(cx, (jit::TempAllocator *) nullptr);
         native_assembler.emplace(&alloc, shared, cx->runtime(), mode, (data->capture_count + 1) * 2);
         assembler = native_assembler.ptr();
     } else {
--- a/js/src/irregexp/RegExpEngine.h
+++ b/js/src/irregexp/RegExpEngine.h
@@ -83,17 +83,17 @@ struct RegExpCode
     void destroy() {
         js_free(byteCode);
     }
 };
 
 RegExpCode
 CompilePattern(JSContext *cx, RegExpShared *shared, RegExpCompileData *data,
                HandleLinearString sample,  bool is_global, bool ignore_case,
-               bool is_ascii, bool match_only);
+               bool is_ascii, bool match_only, bool force_bytecode);
 
 // Note: this may return RegExpRunStatus_Error if an interrupt was requested
 // while the code was executing.
 template <typename CharT>
 RegExpRunStatus
 ExecuteCode(JSContext *cx, jit::JitCode *codeBlock, const CharT *chars, size_t start,
             size_t length, MatchPairs *matches);
 
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/debug/bug999655.js
@@ -0,0 +1,11 @@
+
+var g = newGlobal();
+var dbg = new Debugger(g);
+dbg.onNewScript = function(script) {
+    fscript = script.getChildScripts()[0];
+}
+g.eval("function f(x) { arguments[0] = 3; return x }");
+fscript.setBreakpoint(0, {hit:function(frame) {
+    assertEq(frame.arguments[0], 1);
+}});
+g.f(1);
--- a/js/src/jit/Bailouts.cpp
+++ b/js/src/jit/Bailouts.cpp
@@ -19,89 +19,42 @@
 #include "vm/Probes-inl.h"
 #include "vm/Stack-inl.h"
 
 using namespace js;
 using namespace js::jit;
 
 using mozilla::IsInRange;
 
-// These constructor are exactly the same except for the type of the iterator
-// which is given to the SnapshotIterator constructor. Doing so avoid the
-// creation of virtual functions for the IonIterator but may introduce some
-// weirdness as IonInlineIterator is using a JitFrameIterator reference.
-//
-// If a function relies on ionScript() or to use OsiIndex(), due to the
-// lack of virtual, these functions will use the JitFrameIterator reference
-// contained in the InlineFrameIterator and thus are not able to recover
-// correctly the data stored in IonBailoutIterator.
-//
-// Currently, such cases should not happen because our only use case of the
-// JitFrameIterator within InlineFrameIterator is to read the frame content, or
-// to clone it to find the parent scripted frame.  Both use cases are fine and
-// should not cause any issue since the only potential issue is to read the
-// bailed out frame.
-
-SnapshotIterator::SnapshotIterator(const IonBailoutIterator &iter)
-  : snapshot_(iter.ionScript()->snapshots(),
-              iter.snapshotOffset(),
-              iter.ionScript()->snapshotsRVATableSize(),
-              iter.ionScript()->snapshotsListSize()),
-    recover_(snapshot_,
-             iter.ionScript()->recovers(),
-             iter.ionScript()->recoversSize()),
-    fp_(iter.jsFrame()),
-    machine_(iter.machineState()),
-    ionScript_(iter.ionScript()),
-    instructionResults_(nullptr)
-{
-}
-
-void
-IonBailoutIterator::dump() const
-{
-    if (type_ == JitFrame_IonJS) {
-        InlineFrameIterator frames(GetJSContextFromJitCode(), this);
-        for (;;) {
-            frames.dump();
-            if (!frames.more())
-                break;
-            ++frames;
-        }
-    } else {
-        JitFrameIterator::dump();
-    }
-}
-
 uint32_t
 jit::Bailout(BailoutStack *sp, BaselineBailoutInfo **bailoutInfo)
 {
     JSContext *cx = GetJSContextFromJitCode();
     MOZ_ASSERT(bailoutInfo);
 
     // We don't have an exit frame.
     MOZ_ASSERT(IsInRange(FAKE_JIT_TOP_FOR_BAILOUT, 0, 0x1000) &&
                IsInRange(FAKE_JIT_TOP_FOR_BAILOUT + sizeof(IonCommonFrameLayout), 0, 0x1000),
                "Fake jitTop pointer should be within the first page.");
     cx->mainThread().jitTop = FAKE_JIT_TOP_FOR_BAILOUT;
     gc::AutoSuppressGC suppress(cx);
 
     JitActivationIterator jitActivations(cx->runtime());
-    IonBailoutIterator iter(jitActivations, sp);
-    JitActivation *activation = jitActivations->asJit();
+    BailoutFrameInfo bailoutData(jitActivations, sp);
+    JitFrameIterator iter(jitActivations);
 
     TraceLogger *logger = TraceLoggerForMainThread(cx->runtime());
     TraceLogTimestamp(logger, TraceLogger::Bailout);
 
     JitSpew(JitSpew_IonBailouts, "Took bailout! Snapshot offset: %d", iter.snapshotOffset());
 
     MOZ_ASSERT(IsBaselineEnabled(cx));
 
     *bailoutInfo = nullptr;
-    uint32_t retval = BailoutIonToBaseline(cx, activation, iter, false, bailoutInfo);
+    uint32_t retval = BailoutIonToBaseline(cx, bailoutData.activation(), iter, false, bailoutInfo);
     MOZ_ASSERT(retval == BAILOUT_RETURN_OK ||
                retval == BAILOUT_RETURN_FATAL_ERROR ||
                retval == BAILOUT_RETURN_OVERRECURSED);
     MOZ_ASSERT_IF(retval == BAILOUT_RETURN_OK, *bailoutInfo != nullptr);
 
     if (retval != BAILOUT_RETURN_OK) {
         // If the bailout failed, then bailout trampoline will pop the
         // current frame and jump straight to exception handling code when
@@ -133,31 +86,31 @@ jit::InvalidationBailout(InvalidationBai
 
     JSContext *cx = GetJSContextFromJitCode();
 
     // We don't have an exit frame.
     cx->mainThread().jitTop = FAKE_JIT_TOP_FOR_BAILOUT;
     gc::AutoSuppressGC suppress(cx);
 
     JitActivationIterator jitActivations(cx->runtime());
-    IonBailoutIterator iter(jitActivations, sp);
-    JitActivation *activation = jitActivations->asJit();
+    BailoutFrameInfo bailoutData(jitActivations, sp);
+    JitFrameIterator iter(jitActivations);
 
     TraceLogger *logger = TraceLoggerForMainThread(cx->runtime());
     TraceLogTimestamp(logger, TraceLogger::Invalidation);
 
     JitSpew(JitSpew_IonBailouts, "Took invalidation bailout! Snapshot offset: %d", iter.snapshotOffset());
 
     // Note: the frame size must be computed before we return from this function.
-    *frameSizeOut = iter.topFrameSize();
+    *frameSizeOut = iter.frameSize();
 
     MOZ_ASSERT(IsBaselineEnabled(cx));
 
     *bailoutInfo = nullptr;
-    uint32_t retval = BailoutIonToBaseline(cx, activation, iter, true, bailoutInfo);
+    uint32_t retval = BailoutIonToBaseline(cx, bailoutData.activation(), iter, true, bailoutInfo);
     MOZ_ASSERT(retval == BAILOUT_RETURN_OK ||
                retval == BAILOUT_RETURN_FATAL_ERROR ||
                retval == BAILOUT_RETURN_OVERRECURSED);
     MOZ_ASSERT_IF(retval == BAILOUT_RETURN_OK, *bailoutInfo != nullptr);
 
     if (retval != BAILOUT_RETURN_OK) {
         // If the bailout failed, then bailout trampoline will pop the
         // current frame and jump straight to exception handling code when
@@ -190,29 +143,26 @@ jit::InvalidationBailout(InvalidationBai
         JitSpew(JitSpew_IonInvalidate, "   new  ra %p", (void *) frame->returnAddress());
     }
 
     iter.ionScript()->decref(cx->runtime()->defaultFreeOp());
 
     return retval;
 }
 
-IonBailoutIterator::IonBailoutIterator(const JitActivationIterator &activations,
-                                       const JitFrameIterator &frame)
-  : JitFrameIterator(activations),
-    machine_(frame.machineState())
+BailoutFrameInfo::BailoutFrameInfo(const JitActivationIterator &activations,
+                                   const JitFrameIterator &frame)
+  : machine_(frame.machineState())
 {
-    kind_ = Kind_BailoutIterator;
-    returnAddressToFp_ = frame.returnAddressToFp();
+    framePointer_ = (uint8_t *) frame.fp();
+    topFrameSize_ = frame.frameSize();
     topIonScript_ = frame.ionScript();
+    attachOnJitActivation(activations);
+
     const OsiIndex *osiIndex = frame.osiIndex();
-
-    current_ = (uint8_t *) frame.fp();
-    type_ = JitFrame_IonJS;
-    topFrameSize_ = frame.frameSize();
     snapshotOffset_ = osiIndex->snapshotOffset();
 }
 
 uint32_t
 jit::ExceptionHandlerBailout(JSContext *cx, const InlineFrameIterator &frame,
                              ResumeFromException *rfe,
                              const ExceptionBailoutInfo &excInfo,
                              bool *overrecursed)
@@ -221,21 +171,21 @@ jit::ExceptionHandlerBailout(JSContext *
     // actual exception pending. For instance, when we return false from an
     // operation callback like a timeout handler.
     MOZ_ASSERT_IF(!excInfo.propagatingIonExceptionForDebugMode(), cx->isExceptionPending());
 
     cx->mainThread().jitTop = FAKE_JIT_TOP_FOR_BAILOUT;
     gc::AutoSuppressGC suppress(cx);
 
     JitActivationIterator jitActivations(cx->runtime());
-    IonBailoutIterator iter(jitActivations, frame.frame());
-    JitActivation *activation = jitActivations->asJit();
+    BailoutFrameInfo bailoutData(jitActivations, frame.frame());
+    JitFrameIterator iter(jitActivations);
 
     BaselineBailoutInfo *bailoutInfo = nullptr;
-    uint32_t retval = BailoutIonToBaseline(cx, activation, iter, true, &bailoutInfo, &excInfo);
+    uint32_t retval = BailoutIonToBaseline(cx, bailoutData.activation(), iter, true, &bailoutInfo, &excInfo);
 
     if (retval == BAILOUT_RETURN_OK) {
         MOZ_ASSERT(bailoutInfo);
 
         // Overwrite the kind so HandleException after the bailout returns
         // false, jumping directly to the exception tail.
         if (excInfo.propagatingIonExceptionForDebugMode())
             bailoutInfo->bailoutKind = Bailout_IonExceptionDebugMode;
@@ -292,8 +242,21 @@ jit::CheckFrequentBailouts(JSContext *cx
 
             if (!Invalidate(cx, script))
                 return false;
         }
     }
 
     return true;
 }
+
+void
+BailoutFrameInfo::attachOnJitActivation(const JitActivationIterator &jitActivations)
+{
+    MOZ_ASSERT(jitActivations.jitTop() == FAKE_JIT_TOP_FOR_BAILOUT);
+    activation_ = jitActivations->asJit();
+    activation_->setBailoutData(this);
+}
+
+BailoutFrameInfo::~BailoutFrameInfo()
+{
+    activation_->cleanBailoutData();
+}
--- a/js/src/jit/Bailouts.h
+++ b/js/src/jit/Bailouts.h
@@ -108,60 +108,54 @@ class JitCompartment;
 
 // BailoutStack is an architecture specific pointer to the stack, given by the
 // bailout handler.
 class BailoutStack;
 class InvalidationBailoutStack;
 
 // Must be implemented by each architecture.
 
-// This iterator is constructed at a time where there is no exit frame at the
-// moment. They must be initialized to the first JS frame instead of the exit
-// frame as usually done with JitFrameIterator.
-class IonBailoutIterator : public JitFrameIterator
+// This structure is constructed before recovering the baseline frames for a
+// bailout. It records all information extracted from the stack, and which are
+// needed for the JitFrameIterator.
+class BailoutFrameInfo
 {
     MachineState machine_;
-    uint32_t snapshotOffset_;
+    uint8_t *framePointer_;
     size_t topFrameSize_;
     IonScript *topIonScript_;
+    uint32_t snapshotOffset_;
+    JitActivation *activation_;
+
+    void attachOnJitActivation(const JitActivationIterator &activations);
 
   public:
-    IonBailoutIterator(const JitActivationIterator &activations, BailoutStack *sp);
-    IonBailoutIterator(const JitActivationIterator &activations, InvalidationBailoutStack *sp);
-    IonBailoutIterator(const JitActivationIterator &activations, const JitFrameIterator &frame);
+    BailoutFrameInfo(const JitActivationIterator &activations, BailoutStack *sp);
+    BailoutFrameInfo(const JitActivationIterator &activations, InvalidationBailoutStack *sp);
+    BailoutFrameInfo(const JitActivationIterator &activations, const JitFrameIterator &frame);
+    ~BailoutFrameInfo();
 
+    uint8_t *fp() const {
+        return framePointer_;
+    }
     SnapshotOffset snapshotOffset() const {
-        if (topIonScript_)
-            return snapshotOffset_;
-        return osiIndex()->snapshotOffset();
+        return snapshotOffset_;
     }
     const MachineState machineState() const {
-        if (topIonScript_)
-            return machine_;
-        return JitFrameIterator::machineState();
+        return machine_;
     }
     size_t topFrameSize() const {
-        MOZ_ASSERT(topIonScript_);
         return topFrameSize_;
     }
     IonScript *ionScript() const {
-        if (topIonScript_)
-            return topIonScript_;
-        return JitFrameIterator::ionScript();
+        return topIonScript_;
     }
-
-    IonBailoutIterator &operator++() {
-        JitFrameIterator::operator++();
-        // Clear topIonScript_ now that we've advanced past it, so that
-        // snapshotOffset() and machineState() reflect the current script.
-        topIonScript_ = nullptr;
-        return *this;
+    JitActivation *activation() const {
+        return activation_;
     }
-
-    void dump() const;
 };
 
 bool EnsureHasScopeObjects(JSContext *cx, AbstractFramePtr fp);
 
 struct BaselineBailoutInfo;
 
 // Called from a bailout thunk. Returns a BAILOUT_* error code.
 uint32_t Bailout(BailoutStack *sp, BaselineBailoutInfo **info);
--- a/js/src/jit/BaselineBailouts.cpp
+++ b/js/src/jit/BaselineBailouts.cpp
@@ -69,41 +69,42 @@ class BufferPointer
  * needs to be enlarged to accomodate new data.  Similarly to the C stack, the
  * data that's written to the reconstructed stack grows from high to low in memory.
  *
  * The lowest region of the allocated memory contains a BaselineBailoutInfo structure that
  * points to the start and end of the written data.
  */
 struct BaselineStackBuilder
 {
-    IonBailoutIterator &iter_;
+    JitFrameIterator &iter_;
     IonJSFrameLayout *frame_;
 
     static size_t HeaderSize() {
         return AlignBytes(sizeof(BaselineBailoutInfo), sizeof(void *));
     }
     size_t bufferTotal_;
     size_t bufferAvail_;
     size_t bufferUsed_;
     uint8_t *buffer_;
     BaselineBailoutInfo *header_;
 
     size_t framePushed_;
 
-    BaselineStackBuilder(IonBailoutIterator &iter, size_t initialSize)
+    BaselineStackBuilder(JitFrameIterator &iter, size_t initialSize)
       : iter_(iter),
         frame_(static_cast<IonJSFrameLayout*>(iter.current())),
         bufferTotal_(initialSize),
         bufferAvail_(0),
         bufferUsed_(0),
         buffer_(nullptr),
         header_(nullptr),
         framePushed_(0)
     {
         MOZ_ASSERT(bufferTotal_ >= HeaderSize());
+        MOZ_ASSERT(iter.isBailoutJS());
     }
 
     ~BaselineStackBuilder() {
         js_free(buffer_);
     }
 
     bool init() {
         MOZ_ASSERT(!buffer_);
@@ -382,20 +383,21 @@ struct BaselineStackBuilder
 // Ensure that all value locations are readable from the SnapshotIterator.
 // Remove RInstructionResults from the JitActivation if the frame got recovered
 // ahead of the bailout.
 class SnapshotIteratorForBailout : public SnapshotIterator
 {
     RInstructionResults results_;
   public:
 
-    SnapshotIteratorForBailout(const IonBailoutIterator &iter)
+    SnapshotIteratorForBailout(const JitFrameIterator &iter)
       : SnapshotIterator(iter),
         results_(iter.jsFrame())
     {
+        MOZ_ASSERT(iter.isBailoutJS());
     }
 
     // Take previously computed result out of the activation, or compute the
     // results of all recover instructions contained in the snapshot.
     bool init(JSContext *cx, JitActivation *activation) {
         activation->maybeTakeIonFrameRecovery(fp_, &results_);
         if (!results_.isInitialized() && !computeInstructionResults(cx, &results_))
             return false;
@@ -1282,17 +1284,17 @@ InitFromBailout(JSContext *cx, HandleScr
     MOZ_ASSERT(rectReturnAddr);
     if (!builder.writePtr(rectReturnAddr, "ReturnAddr"))
         return false;
 
     return true;
 }
 
 uint32_t
-jit::BailoutIonToBaseline(JSContext *cx, JitActivation *activation, IonBailoutIterator &iter,
+jit::BailoutIonToBaseline(JSContext *cx, JitActivation *activation, JitFrameIterator &iter,
                           bool invalidate, BaselineBailoutInfo **bailoutInfo,
                           const ExceptionBailoutInfo *excInfo)
 {
     // The Baseline frames we will reconstruct on the heap are not rooted, so GC
     // must be suppressed here.
     MOZ_ASSERT(cx->mainThread().suppressGC);
 
     MOZ_ASSERT(bailoutInfo != nullptr);
@@ -1302,17 +1304,17 @@ jit::BailoutIonToBaseline(JSContext *cx,
     TraceLogStopEvent(logger, TraceLogger::IonMonkey);
     TraceLogStartEvent(logger, TraceLogger::Baseline);
 
     // The caller of the top frame must be one of the following:
     //      IonJS - Ion calling into Ion.
     //      BaselineStub - Baseline calling into Ion.
     //      Entry - Interpreter or other calling into Ion.
     //      Rectifier - Arguments rectifier calling into Ion.
-    MOZ_ASSERT(iter.isIonJS());
+    MOZ_ASSERT(iter.isBailoutJS());
     FrameType prevFrameType = iter.prevType();
     MOZ_ASSERT(prevFrameType == JitFrame_IonJS ||
                prevFrameType == JitFrame_BaselineStub ||
                prevFrameType == JitFrame_Entry ||
                prevFrameType == JitFrame_Rectifier);
 
     // All incoming frames are going to look like this:
     //
--- a/js/src/jit/BaselineJIT.h
+++ b/js/src/jit/BaselineJIT.h
@@ -432,17 +432,17 @@ struct BaselineBailoutInfo
     // Number of baseline frames to push on the stack.
     uint32_t numFrames;
 
     // The bailout kind.
     BailoutKind bailoutKind;
 };
 
 uint32_t
-BailoutIonToBaseline(JSContext *cx, JitActivation *activation, IonBailoutIterator &iter,
+BailoutIonToBaseline(JSContext *cx, JitActivation *activation, JitFrameIterator &iter,
                      bool invalidate, BaselineBailoutInfo **bailoutInfo,
                      const ExceptionBailoutInfo *exceptionInfo = nullptr);
 
 // Mark baseline scripts on the stack as active, so that they are not discarded
 // during GC.
 void
 MarkActiveBaselineScripts(Zone *zone);
 
--- a/js/src/jit/CodeGenerator.cpp
+++ b/js/src/jit/CodeGenerator.cpp
@@ -1293,17 +1293,17 @@ CreateDependentString(MacroAssembler &ma
         masm.storePtr(base, Address(string, JSDependentString::offsetOfBase()));
 
         // Follow any base pointer if the input is itself a dependent string.
         // Watch for undepended strings, which have a base pointer but don't
         // actually share their characters with it.
         Label noBase;
         masm.branchTest32(Assembler::Zero, Address(base, JSString::offsetOfFlags()),
                           Imm32(JSString::HAS_BASE_BIT), &noBase);
-        masm.branchTest32(Assembler::Zero, Address(base, JSString::offsetOfFlags()),
+        masm.branchTest32(Assembler::NonZero, Address(base, JSString::offsetOfFlags()),
                           Imm32(JSString::FLAT_BIT), &noBase);
         masm.loadPtr(Address(base, JSDependentString::offsetOfBase()), temp1);
         masm.storePtr(temp1, Address(string, JSDependentString::offsetOfBase()));
         masm.bind(&noBase);
     }
 
     masm.bind(&done);
 }
--- a/js/src/jit/Ion.cpp
+++ b/js/src/jit/Ion.cpp
@@ -619,17 +619,17 @@ FinishAllOffThreadCompilations(JSCompart
 }
 
 uint8_t *
 jit::LazyLinkTopActivation(JSContext *cx)
 {
     JitActivationIterator iter(cx->runtime());
 
     // First frame should be an exit frame.
-    JitFrameIterator it(iter.jitTop(), SequentialExecution);
+    JitFrameIterator it(iter);
     MOZ_ASSERT(it.type() == JitFrame_Exit);
 
     // Second frame is the Ion frame.
     ++it;
     MOZ_ASSERT(it.type() == JitFrame_IonJS);
 
     // Get the pending builder from the Ion frame.
     IonBuilder *builder = it.script()->ionScript()->pendingBuilder();
@@ -1879,17 +1879,17 @@ AttachFinishedCompilations(JSContext *cx
 #if defined(JS_CODEGEN_X86) || defined(JS_CODEGEN_X64)
         // Try to defer linking if the script is on the stack, to postpone
         // invalidating them.
         if (builder->info().executionMode() == SequentialExecution &&
             builder->script()->hasIonScript())
         {
             bool onStack = false;
             for (JitActivationIterator iter(cx->runtime()); !iter.done(); ++iter) {
-                for (JitFrameIterator it(iter.jitTop(), SequentialExecution); !it.done(); ++it) {
+                for (JitFrameIterator it(iter); !it.done(); ++it) {
                     if (!it.isIonJS())
                         continue;
                     if (it.checkInvalidation())
                         continue;
 
                     JSScript *script = it.script();
                     if (builder->script() == script) {
                         onStack = true;
@@ -2681,35 +2681,42 @@ jit::FastInvoke(JSContext *cx, HandleFun
 
     args.rval().set(result);
 
     MOZ_ASSERT_IF(result.isMagic(), result.isMagic(JS_ION_ERROR));
     return result.isMagic() ? IonExec_Error : IonExec_Ok;
 }
 
 static void
-InvalidateActivation(FreeOp *fop, uint8_t *jitTop, bool invalidateAll)
+InvalidateActivation(FreeOp *fop, const JitActivationIterator &activations, bool invalidateAll)
 {
     JitSpew(JitSpew_IonInvalidate, "BEGIN invalidating activation");
 
     size_t frameno = 1;
 
-    for (JitFrameIterator it(jitTop, SequentialExecution); !it.done(); ++it, ++frameno) {
+    for (JitFrameIterator it(activations); !it.done(); ++it, ++frameno) {
         MOZ_ASSERT_IF(frameno == 1, it.type() == JitFrame_Exit);
 
 #ifdef DEBUG
         switch (it.type()) {
           case JitFrame_Exit:
             JitSpew(JitSpew_IonInvalidate, "#%d exit frame @ %p", frameno, it.fp());
             break;
           case JitFrame_BaselineJS:
           case JitFrame_IonJS:
+          case JitFrame_Bailout:
           {
             MOZ_ASSERT(it.isScripted());
-            const char *type = it.isIonJS() ? "Optimized" : "Baseline";
+            const char *type = "Unknown";
+            if (it.isIonJS())
+                type = "Optimized";
+            else if (it.isBaselineJS())
+                type = "Baseline";
+            else if (it.isBailoutJS())
+                type = "Bailing";
             JitSpew(JitSpew_IonInvalidate, "#%d %s JS frame @ %p, %s:%d (fun: %p, script: %p, pc %p)",
                     frameno, type, it.fp(), it.script()->filename(), it.script()->lineno(),
                     it.maybeCallee(), (JSScript *)it.script(), it.returnAddressToFp());
             break;
           }
           case JitFrame_BaselineStub:
             JitSpew(JitSpew_IonInvalidate, "#%d baseline stub frame @ %p", frameno, it.fp());
             break;
@@ -2836,17 +2843,17 @@ void
 jit::InvalidateAll(FreeOp *fop, Zone *zone)
 {
     for (CompartmentsInZoneIter comp(zone); !comp.done(); comp.next())
         StopAllOffThreadCompilations(comp);
 
     for (JitActivationIterator iter(fop->runtime()); !iter.done(); ++iter) {
         if (iter->compartment()->zone() == zone) {
             JitSpew(JitSpew_IonInvalidate, "Invalidating all frames for GC");
-            InvalidateActivation(fop, iter.jitTop(), true);
+            InvalidateActivation(fop, iter, true);
         }
     }
 }
 
 
 void
 jit::Invalidate(types::TypeZone &types, FreeOp *fop,
                 const Vector<types::RecompileInfo> &invalid, bool resetUses,
@@ -2879,17 +2886,17 @@ jit::Invalidate(types::TypeZone &types, 
     }
 
     if (!numInvalidations) {
         JitSpew(JitSpew_IonInvalidate, " No IonScript invalidation.");
         return;
     }
 
     for (JitActivationIterator iter(fop->runtime()); !iter.done(); ++iter)
-        InvalidateActivation(fop, iter.jitTop(), false);
+        InvalidateActivation(fop, iter, false);
 
     // Drop the references added above. If a script was never active, its
     // IonScript will be immediately destroyed. Otherwise, it will be held live
     // until its last invalidated frame is destroyed.
     for (size_t i = 0; i < invalid.length(); i++) {
         types::CompilerOutput &co = *invalid[i].compilerOutput(types);
         if (!co.isValid())
             continue;
@@ -3345,17 +3352,17 @@ AutoDebugModeInvalidation::~AutoDebugMod
     // mode.
     jit::MarkActiveBaselineScripts(zone);
 
     for (JitActivationIterator iter(rt); !iter.done(); ++iter) {
         JSCompartment *comp = iter->compartment();
         if (comp_ == comp || zone_ == comp->zone()) {
             IonContext ictx(CompileRuntime::get(rt));
             JitSpew(JitSpew_IonInvalidate, "Invalidating frames for debug mode toggle");
-            InvalidateActivation(fop, iter.jitTop(), true);
+            InvalidateActivation(fop, iter, true);
         }
     }
 
     for (gc::ZoneCellIter i(zone, gc::FINALIZE_SCRIPT); !i.done(); i.next()) {
         JSScript *script = i.get<JSScript>();
         if (script->compartment() == comp_ || zone_) {
             FinishInvalidation<SequentialExecution>(fop, script);
             FinishInvalidation<ParallelExecution>(fop, script);
--- a/js/src/jit/IonFrames-inl.h
+++ b/js/src/jit/IonFrames-inl.h
@@ -75,24 +75,12 @@ GetTopBaselineFrame(JSContext *cx)
     MOZ_ASSERT(iter.type() == JitFrame_Exit);
     ++iter;
     if (iter.isBaselineStub())
         ++iter;
     MOZ_ASSERT(iter.isBaselineJS());
     return iter.baselineFrame();
 }
 
-inline JSScript *
-GetTopIonJSScript(JSContext *cx, void **returnAddrOut = nullptr)
-{
-    return GetTopIonJSScript(cx->mainThread().jitTop, returnAddrOut, SequentialExecution);
-}
-
-inline JSScript *
-GetTopIonJSScript(ForkJoinContext *cx, void **returnAddrOut = nullptr)
-{
-    return GetTopIonJSScript(cx->perThreadData->jitTop, returnAddrOut, ParallelExecution);
-}
-
 } // namespace jit
 } // namespace js
 
 #endif /* jit_IonFrames_inl_h */
--- a/js/src/jit/IonFrames.cpp
+++ b/js/src/jit/IonFrames.cpp
@@ -75,63 +75,58 @@ ReadFrameInt32Slot(IonJSFrameLayout *fp,
 }
 
 static inline bool
 ReadFrameBooleanSlot(IonJSFrameLayout *fp, int32_t slot)
 {
     return *(bool *)((char *)fp + OffsetOfFrameSlot(slot));
 }
 
+JitFrameIterator::JitFrameIterator()
+  : current_(nullptr),
+    type_(JitFrame_Exit),
+    returnAddressToFp_(nullptr),
+    frameSize_(0),
+    mode_(SequentialExecution),
+    cachedSafepointIndex_(nullptr),
+    activation_(nullptr)
+{
+}
+
 JitFrameIterator::JitFrameIterator(ThreadSafeContext *cx)
   : current_(cx->perThreadData->jitTop),
     type_(JitFrame_Exit),
     returnAddressToFp_(nullptr),
     frameSize_(0),
     mode_(cx->isForkJoinContext() ? ParallelExecution : SequentialExecution),
-    kind_(Kind_FrameIterator),
     cachedSafepointIndex_(nullptr),
-    activation_(nullptr)
+    activation_(cx->perThreadData->activation()->asJit())
 {
+    if (activation_->bailoutData()) {
+        current_ = activation_->bailoutData()->fp();
+        frameSize_ = activation_->bailoutData()->topFrameSize();
+        type_ = JitFrame_Bailout;
+    }
 }
 
 JitFrameIterator::JitFrameIterator(const ActivationIterator &activations)
   : current_(activations.jitTop()),
     type_(JitFrame_Exit),
     returnAddressToFp_(nullptr),
     frameSize_(0),
     mode_(activations->asJit()->cx()->isForkJoinContext() ? ParallelExecution
                                                           : SequentialExecution),
-    kind_(Kind_FrameIterator),
     cachedSafepointIndex_(nullptr),
     activation_(activations->asJit())
 {
-}
-
-JitFrameIterator::JitFrameIterator(IonJSFrameLayout *fp, ExecutionMode mode)
-  : current_((uint8_t *)fp),
-    type_(JitFrame_IonJS),
-    returnAddressToFp_(fp->returnAddress()),
-    frameSize_(fp->prevFrameLocalSize()),
-    mode_(mode),
-    kind_(Kind_FrameIterator)
-{
-}
-
-IonBailoutIterator *
-JitFrameIterator::asBailoutIterator()
-{
-    MOZ_ASSERT(isBailoutIterator());
-    return static_cast<IonBailoutIterator *>(this);
-}
-
-const IonBailoutIterator *
-JitFrameIterator::asBailoutIterator() const
-{
-    MOZ_ASSERT(isBailoutIterator());
-    return static_cast<const IonBailoutIterator *>(this);
+    if (activation_->bailoutData()) {
+        current_ = activation_->bailoutData()->fp();
+        frameSize_ = activation_->bailoutData()->topFrameSize();
+        type_ = JitFrame_Bailout;
+    }
 }
 
 bool
 JitFrameIterator::checkInvalidation() const
 {
     IonScript *dummy;
     return checkInvalidation(&dummy);
 }
@@ -268,16 +263,17 @@ JitFrameIterator::actualArgs() const
 static inline size_t
 SizeOfFramePrefix(FrameType type)
 {
     switch (type) {
       case JitFrame_Entry:
         return IonEntryFrameLayout::Size();
       case JitFrame_BaselineJS:
       case JitFrame_IonJS:
+      case JitFrame_Bailout:
       case JitFrame_Unwound_IonJS:
         return IonJSFrameLayout::Size();
       case JitFrame_BaselineStub:
         return IonBaselineStubFrameLayout::Size();
       case JitFrame_Rectifier:
         return IonRectifierFrameLayout::Size();
       case JitFrame_Unwound_Rectifier:
         return IonUnwoundRectifierFrameLayout::Size();
@@ -332,26 +328,34 @@ JitFrameIterator::operator++()
 
 
     return *this;
 }
 
 uintptr_t *
 JitFrameIterator::spillBase() const
 {
+    MOZ_ASSERT(isIonJS());
+
     // Get the base address to where safepoint registers are spilled.
     // Out-of-line calls do not unwind the extra padding space used to
     // aggregate bailout tables, so we use frameSize instead of frameLocals,
     // which would only account for local stack slots.
     return reinterpret_cast<uintptr_t *>(fp() - ionScript()->frameSize());
 }
 
 MachineState
 JitFrameIterator::machineState() const
 {
+    MOZ_ASSERT(isIonScripted());
+
+    // The MachineState is used by GCs for marking call-sites.
+    if (MOZ_UNLIKELY(isBailoutJS()))
+        return activation_->bailoutData()->machineState();
+
     SafepointReader reader(ionScript(), safepoint());
     uintptr_t *spill = spillBase();
 
     MachineState machine;
     for (GeneralRegisterBackwardIterator iter(reader.allGprSpills()); iter.more(); iter++)
         machine.setRegisterLocation(*iter, --spill);
 
     uint8_t *spillAlign = alignDoubleSpillWithOffset(reinterpret_cast<uint8_t *>(spill), 0);
@@ -1030,17 +1034,17 @@ MarkBaselineStubFrame(JSTracer *trc, con
         MOZ_ASSERT(ICStub::CanMakeCalls(stub->kind()));
         stub->trace(trc);
     }
 }
 
 void
 JitActivationIterator::jitStackRange(uintptr_t *&min, uintptr_t *&end)
 {
-    JitFrameIterator frames(jitTop(), SequentialExecution);
+    JitFrameIterator frames(*this);
 
     if (frames.isFakeExitFrame()) {
         min = reinterpret_cast<uintptr_t *>(frames.fp());
     } else {
         IonExitFrameLayout *exitFrame = frames.exitFrame();
         IonExitFooterFrame *footer = exitFrame->footer();
         const VMFunction *f = footer->function();
         if (exitFrame->isWrapperExit() && f->outParam == Type_Handle) {
@@ -1361,17 +1365,18 @@ void UpdateJitActivationsForMinorGC<gc::
 void
 GetPcScript(JSContext *cx, JSScript **scriptRes, jsbytecode **pcRes)
 {
     JitSpew(JitSpew_IonSnapshots, "Recover PC & Script from the last frame.");
 
     JSRuntime *rt = cx->runtime();
 
     // Recover the return address.
-    JitFrameIterator it(rt->mainThread.jitTop, SequentialExecution);
+    JitActivationIterator iter(rt);
+    JitFrameIterator it(iter);
 
     // If the previous frame is a rectifier frame (maybe unwound),
     // skip past it.
     if (it.prevType() == JitFrame_Rectifier || it.prevType() == JitFrame_Unwound_Rectifier) {
         ++it;
         MOZ_ASSERT(it.prevType() == JitFrame_BaselineStub ||
                    it.prevType() == JitFrame_BaselineJS ||
                    it.prevType() == JitFrame_IonJS);
@@ -1524,17 +1529,17 @@ SnapshotIterator::SnapshotIterator(IonSc
     ionScript_(ionScript),
     instructionResults_(nullptr)
 {
     MOZ_ASSERT(snapshotOffset < ionScript->snapshotsListSize());
 }
 
 SnapshotIterator::SnapshotIterator(const JitFrameIterator &iter)
   : snapshot_(iter.ionScript()->snapshots(),
-              iter.osiIndex()->snapshotOffset(),
+              iter.snapshotOffset(),
               iter.ionScript()->snapshotsRVATableSize(),
               iter.ionScript()->snapshotsListSize()),
     recover_(snapshot_,
              iter.ionScript()->recovers(),
              iter.ionScript()->recoversSize()),
     fp_(iter.jsFrame()),
     machine_(iter.machineState()),
     ionScript_(iter.ionScript()),
@@ -1908,54 +1913,77 @@ SnapshotIterator::maybeReadAllocByIndex(
     }
 
     while (moreAllocations())
         skip();
 
     return s;
 }
 
+IonJSFrameLayout *
+JitFrameIterator::jsFrame() const
+{
+    MOZ_ASSERT(isScripted());
+    if (isBailoutJS())
+        return (IonJSFrameLayout *) activation_->bailoutData()->fp();
+
+    return (IonJSFrameLayout *) fp();
+}
+
 IonScript *
 JitFrameIterator::ionScript() const
 {
-    MOZ_ASSERT(type() == JitFrame_IonJS);
+    MOZ_ASSERT(isIonScripted());
+    if (isBailoutJS())
+        return activation_->bailoutData()->ionScript();
 
     IonScript *ionScript = nullptr;
     if (checkInvalidation(&ionScript))
         return ionScript;
     return ionScriptFromCalleeToken();
 }
 
 IonScript *
 JitFrameIterator::ionScriptFromCalleeToken() const
 {
-    MOZ_ASSERT(type() == JitFrame_IonJS);
+    MOZ_ASSERT(isIonJS());
     MOZ_ASSERT(!checkInvalidation());
 
     switch (mode_) {
       case SequentialExecution:
         return script()->ionScript();
       case ParallelExecution:
         return script()->parallelIonScript();
       default:
         MOZ_CRASH("No such execution mode");
     }
 }
 
 const SafepointIndex *
 JitFrameIterator::safepoint() const
 {
+    MOZ_ASSERT(isIonJS());
     if (!cachedSafepointIndex_)
         cachedSafepointIndex_ = ionScript()->getSafepointIndex(returnAddressToFp());
     return cachedSafepointIndex_;
 }
 
+SnapshotOffset
+JitFrameIterator::snapshotOffset() const
+{
+    MOZ_ASSERT(isIonScripted());
+    if (isBailoutJS())
+        return activation_->bailoutData()->snapshotOffset();
+    return osiIndex()->snapshotOffset();
+}
+
 const OsiIndex *
 JitFrameIterator::osiIndex() const
 {
+    MOZ_ASSERT(isIonJS());
     SafepointReader reader(ionScript(), safepoint());
     return ionScript()->getOsiIndex(reader.osiReturnPointOffset());
 }
 
 InlineFrameIterator::InlineFrameIterator(ThreadSafeContext *cx, const JitFrameIterator *iter)
   : callee_(cx),
     script_(cx)
 {
@@ -1964,41 +1992,25 @@ InlineFrameIterator::InlineFrameIterator
 
 InlineFrameIterator::InlineFrameIterator(JSRuntime *rt, const JitFrameIterator *iter)
   : callee_(rt),
     script_(rt)
 {
     resetOn(iter);
 }
 
-InlineFrameIterator::InlineFrameIterator(ThreadSafeContext *cx, const IonBailoutIterator *iter)
-  : frame_(iter),
-    framesRead_(0),
-    frameCount_(UINT32_MAX),
-    callee_(cx),
-    script_(cx)
-{
-    if (iter) {
-        start_ = SnapshotIterator(*iter);
-        findNextFrame();
-    }
-}
-
 InlineFrameIterator::InlineFrameIterator(ThreadSafeContext *cx, const InlineFrameIterator *iter)
   : frame_(iter ? iter->frame_ : nullptr),
     framesRead_(0),
     frameCount_(iter ? iter->frameCount_ : UINT32_MAX),
     callee_(cx),
     script_(cx)
 {
     if (frame_) {
-        if (frame_->isBailoutIterator())
-            start_ = SnapshotIterator(*frame_->asBailoutIterator());
-        else
-            start_ = SnapshotIterator(*frame_);
+        start_ = SnapshotIterator(*frame_);
 
         // findNextFrame will iterate to the next frame and init. everything.
         // Therefore to settle on the same frame, we report one frame less readed.
         framesRead_ = iter->framesRead_ - 1;
         findNextFrame();
     }
 }
 
@@ -2327,16 +2339,17 @@ JitFrameIterator::dump() const
       case JitFrame_BaselineJS:
         dumpBaseline();
         break;
       case JitFrame_BaselineStub:
       case JitFrame_Unwound_BaselineStub:
         fprintf(stderr, " Baseline stub frame\n");
         fprintf(stderr, "  Frame size: %u\n", unsigned(current()->prevFrameLocalSize()));
         break;
+      case JitFrame_Bailout:
       case JitFrame_IonJS:
       {
         InlineFrameIterator frames(GetJSContextFromJitCode(), this);
         for (;;) {
             frames.dump();
             if (!frames.more())
                 break;
             ++frames;
--- a/js/src/jit/IonFrames.h
+++ b/js/src/jit/IonFrames.h
@@ -287,19 +287,19 @@ void UpdateJitActivationsForMinorGC(PerT
 static inline uint32_t
 MakeFrameDescriptor(uint32_t frameSize, FrameType type)
 {
     return (frameSize << FRAMESIZE_SHIFT) | type;
 }
 
 // Returns the JSScript associated with the topmost Ion frame.
 inline JSScript *
-GetTopIonJSScript(uint8_t *jitTop, void **returnAddrOut, ExecutionMode mode)
+GetTopIonJSScript(ThreadSafeContext *cx, void **returnAddrOut = nullptr)
 {
-    JitFrameIterator iter(jitTop, mode);
+    JitFrameIterator iter(cx);
     MOZ_ASSERT(iter.type() == JitFrame_Exit);
     ++iter;
 
     MOZ_ASSERT(iter.returnAddressToFp() != nullptr);
     if (returnAddrOut)
         *returnAddrOut = (void *) iter.returnAddressToFp();
 
     if (iter.isBaselineStub()) {
--- a/js/src/jit/JitFrameIterator.h
+++ b/js/src/jit/JitFrameIterator.h
@@ -52,79 +52,63 @@ enum FrameType
 
     // An unwound rectifier frame is a rectifier frame signalling that its callee
     // frame has been turned into an exit frame (see EnsureExitFrame).
     JitFrame_Unwound_Rectifier,
 
     // An exit frame is necessary for transitioning from a JS frame into C++.
     // From within C++, an exit frame is always the last frame in any
     // JitActivation.
-    JitFrame_Exit
+    JitFrame_Exit,
+
+    // A bailout frame is a special IonJS jit frame after a bailout, and before
+    // the reconstruction of the BaselineJS frame. From within C++, a bailout
+    // frame is always the last frame in a JitActivation iff the bailout frame
+    // information is recorded on the JitActivation.
+    JitFrame_Bailout
 };
 
 enum ReadFrameArgsBehavior {
     // Only read formals (i.e. [0 ... callee()->nargs]
     ReadFrame_Formals,
 
     // Only read overflown args (i.e. [callee()->nargs ... numActuals()]
     ReadFrame_Overflown,
 
     // Read all args (i.e. [0 ... numActuals()])
     ReadFrame_Actuals
 };
 
 class IonCommonFrameLayout;
 class IonJSFrameLayout;
 class IonExitFrameLayout;
-class IonBailoutIterator;
 
 class BaselineFrame;
 
 class JitActivation;
 
 class JitFrameIterator
 {
   protected:
     uint8_t *current_;
     FrameType type_;
     uint8_t *returnAddressToFp_;
     size_t frameSize_;
     ExecutionMode mode_;
-    enum Kind {
-        Kind_FrameIterator,
-        Kind_BailoutIterator
-    } kind_;
 
   private:
     mutable const SafepointIndex *cachedSafepointIndex_;
     const JitActivation *activation_;
 
     void dumpBaseline() const;
 
   public:
-    explicit JitFrameIterator(uint8_t *top, ExecutionMode mode)
-      : current_(top),
-        type_(JitFrame_Exit),
-        returnAddressToFp_(nullptr),
-        frameSize_(0),
-        mode_(mode),
-        kind_(Kind_FrameIterator),
-        cachedSafepointIndex_(nullptr),
-        activation_(nullptr)
-    { }
-
+    explicit JitFrameIterator();
     explicit JitFrameIterator(ThreadSafeContext *cx);
     explicit JitFrameIterator(const ActivationIterator &activations);
-    explicit JitFrameIterator(IonJSFrameLayout *fp, ExecutionMode mode);
-
-    bool isBailoutIterator() const {
-        return kind_ == Kind_BailoutIterator;
-    }
-    IonBailoutIterator *asBailoutIterator();
-    const IonBailoutIterator *asBailoutIterator() const;
 
     // Current frame information.
     FrameType type() const {
         return type_;
     }
     uint8_t *fp() const {
         return current_;
     }
@@ -133,40 +117,45 @@ class JitFrameIterator
     }
 
     IonCommonFrameLayout *current() const {
         return (IonCommonFrameLayout *)current_;
     }
 
     inline uint8_t *returnAddress() const;
 
-    IonJSFrameLayout *jsFrame() const {
-        MOZ_ASSERT(isScripted());
-        return (IonJSFrameLayout *) fp();
-    }
+    // Return the pointer of the JitFrame, the iterator is assumed to be settled
+    // on a scripted frame.
+    IonJSFrameLayout *jsFrame() const;
 
     // Returns true iff this exit frame was created using EnsureExitFrame.
     inline bool isFakeExitFrame() const;
 
     inline IonExitFrameLayout *exitFrame() const;
 
     // Returns whether the JS frame has been invalidated and, if so,
     // places the invalidated Ion script in |ionScript|.
     bool checkInvalidation(IonScript **ionScript) const;
     bool checkInvalidation() const;
 
     bool isScripted() const {
-        return type_ == JitFrame_BaselineJS || type_ == JitFrame_IonJS;
+        return type_ == JitFrame_BaselineJS || type_ == JitFrame_IonJS || type_ == JitFrame_Bailout;
     }
     bool isBaselineJS() const {
         return type_ == JitFrame_BaselineJS;
     }
+    bool isIonScripted() const {
+        return type_ == JitFrame_IonJS || type_ == JitFrame_Bailout;
+    }
     bool isIonJS() const {
         return type_ == JitFrame_IonJS;
     }
+    bool isBailoutJS() const {
+        return type_ == JitFrame_Bailout;
+    }
     bool isBaselineStub() const {
         return type_ == JitFrame_BaselineStub;
     }
     bool isBareExit() const;
     template <typename T> bool isExitFrameLayout() const;
 
     bool isEntry() const {
         return type_ == JitFrame_Entry;
@@ -222,16 +211,20 @@ class JitFrameIterator
     // Returns the Safepoint associated with this JS frame. Incurs a lookup
     // overhead.
     const SafepointIndex *safepoint() const;
 
     // Returns the OSI index associated with this JS frame. Incurs a lookup
     // overhead.
     const OsiIndex *osiIndex() const;
 
+    // Returns the Snapshot offset associated with this JS frame. Incurs a
+    // lookup overhead.
+    SnapshotOffset snapshotOffset() const;
+
     uintptr_t *spillBase() const;
     MachineState machineState() const;
 
     template <class Op>
     void unaliasedForEachActual(Op op, ReadFrameArgsBehavior behavior) const {
         MOZ_ASSERT(isBaselineJS());
 
         unsigned nactual = numActualArgs();
@@ -471,17 +464,16 @@ class SnapshotIterator
 
   public:
     // Connect all informations about the current script in order to recover the
     // content of baseline frames.
 
     SnapshotIterator(IonScript *ionScript, SnapshotOffset snapshotOffset,
                      IonJSFrameLayout *fp, const MachineState &machine);
     explicit SnapshotIterator(const JitFrameIterator &iter);
-    explicit SnapshotIterator(const IonBailoutIterator &iter);
     SnapshotIterator();
 
     Value read() {
         return allocationValue(readAllocation());
     }
 
     Value maybeRead(MaybeReadFallback &fallback) {
         RValueAllocation a = readAllocation();
@@ -586,17 +578,16 @@ class InlineFrameIterator
 
   private:
     void findNextFrame();
     JSObject *computeScopeChain(Value scopeChainValue) const;
 
   public:
     InlineFrameIterator(ThreadSafeContext *cx, const JitFrameIterator *iter);
     InlineFrameIterator(JSRuntime *rt, const JitFrameIterator *iter);
-    InlineFrameIterator(ThreadSafeContext *cx, const IonBailoutIterator *iter);
     InlineFrameIterator(ThreadSafeContext *cx, const InlineFrameIterator *iter);
 
     bool more() const {
         return frame_ && framesRead_ < frameCount_;
     }
     JSFunction *callee() const {
         MOZ_ASSERT(callee_);
         return callee_;
--- a/js/src/jit/ParallelFunctions.cpp
+++ b/js/src/jit/ParallelFunctions.cpp
@@ -539,17 +539,18 @@ jit::BailoutPar(BailoutStack *sp, uint8_
 
     // We don't have an exit frame.
     MOZ_ASSERT(IsInRange(FAKE_JIT_TOP_FOR_BAILOUT, 0, 0x1000) &&
                IsInRange(FAKE_JIT_TOP_FOR_BAILOUT + sizeof(IonCommonFrameLayout), 0, 0x1000),
                "Fake jitTop pointer should be within the first page.");
     cx->perThreadData->jitTop = FAKE_JIT_TOP_FOR_BAILOUT;
 
     JitActivationIterator jitActivations(cx->perThreadData);
-    IonBailoutIterator frameIter(jitActivations, sp);
+    BailoutFrameInfo bailoutData(jitActivations, sp);
+    JitFrameIterator frameIter(jitActivations);
     SnapshotIterator snapIter(frameIter);
 
     cx->bailoutRecord->setIonBailoutKind(snapIter.bailoutKind());
     cx->bailoutRecord->rematerializeFrames(cx, frameIter);
 
     MOZ_ASSERT(frameIter.done());
     *entryFramePointer = frameIter.fp();
 }
--- a/js/src/jit/arm/Bailouts-arm.cpp
+++ b/js/src/jit/arm/Bailouts-arm.cpp
@@ -64,63 +64,59 @@ class BailoutStack
 };
 
 // Make sure the compiler doesn't add extra padding.
 static_assert((sizeof(BailoutStack) % 8) == 0, "BailoutStack should be 8-byte aligned.");
 
 } // namespace jit
 } // namespace js
 
-IonBailoutIterator::IonBailoutIterator(const JitActivationIterator &activations,
-                                       BailoutStack *bailout)
-  : JitFrameIterator(activations),
-    machine_(bailout->machine())
+BailoutFrameInfo::BailoutFrameInfo(const JitActivationIterator &activations,
+                                   BailoutStack *bailout)
+  : machine_(bailout->machine())
 {
     uint8_t *sp = bailout->parentStackPointer();
-    uint8_t *fp = sp + bailout->frameSize();
+    framePointer_ = sp + bailout->frameSize();
+    topFrameSize_ = framePointer_ - sp;
 
-    kind_ = Kind_BailoutIterator;
-    current_ = fp;
-    type_ = JitFrame_IonJS;
-    topFrameSize_ = current_ - sp;
-    switch (mode_) {
-      case SequentialExecution: topIonScript_ = script()->ionScript(); break;
-      case ParallelExecution: topIonScript_ = script()->parallelIonScript(); break;
-      default: MOZ_CRASH("No such execution mode");
-    }
+    JSScript *script = ScriptFromCalleeToken(((IonJSFrameLayout *) framePointer_)->calleeToken());
+    JitActivation *activation = activations.activation()->asJit();
+    if (activation->cx()->isForkJoinContext())
+        topIonScript_ = script->parallelIonScript();
+    else
+        topIonScript_ = script->ionScript();
+
+    attachOnJitActivation(activations);
 
     if (bailout->frameClass() == FrameSizeClass::None()) {
         snapshotOffset_ = bailout->snapshotOffset();
         return;
     }
 
     // Compute the snapshot offset from the bailout ID.
-    JitActivation *activation = activations.activation()->asJit();
     JSRuntime *rt = activation->compartment()->runtimeFromMainThread();
     JitCode *code = rt->jitRuntime()->getBailoutTable(bailout->frameClass());
     uintptr_t tableOffset = bailout->tableOffset();
     uintptr_t tableStart = reinterpret_cast<uintptr_t>(Assembler::BailoutTableStart(code->raw()));
 
     MOZ_ASSERT(tableOffset >= tableStart &&
                tableOffset < tableStart + code->instructionsSize());
     MOZ_ASSERT((tableOffset - tableStart) % BAILOUT_TABLE_ENTRY_SIZE == 0);
 
     uint32_t bailoutId = ((tableOffset - tableStart) / BAILOUT_TABLE_ENTRY_SIZE) - 1;
     MOZ_ASSERT(bailoutId < BAILOUT_TABLE_SIZE);
 
     snapshotOffset_ = topIonScript_->bailoutToSnapshot(bailoutId);
 }
 
-IonBailoutIterator::IonBailoutIterator(const JitActivationIterator &activations,
-                                       InvalidationBailoutStack *bailout)
-  : JitFrameIterator(activations),
-    machine_(bailout->machine())
+BailoutFrameInfo::BailoutFrameInfo(const JitActivationIterator &activations,
+                                   InvalidationBailoutStack *bailout)
+  : machine_(bailout->machine())
 {
-    kind_ = Kind_BailoutIterator;
-    returnAddressToFp_ = bailout->osiPointReturnAddress();
+    framePointer_ = (uint8_t*) bailout->fp();
+    topFrameSize_ = framePointer_ - bailout->sp();
     topIonScript_ = bailout->ionScript();
+    attachOnJitActivation(activations);
+
+    uint8_t *returnAddressToFp_ = bailout->osiPointReturnAddress();
     const OsiIndex *osiIndex = topIonScript_->getOsiIndex(returnAddressToFp_);
-
-    current_ = (uint8_t*) bailout->fp();
-    type_ = JitFrame_IonJS;
-    topFrameSize_ = current_ - bailout->sp();
     snapshotOffset_ = osiIndex->snapshotOffset();
 }
--- a/js/src/jit/mips/Bailouts-mips.cpp
+++ b/js/src/jit/mips/Bailouts-mips.cpp
@@ -7,63 +7,59 @@
 #include "jit/mips/Bailouts-mips.h"
 
 #include "jscntxt.h"
 #include "jscompartment.h"
 
 using namespace js;
 using namespace js::jit;
 
-IonBailoutIterator::IonBailoutIterator(const JitActivationIterator &activations,
-                                       BailoutStack *bailout)
-  : JitFrameIterator(activations),
-    machine_(bailout->machine())
+BailoutFrameInfo::BailoutFrameInfo(const JitActivationIterator &activations,
+                                   BailoutStack *bailout)
+  : machine_(bailout->machine())
 {
     uint8_t *sp = bailout->parentStackPointer();
-    uint8_t *fp = sp + bailout->frameSize();
+    framePointer_ = sp + bailout->frameSize();
+    topFrameSize_ = framePointer_ - sp;
 
-    kind_ = Kind_BailoutIterator;
-    current_ = fp;
-    type_ = JitFrame_IonJS;
-    topFrameSize_ = current_ - sp;
-    switch (mode_) {
-      case SequentialExecution: topIonScript_ = script()->ionScript(); break;
-      case ParallelExecution: topIonScript_ = script()->parallelIonScript(); break;
-      default: MOZ_CRASH("No such execution mode");
-    }
+    JSScript *script = ScriptFromCalleeToken(((IonJSFrameLayout *) framePointer_)->calleeToken());
+    JitActivation *activation = activations.activation()->asJit();
+    if (activation->cx()->isForkJoinContext())
+        topIonScript_ = script->parallelIonScript();
+    else
+        topIonScript_ = script->ionScript();
+
+    attachOnJitActivation(activations);
 
     if (bailout->frameClass() == FrameSizeClass::None()) {
         snapshotOffset_ = bailout->snapshotOffset();
         return;
     }
 
     // Compute the snapshot offset from the bailout ID.
-    JitActivation *activation = activations.activation()->asJit();
     JSRuntime *rt = activation->compartment()->runtimeFromMainThread();
     JitCode *code = rt->jitRuntime()->getBailoutTable(bailout->frameClass());
     uintptr_t tableOffset = bailout->tableOffset();
     uintptr_t tableStart = reinterpret_cast<uintptr_t>(code->raw());
 
     MOZ_ASSERT(tableOffset >= tableStart &&
-              tableOffset < tableStart + code->instructionsSize());
+               tableOffset < tableStart + code->instructionsSize());
     MOZ_ASSERT((tableOffset - tableStart) % BAILOUT_TABLE_ENTRY_SIZE == 0);
 
     uint32_t bailoutId = ((tableOffset - tableStart) / BAILOUT_TABLE_ENTRY_SIZE) - 1;
     MOZ_ASSERT(bailoutId < BAILOUT_TABLE_SIZE);
 
     snapshotOffset_ = topIonScript_->bailoutToSnapshot(bailoutId);
 }
 
-IonBailoutIterator::IonBailoutIterator(const JitActivationIterator &activations,
-                                       InvalidationBailoutStack *bailout)
-  : JitFrameIterator(activations),
-    machine_(bailout->machine())
+BailoutFrameInfo::BailoutFrameInfo(const JitActivationIterator &activations,
+                                   InvalidationBailoutStack *bailout)
+  : machine_(bailout->machine())
 {
-    kind_ = Kind_BailoutIterator;
-    returnAddressToFp_ = bailout->osiPointReturnAddress();
+    framePointer_ = (uint8_t*) bailout->fp();
+    topFrameSize_ = framePointer_ - bailout->sp();
     topIonScript_ = bailout->ionScript();
+    attachOnJitActivation(activations);
+
+    uint8_t *returnAddressToFp_ = bailout->osiPointReturnAddress();
     const OsiIndex *osiIndex = topIonScript_->getOsiIndex(returnAddressToFp_);
-
-    current_ = (uint8_t*) bailout->fp();
-    type_ = JitFrame_IonJS;
-    topFrameSize_ = current_ - bailout->sp();
     snapshotOffset_ = osiIndex->snapshotOffset();
 }
--- a/js/src/jit/none/Trampoline-none.cpp
+++ b/js/src/jit/none/Trampoline-none.cpp
@@ -42,24 +42,22 @@ void MacroAssembler::alignFrameForICArgu
 void MacroAssembler::restoreFrameAlignmentForICArguments(AfterICSaveLive &) { MOZ_CRASH(); }
 
 const Register ABIArgGenerator::NonArgReturnReg0 = { 0 };
 const Register ABIArgGenerator::NonArgReturnReg1 = { 0 };
 const Register ABIArgGenerator::NonArg_VolatileReg = { 0 };
 const Register ABIArgGenerator::NonReturn_VolatileReg0 = { 0 };
 const Register ABIArgGenerator::NonReturn_VolatileReg1 = { 0 };
 
-IonBailoutIterator::IonBailoutIterator(const JitActivationIterator &iter, BailoutStack *bailout)
-  : JitFrameIterator(iter)
+BailoutFrameInfo::BailoutFrameInfo(const JitActivationIterator &iter, BailoutStack *bailout)
 {
     MOZ_CRASH();
 }
 
-IonBailoutIterator::IonBailoutIterator(const JitActivationIterator &iter, InvalidationBailoutStack *bailout)
-  : JitFrameIterator(iter)
+BailoutFrameInfo::BailoutFrameInfo(const JitActivationIterator &iter, InvalidationBailoutStack *bailout)
 {
     MOZ_CRASH();
 }
 
 bool ICCompare_Int32::Compiler::generateStubCode(MacroAssembler &) { MOZ_CRASH(); }
 bool ICCompare_Double::Compiler::generateStubCode(MacroAssembler &) { MOZ_CRASH(); }
 bool ICBinaryArith_Int32::Compiler::generateStubCode(MacroAssembler &) { MOZ_CRASH(); }
 bool ICUnaryArith_Int32::Compiler::generateStubCode(MacroAssembler &) { MOZ_CRASH(); }
--- a/js/src/jit/x64/Bailouts-x64.cpp
+++ b/js/src/jit/x64/Bailouts-x64.cpp
@@ -40,43 +40,40 @@ class BailoutStack
 
 } // namespace jit
 } // namespace js
 
 #if defined(_WIN32)
 # pragma pack(pop)
 #endif
 
-IonBailoutIterator::IonBailoutIterator(const JitActivationIterator &activations,
-                                       BailoutStack *bailout)
-  : JitFrameIterator(activations),
-    machine_(bailout->machineState())
+BailoutFrameInfo::BailoutFrameInfo(const JitActivationIterator &activations,
+                                   BailoutStack *bailout)
+  : machine_(bailout->machineState())
 {
     uint8_t *sp = bailout->parentStackPointer();
-    uint8_t *fp = sp + bailout->frameSize();
+    framePointer_ = sp + bailout->frameSize();
+    topFrameSize_ = framePointer_ - sp;
 
-    kind_ = Kind_BailoutIterator;
-    current_ = fp;
-    type_ = JitFrame_IonJS;
-    topFrameSize_ = current_ - sp;
-    switch (mode_) {
-      case SequentialExecution: topIonScript_ = script()->ionScript(); break;
-      case ParallelExecution: topIonScript_ = script()->parallelIonScript(); break;
-      default: MOZ_CRASH("No such execution mode");
-    }
+    JSScript *script = ScriptFromCalleeToken(((IonJSFrameLayout *) framePointer_)->calleeToken());
+    JitActivation *activation = activations.activation()->asJit();
+    if (activation->cx()->isForkJoinContext())
+        topIonScript_ = script->parallelIonScript();
+    else
+        topIonScript_ = script->ionScript();
+
+    attachOnJitActivation(activations);
     snapshotOffset_ = bailout->snapshotOffset();
 }
 
-IonBailoutIterator::IonBailoutIterator(const JitActivationIterator &activations,
-                                       InvalidationBailoutStack *bailout)
-  : JitFrameIterator(activations),
-    machine_(bailout->machine())
+BailoutFrameInfo::BailoutFrameInfo(const JitActivationIterator &activations,
+                                   InvalidationBailoutStack *bailout)
+  : machine_(bailout->machine())
 {
-    kind_ = Kind_BailoutIterator;
-    returnAddressToFp_ = bailout->osiPointReturnAddress();
+    framePointer_ = (uint8_t*) bailout->fp();
+    topFrameSize_ = framePointer_ - bailout->sp();
     topIonScript_ = bailout->ionScript();
+    attachOnJitActivation(activations);
+
+    uint8_t *returnAddressToFp_ = bailout->osiPointReturnAddress();
     const OsiIndex *osiIndex = topIonScript_->getOsiIndex(returnAddressToFp_);
-
-    current_ = (uint8_t*) bailout->fp();
-    type_ = JitFrame_IonJS;
-    topFrameSize_ = current_ - bailout->sp();
     snapshotOffset_ = osiIndex->snapshotOffset();
 }
--- a/js/src/jit/x86/Bailouts-x86.cpp
+++ b/js/src/jit/x86/Bailouts-x86.cpp
@@ -60,63 +60,59 @@ class BailoutStack
 
 } // namespace jit
 } // namespace js
 
 #if defined(_WIN32)
 # pragma pack(pop)
 #endif
 
-IonBailoutIterator::IonBailoutIterator(const JitActivationIterator &activations,
-                                       BailoutStack *bailout)
-  : JitFrameIterator(activations),
-    machine_(bailout->machine())
+BailoutFrameInfo::BailoutFrameInfo(const JitActivationIterator &activations,
+                                   BailoutStack *bailout)
+  : machine_(bailout->machine())
 {
     uint8_t *sp = bailout->parentStackPointer();
-    uint8_t *fp = sp + bailout->frameSize();
+    framePointer_ = sp + bailout->frameSize();
+    topFrameSize_ = framePointer_ - sp;
 
-    kind_ = Kind_BailoutIterator;
-    current_ = fp;
-    type_ = JitFrame_IonJS;
-    topFrameSize_ = current_ - sp;
-    switch (mode_) {
-      case SequentialExecution: topIonScript_ = script()->ionScript(); break;
-      case ParallelExecution: topIonScript_ = script()->parallelIonScript(); break;
-      default: MOZ_CRASH("No such execution mode");
-    }
+    JSScript *script = ScriptFromCalleeToken(((IonJSFrameLayout *) framePointer_)->calleeToken());
+    JitActivation *activation = activations.activation()->asJit();
+    if (activation->cx()->isForkJoinContext())
+        topIonScript_ = script->parallelIonScript();
+    else
+        topIonScript_ = script->ionScript();
+
+    attachOnJitActivation(activations);
 
     if (bailout->frameClass() == FrameSizeClass::None()) {
         snapshotOffset_ = bailout->snapshotOffset();
         return;
     }
 
     // Compute the snapshot offset from the bailout ID.
-    JitActivation *activation = activations.activation()->asJit();
     JSRuntime *rt = activation->compartment()->runtimeFromMainThread();
     JitCode *code = rt->jitRuntime()->getBailoutTable(bailout->frameClass());
     uintptr_t tableOffset = bailout->tableOffset();
     uintptr_t tableStart = reinterpret_cast<uintptr_t>(code->raw());
 
     MOZ_ASSERT(tableOffset >= tableStart &&
                tableOffset < tableStart + code->instructionsSize());
     MOZ_ASSERT((tableOffset - tableStart) % BAILOUT_TABLE_ENTRY_SIZE == 0);
 
     uint32_t bailoutId = ((tableOffset - tableStart) / BAILOUT_TABLE_ENTRY_SIZE) - 1;
     MOZ_ASSERT(bailoutId < BAILOUT_TABLE_SIZE);
 
     snapshotOffset_ = topIonScript_->bailoutToSnapshot(bailoutId);
 }
 
-IonBailoutIterator::IonBailoutIterator(const JitActivationIterator &activations,
-                                       InvalidationBailoutStack *bailout)
-  : JitFrameIterator(activations),
-    machine_(bailout->machine())
+BailoutFrameInfo::BailoutFrameInfo(const JitActivationIterator &activations,
+                                   InvalidationBailoutStack *bailout)
+  : machine_(bailout->machine())
 {
-    kind_ = Kind_BailoutIterator;
-    returnAddressToFp_ = bailout->osiPointReturnAddress();
+    framePointer_ = (uint8_t*) bailout->fp();
+    topFrameSize_ = framePointer_ - bailout->sp();
     topIonScript_ = bailout->ionScript();
+    attachOnJitActivation(activations);
+
+    uint8_t *returnAddressToFp_ = bailout->osiPointReturnAddress();
     const OsiIndex *osiIndex = topIonScript_->getOsiIndex(returnAddressToFp_);
-
-    current_ = (uint8_t*) bailout->fp();
-    type_ = JitFrame_IonJS;
-    topFrameSize_ = current_ - bailout->sp();
     snapshotOffset_ = osiIndex->snapshotOffset();
 }
--- a/js/src/jsobj.cpp
+++ b/js/src/jsobj.cpp
@@ -377,21 +377,28 @@ js::GetOwnPropertyDescriptor(JSContext *
         desc.object().set(nullptr);
         return true;
     }
 
     bool doGet = true;
     if (pobj->isNative()) {
         desc.setAttributes(GetShapeAttributes(pobj, shape));
         if (desc.hasGetterOrSetterObject()) {
+            MOZ_ASSERT(desc.isShared());
             doGet = false;
             if (desc.hasGetterObject())
                 desc.setGetterObject(shape->getterObject());
             if (desc.hasSetterObject())
                 desc.setSetterObject(shape->setterObject());
+        } else {
+            // This is either a straight-up data property or (rarely) a
+            // property with a JSPropertyOp getter/setter. The latter must be
+            // reported to the caller as a plain data property, so don't
+            // populate desc.getter/setter, and mask away the SHARED bit.
+            desc.attributesRef() &= ~JSPROP_SHARED;
         }
     } else {
         if (!JSObject::getGenericAttributes(cx, pobj, id, &desc.attributesRef()))
             return false;
     }
 
     RootedValue value(cx);
     if (doGet && !JSObject::getGeneric(cx, obj, obj, id, &value))
--- a/js/src/jsscript.h
+++ b/js/src/jsscript.h
@@ -1225,22 +1225,22 @@ class JSScript : public js::gc::TenuredC
         // so it can only transition from not being a generator.
         MOZ_ASSERT(!isGenerator());
         generatorKindBits_ = GeneratorKindAsBits(kind);
     }
 
     /*
      * As an optimization, even when argsHasLocalBinding, the function prologue
      * may not need to create an arguments object. This is determined by
-     * needsArgsObj which is set by AnalyzeArgumentsUsage before running
-     * the script the first time. When !needsArgsObj, the prologue may simply
-     * write MagicValue(JS_OPTIMIZED_ARGUMENTS) to 'arguments's slot and any
-     * uses of 'arguments' will be guaranteed to handle this magic value.
-     * So avoid spurious arguments object creation, we maintain the invariant
-     * that needsArgsObj is only called after the script has been analyzed.
+     * needsArgsObj which is set by AnalyzeArgumentsUsage. When !needsArgsObj,
+     * the prologue may simply write MagicValue(JS_OPTIMIZED_ARGUMENTS) to
+     * 'arguments's slot and any uses of 'arguments' will be guaranteed to
+     * handle this magic value. To avoid spurious arguments object creation, we
+     * maintain the invariant that needsArgsObj is only called after the script
+     * has been analyzed.
      */
     bool analyzedArgsUsage() const { return !needsArgsAnalysis_; }
     inline bool ensureHasAnalyzedArgsUsage(JSContext *cx);
     bool needsArgsObj() const {
         MOZ_ASSERT(analyzedArgsUsage());
         return needsArgsObj_;
     }
     void setNeedsArgsObj(bool needsArgsObj);
--- a/js/src/vm/Debugger.cpp
+++ b/js/src/vm/Debugger.cpp
@@ -4615,16 +4615,18 @@ DebuggerArguments_getArg(JSContext *cx, 
      * Since getters can be extracted and applied to other objects,
      * there is no guarantee this object has an ith argument.
      */
     MOZ_ASSERT(i >= 0);
     RootedValue arg(cx);
     RootedScript script(cx);
     if (unsigned(i) < frame.numActualArgs()) {
         script = frame.script();
+        if (!script->ensureHasAnalyzedArgsUsage(cx))
+            return false;
         if (unsigned(i) < frame.numFormalArgs() && script->formalIsAliased(i)) {
             for (AliasedFormalIter fi(script); ; fi++) {
                 if (fi.frameIndex() == unsigned(i)) {
                     arg = frame.callObj().aliasedVar(fi);
                     break;
                 }
             }
         } else if (script->argsObjAliasesFormals() && frame.hasArgsObj()) {
--- a/js/src/vm/ForkJoin.cpp
+++ b/js/src/vm/ForkJoin.cpp
@@ -1876,66 +1876,51 @@ ParallelBailoutRecord::init(JSContext *c
 
 void
 ParallelBailoutRecord::reset()
 {
     RematerializedFrame::FreeInVector(frames());
     cause = ParallelBailoutNone;
 }
 
-template <class T>
-static void
-RematerializeFramesWithIter(ForkJoinContext *cx, T &frameIter,
-                            Vector<RematerializedFrame *> &frames)
+void
+ParallelBailoutRecord::rematerializeFrames(ForkJoinContext *cx, JitFrameIterator &frameIter)
 {
-    // This function as well as |rematerializeFrames| methods below are
-    // infallible. These are only called when we are already erroring out. If
-    // we OOM here, free what we've allocated and return. Error reporting is
-    // then unable to give the user detailed stack information.
+    // This function is infallible. These are only called when we are already
+    // erroring out. If we OOM here, free what we've allocated and return. Error
+    // reporting is then unable to give the user detailed stack information.
 
-    MOZ_ASSERT(frames.empty());
+    MOZ_ASSERT(frames().empty());
 
     for (; !frameIter.done(); ++frameIter) {
         if (!frameIter.isIonJS())
             continue;
 
         InlineFrameIterator inlineIter(cx, &frameIter);
         Vector<RematerializedFrame *> inlineFrames(cx);
 
         if (!RematerializedFrame::RematerializeInlineFrames(cx, frameIter.fp(),
                                                             inlineIter, inlineFrames))
         {
             RematerializedFrame::FreeInVector(inlineFrames);
-            RematerializedFrame::FreeInVector(frames);
+            RematerializedFrame::FreeInVector(frames());
             return;
         }
 
         // Reverse the inline frames into the main vector.
         while (!inlineFrames.empty()) {
-            if (!frames.append(inlineFrames.popCopy())) {
+            if (!frames().append(inlineFrames.popCopy())) {
                 RematerializedFrame::FreeInVector(inlineFrames);
-                RematerializedFrame::FreeInVector(frames);
+                RematerializedFrame::FreeInVector(frames());
                 return;
             }
         }
     }
 }
 
-void
-ParallelBailoutRecord::rematerializeFrames(ForkJoinContext *cx, JitFrameIterator &frameIter)
-{
-    RematerializeFramesWithIter(cx, frameIter, frames());
-}
-
-void
-ParallelBailoutRecord::rematerializeFrames(ForkJoinContext *cx, IonBailoutIterator &frameIter)
-{
-    RematerializeFramesWithIter(cx, frameIter, frames());
-}
-
 //////////////////////////////////////////////////////////////////////////////
 
 //
 // Debug spew
 //
 
 #ifdef FORKJOIN_SPEW
 
--- a/js/src/vm/ForkJoin.h
+++ b/js/src/vm/ForkJoin.h
@@ -321,17 +321,16 @@ enum ParallelBailoutCause {
     // parallel.
     ParallelBailoutRequestedGC,
     ParallelBailoutRequestedZoneGC
 };
 
 namespace jit {
 class BailoutStack;
 class JitFrameIterator;
-class IonBailoutIterator;
 class RematerializedFrame;
 }
 
 // See "Bailouts" section in comment above.
 struct ParallelBailoutRecord
 {
     // Captured Ion frames at the point of bailout. Stored younger-to-older,
     // i.e., the 0th frame is the youngest frame.
@@ -368,17 +367,16 @@ struct ParallelBailoutRecord
     }
 
     void setIonBailoutKind(jit::BailoutKind kind) {
         joinCause(ParallelBailoutExecution);
         ionBailoutKind = kind;
     }
 
     void rematerializeFrames(ForkJoinContext *cx, jit::JitFrameIterator &frameIter);
-    void rematerializeFrames(ForkJoinContext *cx, jit::IonBailoutIterator &frameIter);
 };
 
 class ForkJoinShared;
 
 class ForkJoinContext : public ThreadSafeContext
 {
   public:
     // Bailout record used to record the reason this thread stopped executing
--- a/js/src/vm/RegExpObject.cpp
+++ b/js/src/vm/RegExpObject.cpp
@@ -450,24 +450,25 @@ RegExpShared::trace(JSTracer *trc)
     for (size_t i = 0; i < ArrayLength(compilationArray); i++) {
         RegExpCompilation &compilation = compilationArray[i];
         if (compilation.jitCode)
             MarkJitCode(trc, &compilation.jitCode, "RegExpShared code");
     }
 }
 
 bool
-RegExpShared::compile(JSContext *cx, HandleLinearString input, CompilationMode mode)
+RegExpShared::compile(JSContext *cx, HandleLinearString input,
+                      CompilationMode mode, ForceByteCodeEnum force)
 {
     TraceLogger *logger = TraceLoggerForMainThread(cx->runtime());
     AutoTraceLog logCompile(logger, TraceLogger::IrregexpCompile);
 
     if (!sticky()) {
         RootedAtom pattern(cx, source);
-        return compile(cx, pattern, input, mode);
+        return compile(cx, pattern, input, mode, force);
     }
 
     /*
      * The sticky case we implement hackily by prepending a caret onto the front
      * and relying on |::execute| to pseudo-slice the string when it sees a sticky regexp.
      */
     static const char prefix[] = {'^', '(', '?', ':'};
     static const char postfix[] = {')'};
@@ -480,22 +481,22 @@ RegExpShared::compile(JSContext *cx, Han
     if (!sb.append(source))
         return false;
     sb.infallibleAppend(postfix, ArrayLength(postfix));
 
     RootedAtom fakeySource(cx, sb.finishAtom());
     if (!fakeySource)
         return false;
 
-    return compile(cx, fakeySource, input, mode);
+    return compile(cx, fakeySource, input, mode, force);
 }
 
 bool
 RegExpShared::compile(JSContext *cx, HandleAtom pattern, HandleLinearString input,
-                      CompilationMode mode)
+                      CompilationMode mode, ForceByteCodeEnum force)
 {
     if (!ignoreCase() && !StringHasRegExpMetaChars(pattern)) {
         canStringMatch = true;
         parenCount = 0;
         return true;
     }
 
     CompileOptions options(cx);
@@ -512,47 +513,52 @@ RegExpShared::compile(JSContext *cx, Han
     }
 
     this->parenCount = data.capture_count;
 
     irregexp::RegExpCode code = irregexp::CompilePattern(cx, this, &data, input,
                                                          false /* global() */,
                                                          ignoreCase(),
                                                          input->hasLatin1Chars(),
-                                                         mode == MatchOnly);
+                                                         mode == MatchOnly,
+                                                         force == ForceByteCode);
     if (code.empty())
         return false;
 
     MOZ_ASSERT(!code.jitCode || !code.byteCode);
+    MOZ_ASSERT_IF(force == ForceByteCode, code.byteCode);
 
     RegExpCompilation &compilation = this->compilation(mode, input->hasLatin1Chars());
-    compilation.jitCode = code.jitCode;
-    compilation.byteCode = code.byteCode;
+    if (code.jitCode)
+        compilation.jitCode = code.jitCode;
+    else if (code.byteCode)
+        compilation.byteCode = code.byteCode;
 
     return true;
 }
 
 bool
-RegExpShared::compileIfNecessary(JSContext *cx, HandleLinearString input, CompilationMode mode)
+RegExpShared::compileIfNecessary(JSContext *cx, HandleLinearString input,
+                                 CompilationMode mode, ForceByteCodeEnum force)
 {
-    if (isCompiled(mode, input->hasLatin1Chars()) || canStringMatch)
+    if (isCompiled(mode, input->hasLatin1Chars(), force) || canStringMatch)
         return true;
-    return compile(cx, input, mode);
+    return compile(cx, input, mode, force);
 }
 
 RegExpRunStatus
 RegExpShared::execute(JSContext *cx, HandleLinearString input, size_t start,
                       MatchPairs *matches)
 {
     TraceLogger *logger = TraceLoggerForMainThread(cx->runtime());
 
     CompilationMode mode = matches ? Normal : MatchOnly;
 
     /* Compile the code at point-of-use. */
-    if (!compileIfNecessary(cx, input, mode))
+    if (!compileIfNecessary(cx, input, mode, DontForceByteCode))
         return RegExpRunStatus_Error;
 
     /*
      * Ensure sufficient memory for output vector.
      * No need to initialize it. The RegExp engine fills them in on a match.
      */
     if (matches && !matches->allocOrExpandArray(pairCount()))
         return RegExpRunStatus_Error;
@@ -586,86 +592,93 @@ RegExpShared::execute(JSContext *cx, Han
             (*matches)[0].start = res;
             (*matches)[0].limit = res + source->length();
 
             matches->checkAgainst(origLength);
         }
         return RegExpRunStatus_Success;
     }
 
-    if (uint8_t *byteCode = compilation(mode, input->hasLatin1Chars()).byteCode) {
-        AutoTraceLog logInterpreter(logger, TraceLogger::IrregexpExecute);
-
-        AutoStableStringChars inputChars(cx);
-        if (!inputChars.init(cx, input))
-            return RegExpRunStatus_Error;
+    do {
+        jit::JitCode *code = compilation(mode, input->hasLatin1Chars()).jitCode;
+        if (!code)
+            break;
 
         RegExpRunStatus result;
-        if (inputChars.isLatin1()) {
-            const Latin1Char *chars = inputChars.latin1Range().start().get() + charsOffset;
-            result = irregexp::InterpretCode(cx, byteCode, chars, start, length, matches);
-        } else {
-            const char16_t *chars = inputChars.twoByteRange().start().get() + charsOffset;
-            result = irregexp::InterpretCode(cx, byteCode, chars, start, length, matches);
-        }
-
-        if (result == RegExpRunStatus_Success && matches) {
-            matches->displace(displacement);
-            matches->checkAgainst(origLength);
-        }
-        return result;
-    }
-
-    while (true) {
-        RegExpRunStatus result;
         {
             AutoTraceLog logJIT(logger, TraceLogger::IrregexpExecute);
             AutoCheckCannotGC nogc;
-            jit::JitCode *code = compilation(mode, input->hasLatin1Chars()).jitCode;
             if (input->hasLatin1Chars()) {
                 const Latin1Char *chars = input->latin1Chars(nogc) + charsOffset;
                 result = irregexp::ExecuteCode(cx, code, chars, start, length, matches);
             } else {
                 const char16_t *chars = input->twoByteChars(nogc) + charsOffset;
                 result = irregexp::ExecuteCode(cx, code, chars, start, length, matches);
             }
         }
 
         if (result == RegExpRunStatus_Error) {
             // The RegExp engine might exit with an exception if an interrupt
-            // was requested. Check this case and retry until a clean result is
-            // obtained.
+            // was requested. If this happens, break out and retry the regexp
+            // in the bytecode interpreter, which can execute while tolerating
+            // future interrupts. Otherwise, if we keep getting interrupted we
+            // will never finish executing the regexp.
             bool interrupted;
             {
                 JSRuntime::AutoLockForInterrupt lock(cx->runtime());
                 interrupted = cx->runtime()->interrupt;
             }
 
             if (interrupted) {
                 if (!InvokeInterruptCallback(cx))
                     return RegExpRunStatus_Error;
-                continue;
+                break;
             }
 
             js_ReportOverRecursed(cx);
             return RegExpRunStatus_Error;
         }
 
         if (result == RegExpRunStatus_Success_NotFound)
             return RegExpRunStatus_Success_NotFound;
 
         MOZ_ASSERT(result == RegExpRunStatus_Success);
-        break;
+
+        if (matches) {
+            matches->displace(displacement);
+            matches->checkAgainst(origLength);
+        }
+        return RegExpRunStatus_Success;
+    } while (false);
+
+    // Compile bytecode for the RegExp if necessary.
+    if (!compileIfNecessary(cx, input, mode, ForceByteCode))
+        return RegExpRunStatus_Error;
+
+    uint8_t *byteCode = compilation(mode, input->hasLatin1Chars()).byteCode;
+    AutoTraceLog logInterpreter(logger, TraceLogger::IrregexpExecute);
+
+    AutoStableStringChars inputChars(cx);
+    if (!inputChars.init(cx, input))
+        return RegExpRunStatus_Error;
+
+    RegExpRunStatus result;
+    if (inputChars.isLatin1()) {
+        const Latin1Char *chars = inputChars.latin1Range().start().get() + charsOffset;
+        result = irregexp::InterpretCode(cx, byteCode, chars, start, length, matches);
+    } else {
+        const char16_t *chars = inputChars.twoByteRange().start().get() + charsOffset;
+        result = irregexp::InterpretCode(cx, byteCode, chars, start, length, matches);
     }
 
-    if (matches) {
+    if (result == RegExpRunStatus_Success && matches) {
         matches->displace(displacement);
         matches->checkAgainst(origLength);
     }
-    return RegExpRunStatus_Success;
+    return result;
 }
 
 size_t
 RegExpShared::sizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf)
 {
     size_t n = mallocSizeOf(this);
 
     for (size_t i = 0; i < ArrayLength(compilationArray); i++) {
--- a/js/src/vm/RegExpObject.h
+++ b/js/src/vm/RegExpObject.h
@@ -101,31 +101,38 @@ CloneRegExpObject(JSContext *cx, JSObjec
 class RegExpShared
 {
   public:
     enum CompilationMode {
         Normal,
         MatchOnly
     };
 
+    enum ForceByteCodeEnum {
+        DontForceByteCode,
+        ForceByteCode
+    };
+
   private:
     friend class RegExpCompartment;
     friend class RegExpStatics;
 
     typedef frontend::TokenStream TokenStream;
 
     struct RegExpCompilation
     {
         HeapPtrJitCode jitCode;
         uint8_t *byteCode;
 
         RegExpCompilation() : byteCode(nullptr) {}
         ~RegExpCompilation() { js_free(byteCode); }
 
-        bool compiled() const { return jitCode || byteCode; }
+        bool compiled(ForceByteCodeEnum force = DontForceByteCode) const {
+            return byteCode || (force == DontForceByteCode && jitCode);
+        }
     };
 
     /* Source to the RegExp, for lazy compilation. */
     HeapPtrAtom        source;
 
     RegExpFlag         flags;
     size_t             parenCount;
     bool               canStringMatch;
@@ -140,20 +147,23 @@ class RegExpShared
         }
         MOZ_CRASH();
     }
 
     // Tables referenced by JIT code.
     Vector<uint8_t *, 0, SystemAllocPolicy> tables;
 
     /* Internal functions. */
-    bool compile(JSContext *cx, HandleLinearString input, CompilationMode mode);
-    bool compile(JSContext *cx, HandleAtom pattern, HandleLinearString input, CompilationMode mode);
+    bool compile(JSContext *cx, HandleLinearString input,
+                 CompilationMode mode, ForceByteCodeEnum force);
+    bool compile(JSContext *cx, HandleAtom pattern, HandleLinearString input,
+                 CompilationMode mode, ForceByteCodeEnum force);
 
-    bool compileIfNecessary(JSContext *cx, HandleLinearString input, CompilationMode mode);
+    bool compileIfNecessary(JSContext *cx, HandleLinearString input,
+                            CompilationMode mode, ForceByteCodeEnum force);
 
     const RegExpCompilation &compilation(CompilationMode mode, bool latin1) const {
         return compilationArray[CompilationIndex(mode, latin1)];
     }
 
     RegExpCompilation &compilation(CompilationMode mode, bool latin1) {
         return compilationArray[CompilationIndex(mode, latin1)];
     }
@@ -184,18 +194,19 @@ class RegExpShared
 
     JSAtom *getSource() const           { return source; }
     RegExpFlag getFlags() const         { return flags; }
     bool ignoreCase() const             { return flags & IgnoreCaseFlag; }
     bool global() const                 { return flags & GlobalFlag; }
     bool multiline() const              { return flags & MultilineFlag; }
     bool sticky() const                 { return flags & StickyFlag; }
 
-    bool isCompiled(CompilationMode mode, bool latin1) const {
-        return compilation(mode, latin1).compiled();
+    bool isCompiled(CompilationMode mode, bool latin1,
+                    ForceByteCodeEnum force = DontForceByteCode) const {
+        return compilation(mode, latin1).compiled(force);
     }
     bool isCompiled() const {
         return isCompiled(Normal, true) || isCompiled(Normal, false)
             || isCompiled(MatchOnly, true) || isCompiled(MatchOnly, false);
     }
 
     void trace(JSTracer *trc);
 
--- a/js/src/vm/Stack-inl.h
+++ b/js/src/vm/Stack-inl.h
@@ -346,16 +346,25 @@ FrameIter::unaliasedForEachActual(JSCont
         break;
       case INTERP:
         interpFrame()->unaliasedForEachActual(op);
         return;
       case JIT:
         if (data_.jitFrames_.isIonJS()) {
             jit::MaybeReadFallback recover(cx, activation()->asJit(), &data_.jitFrames_);
             ionInlineFrames_.unaliasedForEachActual(cx, op, jit::ReadFrame_Actuals, recover);
+        } else if (data_.jitFrames_.isBailoutJS()) {
+            // :TODO: (Bug 1070962) If we are introspecting the frame which is
+            // being bailed, then we might be in the middle of recovering
+            // instructions. Stacking computeInstructionResults implies that we
+            // might be recovering result twice. In the mean time, to avoid
+            // that, we just return Undefined values for instruction results
+            // which are not yet recovered.
+            jit::MaybeReadFallback fallback;
+            ionInlineFrames_.unaliasedForEachActual(cx, op, jit::ReadFrame_Actuals, fallback);
         } else {
             MOZ_ASSERT(data_.jitFrames_.isBaselineJS());
             data_.jitFrames_.unaliasedForEachActual(op, jit::ReadFrame_Actuals);
         }
         return;
     }
     MOZ_CRASH("Unexpected state");
 }
--- a/js/src/vm/Stack.cpp
+++ b/js/src/vm/Stack.cpp
@@ -623,17 +623,17 @@ FrameIter::Data::Data(ThreadSafeContext 
                       ContextOption contextOption, JSPrincipals *principals)
   : cx_(cx),
     savedOption_(savedOption),
     contextOption_(contextOption),
     principals_(principals),
     pc_(nullptr),
     interpFrames_(nullptr),
     activations_(cx->perThreadData),
-    jitFrames_((uint8_t *)nullptr, SequentialExecution),
+    jitFrames_(),
     ionInlineFrameNo_(0),
     asmJSFrames_()
 {
 }
 
 FrameIter::Data::Data(const FrameIter::Data &other)
   : cx_(other.cx_),
     savedOption_(other.savedOption_),
@@ -674,50 +674,50 @@ FrameIter::FrameIter(JSContext *cx, Cont
     ionInlineFrames_(cx, (js::jit::JitFrameIterator*) nullptr)
 {
     settleOnActivation();
 }
 
 FrameIter::FrameIter(const FrameIter &other)
   : data_(other.data_),
     ionInlineFrames_(other.data_.cx_,
-                     data_.jitFrames_.isIonJS() ? &other.ionInlineFrames_ : nullptr)
+                     data_.jitFrames_.isIonScripted() ? &other.ionInlineFrames_ : nullptr)
 {
 }
 
 FrameIter::FrameIter(const Data &data)
   : data_(data),
-    ionInlineFrames_(data.cx_, data_.jitFrames_.isIonJS() ? &data_.jitFrames_ : nullptr)
+    ionInlineFrames_(data.cx_, data_.jitFrames_.isIonScripted() ? &data_.jitFrames_ : nullptr)
 {
     MOZ_ASSERT(data.cx_);
 
-    if (data_.jitFrames_.isIonJS()) {
+    if (data_.jitFrames_.isIonScripted()) {
         while (ionInlineFrames_.frameNo() != data.ionInlineFrameNo_)
             ++ionInlineFrames_;
     }
 }
 
 void
 FrameIter::nextJitFrame()
 {
-    if (data_.jitFrames_.isIonJS()) {
+    if (data_.jitFrames_.isIonScripted()) {
         ionInlineFrames_.resetOn(&data_.jitFrames_);
         data_.pc_ = ionInlineFrames_.pc();
     } else {
         MOZ_ASSERT(data_.jitFrames_.isBaselineJS());
         data_.jitFrames_.baselineScriptAndPc(nullptr, &data_.pc_);
     }
 }
 
 void
 FrameIter::popJitFrame()
 {
     MOZ_ASSERT(data_.state_ == JIT);
 
-    if (data_.jitFrames_.isIonJS() && ionInlineFrames_.more()) {
+    if (data_.jitFrames_.isIonScripted() && ionInlineFrames_.more()) {
         ++ionInlineFrames_;
         data_.pc_ = ionInlineFrames_.pc();
         return;
     }
 
     ++data_.jitFrames_;
     while (!data_.jitFrames_.done() && !data_.jitFrames_.isScripted())
         ++data_.jitFrames_;
@@ -784,17 +784,17 @@ FrameIter::operator++()
     return *this;
 }
 
 FrameIter::Data *
 FrameIter::copyData() const
 {
     Data *data = data_.cx_->new_<Data>(data_);
     MOZ_ASSERT(data_.state_ != ASMJS);
-    if (data && data_.jitFrames_.isIonJS())
+    if (data && data_.jitFrames_.isIonScripted())
         data->ionInlineFrameNo_ = ionInlineFrames_.frameNo();
     return data;
 }
 
 AbstractFramePtr
 FrameIter::copyDataAsAbstractFramePtr() const
 {
     AbstractFramePtr frame;
@@ -992,17 +992,17 @@ FrameIter::mutedErrors() const
 bool
 FrameIter::isConstructing() const
 {
     switch (data_.state_) {
       case DONE:
       case ASMJS:
         break;
       case JIT:
-        if (data_.jitFrames_.isIonJS())
+        if (data_.jitFrames_.isIonScripted())
             return ionInlineFrames_.isConstructing();
         MOZ_ASSERT(data_.jitFrames_.isBaselineJS());
         return data_.jitFrames_.isConstructing();
       case INTERP:
         return interpFrame()->isConstructing();
     }
 
     MOZ_CRASH("Unexpected state");
@@ -1021,17 +1021,17 @@ FrameIter::hasUsableAbstractFramePtr() c
     switch (data_.state_) {
       case DONE:
       case ASMJS:
         return false;
       case JIT:
         if (data_.jitFrames_.isBaselineJS())
             return true;
 
-        MOZ_ASSERT(data_.jitFrames_.isIonJS());
+        MOZ_ASSERT(data_.jitFrames_.isIonScripted());
         return !!activation()->asJit()->lookupRematerializedFrame(data_.jitFrames_.fp(),
                                                                   ionInlineFrames_.frameNo());
         break;
       case INTERP:
         return true;
     }
     MOZ_CRASH("Unexpected state");
 }
@@ -1043,17 +1043,17 @@ FrameIter::abstractFramePtr() const
     switch (data_.state_) {
       case DONE:
       case ASMJS:
         break;
       case JIT: {
         if (data_.jitFrames_.isBaselineJS())
             return data_.jitFrames_.baselineFrame();
 
-        MOZ_ASSERT(data_.jitFrames_.isIonJS());
+        MOZ_ASSERT(data_.jitFrames_.isIonScripted());
         return activation()->asJit()->lookupRematerializedFrame(data_.jitFrames_.fp(),
                                                                 ionInlineFrames_.frameNo());
         break;
       }
       case INTERP:
         MOZ_ASSERT(interpFrame());
         return AbstractFramePtr(interpFrame());
     }
@@ -1115,17 +1115,17 @@ FrameIter::callee() const
       case ASMJS:
         break;
       case INTERP:
         MOZ_ASSERT(isFunctionFrame());
         return &interpFrame()->callee();
       case JIT:
         if (data_.jitFrames_.isBaselineJS())
             return data_.jitFrames_.callee();
-        MOZ_ASSERT(data_.jitFrames_.isIonJS());
+        MOZ_ASSERT(data_.jitFrames_.isIonScripted());
         return ionInlineFrames_.callee();
     }
     MOZ_CRASH("Unexpected state");
 }
 
 Value
 FrameIter::calleev() const
 {
@@ -1148,17 +1148,17 @@ FrameIter::numActualArgs() const
     switch (data_.state_) {
       case DONE:
       case ASMJS:
         break;
       case INTERP:
         MOZ_ASSERT(isFunctionFrame());
         return interpFrame()->numActualArgs();
       case JIT:
-        if (data_.jitFrames_.isIonJS())
+        if (data_.jitFrames_.isIonScripted())
             return ionInlineFrames_.numActualArgs();
 
         MOZ_ASSERT(data_.jitFrames_.isBaselineJS());
         return data_.jitFrames_.numActualArgs();
     }
     MOZ_CRASH("Unexpected state");
 }
 
@@ -1177,17 +1177,17 @@ FrameIter::unaliasedActual(unsigned i, M
 JSObject *
 FrameIter::scopeChain() const
 {
     switch (data_.state_) {
       case DONE:
       case ASMJS:
         break;
       case JIT:
-        if (data_.jitFrames_.isIonJS())
+        if (data_.jitFrames_.isIonScripted())
             return ionInlineFrames_.scopeChain();
         return data_.jitFrames_.baselineFrame()->scopeChain();
       case INTERP:
         return interpFrame()->scopeChain();
     }
     MOZ_CRASH("Unexpected state");
 }
 
@@ -1232,17 +1232,17 @@ FrameIter::computedThisValue() const
 Value
 FrameIter::thisv(JSContext *cx)
 {
     switch (data_.state_) {
       case DONE:
       case ASMJS:
         break;
       case JIT:
-        if (data_.jitFrames_.isIonJS()) {
+        if (data_.jitFrames_.isIonScripted()) {
             jit::MaybeReadFallback recover(cx, activation()->asJit(), &data_.jitFrames_);
             return ionInlineFrames_.thisValue(recover);
         }
         return data_.jitFrames_.baselineFrame()->thisValue();
       case INTERP:
         return interpFrame()->thisValue();
     }
     MOZ_CRASH("Unexpected state");
@@ -1288,17 +1288,17 @@ FrameIter::setReturnValue(const Value &v
 size_t
 FrameIter::numFrameSlots() const
 {
     switch (data_.state_) {
       case DONE:
       case ASMJS:
         break;
       case JIT: {
-        if (data_.jitFrames_.isIonJS()) {
+        if (data_.jitFrames_.isIonScripted()) {
             return ionInlineFrames_.snapshotIterator().numAllocations() -
                 ionInlineFrames_.script()->nfixed();
         }
         jit::BaselineFrame *frame = data_.jitFrames_.baselineFrame();
         return frame->numValueSlots() - data_.jitFrames_.script()->nfixed();
       }
       case INTERP:
         MOZ_ASSERT(data_.interpFrames_.sp() >= interpFrame()->base());
@@ -1310,17 +1310,17 @@ FrameIter::numFrameSlots() const
 Value
 FrameIter::frameSlotValue(size_t index) const
 {
     switch (data_.state_) {
       case DONE:
       case ASMJS:
         break;
       case JIT:
-        if (data_.jitFrames_.isIonJS()) {
+        if (data_.jitFrames_.isIonScripted()) {
             jit::SnapshotIterator si(ionInlineFrames_.snapshotIterator());
             index += ionInlineFrames_.script()->nfixed();
             return si.maybeReadAllocByIndex(index);
         }
 
         index += data_.jitFrames_.script()->nfixed();
         return *data_.jitFrames_.baselineFrame()->valueSlot(index);
       case INTERP:
@@ -1399,52 +1399,73 @@ js::CheckLocalUnaliased(MaybeCheckAliasi
     }
 }
 #endif
 
 jit::JitActivation::JitActivation(JSContext *cx, bool active)
   : Activation(cx, Jit),
     active_(active),
     rematerializedFrames_(nullptr),
-    ionRecovery_(cx)
+    ionRecovery_(cx),
+    bailoutData_(nullptr)
 {
     if (active) {
         prevJitTop_ = cx->mainThread().jitTop;
         prevJitJSContext_ = cx->mainThread().jitJSContext;
         cx->mainThread().jitJSContext = cx;
     } else {
         prevJitTop_ = nullptr;
         prevJitJSContext_ = nullptr;
     }
 }
 
 jit::JitActivation::JitActivation(ForkJoinContext *cx)
   : Activation(cx, Jit),
     active_(true),
     rematerializedFrames_(nullptr),
-    ionRecovery_(cx)
+    ionRecovery_(cx),
+    bailoutData_(nullptr)
 {
     prevJitTop_ = cx->perThreadData->jitTop;
     prevJitJSContext_ = cx->perThreadData->jitJSContext;
     cx->perThreadData->jitJSContext = nullptr;
 }
 
 jit::JitActivation::~JitActivation()
 {
     if (active_) {
         cx_->perThreadData->jitTop = prevJitTop_;
         cx_->perThreadData->jitJSContext = prevJitJSContext_;
     }
 
-    clearRematerializedFrames();
     // All reocvered value are taken from activation during the bailout.
     MOZ_ASSERT(ionRecovery_.empty());
+
+    // The BailoutFrameInfo should have unregistered itself from the
+    // JitActivations.
+    MOZ_ASSERT(!bailoutData_);
+
+    clearRematerializedFrames();
     js_delete(rematerializedFrames_);
 }
 
+void
+jit::JitActivation::setBailoutData(jit::BailoutFrameInfo *bailoutData)
+{
+    MOZ_ASSERT(!bailoutData_);
+    bailoutData_ = bailoutData;
+}
+
+void
+jit::JitActivation::cleanBailoutData()
+{
+    MOZ_ASSERT(bailoutData_);
+    bailoutData_ = nullptr;
+}
+
 // setActive() is inlined in GenerateFFIIonExit() with explicit masm instructions so
 // changes to the logic here need to be reflected in GenerateFFIIonExit() in the enable
 // and disable activation instruction sequences.
 void
 jit::JitActivation::setActive(JSContext *cx, bool active)
 {
     // Only allowed to deactivate/activate if activation is top.
     // (Not tested and will probably fail in other situations.)
@@ -1481,24 +1502,23 @@ jit::JitActivation::clearRematerializedF
         return;
 
     for (RematerializedFrameTable::Enum e(*rematerializedFrames_); !e.empty(); e.popFront()) {
         RematerializedFrame::FreeInVector(e.front().value());
         e.removeFront();
     }
 }
 
-template <class T>
 jit::RematerializedFrame *
-jit::JitActivation::getRematerializedFrame(ThreadSafeContext *cx, const T &iter, size_t inlineDepth)
+jit::JitActivation::getRematerializedFrame(ThreadSafeContext *cx, const JitFrameIterator &iter, size_t inlineDepth)
 {
     // Only allow rematerializing from the same thread.
     MOZ_ASSERT(cx->perThreadData == cx_->perThreadData);
     MOZ_ASSERT(iter.activation() == this);
-    MOZ_ASSERT(iter.isIonJS());
+    MOZ_ASSERT(iter.isIonScripted());
 
     if (!rematerializedFrames_) {
         rematerializedFrames_ = cx->new_<RematerializedFrameTable>(cx);
         if (!rematerializedFrames_ || !rematerializedFrames_->init()) {
             rematerializedFrames_ = nullptr;
             return nullptr;
         }
     }
@@ -1518,25 +1538,16 @@ jit::JitActivation::getRematerializedFra
         InlineFrameIterator inlineIter(cx, &iter);
         if (!RematerializedFrame::RematerializeInlineFrames(cx, top, inlineIter, p->value()))
             return nullptr;
     }
 
     return p->value()[inlineDepth];
 }
 
-template jit::RematerializedFrame *
-jit::JitActivation::getRematerializedFrame<jit::JitFrameIterator>(ThreadSafeContext *cx,
-                                                                  const jit::JitFrameIterator &iter,
-                                                                  size_t inlineDepth);
-template jit::RematerializedFrame *
-jit::JitActivation::getRematerializedFrame<jit::IonBailoutIterator>(ThreadSafeContext *cx,
-                                                                    const jit::IonBailoutIterator &iter,
-                                                                    size_t inlineDepth);
-
 jit::RematerializedFrame *
 jit::JitActivation::lookupRematerializedFrame(uint8_t *top, size_t inlineDepth)
 {
     if (!rematerializedFrames_)
         return nullptr;
     if (RematerializedFrameTable::Ptr p = rematerializedFrames_->lookup(top))
         return inlineDepth < p->value().length() ? p->value()[inlineDepth] : nullptr;
     return nullptr;
--- a/js/src/vm/Stack.h
+++ b/js/src/vm/Stack.h
@@ -1296,16 +1296,18 @@ class ActivationIterator
     }
     bool done() const {
         return activation_ == nullptr;
     }
 };
 
 namespace jit {
 
+class BailoutFrameInfo;
+
 // A JitActivation is used for frames running in Baseline or Ion.
 class JitActivation : public Activation
 {
     uint8_t *prevJitTop_;
     JSContext *prevJitJSContext_;
     bool active_;
 
     // Rematerialized Ion frames which has info copied out of snapshots. Maps
@@ -1322,16 +1324,23 @@ class JitActivation : public Activation
     //
     // RInstructionResults are appended into this vector when Snapshot values
     // have to be read, or when the evaluation has to run before some mutating
     // code.  Each RInstructionResults belongs to one frame which has to bailout
     // as soon as we get back to it.
     typedef Vector<RInstructionResults, 1> IonRecoveryMap;
     IonRecoveryMap ionRecovery_;
 
+    // If we are bailing out from Ion, then this field should be a non-null
+    // pointer which references the BailoutFrameInfo used to walk the inner
+    // frames. This field is used for all newly constructed JitFrameIterators to
+    // read the innermost frame information from this bailout data instead of
+    // reading it from the stack.
+    BailoutFrameInfo *bailoutData_;
+
     void clearRematerializedFrames();
 
 #ifdef CHECK_OSIPOINT_REGISTERS
   protected:
     // Used to verify that live registers don't change between a VM call and
     // the OsiPoint that follows it. Protected to silence Clang warning.
     uint32_t checkRegs_;
     RegisterDump regs_;
@@ -1377,21 +1386,18 @@ class JitActivation : public Activation
     }
 #endif
 
     // Look up a rematerialized frame keyed by the fp, rematerializing the
     // frame if one doesn't already exist. A frame can only be rematerialized
     // if an IonFrameIterator pointing to the nearest uninlined frame can be
     // provided, as values need to be read out of snapshots.
     //
-    // T is either JitFrameIterator or IonBailoutIterator.
-    //
     // The inlineDepth must be within bounds of the frame pointed to by iter.
-    template <class T>
-    RematerializedFrame *getRematerializedFrame(ThreadSafeContext *cx, const T &iter,
+    RematerializedFrame *getRematerializedFrame(ThreadSafeContext *cx, const JitFrameIterator &iter,
                                                 size_t inlineDepth = 0);
 
     // Look up a rematerialized frame by the fp. If inlineDepth is out of
     // bounds of what has been rematerialized, nullptr is returned.
     RematerializedFrame *lookupRematerializedFrame(uint8_t *top, size_t inlineDepth = 0);
 
     bool hasRematerializedFrame(uint8_t *top, size_t inlineDepth = 0) {
         return !!lookupRematerializedFrame(top, inlineDepth);
@@ -1410,16 +1416,25 @@ class JitActivation : public Activation
     RInstructionResults *maybeIonFrameRecovery(IonJSFrameLayout *fp);
 
     // If an Ion frame recovery exists for the |fp| frame exists on the
     // activation, then move its content to the |results| argument, and remove
     // it from the activation.
     void maybeTakeIonFrameRecovery(IonJSFrameLayout *fp, RInstructionResults *results);
 
     void markIonRecovery(JSTracer *trc);
+
+    // Return the bailout information if it is registered.
+    const BailoutFrameInfo *bailoutData() const { return bailoutData_; }
+
+    // Register the bailout data when it is constructed.
+    void setBailoutData(BailoutFrameInfo *bailoutData);
+
+    // Unregister the bailout data when the frame is reconstructed.
+    void cleanBailoutData();
 };
 
 // A filtering of the ActivationIterator to only stop at JitActivations.
 class JitActivationIterator : public ActivationIterator
 {
     void settle() {
         while (!done() && !activation_->isJit())
             ActivationIterator::operator++();
--- a/layout/base/TouchCaret.cpp
+++ b/layout/base/TouchCaret.cpp
@@ -25,16 +25,17 @@
 #include "mozilla/Preferences.h"
 #include "mozilla/BasicEvents.h"
 #include "nsIDOMWindow.h"
 #include "nsQueryContentEventResult.h"
 #include "nsIInterfaceRequestorUtils.h"
 #include "nsView.h"
 #include "nsDOMTokenList.h"
 #include "nsCaret.h"
+#include "mozilla/dom/CustomEvent.h"
 
 using namespace mozilla;
 
 // To enable all the TOUCHCARET_LOG print statements, change the 0 to 1 in the
 // following #define.
 #define ENABLE_TOUCHCARET_LOG 0
 
 #if ENABLE_TOUCHCARET_LOG
@@ -53,17 +54,18 @@ NS_IMPL_ISUPPORTS(TouchCaret, nsISelecti
 
 /*static*/ int32_t TouchCaret::sTouchCaretInflateSize = 0;
 /*static*/ int32_t TouchCaret::sTouchCaretExpirationTime = 0;
 
 TouchCaret::TouchCaret(nsIPresShell* aPresShell)
   : mState(TOUCHCARET_NONE),
     mActiveTouchId(-1),
     mCaretCenterToDownPointOffsetY(0),
-    mVisible(false)
+    mVisible(false),
+    mIsValidTap(false)
 {
   TOUCHCARET_LOG("Constructor, PresShell=%p", aPresShell);
   MOZ_ASSERT(NS_IsMainThread());
 
   static bool addedTouchCaretPref = false;
   if (!addedTouchCaretPref) {
     Preferences::AddIntVarCache(&sTouchCaretInflateSize,
                                 "touchcaret.inflatesize.threshold");
@@ -596,16 +598,17 @@ TouchCaret::HandleMouseMoveEvent(WidgetM
     case TOUCHCARET_MOUSEDRAG_ACTIVE:
       {
         nsPoint movePoint = GetEventPosition(aEvent);
         movePoint.y += mCaretCenterToDownPointOffsetY;
         nsRect contentBoundary = GetContentBoundary();
         movePoint = contentBoundary.ClampPoint(movePoint);
 
         MoveCaret(movePoint);
+        mIsValidTap = false;
         status = nsEventStatus_eConsumeNoDefault;
       }
       break;
 
     case TOUCHCARET_TOUCHDRAG_ACTIVE:
     case TOUCHCARET_TOUCHDRAG_INACTIVE:
       // Consume mouse event in touch sequence.
       status = nsEventStatus_eConsumeNoDefault;
@@ -633,16 +636,17 @@ TouchCaret::HandleTouchMoveEvent(WidgetT
     case TOUCHCARET_TOUCHDRAG_ACTIVE:
       {
         nsPoint movePoint = GetEventPosition(aEvent, mActiveTouchId);
         movePoint.y += mCaretCenterToDownPointOffsetY;
         nsRect contentBoundary = GetContentBoundary();
         movePoint = contentBoundary.ClampPoint(movePoint);
 
         MoveCaret(movePoint);
+        mIsValidTap = false;
         status = nsEventStatus_eConsumeNoDefault;
       }
       break;
 
     case TOUCHCARET_TOUCHDRAG_INACTIVE:
       // Consume NS_TOUCH_MOVE event in TOUCHCARET_TOUCHDRAG_INACTIVE state.
       status = nsEventStatus_eConsumeNoDefault;
       break;
@@ -844,16 +848,45 @@ TouchCaret::HandleTouchDownEvent(WidgetT
       mTouchesId.AppendElement(aEvent->touches[i]->mIdentifier);
     }
   }
 
   return status;
 }
 
 void
+TouchCaret::DispatchTapEvent()
+{
+  nsCOMPtr<nsIPresShell> presShell = do_QueryReferent(mPresShell);
+  if (!presShell) {
+    return;
+  }
+
+  nsCOMPtr<nsIDocument> doc = presShell->GetDocument();
+  if (!doc) {
+    return;
+  }
+
+  ErrorResult res;
+  nsRefPtr<dom::Event> domEvent =
+    doc->CreateEvent(NS_LITERAL_STRING("CustomEvent"), res);
+  if (res.Failed()) {
+    return;
+  }
+
+  dom::CustomEvent* customEvent = static_cast<dom::CustomEvent*>(domEvent.get());
+  customEvent->InitCustomEvent(NS_LITERAL_STRING("touchcarettap"),
+                               true, false, nullptr);
+  customEvent->SetTrusted(true);
+  customEvent->GetInternalNSEvent()->mFlags.mOnlyChromeDispatch = true;
+  bool ret;
+  doc->DispatchEvent(domEvent, &ret);
+}
+
+void
 TouchCaret::SetState(TouchCaretState aState)
 {
   TOUCHCARET_LOG("state changed from %d to %d", mState, aState);
   if (mState == TOUCHCARET_NONE) {
     MOZ_ASSERT(aState != TOUCHCARET_TOUCHDRAG_INACTIVE,
                "mState: NONE => TOUCHDRAG_INACTIVE isn't allowed!");
   }
 
@@ -874,10 +907,17 @@ TouchCaret::SetState(TouchCaretState aSt
                "TOUCHDRAG_INACTIVE allowed next state: NONE!");
   }
 
   mState = aState;
 
   if (mState == TOUCHCARET_NONE) {
     mActiveTouchId = -1;
     mCaretCenterToDownPointOffsetY = 0;
+    if (mIsValidTap) {
+      DispatchTapEvent();
+      mIsValidTap = false;
+    }
+  } else if (mState == TOUCHCARET_TOUCHDRAG_ACTIVE ||
+             mState == TOUCHCARET_MOUSEDRAG_ACTIVE) {
+    mIsValidTap = true;
   }
 }
--- a/layout/base/TouchCaret.h
+++ b/layout/base/TouchCaret.h
@@ -205,16 +205,21 @@ private:
   };
 
   /**
    * Do actual state transition and reset substates.
    */
   void SetState(TouchCaretState aState);
 
   /**
+   * Dispatch touch caret tap event to chrome.
+   */
+  void DispatchTapEvent();
+
+  /**
    * Current state we're dealing with.
    */
   TouchCaretState mState;
 
   /**
    * Array containing all active touch IDs. When a touch happens, it gets added
    * to this array, even if we choose not to handle it. When it ends, we remove
    * it. We need to maintain this array in order to detect the end of the
@@ -244,16 +249,18 @@ private:
   {
     return sTouchCaretExpirationTime;
   }
 
   nsWeakPtr mPresShell;
 
   // Touch caret visibility
   bool mVisible;
+  // Use for detecting single tap on touch caret.
+  bool mIsValidTap;
   // Touch caret timer
   nsCOMPtr<nsITimer> mTouchCaretExpirationTimer;
 
   // Preference
   static int32_t sTouchCaretInflateSize;
   static int32_t sTouchCaretExpirationTime;
 
   // The auto scroll timer's interval in miliseconds.
--- a/layout/reftests/forms/input/range/reftest.list
+++ b/layout/reftests/forms/input/range/reftest.list
@@ -17,17 +17,17 @@
 == value-prop.html 75pct-common-ref.html
 == valueAsNumber-prop-unthemed.html 75pct-unthemed-common-ref.html
 == valueAsNumber-prop.html 75pct-common-ref.html
 fuzzy-if(B2G,1,1) == stepDown-unthemed.html 75pct-unthemed-common-ref.html
 fuzzy-if(B2G,1,1) == stepDown.html 75pct-common-ref.html
 == stepUp-unthemed.html 75pct-unthemed-common-ref.html
 == stepUp.html 75pct-common-ref.html
 fuzzy-if(B2G,1,1) == max-prop.html 100pct-common-ref.html
+== reset-value.html reset-value-ref.html
 
 # 'direction' property:
 == direction-unthemed-1.html direction-unthemed-1-ref.html
 
 # ::-moz-range-progress pseudo-element:
 fails-if(B2G||Android) == moz-range-progress-1.html moz-range-progress-1-ref.html
 == moz-range-progress-2.html moz-range-progress-2-ref.html
 == moz-range-progress-3.html moz-range-progress-3-ref.html
-
new file mode 100644
--- /dev/null
+++ b/layout/reftests/forms/input/range/reset-value-ref.html
@@ -0,0 +1,14 @@
+<!DOCTYPE html>
+<html lang="en-us">
+  <head>
+    <title>1080352</title>
+  </head>
+  <body>
+    <form id="form">
+      <input id='inputRange' type='range' step='10' min='0' max='50' value='20'><br>
+      <input id='inputNumber' type='number' step='10' min='0' max='500' value='30'><br>
+      
+      <input type='reset'><br>
+    </form>
+  </body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/forms/input/range/reset-value.html
@@ -0,0 +1,14 @@
+<!DOCTYPE html>
+<html lang="en-us">
+  <head>
+    <title>1080352</title>
+  </head>
+  <body onload="inputRange.value=40;inputNumber.value=40; form.reset()">
+    <form id="form">
+      <input id='inputRange' type='range' step='10' min='0' max='50' value='20'><br>
+      <input id='inputNumber' type='number' step='10' min='0' max='500' value='30'><br>
+      
+      <input type='reset'><br>
+    </form>
+  </body>
+</html>
--- a/netwerk/base/public/nsIEncodedChannel.idl
+++ b/netwerk/base/public/nsIEncodedChannel.idl
@@ -8,17 +8,17 @@
 interface nsIUTF8StringEnumerator;
 interface nsIStreamListener;
 interface nsISupports;
 
 /**
  * A channel interface which allows special handling of encoded content
  */
 
-[scriptable, uuid(30d7ec3a-f376-4652-9276-3092ec57abb6)]
+[scriptable, uuid(29c29ce6-8ce4-45e6-8d60-36c8fa3e255b)]
 interface nsIEncodedChannel : nsISupports
 {
     /**
      * This attribute holds the MIME types corresponding to the content
      * encodings on the channel.  The enumerator returns nsISupportsCString
      * objects.  The first one corresponds to the outermost encoding on the
      * channel and then we work our way inward.  "identity" is skipped and not
      * represented on the list.  Unknown encodings make the enumeration stop.
--- a/security/manager/ssl/public/nsIX509CertList.idl
+++ b/security/manager/ssl/public/nsIX509CertList.idl
@@ -2,17 +2,17 @@
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "nsISupports.idl"
 
 interface nsISimpleEnumerator;
 interface nsIX509Cert;
 
-[scriptable, uuid(a539759b-e22d-462f-94ea-2915b11b33e8)]
+[scriptable, uuid(ae74cda5-cd2f-473f-96f5-f0b7fff62c68)]
 interface nsIX509CertList : nsISupports {
    void addCert(in nsIX509Cert cert);
    void deleteCert(in nsIX509Cert cert);
    nsISimpleEnumerator getEnumerator();
 
    /* getRawCertList MUST be called only from functions where
     * the nssShutdownPreventionLock has been adquired.
     */
--- a/testing/marionette/client/marionette/marionette.py
+++ b/testing/marionette/client/marionette/marionette.py
@@ -810,17 +810,17 @@ class Marionette(object):
         """Create a new Marionette session.
 
         This method must be called before performing any other action.
 
         :params desired_capabilities: An optional dict of desired
             capabilities.  This is currently ignored.
 
         :returns: A dict of the capabilities offered."""
-        self.session = self._send_message('newSession', 'value')
+        self.session = self._send_message('newSession', 'value', capabilities=desired_capabilities)
         self.b2g = 'b2g' in self.session
         return self.session
 
     @property
     def test_name(self):
         return self._test_name
 
     @test_name.setter
--- a/testing/marionette/client/marionette/tests/unit/test_capabilities.py
+++ b/testing/marionette/client/marionette/tests/unit/test_capabilities.py
@@ -47,8 +47,15 @@ class TestCapabilities(MarionetteTestCas
         self.assertIn("XULappId", self.caps)
         self.assertIn("appBuildId", self.caps)
         self.assertIn("device", self.caps)
         self.assertIn("version", self.caps)
 
         self.assertEqual(self.caps["XULappId"], self.appinfo["ID"])
         self.assertEqual(self.caps["appBuildId"], self.appinfo["appBuildID"])
         self.assertEqual(self.caps["version"], self.appinfo["version"])
+
+    def test_we_can_pass_in_capabilities_on_session_start(self):
+        self.marionette.delete_session()
+        capabilities = {"somethingAwesome": "cake"}
+        self.marionette.start_session(capabilities)
+        caps = self.marionette.session_capabilities
+        self.assertIn("somethingAwesome", caps)
\ No newline at end of file
--- a/testing/marionette/marionette-server.js
+++ b/testing/marionette/marionette-server.js
@@ -137,16 +137,40 @@ function MarionetteServerConnection(aPre
   this.curFrame = null; // chrome iframe that currently has focus
   this.mainContentFrameId = null;
   this.importedScripts = FileUtils.getFile('TmpD', ['marionetteChromeScripts']);
   this.importedScriptHashes = {"chrome" : [], "content": []};
   this.currentFrameElement = null;
   this.testName = null;
   this.mozBrowserClose = null;
   this.oopFrameId = null; // frame ID of current remote frame, used for mozbrowserclose events
+  this.sessionCapabilities = {
+    // Mandated capabilities
+    "browserName": appName,
+    "browserVersion": Services.appinfo.version,
+    "platformName": Services.appinfo.OS.toUpperCase(),
+    "platformVersion": Services.appinfo.platformVersion,
+
+    // Supported features
+    "handlesAlerts": false,
+    "nativeEvents": false,
+    "rotatable": appName == "B2G",
+    "secureSsl": false,
+    "takesElementScreenshot": true,
+    "takesScreenshot": true,
+
+    // Selenium 2 compat
+    "platform": Services.appinfo.OS.toUpperCase(),
+
+    // Proprietary extensions
+    "XULappId" : Services.appinfo.ID,
+    "appBuildId" : Services.appinfo.appBuildID,
+    "device": qemu == "1" ? "qemu" : (!device ? "desktop" : device),
+    "version": Services.appinfo.version
+  };
 }
 
 MarionetteServerConnection.prototype = {
 
   QueryInterface: XPCOMUtils.generateQI([Ci.nsIMessageListener,
                                          Ci.nsIObserver,
                                          Ci.nsISupportsWeakReference]),
 
@@ -511,21 +535,25 @@ MarionetteServerConnection.prototype = {
    *
    * In a desktop environment, this opens a new browser with
    * "about:blank" which subsequent commands will be sent to.
    *
    * This will send a hash map of supported capabilities to the client
    * as part of the Marionette:register IPC command in the
    * receiveMessage callback when a new browser is created.
    */
-  newSession: function MDA_newSession() {
+  newSession: function MDA_newSession(aRequest) {
+    logger.info("The newSession request is " + JSON.stringify(aRequest))
     this.command_id = this.getCommandId();
     this.newSessionCommandId = this.command_id;
 
     this.scriptTimeout = 10000;
+    if (aRequest && aRequest.parameters) {
+      this.setSessionCapabilities(aRequest.parameters.capabilities);
+    }
 
     function waitForWindow() {
       let win = this.getCurrentWindow();
       if (!win) {
         // If the window isn't even created, just poll wait for it
         let checkTimer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer);
         checkTimer.initWithCallback(waitForWindow.bind(this), 100,
                                     Ci.nsITimer.TYPE_ONE_SHOT);
@@ -574,51 +602,48 @@ MarionetteServerConnection.prototype = {
    *
    * The return value is an immutable map of string keys
    * ("capabilities") to values, which may be of types boolean,
    * numerical or string.
    */
   getSessionCapabilities: function MDA_getSessionCapabilities() {
     this.command_id = this.getCommandId();
 
-    let isB2G = appName == "B2G";
-    let platformName = Services.appinfo.OS.toUpperCase();
-
-    let caps = {
-      // Mandated capabilities
-      "browserName": appName,
-      "browserVersion": Services.appinfo.version,
-      "platformName": platformName,
-      "platformVersion": Services.appinfo.platformVersion,
-
-      // Supported features
-      "handlesAlerts": false,
-      "nativeEvents": false,
-      "rotatable": isB2G,
-      "secureSsl": false,
-      "takesElementScreenshot": true,
-      "takesScreenshot": true,
-
-      // Selenium 2 compat
-      "platform": platformName,
-
-      // Proprietary extensions
-      "XULappId" : Services.appinfo.ID,
-      "appBuildId" : Services.appinfo.appBuildID,
-      "device": qemu == "1" ? "qemu" : (!device ? "desktop" : device),
-      "version": Services.appinfo.version
-    };
-
     // eideticker (bug 965297) and mochitest (bug 965304)
     // compatibility.  They only check for the presence of this
     // property and should so not be in caps if not on a B2G device.
-    if (isB2G)
-      caps.b2g = true;
+    if (appName == "B2G")
+      this.sessionCapabilities.b2g = true;
+
+    this.sendResponse(this.sessionCapabilities, this.command_id);
+  },
 
-    this.sendResponse(caps, this.command_id);
+  /**
+   * Update the sessionCapabilities object with the keys that have been
+   * passed in when a new session is created
+   * This part of the WebDriver spec is currently in flux see
+   * http://lists.w3.org/Archives/Public/public-browser-tools-testing/2014OctDec/0000.html
+   *
+   * This is not a public API, only available when a new Session is created
+   *
+   * @param Object capabilities holds all the keys for capabilities
+   *
+   */
+  setSessionCapabilities: function MDA_setSessionCapabilities (capabilities) {
+    this.command_id = this.getCommandId();
+    var tempCapabilities = {};
+    for (var caps in this.sessionCapabilities) {
+      tempCapabilities[caps] = this.sessionCapabilities[caps];
+    }
+
+    for (var caps in capabilities) {
+      tempCapabilities[caps] = capabilities[caps];
+    }
+
+    this.sessionCapabilities = tempCapabilities;
   },
 
   /**
    * Log message. Accepts user defined log-level.
    *
    * @param object aRequest
    *        'value' member holds log message
    *        'level' member hold log level
--- a/testing/mochitest/server.js
+++ b/testing/mochitest/server.js
@@ -105,16 +105,19 @@ if (this["nsHttpServer"]) {
   // Impossible as the stop callback should have been called, but to be safe...
   dumpn("TEST-UNEXPECTED-FAIL | failure to correctly shut down HTTP server");
   quit(1);
 }
 
 var serverBasePath;
 var displayResults = true;
 
+var gServerAddress;
+var SERVER_PORT;
+
 //
 // SERVER SETUP
 //
 function runServer()
 {
   serverBasePath = __LOCATION__.parent;
   server = createMochitestServer(serverBasePath);
 
@@ -169,17 +172,17 @@ function runServer()
   }
 
   // If we're running outside of the test harness, there might
   // not be a test profile directory present
   if (serverAlive.exists()) {
     serverAlive.append("server_alive.txt");
     foStream.init(serverAlive,
                   0x02 | 0x08 | 0x20, 436, 0); // write, create, truncate
-    data = "It's alive!";
+    var data = "It's alive!";
     foStream.write(data, data.length);
     foStream.close();
   }
 
   makeTags();
 
   //
   // The following is threading magic to spin an event loop -- this has to
@@ -436,17 +439,17 @@ function isTest(filename, pattern)
   if (pattern)
     return pattern.test(filename);
 
   // File name is a URL style path to a test file, make sure that we check for
   // tests that start with the appropriate prefix.
   var testPrefix = typeof(_TEST_PREFIX) == "string" ? _TEST_PREFIX : "test_";
   var testPattern = new RegExp("^" + testPrefix);
 
-  pathPieces = filename.split('/');
+  var pathPieces = filename.split('/');
     
   return testPattern.test(pathPieces[pathPieces.length - 1]) &&
          filename.indexOf(".js") == -1 &&
          filename.indexOf(".css") == -1 &&
          !/\^headers\^$/.test(filename);
 }
 
 /**
@@ -489,17 +492,17 @@ function linksToListItems(links)
 function linksToTableRows(links, recursionLevel)
 {
   var response = "";
   for (var [link, value] in links) {
     var classVal = (!isTest(link) && !(value instanceof Object))
       ? "non-test invisible"
       : "";
 
-    spacer = "padding-left: " + (10 * recursionLevel) + "px";
+    var spacer = "padding-left: " + (10 * recursionLevel) + "px";
 
     if (value instanceof Object) {
       response += TR({class: "dir", id: "tr-" + link },
                      TD({colspan: "3"}, "&#160;"),
                      TD({style: spacer},
                         A({href: link}, link)));
       response += linksToTableRows(value, recursionLevel + 1);
     } else {
--- a/testing/mozbase/mozdebug/mozdebug/mozdebug.py
+++ b/testing/mozbase/mozdebug/mozdebug/mozdebug.py
@@ -118,17 +118,17 @@ def get_debugger_info(debugger, debugger
         ['path', 'interactive', 'args', 'requiresEscapedArgs']
     )
 
     debugger_arguments = get_debugger_info('args', [])
 
     # Extend the default arguments for the chosen debugger with the ones passed in, if any.
     if debuggerArgs:
         # Append the provided debugger arguments at the end of the arguments list.
-        debugger_arguments.extend(debuggerArgs)
+        debugger_arguments += debuggerArgs.split()
 
     # Override the default debugger interactive mode if needed.
     debugger_interactive = get_debugger_info('interactive', False)
     if debuggerInteractive:
         debugger_interactive = debuggerInteractive
 
     d = DebuggerInfo(
         debuggerPath,
--- a/testing/mozbase/mozdevice/adb_tests/test_devicemanagerADB.py
+++ b/testing/mozbase/mozdevice/adb_tests/test_devicemanagerADB.py
@@ -169,19 +169,17 @@ class TestFileOperations(DeviceManagerAD
 class TestOther(DeviceManagerADBTestCase):
     def test_get_list_of_processes(self):
         self.assertEquals(type(self.dm.getProcessList()), list)
 
     def test_get_current_time(self):
         self.assertEquals(type(self.dm.getCurrentTime()), int)
 
     def test_get_info(self):
-        self.assertEquals(self.dm.getInfo(), {})
-        # Commented since it is too nosiy
-        #self.assertEquals(self.dm.getInfo("all"), dict)
+        self.assertEquals(type(self.dm.getInfo()), dict)
 
     def test_list_devices(self):
         self.assertEquals(len(list(self.dm.devices())), 1)
 
     def test_shell(self):
         out = StringIO()
         self.dm.shell(["echo", "$COMPANY", ";", "pwd"], out,
                 env={"COMPANY":"Mozilla"}, cwd="/", timeout=4, root=True)
--- a/testing/mozbase/mozdevice/mozdevice/devicemanagerADB.py
+++ b/testing/mozbase/mozdevice/mozdevice/devicemanagerADB.py
@@ -492,36 +492,33 @@ class DeviceManagerADB(DeviceManager):
 
     def getCurrentTime(self):
         timestr = str(self._runCmd(["shell", "date", "+%s"]).output[0])
         if (not timestr or not timestr.isdigit()):
             raise DMError("Unable to get current time using date (got: '%s')" % timestr)
         return int(timestr)*1000
 
     def getInfo(self, directive=None):
+        directive = directive or "all"
         ret = {}
-        if (directive == "id" or directive == "all"):
+        if directive == "id" or directive == "all":
             ret["id"] = self._runCmd(["get-serialno"]).output[0]
-        if (directive == "os" or directive == "all"):
-            ret["os"] = self._runCmd(["shell", "getprop", "ro.build.display.id"]).output[0]
-        if (directive == "uptime" or directive == "all"):
-            utime = self._runCmd(["shell", "uptime"]).output[0]
+        if directive == "os" or directive == "all":
+            ret["os"] = self.shellCheckOutput(["getprop", "ro.build.display.id"])
+        if directive == "uptime" or directive == "all":
+            utime = self.shellCheckOutput(["uptime"])
             if (not utime):
                 raise DMError("error getting uptime")
-            utime = utime[9:]
-            hours = utime[0:utime.find(":")]
-            utime = utime[utime[1:].find(":") + 2:]
-            minutes = utime[0:utime.find(":")]
-            utime = utime[utime[1:].find(":") +  2:]
-            seconds = utime[0:utime.find(",")]
-            ret["uptime"] = ["0 days " + hours + " hours " + minutes + " minutes " + seconds + " seconds"]
-        if (directive == "process" or directive == "all"):
-            ret["process"] = self._runCmd(["shell", "ps"]).output
-        if (directive == "systime" or directive == "all"):
-            ret["systime"] = self._runCmd(["shell", "date"]).output[0]
+            m = re.match("up time: ((\d+) days, )*(\d{2}):(\d{2}):(\d{2})", utime)
+            ret["uptime"] = "%d days %d hours %d minutes %d seconds" % tuple(
+                [int(g or 0) for g in m.groups()[1:]])
+        if directive == "process" or directive == "all":
+            ret["process"] = self.shellCheckOutput(["ps"])
+        if directive == "systime" or directive == "all":
+            ret["systime"] = self.shellCheckOutput(["date"])
         self._logger.info(ret)
         return ret
 
     def uninstallApp(self, appName, installPath=None):
         status = self._runCmd(["uninstall", appName]).output[0].strip()
         if status != 'Success':
             raise DMError("uninstall failed for %s. Got: %s" % (appName, status))
 
--- a/testing/mozbase/mozdevice/mozdevice/dmcli.py
+++ b/testing/mozbase/mozdevice/mozdevice/dmcli.py
@@ -277,24 +277,21 @@ class DMCli(object):
         buf = StringIO.StringIO()
         self.dm.shell(args.command, buf, root=args.root)
         print str(buf.getvalue()[0:-1]).rstrip()
 
     def getinfo(self, args):
         info = self.dm.getInfo(directive=args.directive)
         for (infokey, infoitem) in sorted(info.iteritems()):
             if infokey == "process":
-                pass # skip process list: get that through ps
-            elif not args.directive and not infoitem:
-                print "%s:" % infokey.upper()
-            elif not args.directive:
-                for line in infoitem:
-                    print "%s: %s" % (infokey.upper(), line)
+                pass  # skip process list: get that through ps
+            elif args.directive is None:
+                print "%s: %s" % (infokey.upper(), infoitem)
             else:
-                print "%s" % "\n".join(infoitem)
+                print infoitem
 
     def logcat(self, args):
         print ''.join(self.dm.getLogcat())
 
     def clearlogcat(self, args):
         self.dm.recordLogcat()
 
     def reboot(self, args):
--- a/testing/specialpowers/content/MockFilePicker.jsm
+++ b/testing/specialpowers/content/MockFilePicker.jsm
@@ -84,17 +84,17 @@ this.MockFilePicker = {
       registrar.unregisterFactory(newClassID, previousFactory);
       registrar.registerFactory(oldClassID, "", CONTRACT_ID, oldFactory);
     }
   },
 
   useAnyFile: function() {
     var file = FileUtils.getDir("TmpD", [], false);
     file.append("testfile");
-    file.createUnique(Ci.nsIFile.NORMAL_FILE_TYPE, 0644);
+    file.createUnique(Ci.nsIFile.NORMAL_FILE_TYPE, 0o644);
     this.returnFiles = [file];
   },
 
   useBlobFile: function() {
     var blob = new this.window.Blob([]);
     var file = new this.window.File([blob], 'helloworld.txt', { type: 'plain/text' });
     this.returnFiles = [file];
   },