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 id27645
push userkwierso@gmail.com
push dateTue, 14 Oct 2014 01:50:26 +0000
treeherdermozilla-central@54217864bae9 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmerge
milestone36.0a1
first release with
nightly linux32
54217864bae9 / 36.0a1 / 20141014030201 / files
nightly linux64
54217864bae9 / 36.0a1 / 20141014030201 / files
nightly mac
54217864bae9 / 36.0a1 / 20141014030201 / files
nightly win32
54217864bae9 / 36.0a1 / 20141014030201 / files
nightly win64
54217864bae9 / 36.0a1 / 20141014030201 / files
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
releases
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
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];
   },