Merge m-c to fx-team. a=merge
authorRyan VanderMeulen <ryanvm@gmail.com>
Fri, 07 Nov 2014 13:50:07 -0500
changeset 226073 bc84a9d465dbe51698c7cbdfa5768968aca60675
parent 226072 f7ba147a8b5f2e4cb6cc0d87e51ae16e8fed7563 (current diff)
parent 226003 f2a91c7332be4b47b84b364c27caace14ccd8b00 (diff)
child 226074 53d7570e20f2f5b2f0c01519d089755fed48c873
push id32
push userbmcbride@mozilla.com
push dateSun, 09 Nov 2014 12:47:32 +0000
reviewersmerge
milestone36.0a1
Merge m-c to fx-team. a=merge
--- a/browser/app/profile/firefox.js
+++ b/browser/app/profile/firefox.js
@@ -1239,16 +1239,19 @@ pref("services.sync.prefs.sync.addons.ig
 // The addons prefs related to repository verification are intentionally
 // not synced for security reasons. If a system is compromised, a user
 // could weaken the pref locally, install an add-on from an untrusted
 // source, and this would propagate automatically to other,
 // uncompromised Sync-connected devices.
 pref("services.sync.prefs.sync.app.update.mode", true);
 pref("services.sync.prefs.sync.browser.formfill.enable", true);
 pref("services.sync.prefs.sync.browser.link.open_newwindow", true);
+pref("services.sync.prefs.sync.browser.newtabpage.enabled", true);
+pref("services.sync.prefs.sync.browser.newtabpage.enhanced", true);
+pref("services.sync.prefs.sync.browser.newtabpage.pinned", true);
 pref("services.sync.prefs.sync.browser.offline-apps.notify", true);
 pref("services.sync.prefs.sync.browser.safebrowsing.enabled", true);
 pref("services.sync.prefs.sync.browser.safebrowsing.malware.enabled", true);
 pref("services.sync.prefs.sync.browser.search.update", true);
 pref("services.sync.prefs.sync.browser.sessionstore.restore_on_demand", true);
 pref("services.sync.prefs.sync.browser.startup.homepage", true);
 pref("services.sync.prefs.sync.browser.startup.page", true);
 pref("services.sync.prefs.sync.browser.tabs.loadInBackground", true);
--- a/browser/devtools/debugger/test/browser.ini
+++ b/browser/devtools/debugger/test/browser.ini
@@ -387,23 +387,23 @@ skip-if = e10s
 skip-if = e10s
 [browser_dbg_searchbox-help-popup-01.js]
 skip-if = e10s
 [browser_dbg_searchbox-help-popup-02.js]
 skip-if = e10s
 [browser_dbg_searchbox-parse.js]
 skip-if = e10s
 [browser_dbg_source-maps-01.js]
-skip-if = e10s
+skip-if = e10s && debug
 [browser_dbg_source-maps-02.js]
-skip-if = e10s
+skip-if = e10s && debug
 [browser_dbg_source-maps-03.js]
-skip-if = e10s
+skip-if = e10s && debug
 [browser_dbg_source-maps-04.js]
-skip-if = e10s
+skip-if = e10s # Bug 1093535
 [browser_dbg_sources-cache.js]
 skip-if = e10s
 [browser_dbg_sources-labels.js]
 skip-if = e10s
 [browser_dbg_sources-sorting.js]
 skip-if = e10s
 [browser_dbg_split-console-paused-reload.js]
 skip-if = e10s
--- a/browser/devtools/debugger/test/browser_dbg_source-maps-01.js
+++ b/browser/devtools/debugger/test/browser_dbg_source-maps-01.js
@@ -4,23 +4,22 @@
 /**
  * Test that we can set breakpoints and step through source mapped
  * coffee script.
  */
 
 const TAB_URL = EXAMPLE_URL + "doc_binary_search.html";
 const COFFEE_URL = EXAMPLE_URL + "code_binary_search.coffee";
 
-let gTab, gDebuggee, gPanel, gDebugger;
+let gTab, gPanel, gDebugger;
 let gEditor, gSources;
 
 function test() {
-  initDebugger(TAB_URL).then(([aTab, aDebuggee, aPanel]) => {
+  initDebugger(TAB_URL).then(([aTab,, aPanel]) => {
     gTab = aTab;
-    gDebuggee = aDebuggee;
     gPanel = aPanel;
     gDebugger = gPanel.panelWin;
     gEditor = gDebugger.DebuggerView.editor;
     gSources = gDebugger.DebuggerView.Sources;
 
     checkSourceMapsEnabled();
 
     waitForSourceShown(gPanel, ".coffee")
@@ -114,17 +113,17 @@ function testHitBreakpoint() {
       is(aPacket.frame.environment.bindings.variables.pivot.value.type, "undefined",
          "'pivot' hasn't been assigned to yet.");
 
       waitForCaretUpdated(gPanel, 5).then(deferred.resolve);
     });
 
     // This will cause the breakpoint to be hit, and put us back in the
     // paused state.
-    gDebuggee.binary_search([0, 2, 3, 5, 7, 10], 5);
+    callInTab(gTab, "binary_search", [0, 2, 3, 5, 7, 10], 5);
   });
 
   return deferred.promise;
 }
 
 function testStepping() {
   let deferred = promise.defer();
 
@@ -152,14 +151,13 @@ function testStepping() {
     });
   });
 
   return deferred.promise;
 }
 
 registerCleanupFunction(function() {
   gTab = null;
-  gDebuggee = null;
   gPanel = null;
   gDebugger = null;
   gEditor = null;
   gSources = null;
 });
--- a/browser/devtools/debugger/test/browser_dbg_source-maps-02.js
+++ b/browser/devtools/debugger/test/browser_dbg_source-maps-02.js
@@ -3,22 +3,22 @@
 
 /**
  * Test that we can toggle between the original and generated sources.
  */
 
 const TAB_URL = EXAMPLE_URL + "doc_binary_search.html";
 const JS_URL = EXAMPLE_URL + "code_binary_search.js";
 
-let gDebuggee, gPanel, gDebugger, gEditor;
+let gTab, gPanel, gDebugger, gEditor;
 let gSources, gFrames, gPrefs, gOptions;
 
 function test() {
-  initDebugger(TAB_URL).then(([aTab, aDebuggee, aPanel]) => {
-    gDebuggee = aDebuggee;
+  initDebugger(TAB_URL).then(([aTab,, aPanel]) => {
+    gTab = aTab;
     gPanel = aPanel;
     gDebugger = gPanel.panelWin;
     gEditor = gDebugger.DebuggerView.editor;
     gSources = gDebugger.DebuggerView.Sources;
     gFrames = gDebugger.DebuggerView.StackFrames;
     gPrefs = gDebugger.Prefs;
     gOptions = gDebugger.DebuggerView.Options;
 
@@ -76,17 +76,17 @@ function testSetBreakpoint() {
         isnot(gFrames.getItemAtIndex(0).attachment.url.indexOf(".js"), -1,
           "First frame should be a JS frame.");
 
         deferred.resolve();
       });
 
       // This will cause the breakpoint to be hit, and put us back in the
       // paused state.
-      gDebuggee.binary_search([0, 2, 3, 5, 7, 10], 5);
+      callInTab(gTab, "binary_search", [0, 2, 3, 5, 7, 10], 5);
     });
   });
 
   return deferred.promise;
 }
 
 function testToggleOnPause() {
   let finished = waitForSourceAndCaretAndScopes(gPanel, ".coffee", 5).then(() => {
@@ -130,17 +130,17 @@ function testResume() {
 
     deferred.resolve();
   });
 
   return deferred.promise;
 }
 
 registerCleanupFunction(function() {
-  gDebuggee = null;
+  gTab = null;
   gPanel = null;
   gDebugger = null;
   gEditor = null;
   gSources = null;
   gFrames = null;
   gPrefs = null;
   gOptions = null;
 });
--- a/browser/devtools/debugger/test/browser_dbg_source-maps-03.js
+++ b/browser/devtools/debugger/test/browser_dbg_source-maps-03.js
@@ -3,22 +3,22 @@
 
 /**
  * Test that we can debug minified javascript with source maps.
  */
 
 const TAB_URL = EXAMPLE_URL + "doc_minified.html";
 const JS_URL = EXAMPLE_URL + "code_math.js";
 
-let gDebuggee, gPanel, gDebugger;
+let gTab, gPanel, gDebugger;
 let gEditor, gSources, gFrames;
 
 function test() {
-  initDebugger(TAB_URL).then(([aTab, aDebuggee, aPanel]) => {
-    gDebuggee = aDebuggee;
+  initDebugger(TAB_URL).then(([aTab,, aPanel]) => {
+    gTab = aTab;
     gPanel = aPanel;
     gDebugger = gPanel.panelWin;
     gEditor = gDebugger.DebuggerView.editor;
     gSources = gDebugger.DebuggerView.Sources;
     gFrames = gDebugger.DebuggerView.StackFrames;
 
     waitForSourceShown(gPanel, JS_URL)
       .then(checkInitialSource)
@@ -59,23 +59,23 @@ function testSetBreakpoint() {
         isnot(gFrames.getItemAtIndex(0).attachment.url.indexOf(".js"), -1,
           "First frame should be a JS frame.");
 
         deferred.resolve();
       });
 
       // This will cause the breakpoint to be hit, and put us back in the
       // paused state.
-      gDebuggee.arithmetic();
+      callInTab(gTab, "arithmetic");
     });
   });
 
   return deferred.promise;
 }
 
 registerCleanupFunction(function() {
-  gDebuggee = null;
+  gTab = null;
   gPanel = null;
   gDebugger = null;
   gEditor = null;
   gSources = null;
   gFrames = null;
 });
--- a/browser/devtools/debugger/test/browser_dbg_source-maps-04.js
+++ b/browser/devtools/debugger/test/browser_dbg_source-maps-04.js
@@ -11,17 +11,17 @@ const JS_URL = EXAMPLE_URL + "code_math_
 // This test causes an error to be logged in the console, which appears in TBPL
 // logs, so we are disabling that here.
 let { DevToolsUtils } = Cu.import("resource://gre/modules/devtools/DevToolsUtils.jsm", {});
 DevToolsUtils.reportingDisabled = true;
 
 let gPanel, gDebugger, gFrames, gSources, gPrefs, gOptions;
 
 function test() {
-  initDebugger(TAB_URL).then(([aTab, aDebuggee, aPanel]) => {
+  initDebugger(TAB_URL).then(([aTab,, aPanel]) => {
     gPanel = aPanel;
     gDebugger = gPanel.panelWin;
     gFrames = gDebugger.DebuggerView.StackFrames;
     gSources = gDebugger.DebuggerView.Sources;
     gPrefs = gDebugger.Prefs;
     gOptions = gDebugger.DebuggerView.Options;
 
     is(gPrefs.pauseOnExceptions, false,
--- a/browser/devtools/debugger/test/code_frame-script.js
+++ b/browser/devtools/debugger/test/code_frame-script.js
@@ -5,19 +5,20 @@ const { loadSubScript } = Cc['@mozilla.o
                           getService(Ci.mozIJSSubScriptLoader);
 
 const EventUtils = {};
 loadSubScript("chrome://marionette/content/EventUtils.js", EventUtils);
 
 dump("Frame script loaded.\n");
 
 addMessageListener("test:call", function (message) {
-  dump("Calling function with name " + message.data + ".\n");
+  dump("Calling function with name " + message.data.name + ".\n");
 
-  XPCNativeWrapper.unwrap(content)[message.data]();
+  let data = message.data;
+  XPCNativeWrapper.unwrap(content)[data.name].apply(undefined, data.args);
   sendAsyncMessage("test:call");
 });
 
 addMessageListener("test:click", function (message) {
   dump("Sending mouse click.\n");
 
   let target = message.objects.target;
   EventUtils.synthesizeMouseAtCenter(target, {},
--- a/browser/devtools/debugger/test/head.js
+++ b/browser/devtools/debugger/test/head.js
@@ -958,17 +958,20 @@ function waitForMessageFromTab(tab, name
       resolve(message);
     });
   });
 }
 
 function callInTab(tab, name) {
   info("Calling function with name " + name + " in tab.");
 
-  sendMessageToTab(tab, "test:call", name);
+  sendMessageToTab(tab, "test:call", {
+    name: name,
+    args: Array.prototype.slice.call(arguments, 2)
+  });
   waitForMessageFromTab(tab, "test:call");
 }
 
 function sendMouseClickToTab(tab, target) {
   info("Sending mouse click to tab.");
 
   sendMessageToTab(tab, "test:click", undefined, {
     target: target
--- a/dom/base/WebSocket.cpp
+++ b/dom/base/WebSocket.cpp
@@ -2291,16 +2291,22 @@ WebSocketImpl::Cancel(nsresult aStatus)
   return CancelInternal();
 }
 
 nsresult
 WebSocketImpl::CancelInternal()
 {
   AssertIsOnTargetThread();
 
+   // If CancelInternal is called by a runnable, we may already be disconnected
+   // by the time it runs.
+  if (mDisconnected) {
+    return NS_OK;
+  }
+
   int64_t readyState = mWebSocket->ReadyState();
   if (readyState == WebSocket::CLOSING || readyState == WebSocket::CLOSED) {
     return NS_OK;
   }
 
   ConsoleError();
 
   return CloseConnection(nsIWebSocketChannel::CLOSE_GOING_AWAY);
--- a/dom/base/nsCSPContext.cpp
+++ b/dom/base/nsCSPContext.cpp
@@ -180,18 +180,19 @@ nsCSPContext::ShouldLoad(nsContentPolicy
         CSPCONTEXTLOG(("nsCSPContext::ShouldLoad, nsIContentPolicy::REJECT_SERVER"));
         *outDecision = nsIContentPolicy::REJECT_SERVER;
       }
 
       // Do not send a report or notify observers if this is a preload - the
       // decision may be wrong due to the inability to get the nonce, and will
       // incorrectly fail the unit tests.
       if (!isPreload) {
+        nsCOMPtr<nsIURI> originalURI = do_QueryInterface(aExtra);
         this->AsyncReportViolation(aContentLocation,
-                                   mSelfURI,
+                                   originalURI,   /* in case of redirect originalURI is not null */
                                    violatedDirective,
                                    p,             /* policy index        */
                                    EmptyString(), /* no observer subject */
                                    EmptyString(), /* no source file      */
                                    EmptyString(), /* no script sample    */
                                    0);            /* no line number      */
       }
     }
@@ -413,17 +414,17 @@ nsCSPContext::GetAllowsHash(const nsAStr
     PR_BEGIN_MACRO                                                             \
     if (!mPolicies[p]->allows(nsIContentPolicy::TYPE_ ## contentPolicyType,    \
                               keyword, nonceOrHash))                           \
     {                                                                          \
       nsAutoString violatedDirective;                                          \
       mPolicies[p]->getDirectiveStringForContentType(                          \
                         nsIContentPolicy::TYPE_ ## contentPolicyType,          \
                         violatedDirective);                                    \
-      this->AsyncReportViolation(selfISupports, mSelfURI, violatedDirective, p, \
+      this->AsyncReportViolation(selfISupports, nullptr, violatedDirective, p, \
                                  NS_LITERAL_STRING(observerTopic),             \
                                  aSourceFile, aScriptSample, aLineNum);        \
     }                                                                          \
     PR_END_MACRO;                                                              \
     break
 
 /**
  * For each policy, log any violation on the Error Console and send a report
@@ -535,16 +536,33 @@ nsCSPContext::SetRequestContext(nsIURI* 
     else {
       NS_WARNING("Channel provided to SetRequestContext is not an nsIHttpChannel so referrer is not available for reporting." );
     }
   }
 
   return NS_OK;
 }
 
+/**
+ * Sends CSP violation reports to all sources listed under report-uri.
+ *
+ * @param aBlockedContentSource
+ *        Either a CSP Source (like 'self', as string) or nsIURI: the source
+ *        of the violation.
+ * @param aOriginalUri
+ *        The original URI if the blocked content is a redirect, else null
+ * @param aViolatedDirective
+ *        the directive that was violated (string).
+ * @param aSourceFile
+ *        name of the file containing the inline script violation
+ * @param aScriptSample
+ *        a sample of the violating inline script
+ * @param aLineNum
+ *        source line number of the violation (if available)
+ */
 nsresult
 nsCSPContext::SendReports(nsISupports* aBlockedContentSource,
                           nsIURI* aOriginalURI,
                           nsAString& aViolatedDirective,
                           uint32_t aViolatedPolicyIndex,
                           nsAString& aSourceFile,
                           nsAString& aScriptSample,
                           uint32_t aLineNum)
@@ -564,37 +582,43 @@ nsCSPContext::SendReports(nsISupports* a
   nsresult rv;
 
   // blocked-uri
   if (aBlockedContentSource) {
     nsAutoCString reportBlockedURI;
     nsCOMPtr<nsIURI> uri = do_QueryInterface(aBlockedContentSource);
     // could be a string or URI
     if (uri) {
-      uri->GetSpecIgnoringRef(reportBlockedURI);
+      // aOriginalURI will only be *not* null in case of a redirect in which
+      // case aOriginalURI is the uri before the redirect.
+      if (aOriginalURI) {
+        // do not report anything else than the origin in case of a redirect, see:
+        // http://www.w3.org/TR/CSP/#violation-reports
+        uri->GetPrePath(reportBlockedURI);
+      } else {
+        uri->GetSpecIgnoringRef(reportBlockedURI);
+      }
     } else {
       nsCOMPtr<nsISupportsCString> cstr = do_QueryInterface(aBlockedContentSource);
       if (cstr) {
         cstr->GetData(reportBlockedURI);
       }
     }
     if (reportBlockedURI.IsEmpty()) {
       // this can happen for frame-ancestors violation where the violating
       // ancestor is cross-origin.
       NS_WARNING("No blocked URI (null aBlockedContentSource) for CSP violation report.");
     }
     report.mCsp_report.mBlocked_uri = NS_ConvertUTF8toUTF16(reportBlockedURI);
   }
 
   // document-uri
-  if (aOriginalURI) {
-    nsAutoCString reportDocumentURI;
-    aOriginalURI->GetSpecIgnoringRef(reportDocumentURI);
-    report.mCsp_report.mDocument_uri = NS_ConvertUTF8toUTF16(reportDocumentURI);
-  }
+  nsAutoCString reportDocumentURI;
+  mSelfURI->GetSpecIgnoringRef(reportDocumentURI);
+  report.mCsp_report.mDocument_uri = NS_ConvertUTF8toUTF16(reportDocumentURI);
 
   // original-policy
   nsAutoString originalPolicy;
   rv = this->GetPolicy(aViolatedPolicyIndex, originalPolicy);
   NS_ENSURE_SUCCESS(rv, rv);
   report.mCsp_report.mOriginal_policy = originalPolicy;
 
   // referrer
@@ -726,17 +750,17 @@ nsCSPContext::SendReports(nsISupports* a
     int16_t shouldLoad = nsIContentPolicy::ACCEPT;
     nsCOMPtr<nsIContentPolicy> cp = do_GetService(NS_CONTENTPOLICY_CONTRACTID);
     if (!cp) {
       return NS_ERROR_FAILURE;
     }
 
     rv = cp->ShouldLoad(nsIContentPolicy::TYPE_CSP_REPORT,
                         reportURI,
-                        aOriginalURI,
+                        mSelfURI,
                         nullptr,        // Context
                         EmptyCString(), // mime type
                         nullptr,        // Extra parameter
                         nullptr,        // optional request principal
                         &shouldLoad);
 
     // refuse to load if we can't do a security check
     NS_ENSURE_SUCCESS(rv, rv);
@@ -1042,17 +1066,17 @@ nsCSPContext::PermitsAncestry(nsIDocShel
                                  false, // no redirect
                                  violatedDirective)) {
         // Policy is violated
         // Send reports, but omit the ancestor URI if cross-origin as per spec
         // (it is a violation of the same-origin policy).
         bool okToSendAncestor = NS_SecurityCompareURIs(ancestorsArray[a], mSelfURI, true);
 
         this->AsyncReportViolation((okToSendAncestor ? ancestorsArray[a] : nullptr),
-                                   mSelfURI,
+                                   nullptr,       /* originalURI in case of redirect */
                                    violatedDirective,
                                    i,             /* policy index        */
                                    EmptyString(), /* no observer subject */
                                    EmptyString(), /* no source file      */
                                    EmptyString(), /* no script sample    */
                                    0);            /* no line number      */
         *outPermitsAncestry = false;
       }
@@ -1075,17 +1099,17 @@ nsCSPContext::PermitsBaseURI(nsIURI* aUR
     if (!mPolicies[i]->permitsBaseURI(aURI)) {
       // policy is violated, report to caller if not report-only
       if (!mPolicies[i]->getReportOnlyFlag()) {
         *outPermitsBaseURI = false;
       }
       nsAutoString violatedDirective;
       mPolicies[i]->getDirectiveStringForBaseURI(violatedDirective);
       this->AsyncReportViolation(aURI,
-                                 mSelfURI,
+                                 nullptr,       /* originalURI in case of redirect */
                                  violatedDirective,
                                  i,             /* policy index        */
                                  EmptyString(), /* no observer subject */
                                  EmptyString(), /* no source file      */
                                  EmptyString(), /* no script sample    */
                                  0);            /* no line number      */
     }
   }
--- a/dom/base/nsDOMWindowUtils.cpp
+++ b/dom/base/nsDOMWindowUtils.cpp
@@ -270,18 +270,23 @@ nsDOMWindowUtils::Redraw(uint32_t aCount
   }
   return NS_ERROR_FAILURE;
 }
 
 NS_IMETHODIMP
 nsDOMWindowUtils::UpdateLayerTree()
 {
   if (nsIPresShell* presShell = GetPresShell()) {
+    presShell->FlushPendingNotifications(Flush_Display);
     nsRefPtr<nsViewManager> vm = presShell->GetViewManager();
-    vm->ProcessPendingUpdates();
+    nsView* view = vm->GetRootView();
+    if (view) {
+      presShell->Paint(view, view->GetBounds(),
+          nsIPresShell::PAINT_LAYERS | nsIPresShell::PAINT_SYNC_DECODE_IMAGES);
+    }
   }
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsDOMWindowUtils::SetCSSViewport(float aWidthPx, float aHeightPx)
 {
   if (!nsContentUtils::IsCallerChrome()) {
--- a/dom/base/nsGlobalWindow.cpp
+++ b/dom/base/nsGlobalWindow.cpp
@@ -189,17 +189,16 @@
 #ifdef MOZ_GAMEPAD
 #include "mozilla/dom/GamepadService.h"
 #endif
 
 #include "nsRefreshDriver.h"
 
 #include "mozilla/dom/SelectionChangeEvent.h"
 
-#include "mozilla/AddonPathService.h"
 #include "mozilla/Services.h"
 #include "mozilla/Telemetry.h"
 #include "nsLocation.h"
 #include "nsHTMLDocument.h"
 #include "nsWrapperCacheInlines.h"
 #include "mozilla/DOMEventTargetHelper.h"
 #include "prrng.h"
 #include "nsSandboxFlags.h"
@@ -2261,22 +2260,16 @@ CreateNativeGlobalForInner(JSContext* aC
   nsCOMPtr<nsIExpandedPrincipal> nsEP = do_QueryInterface(aPrincipal);
   MOZ_RELEASE_ASSERT(!nsEP, "DOMWindow with nsEP is not supported");
 
   nsGlobalWindow *top = nullptr;
   if (aNewInner->GetOuterWindow()) {
     top = aNewInner->GetTop();
   }
   JS::CompartmentOptions options;
-
-  // Sometimes add-ons load their own XUL windows, either as separate top-level
-  // windows or inside a browser element. In such cases we want to tag the
-  // window's compartment with the add-on ID. See bug 1092156.
-  options.setAddonId(MapURIToAddonID(aURI));
-
   if (top) {
     if (top->GetGlobalJSObject()) {
       options.setSameZoneAs(top->GetGlobalJSObject());
     }
   }
 
   // Determine if we need the Components object.
   bool needComponents = nsContentUtils::IsSystemPrincipal(aPrincipal) ||
--- a/dom/media/webspeech/recognition/SpeechRecognition.cpp
+++ b/dom/media/webspeech/recognition/SpeechRecognition.cpp
@@ -935,21 +935,21 @@ SpeechEvent::Run()
   return NS_OK;
 }
 
 NS_IMPL_ISUPPORTS(SpeechRecognition::GetUserMediaSuccessCallback, nsIDOMGetUserMediaSuccessCallback)
 
 NS_IMETHODIMP
 SpeechRecognition::GetUserMediaSuccessCallback::OnSuccess(nsISupports* aStream)
 {
-  DOMLocalMediaStream *localStream = nullptr;
-  nsresult rv = CallQueryInterface(aStream, &localStream);
-  if (NS_SUCCEEDED(rv)) {
-    mRecognition->StartRecording(localStream);
+  nsRefPtr<DOMMediaStream> stream = do_QueryObject(aStream);
+  if (!stream) {
+    return NS_ERROR_NO_INTERFACE;
   }
+  mRecognition->StartRecording(stream);
   return NS_OK;
 }
 
 NS_IMPL_ISUPPORTS(SpeechRecognition::GetUserMediaErrorCallback, nsIDOMGetUserMediaErrorCallback)
 
 NS_IMETHODIMP
 SpeechRecognition::GetUserMediaErrorCallback::OnError(nsISupports* aError)
 {
--- a/gfx/thebes/gfxUtils.cpp
+++ b/gfx/thebes/gfxUtils.cpp
@@ -38,16 +38,54 @@
 
 using namespace mozilla;
 using namespace mozilla::image;
 using namespace mozilla::layers;
 using namespace mozilla::gfx;
 
 #include "DeprecatedPremultiplyTables.h"
 
+extern "C" {
+
+/**
+ * Dump a raw image to the default log.  This function is exported
+ * from libxul, so it can be called from any library in addition to
+ * (of course) from a debugger.
+ *
+ * Note: this helper currently assumes that all 2-bytepp images are
+ * r5g6b5, and that all 4-bytepp images are r8g8b8a8.
+ */
+NS_EXPORT
+void mozilla_dump_image(void* bytes, int width, int height, int bytepp,
+                        int strideBytes)
+{
+    if (0 == strideBytes) {
+        strideBytes = width * bytepp;
+    }
+    SurfaceFormat format;
+    // TODO more flexible; parse string?
+    switch (bytepp) {
+    case 2:
+        format = SurfaceFormat::R5G6B5;
+        break;
+    case 4:
+    default:
+        format = SurfaceFormat::R8G8B8A8;
+        break;
+    }
+
+    RefPtr<DataSourceSurface> surf =
+        Factory::CreateWrappingDataSourceSurface((uint8_t*)bytes, strideBytes,
+                                                 gfx::IntSize(width, height),
+                                                 format);
+    gfxUtils::DumpAsDataURI(surf);
+}
+
+}
+
 static const uint8_t PremultiplyValue(uint8_t a, uint8_t v) {
     return gfxUtils::sPremultiplyTable[a*256+v];
 }
 
 static const uint8_t UnpremultiplyValue(uint8_t a, uint8_t v) {
     return gfxUtils::sUnpremultiplyTable[a*256+v];
 }
 
--- a/js/src/jsapi.cpp
+++ b/js/src/jsapi.cpp
@@ -1218,17 +1218,19 @@ static const JSStdName builtin_property_
     { EAGER_ATOM(encodeURIComponent), JSProto_String },
 #if JS_HAS_UNEVAL
     { EAGER_ATOM(uneval), JSProto_String },
 #endif
 #ifdef ENABLE_BINARYDATA
     { EAGER_ATOM(SIMD), JSProto_SIMD },
     { EAGER_ATOM(TypedObject), JSProto_TypedObject },
 #endif
+#ifdef ENABLE_SHARED_ARRAY_BUFFER
     { EAGER_ATOM(Atomics), JSProto_Atomics },
+#endif
 
     { 0, JSProto_LIMIT }
 };
 
 #undef EAGER_ATOM
 
 JS_PUBLIC_API(bool)
 JS_ResolveStandardClass(JSContext *cx, HandleObject obj, HandleId id, bool *resolved)
--- a/js/xpconnect/src/XPCWrappedNativeScope.cpp
+++ b/js/xpconnect/src/XPCWrappedNativeScope.cpp
@@ -341,26 +341,16 @@ XPCWrappedNativeScope::EnsureAddonScope(
 {
     JS::RootedObject global(cx, GetGlobalJSObject());
     MOZ_ASSERT(js::IsObjectInContextCompartment(global, cx));
     MOZ_ASSERT(!mIsContentXBLScope);
     MOZ_ASSERT(!mIsAddonScope);
     MOZ_ASSERT(addonId);
     MOZ_ASSERT(nsContentUtils::IsSystemPrincipal(GetPrincipal()));
 
-    // In bug 1092156, we found that add-on scopes don't work correctly when the
-    // window navigates. The add-on global's prototype is an outer window, so,
-    // after the navigation, looking up window properties in the add-on scope
-    // will fail. However, in most cases where the window can be navigated, the
-    // entire window is part of the add-on. To solve the problem, we avoid
-    // returning an add-on scope for a window that is already tagged with the
-    // add-on ID.
-    if (AddonIdOfObject(global) == addonId)
-        return global;
-
     // If we already have an addon scope object, we know what to use.
     for (size_t i = 0; i < mAddonScopes.Length(); i++) {
         if (JS::AddonIdOfObject(js::UncheckedUnwrap(mAddonScopes[i])) == addonId)
             return mAddonScopes[i];
     }
 
     SandboxOptions options;
     options.wantComponents = true;
--- a/layout/base/nsIPresShell.h
+++ b/layout/base/nsIPresShell.h
@@ -1419,16 +1419,18 @@ public:
 
   enum PaintFlags {
     /* Update the layer tree and paint PaintedLayers. If this is not specified,
      * we may still have to do it if the layer tree lost PaintedLayer contents
      * we need for compositing. */
     PAINT_LAYERS = 0x01,
     /* Composite layers to the window. */
     PAINT_COMPOSITE = 0x02,
+    /* Sync-decode images. */
+    PAINT_SYNC_DECODE_IMAGES = 0x04
   };
   virtual void Paint(nsView* aViewToPaint, const nsRegion& aDirtyRegion,
                      uint32_t aFlags) = 0;
   virtual nsresult HandleEvent(nsIFrame* aFrame,
                                mozilla::WidgetGUIEvent* aEvent,
                                bool aDontRetargetEvents,
                                nsEventStatus* aEventStatus) = 0;
   virtual bool ShouldIgnoreInvalidation() = 0;
--- a/layout/base/nsPresShell.cpp
+++ b/layout/base/nsPresShell.cpp
@@ -6265,17 +6265,18 @@ PresShell::Paint(nsView*        aViewToP
 
     if (!(aFlags & PAINT_LAYERS)) {
       if (layerManager->EndEmptyTransaction()) {
         return;
       }
       NS_WARNING("Must complete empty transaction when compositing!");
     }
 
-    if (!(frame->GetStateBits() & NS_FRAME_UPDATE_LAYER_TREE) &&
+    if (!(aFlags & PAINT_SYNC_DECODE_IMAGES) &&
+        !(frame->GetStateBits() & NS_FRAME_UPDATE_LAYER_TREE) &&
         !mNextPaintCompressed) {
       NotifySubDocInvalidationFunc computeInvalidFunc =
         presContext->MayHavePaintEventListenerInSubDocument() ? nsPresContext::NotifySubDocInvalidation : 0;
       bool computeInvalidRect = computeInvalidFunc ||
                                 (layerManager->GetBackendType() == LayersBackend::LAYERS_BASIC);
 
       UniquePtr<LayerProperties> props;
       if (computeInvalidRect) {
@@ -6318,16 +6319,19 @@ PresShell::Paint(nsView*        aViewToP
     frame->ClearPresShellsFromLastPaint();
   }
 
   nscolor bgcolor = ComputeBackstopColor(aViewToPaint);
   uint32_t flags = nsLayoutUtils::PAINT_WIDGET_LAYERS | nsLayoutUtils::PAINT_EXISTING_TRANSACTION;
   if (!(aFlags & PAINT_COMPOSITE)) {
     flags |= nsLayoutUtils::PAINT_NO_COMPOSITE;
   }
+  if (aFlags & PAINT_SYNC_DECODE_IMAGES) {
+    flags |= nsLayoutUtils::PAINT_SYNC_DECODE_IMAGES;
+  }
   if (mNextPaintCompressed) {
     flags |= nsLayoutUtils::PAINT_COMPRESSED;
     mNextPaintCompressed = false;
   }
 
   if (frame) {
     // We can paint directly into the widget using its layer manager.
     nsLayoutUtils::PaintFrame(nullptr, frame, aDirtyRegion, bgcolor, flags);
new file mode 100644
--- /dev/null
+++ b/layout/base/tests/bug1093686_inner.html
@@ -0,0 +1,84 @@
+<!DOCTYPE HTML>
+<html id="html" style="height:100%">
+<head>
+  <title>Testing effect of listener on body</title>
+  <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+  <script type="application/javascript" src="/tests/SimpleTest/EventUtils.js"></script>
+  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+  <style>
+  .target { position:absolute; left:200px; top:200px; width:200px; height:200px; background:blue; }
+  </style>
+</head>
+<body id="body" onload="setTimeout(runTest, 0)" style="margin:0; width:100%; height:100%; overflow:hidden">
+<div id="content">
+  <div id="ruler" style="position:absolute; left:0; top:0; width:1mozmm; height:0;"></div>
+  <div class="target" id="t"></div>
+</div>
+<pre id="test">
+<script type="application/javascript">
+var eventTarget;
+window.onmousedown = function(event) { eventTarget = event.target; };
+
+// Make sure the target div is "clickable" by adding a click listener on it.
+document.getElementById('t').addEventListener('click', function(e) {
+  parent.ok(true, "target was clicked on");
+}, false);
+
+// Helper functions
+
+function testMouseClick(aX, aY, aExpectedId, aMsg) {
+  eventTarget = null;
+  synthesizeMouseAtPoint(aX, aY, {});
+  try {
+    parent.is(eventTarget.id, aExpectedId,
+       "checking offset " + aX + "," + aY + " hit " + aExpectedId + " [" + aMsg + "]");
+  } catch (ex) {
+    parent.ok(false, "checking offset " + aX + "," + aY + " hit " + aExpectedId + " [" + aMsg + "]; got " + eventTarget);
+  }
+}
+
+function testWithAndWithoutBodyListener(aX, aY, aExpectedId, aMsg) {
+  var func = function(e) {
+    // no-op function
+    parent.ok(true, "body was clicked on");
+  };
+  testMouseClick(aX, aY, aExpectedId, aMsg + " without listener on body");
+  document.body.addEventListener("click", func, false);
+  testMouseClick(aX, aY, aExpectedId, aMsg + " with listener on body");
+  document.body.removeEventListener("click", func, false);
+}
+
+// Main tests
+
+var mm;
+function runTest() {
+  mm = document.getElementById("ruler").getBoundingClientRect().width;
+  parent.ok(4*mm >= 10, "WARNING: mm " + mm + " too small in this configuration. Test results will be bogus");
+
+  // Test near the target, check it hits the target
+  testWithAndWithoutBodyListener(200 - 2*mm, 200 - 2*mm, "t", "basic click retargeting");
+  // Test on the target, check it hits the target
+  testWithAndWithoutBodyListener(200 + 2*mm, 200 + 2*mm, "t", "direct click");
+  // Test outside the target, check it hits the root
+  testWithAndWithoutBodyListener(40, 40, "body", "click way outside target");
+
+  SpecialPowers.pushPrefEnv({"set": [["ui.mouse.radius.enabled", false]]}, runTest2);
+}
+
+function runTest2() {
+  // In this test, mouse event retargeting is disabled.
+
+  // Test near the target, check it hits the body
+  testWithAndWithoutBodyListener(200 - 2*mm, 200 - 2*mm, "body", "basic click retargeting");
+  // Test on the target, check it hits the target
+  testWithAndWithoutBodyListener(200 + 2*mm, 200 + 2*mm, "t", "direct click");
+  // Test outside the target, check it hits the root
+  testWithAndWithoutBodyListener(40, 40, "body", "click way outside target");
+
+  parent.finishTest();
+}
+
+</script>
+</pre>
+</body>
+</html>
--- a/layout/base/tests/mochitest.ini
+++ b/layout/base/tests/mochitest.ini
@@ -501,8 +501,10 @@ support-files =
 [test_bug1070851.html]
 [test_bug1080360.html]
 support-files = bug1080360_inner.html
 [test_bug1078327.html]
 support-files = bug1078327_inner.html
 [test_bug1080361.html]
 support-files = bug1080361_inner.html
 [test_touchcaret_visibility.html]
+[test_bug1093686.html]
+support-files = bug1093686_inner.html
new file mode 100644
--- /dev/null
+++ b/layout/base/tests/test_bug1093686.html
@@ -0,0 +1,41 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=1093686
+-->
+  <head>
+    <meta charset="utf-8">
+    <title>Testing effect of listener on body with respect to event retargeting</title>
+    <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+    <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+    <script type="text/javascript">
+      var iframe = undefined;
+      function prepareTest() {
+        SimpleTest.waitForExplicitFinish();
+        iframe = document.getElementById("testFrame");
+        turnOnEventRetargeting(startTest);
+      }
+      function turnOnEventRetargeting(callback) {
+        SpecialPowers.pushPrefEnv({
+          "set": [
+            ["ui.mouse.radius.enabled", true],
+            ["ui.mouse.radius.inputSource.touchOnly", false],
+            ["ui.mouse.radius.leftmm", 8],
+            ["ui.mouse.radius.topmm", 12],
+            ["ui.mouse.radius.rightmm", 8],
+            ["ui.mouse.radius.bottommm", 4]
+          ]
+        }, callback);
+      }
+      function startTest() {
+        iframe.src = "bug1093686_inner.html";
+      }
+      function finishTest() {
+        SimpleTest.finish();
+      }
+    </script>
+  </head>
+  <body onload="prepareTest()">
+    <iframe id="testFrame" height="700" width="700"></iframe>
+  </body>
+</html>
--- a/memory/build/jemalloc_config.c
+++ b/memory/build/jemalloc_config.c
@@ -5,17 +5,17 @@
 #ifdef MOZ_JEMALLOC3
 
 #define MOZ_JEMALLOC_IMPL
 
 #include "mozmemory_wrap.h"
 #include "mozilla/Types.h"
 
 /* Override some jemalloc defaults */
-MFBT_DATA const char * je_(malloc_conf) = "narenas:1,lg_chunk:20";
+MFBT_DATA const char * je_(malloc_conf) = "narenas:1,lg_chunk:20,tcache:false";
 
 #ifdef ANDROID
 #include <android/log.h>
 
 static void
 _je_malloc_message(void *cbopaque, const char *s)
 {
   __android_log_print(ANDROID_LOG_INFO, "GeckoJemalloc", "%s", s);
--- a/netwerk/protocol/websocket/WebSocketChannelChild.cpp
+++ b/netwerk/protocol/websocket/WebSocketChannelChild.cpp
@@ -115,16 +115,41 @@ WebSocketChannelChild::DispatchToTargetT
   MOZ_RELEASE_ASSERT(NS_IsMainThread());
   MOZ_RELEASE_ASSERT(mTargetThread);
   MOZ_RELEASE_ASSERT(aChannelEvent);
 
   mTargetThread->Dispatch(new WrappedChannelEvent(aChannelEvent),
                           NS_DISPATCH_NORMAL);
 }
 
+class EventTargetDispatcher : public ChannelEvent
+{
+public:
+  EventTargetDispatcher(ChannelEvent* aChannelEvent,
+                        nsIEventTarget* aEventTarget)
+    : mChannelEvent(aChannelEvent)
+    , mEventTarget(aEventTarget)
+  {}
+
+  void Run()
+  {
+    if (mEventTarget) {
+      mEventTarget->Dispatch(new WrappedChannelEvent(mChannelEvent.forget()),
+                             NS_DISPATCH_NORMAL);
+      return;
+    }
+
+    mChannelEvent->Run();
+  }
+
+private:
+  nsAutoPtr<ChannelEvent> mChannelEvent;
+  nsCOMPtr<nsIEventTarget> mEventTarget;
+};
+
 class StartEvent : public ChannelEvent
 {
  public:
   StartEvent(WebSocketChannelChild* aChild,
              const nsCString& aProtocol,
              const nsCString& aExtensions,
              const nsString& aEffectiveURL,
              bool aEncrypted)
@@ -149,18 +174,20 @@ class StartEvent : public ChannelEvent
 
 bool
 WebSocketChannelChild::RecvOnStart(const nsCString& aProtocol,
                                    const nsCString& aExtensions,
                                    const nsString& aEffectiveURL,
                                    const bool& aEncrypted)
 {
   if (mEventQ->ShouldEnqueue()) {
-    mEventQ->Enqueue(new StartEvent(this, aProtocol, aExtensions,
-                                    aEffectiveURL, aEncrypted));
+    mEventQ->Enqueue(new EventTargetDispatcher(
+                       new StartEvent(this, aProtocol, aExtensions,
+                                      aEffectiveURL, aEncrypted),
+                       mTargetThread));
   } else if (mTargetThread) {
     DispatchToTargetThread(new StartEvent(this, aProtocol, aExtensions,
                                           aEffectiveURL, aEncrypted));
   } else {
     OnStart(aProtocol, aExtensions, aEffectiveURL, aEncrypted);
   }
   return true;
 }
@@ -200,17 +227,18 @@ class StopEvent : public ChannelEvent
   WebSocketChannelChild* mChild;
   nsresult mStatusCode;
 };
 
 bool
 WebSocketChannelChild::RecvOnStop(const nsresult& aStatusCode)
 {
   if (mEventQ->ShouldEnqueue()) {
-    mEventQ->Enqueue(new StopEvent(this, aStatusCode));
+    mEventQ->Enqueue(new EventTargetDispatcher(
+                       new StopEvent(this, aStatusCode), mTargetThread));
   } else if (mTargetThread) {
     DispatchToTargetThread(new StopEvent(this, aStatusCode));
   } else {
     OnStop(aStatusCode);
   }
   return true;
 }
 
@@ -248,17 +276,18 @@ class MessageEvent : public ChannelEvent
   nsCString mMessage;
   bool mBinary;
 };
 
 bool
 WebSocketChannelChild::RecvOnMessageAvailable(const nsCString& aMsg)
 {
   if (mEventQ->ShouldEnqueue()) {
-    mEventQ->Enqueue(new MessageEvent(this, aMsg, false));
+    mEventQ->Enqueue(new EventTargetDispatcher(
+                       new MessageEvent(this, aMsg, false), mTargetThread));
   } else if (mTargetThread) {
     DispatchToTargetThread(new MessageEvent(this, aMsg, false));
    } else {
     OnMessageAvailable(aMsg);
   }
   return true;
 }
 
@@ -271,17 +300,18 @@ WebSocketChannelChild::OnMessageAvailabl
     mListener->OnMessageAvailable(mContext, aMsg);
   }
 }
 
 bool
 WebSocketChannelChild::RecvOnBinaryMessageAvailable(const nsCString& aMsg)
 {
   if (mEventQ->ShouldEnqueue()) {
-    mEventQ->Enqueue(new MessageEvent(this, aMsg, true));
+    mEventQ->Enqueue(new EventTargetDispatcher(
+                       new MessageEvent(this, aMsg, true), mTargetThread));
   } else if (mTargetThread) {
     DispatchToTargetThread(new MessageEvent(this, aMsg, true));
   } else {
     OnBinaryMessageAvailable(aMsg);
   }
   return true;
 }
 
@@ -312,17 +342,18 @@ class AcknowledgeEvent : public ChannelE
   WebSocketChannelChild* mChild;
   uint32_t mSize;
 };
 
 bool
 WebSocketChannelChild::RecvOnAcknowledge(const uint32_t& aSize)
 {
   if (mEventQ->ShouldEnqueue()) {
-    mEventQ->Enqueue(new AcknowledgeEvent(this, aSize));
+    mEventQ->Enqueue(new EventTargetDispatcher(
+                       new AcknowledgeEvent(this, aSize), mTargetThread));
   } else if (mTargetThread) {
     DispatchToTargetThread(new AcknowledgeEvent(this, aSize));
   } else {
     OnAcknowledge(aSize);
   }
   return true;
 }
 
@@ -357,17 +388,19 @@ class ServerCloseEvent : public ChannelE
   nsCString              mReason;
 };
 
 bool
 WebSocketChannelChild::RecvOnServerClose(const uint16_t& aCode,
                                          const nsCString& aReason)
 {
   if (mEventQ->ShouldEnqueue()) {
-    mEventQ->Enqueue(new ServerCloseEvent(this, aCode, aReason));
+    mEventQ->Enqueue(new EventTargetDispatcher(
+                       new ServerCloseEvent(this, aCode, aReason),
+                       mTargetThread));
   } else if (mTargetThread) {
     DispatchToTargetThread(new ServerCloseEvent(this, aCode, aReason));
   } else {
     OnServerClose(aCode, aReason);
   }
   return true;
 }
 
--- a/testing/marionette/client/marionette/runner/base.py
+++ b/testing/marionette/client/marionette/runner/base.py
@@ -18,16 +18,17 @@ import xml.dom.minidom as dom
 
 from manifestparser import TestManifest
 from marionette import Marionette
 from mixins.b2g import B2GTestResultMixin, get_b2g_pid, get_dm
 from mozhttpd import MozHttpd
 from mozlog.structured.structuredlog import get_default_logger
 from moztest.adapters.unit import StructuredTestRunner, StructuredTestResult
 from moztest.results import TestResultCollection, TestResult, relevant_line
+import mozversion
 
 class MarionetteTest(TestResult):
 
     @property
     def test_name(self):
         if self.test_class is not None:
             return '%s.py %s.%s' % (self.test_class.split('.')[0],
                                     self.test_class,
@@ -707,17 +708,28 @@ setReq.onerror = function() {
 
         if not self.httpd:
             self.logger.info("starting httpd")
             self.start_httpd(need_external_ip)
 
         for test in tests:
             self.add_test(test)
 
-        self.logger.suite_start(self.tests)
+        version_info = mozversion.get_version(binary=self.bin,
+                                              sources=self.sources,
+                                              dm_type=os.environ.get('DM_TRANS', 'adb'))
+
+        device_info = None
+        if self.capabilities['device'] != 'desktop' and self.capabilities['browserName'] == 'B2G':
+            dm = get_dm(self.marionette)
+            device_info = dm.getInfo()
+
+        self.logger.suite_start(self.tests,
+                                version_info=version_info,
+                                device_info=device_info)
 
         for test in self.manifest_skipped_tests:
             name = os.path.basename(test['path'])
             self.logger.test_start(name)
             self.logger.test_end(name,
                                  'SKIP',
                                  message=test['disabled'])
             self.todo += 1
--- a/testing/marionette/client/requirements.txt
+++ b/testing/marionette/client/requirements.txt
@@ -1,13 +1,13 @@
 marionette-transport == 0.3
 manifestparser
 mozhttpd >= 0.5
 mozinfo >= 0.7
 mozprocess >= 0.9
 mozrunner >= 6.2
 mozdevice >= 0.37
-mozlog >= 2.6
+mozlog >= 2.7
 moznetwork >= 0.21
 mozcrash >= 0.5
 mozprofile >= 0.7
 moztest >= 0.7
 mozversion >= 0.2
--- a/widget/android/nsWindow.cpp
+++ b/widget/android/nsWindow.cpp
@@ -924,31 +924,31 @@ nsWindow::OnGlobalAndroidEvent(AndroidGe
             // Keys synthesized by Java IME code are saved in the mIMEKeyEvents
             // array until the next IME_REPLACE_TEXT event, at which point
             // these keys are dispatched in sequence.
             if (win->mFocus) {
                 win->mFocus->mIMEKeyEvents.AppendElement(*ae);
             }
             break;
 
-        case AndroidGeckoEvent::COMPOSITOR_CREATE:
-            win->CreateLayerManager(ae->Width(), ae->Height());
-            break;
-
         case AndroidGeckoEvent::COMPOSITOR_PAUSE:
             // The compositor gets paused when the app is about to go into the
             // background. While the compositor is paused, we need to ensure that
             // no layer tree updates (from draw events) occur, since the compositor
             // cannot make a GL context current in order to process updates.
             if (sCompositorChild) {
                 sCompositorChild->SendPause();
             }
             sCompositorPaused = true;
             break;
 
+        case AndroidGeckoEvent::COMPOSITOR_CREATE:
+            win->CreateLayerManager(ae->Width(), ae->Height());
+            // Fallthrough
+
         case AndroidGeckoEvent::COMPOSITOR_RESUME:
             // When we receive this, the compositor has already been told to
             // resume. (It turns out that waiting till we reach here to tell
             // the compositor to resume takes too long, resulting in a black
             // flash.) This means it's now safe for layer updates to occur.
             // Since we might have prevented one or more draw events from
             // occurring while the compositor was paused, we need to schedule
             // a draw event now.
--- a/xpcom/reflect/xptcall/md/unix/xptcinvoke_arm.cpp
+++ b/xpcom/reflect/xptcall/md/unix/xptcinvoke_arm.cpp
@@ -219,16 +219,17 @@ static inline void copy_dword(uint32_t* 
 {
   if (ireg_args + 1 < end) {
     if ((uint32_t)ireg_args & 4) {
       ireg_args++;
     }
     *(uint64_t *)ireg_args = data;
     ireg_args += 2;
   } else {
+    ireg_args = end;
     if ((uint32_t)stack_args & 4) {
       stack_args++;
     }
     *(uint64_t *)stack_args = data;
     stack_args += 2;
   }
 }