merge mozilla-inbound to mozilla-central a=merge
authorCarsten "Tomcat" Book <cbook@mozilla.com>
Tue, 28 Feb 2017 11:24:33 +0100
changeset 345149 1bc2ad020aee2830e0a7941f10958dbec108c254
parent 345122 682ee6f4802745005eccdb88f831828051ae4c1b (current diff)
parent 345148 22974497e57e814c3119a30b483842c793067434 (diff)
child 345159 0d6ca3d14e5b4e0a6ace7e72f074e2b29e8400f6
child 345229 697dbeae416bf99e4a43b60ee246d68b576be330
child 345787 95480a61674b3bb87b358d09c81e1f2f06d57545
push id31432
push usercbook@mozilla.com
push dateTue, 28 Feb 2017 10:24:46 +0000
treeherdermozilla-central@1bc2ad020aee [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmerge
milestone54.0a1
first release with
nightly linux32
1bc2ad020aee / 54.0a1 / 20170228110308 / files
nightly linux64
1bc2ad020aee / 54.0a1 / 20170228110308 / files
nightly mac
1bc2ad020aee / 54.0a1 / 20170228030203 / files
nightly win32
1bc2ad020aee / 54.0a1 / 20170228030203 / files
nightly win64
1bc2ad020aee / 54.0a1 / 20170228030203 / 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 mozilla-inbound to mozilla-central a=merge
testing/mozharness/configs/partner_repacks/staging_release_mozilla-esr52_desktop.py
--- a/browser/installer/package-manifest.in
+++ b/browser/installer/package-manifest.in
@@ -515,16 +515,19 @@
 @RESPATH@/components/NotificationStorage.manifest
 @RESPATH@/components/Push.js
 @RESPATH@/components/Push.manifest
 @RESPATH@/components/PushComponents.js
 
 @RESPATH@/components/remotebrowserutils.manifest
 @RESPATH@/components/RemoteWebNavigation.js
 
+@RESPATH@/components/ProcessSelector.js
+@RESPATH@/components/ProcessSelector.manifest
+
 @RESPATH@/components/SlowScriptDebug.manifest
 @RESPATH@/components/SlowScriptDebug.js
 
 #ifdef MOZ_WEBRTC
 @RESPATH@/components/PeerConnection.js
 @RESPATH@/components/PeerConnection.manifest
 #endif
 
new file mode 100644
--- /dev/null
+++ b/dom/base/ProcessSelector.js
@@ -0,0 +1,62 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+const { classes: Cc, interfaces: Ci, utils: Cu } = Components;
+
+Cu.import("resource://gre/modules/XPCOMUtils.jsm");
+Cu.import('resource://gre/modules/Services.jsm');
+
+const BASE_PREF = "dom.ipc.processCount"
+const PREF_BRANCH = BASE_PREF + ".";
+
+// Utilities:
+function getMaxContentParents(processType) {
+  let maxContentParents = -1;
+  try {
+    maxContentParents = Services.prefs.getIntPref(PREF_BRANCH + processType);
+  } catch (e) {
+    // Pref probably didn't exist, get the default number of processes.
+    try {
+      maxContentParents = Services.prefs.getIntPref(BASE_PREF);
+    } catch (e) {
+      // No prefs? That's odd, use only one process.
+      maxContentParents = 1;
+    }
+  }
+
+  return maxContentParents;
+}
+
+// Fills up aProcesses until max and then selects randomly from the available
+// ones.
+function RandomSelector() {
+}
+
+RandomSelector.prototype = {
+  classID:          Components.ID("{c616fcfd-9737-41f1-aa74-cee72a38f91b}"),
+  QueryInterface:   XPCOMUtils.generateQI([Ci.nsIContentProcessProvider]),
+
+  provideProcess(aType, aOpener, aProcesses, aCount) {
+    let maxContentParents = getMaxContentParents(aType);
+    if (aCount < maxContentParents) {
+      return Ci.nsIContentProcessProvider.NEW_PROCESS;
+    }
+
+    let startIdx = Math.floor(Math.random() * maxContentParents);
+    let curIdx = startIdx;
+
+    do {
+      if (aProcesses[curIdx].opener === aOpener) {
+        return curIdx;
+      }
+
+      curIdx = (curIdx + 1) % maxContentParents;
+    } while (curIdx !== startIdx);
+
+    return Ci.nsIContentProcessProvider.NEW_PROCESS;
+  },
+};
+
+var components = [RandomSelector];
+this.NSGetFactory = XPCOMUtils.generateNSGetFactory(components);
new file mode 100644
--- /dev/null
+++ b/dom/base/ProcessSelector.manifest
@@ -0,0 +1,2 @@
+component {c616fcfd-9737-41f1-aa74-cee72a38f91b} ProcessSelector.js
+contract @mozilla.org/ipc/processselector;1 {c616fcfd-9737-41f1-aa74-cee72a38f91b}
--- a/dom/base/TimeoutManager.cpp
+++ b/dom/base/TimeoutManager.cpp
@@ -66,16 +66,21 @@ static int32_t gTimeoutBucketingStrategy
 // timer code can handle, really. See DELAY_INTERVAL_LIMIT in
 // nsTimerImpl.h for details.
 #define DOM_MAX_TIMEOUT_VALUE    DELAY_INTERVAL_LIMIT
 
 uint32_t TimeoutManager::sNestingLevel = 0;
 
 namespace {
 
+// The maximum number of timer callbacks we will try to run in a single event
+// loop runnable.
+#define DEFAULT_TARGET_MAX_CONSECUTIVE_CALLBACKS 5
+uint32_t gTargetMaxConsecutiveCallbacks;
+
 // The number of queued runnables within the TabGroup ThrottledEventQueue
 // at which to begin applying back pressure to the window.
 #define DEFAULT_THROTTLED_EVENT_QUEUE_BACK_PRESSURE 5000
 static uint32_t gThrottledEventQueueBackPressure;
 
 // The amount of delay to apply to timers when back pressure is triggered.
 // As the length of the ThrottledEventQueue grows delay is increased.  The
 // delay is scaled such that every kThrottledEventQueueBackPressure runnables
@@ -177,16 +182,20 @@ TimeoutManager::Initialize()
                                "dom.timeout.back_pressure_delay_ms",
                                DEFAULT_BACK_PRESSURE_DELAY_MS);
   Preferences::AddUintVarCache(&gBackPressureDelayReductionThresholdMS,
                                "dom.timeout.back_pressure_delay_reduction_threshold_ms",
                                DEFAULT_BACK_PRESSURE_DELAY_REDUCTION_THRESHOLD_MS);
   Preferences::AddUintVarCache(&gBackPressureDelayMinimumMS,
                                "dom.timeout.back_pressure_delay_minimum_ms",
                                DEFAULT_BACK_PRESSURE_DELAY_MINIMUM_MS);
+
+  Preferences::AddUintVarCache(&gTargetMaxConsecutiveCallbacks,
+                               "dom.timeout.max_consecutive_callbacks",
+                               DEFAULT_TARGET_MAX_CONSECUTIVE_CALLBACKS);
 }
 
 uint32_t
 TimeoutManager::GetTimeoutId(Timeout::Reason aReason)
 {
   switch (aReason) {
     case Timeout::Reason::eIdleCallbackTimeout:
       return ++mIdleCallbackTimeoutCounter;
@@ -439,16 +448,20 @@ TimeoutManager::RunTimeout(Timeout* aTim
   // nothing past that point is expired.
   {
     // Use a nested scope in order to make sure the strong references held by
     // the iterator are freed after the loop.
     OrderedTimeoutIterator expiredIter(mNormalTimeouts,
                                        mTrackingTimeouts,
                                        nullptr,
                                        nullptr);
+
+    uint32_t numTimersToRun = 0;
+    bool targetTimerSeen = false;
+
     while (true) {
       Timeout* timeout = expiredIter.Next();
       if (!timeout || timeout->When() > deadline) {
         break;
       }
 
       if (timeout->mFiringDepth == 0) {
         // Mark any timeouts that are on the list to be fired with the
@@ -456,29 +469,39 @@ TimeoutManager::RunTimeout(Timeout* aTim
         timeout->mFiringDepth = firingDepth;
         last_expired_timeout_is_normal = expiredIter.PickedNormalIter();
         if (last_expired_timeout_is_normal) {
           last_expired_normal_timeout = timeout;
         } else {
           last_expired_tracking_timeout = timeout;
         }
 
-        // Run available timers until we see our target timer.  After
-        // that, however, stop coalescing timers so we can yield the
-        // main thread.  Further timers that are ready will get picked
-        // up by their own nsITimer runnables when they execute.
+        // Note that we have seen our target timer.  This means we can now
+        // stop processing timers once we hit our threshold below.
+        if (timeout == aTimeout) {
+          targetTimerSeen = true;
+        }
+
+        // Run only a limited number of timers based on the configured
+        // maximum.  Note, we must always run our target timer however.
+        // Further timers that are ready will get picked up by their own
+        // nsITimer runnables when they execute.
         //
         // For chrome windows, however, we do coalesce all timers and
         // do not yield the main thread.  This is partly because we
         // trust chrome windows not to misbehave and partly because a
         // number of browser chrome tests have races that depend on this
         // coalescing.
-        if (timeout == aTimeout && !mWindow.IsChromeWindow()) {
+        if (targetTimerSeen &&
+            numTimersToRun >= gTargetMaxConsecutiveCallbacks &&
+            !mWindow.IsChromeWindow()) {
           break;
         }
+
+        numTimersToRun += 1;
       }
 
       expiredIter.UpdateIterator();
     }
   }
 
   // Maybe the timeout that the event was fired for has been deleted
   // and there are no others timeouts with deadlines that make them
--- a/dom/base/UseCounters.conf
+++ b/dom/base/UseCounters.conf
@@ -57,16 +57,22 @@ attribute OfflineResourceList.onchecking
 attribute OfflineResourceList.onerror
 attribute OfflineResourceList.onnoupdate
 attribute OfflineResourceList.ondownloading
 attribute OfflineResourceList.onprogress
 attribute OfflineResourceList.onupdateready
 attribute OfflineResourceList.oncached
 attribute OfflineResourceList.onobsolete
 
+// Non-standard IndexedDB API
+method IDBDatabase.createMutableFile
+method IDBDatabase.mozCreateFileHandle
+method IDBMutableFile.open
+method IDBMutableFile.getFile
+
 // DataTransfer API (gecko-only methods)
 method DataTransfer.addElement
 attribute DataTransfer.mozItemCount
 attribute DataTransfer.mozCursor
 method DataTransfer.mozTypesAt
 method DataTransfer.mozClearDataAt
 method DataTransfer.mozSetDataAt
 method DataTransfer.mozGetDataAt
--- a/dom/base/moz.build
+++ b/dom/base/moz.build
@@ -396,16 +396,18 @@ if CONFIG['INTEL_ARCHITECTURE']:
     SOURCES += ['nsTextFragmentSSE2.cpp']
     SOURCES['nsTextFragmentSSE2.cpp'].flags += CONFIG['SSE2_FLAGS']
 
 EXTRA_COMPONENTS += [
     'contentAreaDropListener.js',
     'contentAreaDropListener.manifest',
     'messageWakeupService.js',
     'messageWakeupService.manifest',
+    'ProcessSelector.js',
+    'ProcessSelector.manifest',
     'SlowScriptDebug.js',
     'SlowScriptDebug.manifest',
 ]
 
 # Firefox for Android provides an alternate version of this component
 if CONFIG['MOZ_BUILD_APP'] != 'mobile/android':
     EXTRA_COMPONENTS += [
         'SiteSpecificUserAgent.js',
--- a/dom/interfaces/base/moz.build
+++ b/dom/interfaces/base/moz.build
@@ -6,16 +6,17 @@
 
 XPIDL_SOURCES += [
     'domstubs.idl',
     'nsIBrowser.idl',
     'nsIBrowserDOMWindow.idl',
     'nsIContentPermissionPrompt.idl',
     'nsIContentPrefService.idl',
     'nsIContentPrefService2.idl',
+    'nsIContentProcess.idl',
     'nsIContentURIGrouper.idl',
     'nsIDOMChromeWindow.idl',
     'nsIDOMClientRect.idl',
     'nsIDOMClientRectList.idl',
     'nsIDOMConstructor.idl',
     'nsIDOMCrypto.idl',
     'nsIDOMGlobalPropertyInitializer.idl',
     'nsIDOMHistory.idl',
new file mode 100644
--- /dev/null
+++ b/dom/interfaces/base/nsIContentProcess.idl
@@ -0,0 +1,53 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "nsISupports.idl"
+
+interface nsIDOMElement;
+interface nsIMessageSender;
+interface nsIURI;
+
+[scriptable, builtinclass, uuid(456f58be-29dd-4973-885b-95aece1c9a8a)]
+interface nsIContentProcessInfo : nsISupports
+{
+  /**
+   * Is this content process alive?
+   */
+  readonly attribute boolean isAlive;
+
+  /**
+   * The content process's PID.
+   * Throws if the process is not alive.
+   */
+  readonly attribute int32_t processId;
+
+  /**
+   * This content process's opener.
+   */
+  readonly attribute nsIContentProcessInfo opener;
+
+  /**
+   * The process manager for this ContentParent (so a process message manager
+   * as opposed to a frame message manager.
+   */
+  readonly attribute nsIMessageSender messageManager;
+};
+
+[scriptable, uuid(83ffb063-5f65-4c45-ae07-3f553e0809bb)]
+interface nsIContentProcessProvider : nsISupports
+{
+  /**
+   * Return this from provideProcess to create a new process.
+   */
+  const int32_t NEW_PROCESS = -1;
+
+  /**
+   * Given aAliveProcesses (with an opener aOpener), choose which process of
+   * aType to use. Return nsIContentProcessProvider.NEW_PROCESS to ask the
+   * caller to create a new content process.
+   */
+  int32_t provideProcess(in AString aType, in nsIContentProcessInfo aOpener,
+                         [array, size_is(aCount)] in nsIContentProcessInfo aAliveProcesses,
+                         in uint32_t aCount);
+};
--- a/dom/ipc/ContentParent.cpp
+++ b/dom/ipc/ContentParent.cpp
@@ -107,16 +107,17 @@
 #include "nsContentUtils.h"
 #include "nsDebugImpl.h"
 #include "nsFrameLoader.h"
 #include "nsFrameMessageManager.h"
 #include "nsHashPropertyBag.h"
 #include "nsIAlertsService.h"
 #include "nsIClipboard.h"
 #include "nsContentPermissionHelper.h"
+#include "nsIContentProcess.h"
 #include "nsICycleCollectorListener.h"
 #include "nsIDocShellTreeOwner.h"
 #include "nsIDocument.h"
 #include "nsIDOMGeoGeolocation.h"
 #include "nsIDOMGeoPositionError.h"
 #include "nsIDragService.h"
 #include "mozilla/dom/WakeLock.h"
 #include "nsIDOMWindow.h"
@@ -430,16 +431,100 @@ ContentParentsMemoryReporter::CollectRep
                             KIND_OTHER, UNITS_COUNT,
                             numQueuedMessages, desc, aData);
   }
 
   return NS_OK;
 }
 
 nsClassHashtable<nsStringHashKey, nsTArray<ContentParent*>>* ContentParent::sBrowserContentParents;
+
+namespace {
+
+class ScriptableCPInfo final : public nsIContentProcessInfo
+{
+public:
+  explicit ScriptableCPInfo(ContentParent* aParent)
+    : mContentParent(aParent)
+  {
+    MOZ_ASSERT(mContentParent);
+  }
+
+  NS_DECL_ISUPPORTS
+  NS_DECL_NSICONTENTPROCESSINFO
+
+  void ProcessDied()
+  {
+    mContentParent = nullptr;
+  }
+
+private:
+  ~ScriptableCPInfo()
+  {
+    MOZ_ASSERT(!mContentParent, "must call ProcessDied");
+  }
+
+  ContentParent* mContentParent;
+};
+
+NS_IMPL_ISUPPORTS(ScriptableCPInfo, nsIContentProcessInfo)
+
+NS_IMETHODIMP
+ScriptableCPInfo::GetIsAlive(bool* aIsAlive)
+{
+  *aIsAlive = mContentParent != nullptr;
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+ScriptableCPInfo::GetProcessId(int32_t* aPID)
+{
+  if (!mContentParent) {
+    *aPID = -1;
+    return NS_ERROR_NOT_INITIALIZED;
+  }
+
+  *aPID = mContentParent->Pid();
+  if (*aPID == -1) {
+    return NS_ERROR_FAILURE;
+  }
+
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+ScriptableCPInfo::GetOpener(nsIContentProcessInfo** aInfo)
+{
+  *aInfo = nullptr;
+  if (!mContentParent) {
+    return NS_ERROR_NOT_INITIALIZED;
+  }
+
+  if (ContentParent* opener = mContentParent->Opener()) {
+    nsCOMPtr<nsIContentProcessInfo> info = opener->ScriptableHelper();
+    info.forget(aInfo);
+  }
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+ScriptableCPInfo::GetMessageManager(nsIMessageSender** aMessenger)
+{
+  *aMessenger = nullptr;
+  if (!mContentParent) {
+    return NS_ERROR_NOT_INITIALIZED;
+  }
+
+  nsCOMPtr<nsIMessageSender> manager = mContentParent->GetMessageManager();
+  manager.forget(aMessenger);
+  return NS_OK;
+}
+
+} // anonymous namespace
+
 nsTArray<ContentParent*>* ContentParent::sPrivateContent;
 StaticAutoPtr<LinkedList<ContentParent> > ContentParent::sContentParents;
 #if defined(XP_LINUX) && defined(MOZ_CONTENT_SANDBOX)
 UniquePtr<SandboxBrokerPolicyFactory> ContentParent::sSandboxBrokerPolicyFactory;
 #endif
 
 // This is true when subprocess launching is enabled.  This is the
 // case between StartUp() and ShutDown() or JoinAllSubprocesses().
@@ -692,47 +777,74 @@ ContentParent::RandomSelect(const nsTArr
 }
 
 /*static*/ already_AddRefed<ContentParent>
 ContentParent::GetNewOrUsedBrowserProcess(const nsAString& aRemoteType,
                                           ProcessPriority aPriority,
                                           ContentParent* aOpener)
 {
   nsTArray<ContentParent*>& contentParents = GetOrCreatePool(aRemoteType);
-
   uint32_t maxContentParents = GetMaxProcessCount(aRemoteType);
 
-  RefPtr<ContentParent> p;
-  if (contentParents.Length() >= maxContentParents) {
+  if (aRemoteType.EqualsLiteral(LARGE_ALLOCATION_REMOTE_TYPE)) {
     // We never want to re-use Large-Allocation processes.
-    if (aRemoteType.EqualsLiteral(LARGE_ALLOCATION_REMOTE_TYPE)) {
+    if (contentParents.Length() >= maxContentParents) {
       return GetNewOrUsedBrowserProcess(NS_LITERAL_STRING(DEFAULT_REMOTE_TYPE),
                                         aPriority,
                                         aOpener);
     }
-
-    if ((p = RandomSelect(contentParents, aOpener, maxContentParents))) {
+  } else {
+    nsTArray<nsIContentProcessInfo*> infos(contentParents.Length());
+    for (auto* cp : contentParents) {
+      infos.AppendElement(cp->mScriptableHelper);
+    }
+
+    nsCOMPtr<nsIContentProcessProvider> cpp =
+      do_GetService("@mozilla.org/ipc/processselector;1");
+    nsIContentProcessInfo* openerInfo = aOpener ? aOpener->mScriptableHelper.get() : nullptr;
+    int32_t index;
+    if (cpp &&
+        NS_SUCCEEDED(cpp->ProvideProcess(aRemoteType, openerInfo,
+                                         infos.Elements(), infos.Length(),
+                                         &index))) {
+      // If the provider returned an existing ContentParent, use that one.
+      if (0 <= index && static_cast<uint32_t>(index) <= maxContentParents) {
+        RefPtr<ContentParent> retval = contentParents[index];
+        return retval.forget();
+      }
+    } else {
+      // If there was a problem with the JS chooser, fall back to a random
+      // selection.
+      NS_WARNING("nsIContentProcessProvider failed to return a process");
+      RefPtr<ContentParent> random;
+      if (contentParents.Length() >= maxContentParents &&
+          (random = RandomSelect(contentParents, aOpener, maxContentParents))) {
+        return random.forget();
+      }
+    }
+
+    // Try to take the preallocated process only for the default process type.
+    RefPtr<ContentParent> p;
+    if (aRemoteType.EqualsLiteral(DEFAULT_REMOTE_TYPE) &&
+        (p = PreallocatedProcessManager::Take())) {
+      // For pre-allocated process we have not set the opener yet.
+      p->mOpener = aOpener;
+      contentParents.AppendElement(p);
       return p.forget();
     }
   }
 
-  // Try to take the preallocated process only for the default process type.
-  if (aRemoteType.Equals(NS_LITERAL_STRING(DEFAULT_REMOTE_TYPE)) &&
-      (p = PreallocatedProcessManager::Take())) {
-    // For pre-allocated process we have not set the opener yet.
-    p->mOpener = aOpener;
-  } else {
-    p = new ContentParent(aOpener, aRemoteType);
-
-    if (!p->LaunchSubprocess(aPriority)) {
-      return nullptr;
-    }
-
-    p->Init();
-  }
+  // Create a new process from scratch.
+  RefPtr<ContentParent> p = new ContentParent(aOpener, aRemoteType);
+
+  if (!p->LaunchSubprocess(aPriority)) {
+    return nullptr;
+  }
+
+  p->Init();
 
   contentParents.AppendElement(p);
   return p.forget();
 }
 
 /*static*/ ProcessPriority
 ContentParent::GetInitialProcessPriority(Element* aFrameElement)
 {
@@ -1199,16 +1311,18 @@ ContentParent::Init()
     mIsProfilerActive = true;
 
     StartProfiler(currentProfilerParams);
   }
 #endif
 
   RefPtr<GeckoMediaPluginServiceParent> gmps(GeckoMediaPluginServiceParent::GetSingleton());
   gmps->UpdateContentProcessGMPCapabilities();
+
+  mScriptableHelper = new ScriptableCPInfo(this);
 }
 
 namespace {
 
 class RemoteWindowContext final : public nsIRemoteWindowContext
                                 , public nsIInterfaceRequestor
 {
 public:
@@ -1269,16 +1383,21 @@ ContentParent::SetPriorityAndCheckIsAliv
 #endif
 
   return true;
 }
 
 void
 ContentParent::ShutDownProcess(ShutDownMethod aMethod)
 {
+  if (mScriptableHelper) {
+    static_cast<ScriptableCPInfo*>(mScriptableHelper.get())->ProcessDied();
+    mScriptableHelper = nullptr;
+  }
+
   // Shutting down by sending a shutdown message works differently than the
   // other methods. We first call Shutdown() in the child. After the child is
   // ready, it calls FinishShutdown() on us. Then we close the channel.
   if (aMethod == SEND_SHUTDOWN_MESSAGE) {
     if (mIPCOpen && !mShutdownPending && SendShutdown()) {
       mShutdownPending = true;
       // Start the force-kill timer if we haven't already.
       StartForceKillTimer();
--- a/dom/ipc/ContentParent.h
+++ b/dom/ipc/ContentParent.h
@@ -40,16 +40,17 @@
 #define DEFAULT_REMOTE_TYPE "web"
 #define FILE_REMOTE_TYPE "file"
 #define EXTENSION_REMOTE_TYPE "extension"
 
 // This must start with the DEFAULT_REMOTE_TYPE above.
 #define LARGE_ALLOCATION_REMOTE_TYPE "webLargeAllocation"
 
 class nsConsoleService;
+class nsIContentProcessInfo;
 class nsICycleCollectorLogSink;
 class nsIDumpGCAndCCLogsCallback;
 class nsITabParent;
 class nsITimer;
 class ParentIdleListener;
 class nsIWidget;
 
 namespace mozilla {
@@ -366,16 +367,20 @@ public:
   {
     return mSubprocess;
   }
 
   ContentParent* Opener() const
   {
     return mOpener;
   }
+  nsIContentProcessInfo* ScriptableHelper() const
+  {
+    return mScriptableHelper;
+  }
 
   bool NeedsPermissionsUpdate() const
   {
     return mSendPermissionUpdates;
   }
 
   /**
    * Kill our subprocess and make sure it dies.  Should only be used
@@ -1168,16 +1173,17 @@ private:
   bool mCalledClose;
   bool mCalledKillHard;
   bool mCreatedPairedMinidumps;
   bool mShutdownPending;
   bool mIPCOpen;
 
   RefPtr<nsConsoleService>  mConsoleService;
   nsConsoleService* GetConsoleService();
+  nsCOMPtr<nsIContentProcessInfo> mScriptableHelper;
 
   nsTArray<nsCOMPtr<nsIObserver>> mIdleListeners;
 
 #ifdef MOZ_X11
   // Dup of child's X socket, used to scope its resources to this
   // object instead of the child process's lifetime.
   ScopedClose mChildXSocketFdDup;
 #endif
--- a/dom/webidl/IDBDatabase.webidl
+++ b/dom/webidl/IDBDatabase.webidl
@@ -34,15 +34,15 @@ interface IDBDatabase : EventTarget {
                 attribute EventHandler       onerror;
                 attribute EventHandler       onversionchange;
 };
 
 partial interface IDBDatabase {
     [Func="mozilla::dom::IndexedDatabaseManager::ExperimentalFeaturesEnabled"]
     readonly    attribute StorageType        storage;
 
-    [Exposed=Window, Throws]
+    [Exposed=Window, Throws, UseCounter]
     IDBRequest createMutableFile (DOMString name, optional DOMString type);
 
     // this is deprecated due to renaming in the spec
-    [Exposed=Window, Throws]
+    [Exposed=Window, Throws, UseCounter]
     IDBRequest mozCreateFileHandle (DOMString name, optional DOMString type); // now createMutableFile
 };
--- a/dom/webidl/IDBMutableFile.webidl
+++ b/dom/webidl/IDBMutableFile.webidl
@@ -5,17 +5,17 @@
 
 [Exposed=(Window,System)]
 interface IDBMutableFile : EventTarget {
   readonly attribute DOMString name;
   readonly attribute DOMString type;
 
   readonly attribute IDBDatabase database;
 
-  [Throws]
+  [Throws, UseCounter]
   IDBFileHandle open(optional FileMode mode = "readonly");
 
-  [Throws]
+  [Throws, UseCounter]
   DOMRequest getFile();
 
   attribute EventHandler onabort;
   attribute EventHandler onerror;
 };
new file mode 100755
--- /dev/null
+++ b/intl/hyphenation/hyphen/NEWS
@@ -0,0 +1,106 @@
+2014-09-18 Hyphen 2.8.8:
+  - remove last coverity warning, 0 remaining
+
+2014-06-27 Hyphen 2.8.7:
+  - various clang scan-build warning fixes
+
+2012-09-13 Hyphen 2.8.6:
+  - righthyphenmin fix for 3-byte or more UTF-8
+    multibyte characters by Steven Dickson
+  - fix for fdo#43931 (removing hard hyphen hyphenation for LibreOffice)
+
+2012-07-12 Hyphen 2.8.5:
+  - fix short alloc
+
+2012-06-29 Hyphen 2.8.4:
+  - coverity warnings
+
+2011-10-10 Hyphen 2.8.3:
+  - fix NOHYPHEN
+  - fix unbalanced hyphenation of LibreOffice/OOo
+  - set default COMPOUNDHYPHENMIN=3 at hyphens and apostrophes
+  - fix VERBOSE in hyphen.c
+  - new ./example option: -n to print hyphenation vector
+
+2011-10-07 Hyphen 2.8.2:
+  - fix for explicite COMPOUNDHYPHENMIN values
+
+2011-10-06 Hyphen 2.8.1:
+  - force minimal lefthyphenmin and righthyphenmin values of the dictionary
+    (eg. righthyphenmin=3 of English dictionaries in LibreOffice/OOo,
+    also the original TeX hyphenation patterns are correct only with this
+    righthyphenmin value).
+
+2011-10-04 Hyphen 2.8:
+  - Ignore leading and ending numbers (eg. manual/field based indexes
+    in LibreOffice/OOo)
+
+  - Fix LibreOffice/OpenOffice.org hyphenation errors at apostrophes and
+    hyphens, n-dashes with default NOHYPHEN separators.
+    Eg. *o'c=lock -> o'clock.
+
+2010-12-01 Hyphen 2.7.1 bug fix release
+
+2010-11-27 Hyphen 2.7 release:
+  - The new hyphenation problem of OpenOffice.org 3.2, related to its
+    modified word breaking of words with hyphen characters, can be fixed
+    with the new NOHYPHEN feature. Also it's possible to solve the similar old
+    problem with apostrophes. More information: README.compound.
+
+  - improved English dictionaries
+
+2010-08-10 Hyphen 2.6 release:
+  - maintainance release, fix all warnings, tidy up
+    make check with VALGRIND=memcheck, etc.
+
+2010-02-23 Hyphen 2.5 release:
+  - add Unicode ligature support for correct hyphenmin calculation
+    (ff, fi, fl, St, st are 1-character, ffi and ffl are 2-character length for
+    hyphenation)
+  - fix lefthyphenmin calculation for UTF-8 encoded input
+
+  - en_US hyphenation dictionary:
+      - add OpenOffice.org patch to fix apostrophe handling
+      - add correct hyphenation for words with Unicode f-ligatures
+        (NOTE: hyphenation within ligatures is not supported yet
+        because of an implementation problem of OpenOffice.org,
+        see OOo issue 71608.)
+
+    - small patches from OpenOffice.org
+
+2008-05-01 Hyphen 2.4 release:
+  - compound word hyphenation support by recursive pattern matching
+    based on two hyphenation pattern sets, see README.compound.
+    Especially useful for languages with arbitrary number of compounds (Danish,
+    Dutch, Finnish, German, Hungarian, Icelandic, Norwegian, Swedish etc.).
+
+  - new dictionary parameters (minimal character numbers for hyph. distances):
+    LEFTHYPHENMIN: minimal hyphenation distance from the left end of the word
+    RIGHTHYPHENMIN: minimal hyphenation distance from the right end of the word
+    COMPOUNDLEFTHYPHENMIN: min. hyph. dist. from the left compound word boundary
+    COMPOUNDRIGHTHYPHENMIN: min. hyph. dist. from the right comp. word boundary
+
+  - new API function: hnj_hyphen_hyphenate3() (like hyphenate2(), but
+    with hyphenmin options)
+
+en_US hyphenation patterns:
+
+  - extended hyph_en_US.dic with TugBoat hyphenation log (fix thousand 
+    incompletely or badly hyphenated words, for example acad-e-my, acro-nym,
+    acryl-amide, adren-a-line, aero-space, am-phet-a-mine, anom-aly etc.)
+
+  - fixed hyph_en_US.dic: set the right default hyphenation distance of
+    the original TeX hyphenation patterns:
+    LEFTHYPHENMIN 2
+    RIGHTHYPHENMIN 3 (not 2!)
+    It is not only a typographical issue. It seems, TeX hyphenation
+    patterns are right only with these settings, for example,
+    the bad "anoma-ly" is restricted in TeX only by the default
+    \righthyphenmin=3 (but not restricted in OpenOffice.org, until now).
+
+  - documentation (README_hyph_en_US.dic)
+
+  - fixes for automake configuration, compiling and checking, see ChangeLog
+
+2008-02-19: Hyphen 2.3.1 release:
+  - fix obsolete API function hnj_hyphen_hyphenate()
--- a/js/src/frontend/NameAnalysisTypes.h
+++ b/js/src/frontend/NameAnalysisTypes.h
@@ -73,16 +73,17 @@ enum class DeclarationKind : uint8_t
     FormalParameter,
     CoverArrowParameter,
     Var,
     ForOfVar,
     Let,
     Const,
     Import,
     BodyLevelFunction,
+    ModuleBodyLevelFunction,
     LexicalFunction,
     VarForAnnexBLexicalFunction,
     SimpleCatchParameter,
     CatchParameter
 };
 
 static inline BindingKind
 DeclarationKindToBindingKind(DeclarationKind kind)
@@ -90,16 +91,17 @@ DeclarationKindToBindingKind(Declaration
     switch (kind) {
       case DeclarationKind::PositionalFormalParameter:
       case DeclarationKind::FormalParameter:
       case DeclarationKind::CoverArrowParameter:
         return BindingKind::FormalParameter;
 
       case DeclarationKind::Var:
       case DeclarationKind::BodyLevelFunction:
+      case DeclarationKind::ModuleBodyLevelFunction:
       case DeclarationKind::VarForAnnexBLexicalFunction:
       case DeclarationKind::ForOfVar:
         return BindingKind::Var;
 
       case DeclarationKind::Let:
       case DeclarationKind::LexicalFunction:
       case DeclarationKind::SimpleCatchParameter:
       case DeclarationKind::CatchParameter:
--- a/js/src/frontend/Parser.cpp
+++ b/js/src/frontend/Parser.cpp
@@ -112,16 +112,17 @@ DeclarationKindString(DeclarationKind ki
         return "var";
       case DeclarationKind::Let:
         return "let";
       case DeclarationKind::Const:
         return "const";
       case DeclarationKind::Import:
         return "import";
       case DeclarationKind::BodyLevelFunction:
+      case DeclarationKind::ModuleBodyLevelFunction:
       case DeclarationKind::LexicalFunction:
         return "function";
       case DeclarationKind::VarForAnnexBLexicalFunction:
         return "annex b var";
       case DeclarationKind::ForOfVar:
         return "var in for-of";
       case DeclarationKind::SimpleCatchParameter:
       case DeclarationKind::CatchParameter:
@@ -1374,16 +1375,34 @@ Parser<ParseHandler>::noteDeclaredName(H
         if (redeclaredKind) {
             reportRedeclaration(name, *redeclaredKind, pos, prevPos);
             return false;
         }
 
         break;
       }
 
+      case DeclarationKind::ModuleBodyLevelFunction: {
+          MOZ_ASSERT(pc->atModuleLevel());
+
+          AddDeclaredNamePtr p = pc->varScope().lookupDeclaredNameForAdd(name);
+          if (p) {
+              reportRedeclaration(name, p->value()->kind(), pos, p->value()->pos());
+              return false;
+          }
+
+          if (!pc->varScope().addDeclaredName(pc, p, name, kind, pos.begin))
+              return false;
+
+          // Body-level functions in modules are always closed over.
+          pc->varScope().lookupDeclaredName(name)->value()->setClosedOver();
+
+          break;
+      }
+
       case DeclarationKind::FormalParameter: {
         // It is an early error if any non-positional formal parameter name
         // (e.g., destructuring formal parameter) is duplicated.
 
         AddDeclaredNamePtr p = pc->functionScope().lookupDeclaredNameForAdd(name);
         if (p) {
             error(JSMSG_BAD_DUP_ARGS);
             return false;
@@ -3713,22 +3732,21 @@ Parser<ParseHandler>::functionStmt(Yield
             // the start of the block.
             if (!tryDeclareVarForAnnexBLexicalFunction(name, pos().begin, &tryAnnexB))
                 return null();
         }
 
         if (!noteDeclaredName(name, DeclarationKind::LexicalFunction, pos()))
             return null();
     } else {
-        if (!noteDeclaredName(name, DeclarationKind::BodyLevelFunction, pos()))
-            return null();
-
-        // Body-level functions in modules are always closed over.
-        if (pc->atModuleLevel())
-            pc->varScope().lookupDeclaredName(name)->value()->setClosedOver();
+        DeclarationKind kind = pc->atModuleLevel()
+                               ? DeclarationKind::ModuleBodyLevelFunction
+                               : DeclarationKind::BodyLevelFunction;
+        if (!noteDeclaredName(name, kind, pos()))
+            return null();
     }
 
     Node pn = handler.newFunctionStatement();
     if (!pn)
         return null();
 
     YieldHandling newYieldHandling = GetYieldHandling(generatorKind, asyncKind);
     return functionDefinition(pn, InAllowed, newYieldHandling, name, Statement, generatorKind,
--- a/js/src/jit-test/modules/export-default-async-asi.js
+++ b/js/src/jit-test/modules/export-default-async-asi.js
@@ -1,4 +1,2 @@
-function async() { return 42; } // overwritten by subsequent declaration
-
 export default async // ASI occurs here due to the [no LineTerminator here] restriction on default-exporting an async function
 function async() { return 17; }
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/modules/function-redeclaration.js
@@ -0,0 +1,94 @@
+load(libdir + "asserts.js");
+
+var functionDeclarations = [
+    "function f(){}",
+    "function* f(){}",
+    "async function f(){}",
+];
+
+var varDeclarations = [
+    "var f",
+    "{ var f; }",
+    "for (var f in null);",
+    "for (var f of null);",
+    "for (var f; ;);",
+];
+
+var lexicalDeclarations = [
+    "let f;",
+    "const f = 0;",
+    "class f {};",
+];
+
+var imports = [
+    "import f from '';",
+    "import f, {} from '';",
+    "import d, {f} from '';",
+    "import d, {f as f} from '';",
+    "import d, {foo as f} from '';",
+    "import f, * as d from '';",
+    "import d, * as f from '';",
+    "import {f} from '';",
+    "import {f as f} from '';",
+    "import {foo as f} from '';",
+    "import* as f from '';",
+];
+
+var exports = [
+    "export var f;",
+    ...functionDeclarations.map(fn => `export ${fn};`),
+    ...lexicalDeclarations.map(ld => `export ${ld};`),
+    ...functionDeclarations.map(fn => `export default ${fn};`),
+    "export default class f {};",
+];
+
+var redeclarations = [
+    ...functionDeclarations,
+    ...varDeclarations,
+    ...lexicalDeclarations,
+    ...imports,
+    ...exports,
+];
+
+var noredeclarations = [
+    ...functionDeclarations.map(fn => `{ ${fn} }`),
+    ...lexicalDeclarations.map(ld => `{ ${ld} }`),
+    ...["let", "const"].map(ld => `for (${ld} f in null);`),
+    ...["let", "const"].map(ld => `for (${ld} f of null);`),
+    ...["let", "const"].map(ld => `for (${ld} f = 0; ;);`),
+    "export {f};",
+    "export {f as f};",
+    "export {foo as f}; var foo;",
+    "export {f} from '';",
+    "export {f as f} from '';",
+    "export {foo as f} from '';",
+];
+
+for (var decl of functionDeclarations) {
+    for (var redecl of redeclarations) {
+        assertThrowsInstanceOf(() => {
+            parseModule(`
+                ${decl}
+                ${redecl}
+            `);
+        }, SyntaxError);
+
+        assertThrowsInstanceOf(() => {
+            parseModule(`
+                ${redecl}
+                ${decl}
+            `);
+        }, SyntaxError);
+    }
+
+    for (var redecl of noredeclarations) {
+        parseModule(`
+            ${decl}
+            ${redecl}
+        `);
+        parseModule(`
+            ${redecl}
+            ${decl}
+        `);
+    }
+}
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/wasm/import-export-sigs.js
@@ -0,0 +1,88 @@
+// Tests that function imports and function exports descriptors have
+// signatures, in the test mode only, for fuzzers.
+
+var module = new WebAssembly.Module(wasmTextToBinary(`(module
+  (import $vv "env" "v_v")
+  (export "v_v" $vv)
+
+  (import $vi "env" "v_i" (param i32))
+  (export "v_i" $vi)
+
+  (import $vI "env" "v_I" (param i64))
+  (export "v_I" $vI)
+
+  (import $vf "env" "v_f" (param f32))
+  (export "v_f" $vf)
+
+  (import $mem "env" "memory" (memory 0))
+  (export "mem" (memory $mem))
+
+  (import $vd "env" "v_d" (param f64))
+  (export "v_d" $vd)
+
+  (import $vfd "env" "v_fd" (param f32) (param f64))
+  (export "v_fd" $vfd)
+
+  (import $vIfifd "env" "v_Ififd" (param i64) (param f32) (param i32) (param f32) (param f64))
+  (export "v_Ififd" $vIfifd)
+
+  (import $iv "env" "i_v" (result i32))
+  (export "i_v" $iv)
+
+  (import $Ii "env" "I_i" (result i64) (param i32))
+  (export "I_i" $Ii)
+
+  (import $table "env" "table" (table 0 anyfunc))
+  (export "table" (table $table))
+
+  (import $fd "env" "f_d" (result f32) (param f64))
+  (export "f_d" $fd)
+
+  (import $dffd "env" "d_ffd" (result f64) (param f32) (param f32) (param f64))
+  (export "d_ffd" $dffd)
+)`));
+
+for (let desc of WebAssembly.Module.imports(module)) {
+    assertEq(typeof desc.signature, 'undefined');
+}
+for (let desc of WebAssembly.Module.exports(module)) {
+    assertEq(typeof desc.signature, 'undefined');
+}
+
+setJitCompilerOption('wasm.test-mode', 1);
+
+function shortToType(s) {
+    switch (s) {
+        case 'v': return "";
+        case 'i': return "i32";
+        case 'I': return "i64";
+        case 'f': return "f32";
+        case 'd': return "f64";
+    }
+    throw new Error("unexpected shorthand type");
+}
+
+function expectedSignature(name) {
+    let [ret, args] = name.split('_');
+
+    args = args.split('').map(shortToType).join(', ');
+    ret = shortToType(ret);
+
+    return `(${args}) -> (${ret})`;
+}
+
+for (let desc of WebAssembly.Module.imports(module)) {
+    if (desc.kind !== 'function') {
+        assertEq(typeof desc.signature, 'undefined');
+    } else {
+        assertEq(desc.signature, expectedSignature(desc.name))
+    }
+}
+
+for (let desc of WebAssembly.Module.exports(module)) {
+    if (desc.kind !== 'function') {
+        assertEq(typeof desc.signature, 'undefined');
+    } else {
+        assertEq(desc.signature, expectedSignature(desc.name))
+    }
+}
--- a/js/src/tests/test262-intl-extras.js
+++ b/js/src/tests/test262-intl-extras.js
@@ -1,7 +1,14 @@
 // This Source Code Form is subject to the terms of the Mozilla Public
 // License, v. 2.0. If a copy of the MPL was not distributed with this
 // file, You can obtain one at http://mozilla.org/MPL/2.0/.
 
 // Call the shell helper to add experimental features to the Intl object.
-if (typeof addIntlExtras === "function")
-    addIntlExtras(Intl);
+if (typeof addIntlExtras === "function") {
+    let intlExtras = {};
+    addIntlExtras(intlExtras);
+
+    Object.defineProperty(Intl, "PluralRules", {
+        value: intlExtras.PluralRules,
+        writable: true, enumerable: false, configurable: true
+    });
+}
--- a/js/src/tests/test262/intl402/PluralRules/shell.js
+++ b/js/src/tests/test262/intl402/PluralRules/shell.js
@@ -1,8 +1,15 @@
 // file: test262-intl-extras.js
 // This Source Code Form is subject to the terms of the Mozilla Public
 // License, v. 2.0. If a copy of the MPL was not distributed with this
 // file, You can obtain one at http://mozilla.org/MPL/2.0/.
 
 // Call the shell helper to add experimental features to the Intl object.
-if (typeof addIntlExtras === "function")
-    addIntlExtras(Intl);
+if (typeof addIntlExtras === "function") {
+    let intlExtras = {};
+    addIntlExtras(intlExtras);
+
+    Object.defineProperty(Intl, "PluralRules", {
+        value: intlExtras.PluralRules,
+        writable: true, enumerable: false, configurable: true
+    });
+}
--- a/js/src/vm/Interpreter.cpp
+++ b/js/src/vm/Interpreter.cpp
@@ -1495,18 +1495,29 @@ SetObjectElementOperation(JSContext* cx,
         int32_t i = JSID_TO_INT(id);
         if ((uint32_t)i >= length) {
             // Annotate script if provided with information (e.g. baseline)
             if (script && script->hasBaselineScript() && IsSetElemPC(pc))
                 script->baselineScript()->noteHasDenseAdd(script->pcToOffset(pc));
         }
     }
 
-    if (obj->isNative() && !JSID_IS_INT(id) && !JSObject::setHadElementsAccess(cx, obj))
-        return false;
+    // Set the HadElementsAccess flag on the object if needed. This flag is
+    // used to do more eager dictionary-mode conversion for objects that are
+    // used as hashmaps. Set this flag only for objects with many properties,
+    // to avoid unnecessary Shape changes.
+    if (obj->isNative() &&
+        JSID_IS_ATOM(id) &&
+        !obj->as<NativeObject>().inDictionaryMode() &&
+        !obj->hadElementsAccess() &&
+        obj->as<NativeObject>().slotSpan() > PropertyTree::MAX_HEIGHT_WITH_ELEMENTS_ACCESS / 3)
+    {
+        if (!JSObject::setHadElementsAccess(cx, obj))
+            return false;
+    }
 
     ObjectOpResult result;
     return SetProperty(cx, obj, id, value, receiver, result) &&
            result.checkStrictErrorOrWarning(cx, obj, id, strict);
 }
 
 /*
  * Get the innermost enclosing function that has a 'this' binding.
--- a/js/src/wasm/WasmJS.cpp
+++ b/js/src/wasm/WasmJS.cpp
@@ -23,16 +23,17 @@
 #include "mozilla/RangedPtr.h"
 
 #include "jsprf.h"
 
 #include "builtin/Promise.h"
 #include "jit/JitOptions.h"
 #include "vm/Interpreter.h"
 #include "vm/String.h"
+#include "vm/StringBuffer.h"
 #include "wasm/WasmCompile.h"
 #include "wasm/WasmInstance.h"
 #include "wasm/WasmModule.h"
 #include "wasm/WasmSignalHandlers.h"
 #include "wasm/WasmValidate.h"
 
 #include "jsobjinlines.h"
 
@@ -549,18 +550,19 @@ GetModuleArg(JSContext* cx, CallArgs arg
     return true;
 }
 
 struct KindNames
 {
     RootedPropertyName kind;
     RootedPropertyName table;
     RootedPropertyName memory;
+    RootedPropertyName signature;
 
-    explicit KindNames(JSContext* cx) : kind(cx), table(cx), memory(cx) {}
+    explicit KindNames(JSContext* cx) : kind(cx), table(cx), memory(cx), signature(cx) {}
 };
 
 static bool
 InitKindNames(JSContext* cx, KindNames* names)
 {
     JSAtom* kind = Atomize(cx, "kind", strlen("kind"));
     if (!kind)
         return false;
@@ -571,16 +573,21 @@ InitKindNames(JSContext* cx, KindNames* 
         return false;
     names->table = table->asPropertyName();
 
     JSAtom* memory = Atomize(cx, "memory", strlen("memory"));
     if (!memory)
         return false;
     names->memory = memory->asPropertyName();
 
+    JSAtom* signature = Atomize(cx, "signature", strlen("signature"));
+    if (!signature)
+        return false;
+    names->signature = signature->asPropertyName();
+
     return true;
 }
 
 static JSString*
 KindToString(JSContext* cx, const KindNames& names, DefinitionKind kind)
 {
     switch (kind) {
       case DefinitionKind::Function:
@@ -592,16 +599,50 @@ KindToString(JSContext* cx, const KindNa
       case DefinitionKind::Global:
         return cx->names().global;
     }
 
     MOZ_CRASH("invalid kind");
 }
 
 static JSString*
+SigToString(JSContext* cx, const Sig& sig)
+{
+    StringBuffer buf(cx);
+    if (!buf.append('('))
+        return nullptr;
+
+    bool first = true;
+    for (ValType arg : sig.args()) {
+        if (!first && !buf.append(", ", strlen(", ")))
+            return nullptr;
+
+        const char* argStr = ToCString(arg);
+        if (!buf.append(argStr, strlen(argStr)))
+            return nullptr;
+
+        first = false;
+    }
+
+    if (!buf.append(") -> (", strlen(") -> (")))
+        return nullptr;
+
+    if (sig.ret() != ExprType::Void) {
+        const char* retStr = ToCString(sig.ret());
+        if (!buf.append(retStr, strlen(retStr)))
+            return nullptr;
+    }
+
+    if (!buf.append(')'))
+        return nullptr;
+
+    return buf.finishString();
+}
+
+static JSString*
 UTF8CharsToString(JSContext* cx, const char* chars)
 {
     return NewStringCopyUTF8Z<CanGC>(cx, JS::ConstUTF8CharsZ(chars, strlen(chars)));
 }
 
 /* static */ bool
 WasmModuleObject::imports(JSContext* cx, unsigned argc, Value* vp)
 {
@@ -614,16 +655,17 @@ WasmModuleObject::imports(JSContext* cx,
     KindNames names(cx);
     if (!InitKindNames(cx, &names))
         return false;
 
     AutoValueVector elems(cx);
     if (!elems.reserve(module->imports().length()))
         return false;
 
+    size_t numFuncImport = 0;
     for (const Import& import : module->imports()) {
         Rooted<IdValueVector> props(cx, IdValueVector(cx));
         if (!props.reserve(3))
             return false;
 
         JSString* moduleStr = UTF8CharsToString(cx, import.module.get());
         if (!moduleStr)
             return false;
@@ -634,16 +676,24 @@ WasmModuleObject::imports(JSContext* cx,
             return false;
         props.infallibleAppend(IdValuePair(NameToId(cx->names().name), StringValue(nameStr)));
 
         JSString* kindStr = KindToString(cx, names, import.kind);
         if (!kindStr)
             return false;
         props.infallibleAppend(IdValuePair(NameToId(names.kind), StringValue(kindStr)));
 
+        if (JitOptions.wasmTestMode && import.kind == DefinitionKind::Function) {
+            JSString* sigStr = SigToString(cx, module->metadata().funcImports[numFuncImport++].sig());
+            if (!sigStr)
+                return false;
+            if (!props.append(IdValuePair(NameToId(names.signature), StringValue(sigStr))))
+                return false;
+        }
+
         JSObject* obj = ObjectGroup::newPlainObject(cx, props.begin(), props.length(), GenericObject);
         if (!obj)
             return false;
 
         elems.infallibleAppend(ObjectValue(*obj));
     }
 
     JSObject* arr = NewDenseCopiedArray(cx, elems.length(), elems.begin());
@@ -666,31 +716,40 @@ WasmModuleObject::exports(JSContext* cx,
     KindNames names(cx);
     if (!InitKindNames(cx, &names))
         return false;
 
     AutoValueVector elems(cx);
     if (!elems.reserve(module->exports().length()))
         return false;
 
+    size_t numFuncExport = 0;
     for (const Export& exp : module->exports()) {
         Rooted<IdValueVector> props(cx, IdValueVector(cx));
         if (!props.reserve(2))
             return false;
 
         JSString* nameStr = UTF8CharsToString(cx, exp.fieldName());
         if (!nameStr)
             return false;
         props.infallibleAppend(IdValuePair(NameToId(cx->names().name), StringValue(nameStr)));
 
         JSString* kindStr = KindToString(cx, names, exp.kind());
         if (!kindStr)
             return false;
         props.infallibleAppend(IdValuePair(NameToId(names.kind), StringValue(kindStr)));
 
+        if (JitOptions.wasmTestMode && exp.kind() == DefinitionKind::Function) {
+            JSString* sigStr = SigToString(cx, module->metadata().funcExports[numFuncExport++].sig());
+            if (!sigStr)
+                return false;
+            if (!props.append(IdValuePair(NameToId(names.signature), StringValue(sigStr))))
+                return false;
+        }
+
         JSObject* obj = ObjectGroup::newPlainObject(cx, props.begin(), props.length(), GenericObject);
         if (!obj)
             return false;
 
         elems.infallibleAppend(ObjectValue(*obj));
     }
 
     JSObject* arr = NewDenseCopiedArray(cx, elems.length(), elems.begin());
--- a/layout/base/crashtests/1338772-1.html
+++ b/layout/base/crashtests/1338772-1.html
@@ -16,15 +16,27 @@ function loadHandler() {
     outer.remove();
     document.documentElement.removeAttribute("class");
   };
 
   // Trigger the resize handler:
   inner.height = "5px";
   inner.offsetTop;
 }
+
+// This function is a hack to avoid sporadic test-failures with...
+//   "...timed out waiting for reftest-wait to be removed".
+// Occasionally, it seems this test loses a race condition of some sort, and
+// its resize handler isn't invoked. When that happens (and specifically, when
+// the test runs for longer than 500ms), we clear reftest-wait and call the
+// run a "pass" (which is kind of valid, because we didn't crash!) and move on.
+function setupFailsafe() {
+  setTimeout(() => {
+    document.documentElement.removeAttribute("class");
+  }, 500);
+}
 </script>
-<body>
+<body onload="setupFailsafe()">
   <iframe id="outer"
           src="data:text/html,<html><body>"
           onload="loadHandler()">
   </iframe>
 </body>
--- a/media/libcubeb/README_MOZILLA
+++ b/media/libcubeb/README_MOZILLA
@@ -1,8 +1,8 @@
 The source from this directory was copied from the cubeb 
 git repository using the update.sh script.  The only changes
 made were those applied by update.sh and the addition of
 Makefile.in build files for the Mozilla build system.
 
 The cubeb git repository is: git://github.com/kinetiknz/cubeb.git
 
-The git commit ID used was 25b593fa59d0c284ff2de54b10db927d48579f5e.
+The git commit ID used was 25b593fa59d0c284ff2de54b10db927d48579f5e (2017-02-23 14:05:03 +0200)
--- a/media/libcubeb/update.sh
+++ b/media/libcubeb/update.sh
@@ -43,22 +43,23 @@ cp $1/test/test_resampler.cpp gtest
 cp $1/test/test_ring_array.cpp gtest
 cp $1/test/test_sanity.cpp gtest
 cp $1/test/test_tone.cpp gtest
 cp $1/test/test_utils.cpp gtest
 cp $1/test/test_mixer.cpp gtest
 
 if [ -d $1/.git ]; then
   rev=$(cd $1 && git rev-parse --verify HEAD)
+  date=$(cd $1 && git show -s --format=%ci HEAD)
   dirty=$(cd $1 && git diff-index --name-only HEAD)
 fi
 
 if [ -n "$rev" ]; then
   version=$rev
   if [ -n "$dirty" ]; then
     version=$version-dirty
     echo "WARNING: updating from a dirty git repository."
   fi
-  sed -i.bak -e "/The git commit ID used was/ s/[0-9a-f]\{40\}\(-dirty\)\{0,1\}\./$version./" README_MOZILLA
+  sed -i.bak -e "/The git commit ID used was/ s/[0-9a-f]\{40\}\(-dirty\)\{0,1\} .\{1,100\}/$version ($date)/" README_MOZILLA
   rm README_MOZILLA.bak
 else
   echo "Remember to update README_MOZILLA with the version details."
 fi
--- a/mobile/android/base/java/org/mozilla/gecko/FilePicker.java
+++ b/mobile/android/base/java/org/mozilla/gecko/FilePicker.java
@@ -1,19 +1,21 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 package org.mozilla.gecko;
 
 import org.mozilla.gecko.GeckoAppShell;
+import org.mozilla.gecko.permissions.Permissions;
 import org.mozilla.gecko.util.BundleEventListener;
 import org.mozilla.gecko.util.EventCallback;
 import org.mozilla.gecko.util.GeckoBundle;
 
+import android.Manifest;
 import android.content.ComponentName;
 import android.content.Context;
 import android.content.Intent;
 import android.content.pm.PackageManager;
 import android.content.pm.ResolveInfo;
 import android.net.Uri;
 import android.os.Environment;
 import android.os.Parcelable;
@@ -56,25 +58,52 @@ public class FilePicker implements Bundl
             final String title = message.getString("title", "");
 
             if ("mimeType".equals(mode)) {
                 mimeType = message.getString("mimeType", "");
             } else if ("extension".equals(mode)) {
                 mimeType = GeckoAppShell.getMimeTypeFromExtensions(message.getString("extensions", ""));
             }
 
-            showFilePickerAsync(title, mimeType, new ResultHandler() {
-                @Override
-                public void gotFile(final String filename) {
-                    callback.sendSuccess(filename);
-                }
-            }, tabId);
+            final String[] requiredPermission = getPermissionsForMimeType(mimeType);
+            final String finalMimeType = mimeType;
+            // Use activity context cause we want to prompt for runtime permission. (bug 1337692)
+            Permissions.from(GeckoAppShell.getGeckoInterface().getActivity())
+                    .withPermissions(requiredPermission)
+                    .andFallback(new Runnable() {
+                        @Override
+                        public void run() {
+                            callback.sendError(null);
+                        }
+                    })
+                    .run(new Runnable() {
+                        @Override
+                        public void run() {
+                            showFilePickerAsync(title, finalMimeType, new ResultHandler() {
+                                @Override
+                                public void gotFile(final String filename) {
+                                    callback.sendSuccess(filename);
+                                }
+                            }, tabId);
+                        }
+                    });
         }
     }
 
+    private static String[] getPermissionsForMimeType(final String mimeType) {
+        if (mimeType.startsWith("audio/")) {
+            return new String[] { Manifest.permission.RECORD_AUDIO };
+        } else if (mimeType.startsWith("image/")) {
+            return new String[] { Manifest.permission.CAMERA };
+        } else if (mimeType.startsWith("video/")) {
+            return new String[] { Manifest.permission.CAMERA };
+        }
+        return new String[] { Manifest.permission.CAMERA, Manifest.permission.RECORD_AUDIO };
+    }
+
     private void addActivities(Intent intent, HashMap<String, Intent> intents, HashMap<String, Intent> filters) {
         PackageManager pm = context.getPackageManager();
         List<ResolveInfo> lri = pm.queryIntentActivities(intent, 0);
         for (ResolveInfo ri : lri) {
             ComponentName cn = new ComponentName(ri.activityInfo.applicationInfo.packageName, ri.activityInfo.name);
             if (filters != null && !filters.containsKey(cn.toString())) {
                 Intent rintent = new Intent(intent);
                 rintent.setComponent(cn);
--- a/mobile/android/base/java/org/mozilla/gecko/PresentationView.java
+++ b/mobile/android/base/java/org/mozilla/gecko/PresentationView.java
@@ -12,16 +12,16 @@ import org.mozilla.gecko.GeckoView;
 import org.mozilla.gecko.ScreenManagerHelper;
 
 import android.content.Context;
 import android.util.AttributeSet;
 import android.util.DisplayMetrics;
 
 public class PresentationView extends GeckoView {
     private static final String LOGTAG = "PresentationView";
-    private static final String presentationViewURI = "chrome://browser/content/PresentationView.xul";
+    private static final String PRESENTATION_VIEW_URI = "chrome://browser/content/PresentationView.xul";
 
     public PresentationView(Context context, String deviceId, int screenId) {
         super(context);
-        this.chromeURI = presentationViewURI + "#" + deviceId;
-        this.screenId = screenId;
+        this.mChromeUri = PRESENTATION_VIEW_URI + "#" + deviceId;
+        this.mScreenId = screenId;
     }
 }
--- a/mobile/android/chrome/content/GeckoViewContent.js
+++ b/mobile/android/chrome/content/GeckoViewContent.js
@@ -2,40 +2,39 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 var { classes: Cc, interfaces: Ci, utils: Cu } = Components;
 
 var dump = Cu.import("resource://gre/modules/AndroidLog.jsm", {}).AndroidLog.d.bind(null, "ViewContent");
 
-var DEBUG = false;
+function debug(aMsg) {
+  // dump(aMsg);
+}
 
 // This is copied from desktop's tab-content.js. See bug 1153485 about sharing this code somehow.
 var DOMTitleChangedListener = {
   init: function() {
     addEventListener("DOMTitleChanged", this, false);
   },
 
-  receiveMessage: function(message) {
-    if (DEBUG) {
-      dump("receiveMessage " + message.name);
-    }
+  receiveMessage: function(aMsg) {
+    debug("receiveMessage " + aMsg.name);
   },
 
   handleEvent: function(aEvent) {
     if (aEvent.originalTarget.defaultView != content) {
       return;
     }
 
-    if (DEBUG) {
-      dump("handleEvent " + aEvent.type);
-    }
+    debug("handleEvent " + aEvent.type);
 
     switch (aEvent.type) {
       case "DOMTitleChanged":
-        sendAsyncMessage("GeckoView:DOMTitleChanged", { title: content.document.title });
+        sendAsyncMessage("GeckoView:DOMTitleChanged",
+                         { title: content.document.title });
         break;
     }
   },
 };
 
 DOMTitleChangedListener.init();
--- a/mobile/android/chrome/content/geckoview.js
+++ b/mobile/android/chrome/content/geckoview.js
@@ -24,29 +24,30 @@ var dump = Cu.import("resource://gre/mod
 // and remove by calling
 //   remove(<type name>)
 var ModuleManager = {
   init: function() {
     this.browser = document.getElementById("content");
     this.modules = {};
   },
 
-  add: function(resource, type, ...args) {
-    this.remove(type);
+  add: function(aResource, aType, ...aArgs) {
+    this.remove(aType);
     let scope = {};
-    Cu.import(resource, scope);
-    this.modules[type] = new scope[type](
-      window, this.browser, WindowEventDispatcher, ...args);
+    Cu.import(aResource, scope);
+    this.modules[aType] = new scope[aType](
+      window, this.browser, WindowEventDispatcher, ...aArgs
+    );
   },
 
-  remove: function(type) {
-    if (!(type in this.modules)) {
+  remove: function(aType) {
+    if (!(aType in this.modules)) {
       return;
     }
-    delete this.modules[type];
+    delete this.modules[aType];
   }
 };
 
 function startup() {
   ModuleManager.init();
   ModuleManager.add("resource://gre/modules/GeckoViewSettings.jsm",
                     "GeckoViewSettings");
   ModuleManager.add("resource://gre/modules/GeckoViewContent.jsm",
--- a/mobile/android/geckoview/src/main/java/org/mozilla/gecko/GeckoView.java
+++ b/mobile/android/geckoview/src/main/java/org/mozilla/gecko/GeckoView.java
@@ -38,38 +38,38 @@ import android.view.inputmethod.InputCon
 public class GeckoView extends LayerView
     implements ContextGetter {
 
     private static final String DEFAULT_SHARED_PREFERENCES_FILE = "GeckoView";
     private static final String LOGTAG = "GeckoView";
 
     private static final boolean DEBUG = false;
 
-    private final EventDispatcher eventDispatcher = new EventDispatcher();
+    private final EventDispatcher mEventDispatcher = new EventDispatcher();
 
     private ChromeDelegate mChromeDelegate;
     /* package */ ContentListener mContentListener;
     /* package */ NavigationListener mNavigationListener;
     /* package */ ProgressListener mProgressListener;
     private InputConnectionListener mInputConnectionListener;
 
     private GeckoViewSettings mSettings;
 
-    protected boolean onAttachedToWindowCalled;
-    protected String chromeURI;
-    protected int screenId = 0; // default to the primary screen
+    protected boolean mOnAttachedToWindowCalled;
+    protected String mChromeUri;
+    protected int mScreenId = 0; // default to the primary screen
 
     @WrapForJNI(dispatchTo = "proxy")
     protected static final class Window extends JNIObject {
         @WrapForJNI(skip = true)
         /* package */ Window() {}
 
         static native void open(Window instance, GeckoView view,
                                 Object compositor, EventDispatcher dispatcher,
-                                String chromeURI, GeckoBundle settings,
+                                String chromeUri, GeckoBundle settings,
                                 int screenId);
 
         @Override protected native void disposeNative();
         native void close();
         native void reattach(GeckoView view, Object compositor, EventDispatcher dispatcher);
         native void loadUri(String uri, int flags);
     }
 
@@ -137,17 +137,17 @@ public class GeckoView extends LayerView
 
             if ("GeckoView:DOMTitleChanged".equals(event)) {
                 if (mContentListener != null) {
                     mContentListener.onTitleChanged(GeckoView.this, message.getString("title"));
                 }
             } else if ("GeckoView:LocationChange".equals(event)) {
                 if (mNavigationListener == null) {
                     // We shouldn't be getting this event.
-                    eventDispatcher.dispatch("GeckoViewNavigation:Inactive", null);
+                    mEventDispatcher.dispatch("GeckoViewNavigation:Inactive", null);
                 } else {
                     mNavigationListener.onLocationChange(GeckoView.this, message.getString("uri"));
                     mNavigationListener.onCanGoBack(GeckoView.this, message.getBoolean("canGoBack"));
                     mNavigationListener.onCanGoForward(GeckoView.this, message.getBoolean("canGoForward"));
                 }
             } else if ("GeckoView:PageStart".equals(event)) {
                 if (mProgressListener != null) {
                     mProgressListener.onPageStart(GeckoView.this, message.getString("uri"));
@@ -195,94 +195,90 @@ public class GeckoView extends LayerView
 
         initializeView();
         listener.registerListeners();
 
         mSettings = new GeckoViewSettings(getEventDispatcher());
     }
 
     @Override
-    protected Parcelable onSaveInstanceState()
-    {
+    protected Parcelable onSaveInstanceState() {
         final Parcelable superState = super.onSaveInstanceState();
         stateSaved = true;
         return new StateBinder(superState, this.window);
     }
 
     @Override
-    protected void onRestoreInstanceState(final Parcelable state)
-    {
+    protected void onRestoreInstanceState(final Parcelable state) {
         final StateBinder stateBinder = (StateBinder) state;
 
         if (stateBinder.window != null) {
             this.window = stateBinder.window;
         }
         stateSaved = false;
 
-        if (onAttachedToWindowCalled) {
+        if (mOnAttachedToWindowCalled) {
             reattachWindow();
         }
 
         // We have to always call super.onRestoreInstanceState because View keeps
         // track of these calls and throws an exception when we don't call it.
         super.onRestoreInstanceState(stateBinder.superState);
     }
 
     protected void openWindow() {
-        if (chromeURI == null) {
-            chromeURI = getGeckoInterface().getDefaultChromeURI();
+        if (mChromeUri == null) {
+            mChromeUri = getGeckoInterface().getDefaultChromeURI();
         }
 
         if (GeckoThread.isStateAtLeast(GeckoThread.State.PROFILE_READY)) {
-            Window.open(window, this, getCompositor(), eventDispatcher,
-                        chromeURI, mSettings.asBundle(), screenId);
+            Window.open(window, this, getCompositor(), mEventDispatcher,
+                        mChromeUri, mSettings.asBundle(), mScreenId);
         } else {
             GeckoThread.queueNativeCallUntil(
                 GeckoThread.State.PROFILE_READY,
                 Window.class, "open", window,
                 GeckoView.class, this,
                 Object.class, getCompositor(),
-                EventDispatcher.class, eventDispatcher,
-                String.class, chromeURI,
+                EventDispatcher.class, mEventDispatcher,
+                String.class, mChromeUri,
                 GeckoBundle.class, mSettings.asBundle(),
-                screenId);
+                mScreenId);
         }
     }
 
     protected void reattachWindow() {
         if (GeckoThread.isStateAtLeast(GeckoThread.State.PROFILE_READY)) {
-            window.reattach(this, getCompositor(), eventDispatcher);
+            window.reattach(this, getCompositor(), mEventDispatcher);
         } else {
             GeckoThread.queueNativeCallUntil(GeckoThread.State.PROFILE_READY,
                     window, "reattach", GeckoView.class, this,
-                    Object.class, getCompositor(), EventDispatcher.class, eventDispatcher);
+                    Object.class, getCompositor(), EventDispatcher.class, mEventDispatcher);
         }
     }
 
     @Override
-    public void onAttachedToWindow()
-    {
+    public void onAttachedToWindow() {
         final DisplayMetrics metrics = getContext().getResources().getDisplayMetrics();
 
         if (window == null) {
             // Open a new nsWindow if we didn't have one from before.
             window = new Window();
             openWindow();
         } else {
             reattachWindow();
         }
 
         super.onAttachedToWindow();
 
-        onAttachedToWindowCalled = true;
+        mOnAttachedToWindowCalled = true;
     }
 
     @Override
-    public void onDetachedFromWindow()
-    {
+    public void onDetachedFromWindow() {
         super.onDetachedFromWindow();
         super.destroy();
 
         if (stateSaved) {
             // If we saved state earlier, we don't want to close the nsWindow.
             return;
         }
 
@@ -291,17 +287,17 @@ public class GeckoView extends LayerView
             window.disposeNative();
         } else {
             GeckoThread.queueNativeCallUntil(GeckoThread.State.PROFILE_READY,
                     window, "close");
             GeckoThread.queueNativeCallUntil(GeckoThread.State.PROFILE_READY,
                     window, "disposeNative");
         }
 
-        onAttachedToWindowCalled = false;
+        mOnAttachedToWindowCalled = false;
     }
 
     @WrapForJNI public static final int LOAD_DEFAULT = 0;
     @WrapForJNI public static final int LOAD_NEW_TAB = 1;
     @WrapForJNI public static final int LOAD_SWITCH_TAB = 2;
 
     /**
     * Load the given URI.
@@ -315,32 +311,39 @@ public class GeckoView extends LayerView
 
         if (GeckoThread.isRunning()) {
             window.loadUri(uri, flags);
         }  else {
             GeckoThread.queueNativeCall(window, "loadUri", String.class, uri, flags);
         }
     }
 
+    /**
+    * Reload the current URI.
+    */
+    public void reload() {
+        mEventDispatcher.dispatch("GeckoView:Reload", null);
+    }
+
     /* package */ void setInputConnectionListener(final InputConnectionListener icl) {
         mInputConnectionListener = icl;
     }
 
     /**
     * Go back in history.
     */
     public void goBack() {
-        eventDispatcher.dispatch("GeckoView:GoBack", null);
+        mEventDispatcher.dispatch("GeckoView:GoBack", null);
     }
 
     /**
     * Go forward in history.
     */
     public void goForward() {
-        eventDispatcher.dispatch("GeckoView:GoForward", null);
+        mEventDispatcher.dispatch("GeckoView:GoForward", null);
     }
 
     public GeckoViewSettings getSettings() {
         return mSettings;
     }
 
     @Override
     public Handler getHandler() {
@@ -465,19 +468,19 @@ public class GeckoView extends LayerView
     * This will replace the current handler.
     * @param navigation An implementation of NavigationListener.
     */
     public void setNavigationDelegate(NavigationListener listener) {
         if (mNavigationListener == listener) {
             return;
         }
         if (listener == null) {
-            eventDispatcher.dispatch("GeckoViewNavigation:Inactive", null);
+            mEventDispatcher.dispatch("GeckoViewNavigation:Inactive", null);
         } else if (mNavigationListener == null) {
-            eventDispatcher.dispatch("GeckoViewNavigation:Active", null);
+            mEventDispatcher.dispatch("GeckoViewNavigation:Active", null);
         }
 
         mNavigationListener = listener;
     }
 
     /**
     * Get the navigation callback handler.
     * @return The current navigation callback handler.
@@ -499,17 +502,17 @@ public class GeckoView extends LayerView
     }
 
     @Override
     public SharedPreferences getSharedPreferences() {
         return getContext().getSharedPreferences(getSharedPreferencesFile(), 0);
     }
 
     public EventDispatcher getEventDispatcher() {
-        return eventDispatcher;
+        return mEventDispatcher;
     }
 
     /* Provides a means for the client to indicate whether a JavaScript
      * dialog request should proceed. An instance of this class is passed to
      * various GeckoViewChrome callback actions.
      */
     public class PromptResult {
         public PromptResult() {
--- a/mobile/android/geckoview/src/main/java/org/mozilla/gecko/GeckoViewFragment.java
+++ b/mobile/android/geckoview/src/main/java/org/mozilla/gecko/GeckoViewFragment.java
@@ -12,41 +12,41 @@ import android.util.Log;
 import android.util.SparseArray;
 import android.view.LayoutInflater;
 import android.view.View;
 import android.view.ViewGroup;
 
 public class GeckoViewFragment extends android.support.v4.app.Fragment {
     private static final String LOGTAG = "GeckoViewFragment";
 
-    private static Parcelable state = null;
-    private static GeckoViewFragment lastUsed = null;
-    private GeckoView geckoView = null;
+    private static Parcelable mSavedState = null;
+    private static GeckoViewFragment mLastUsed = null;
+    private GeckoView mGeckoView = null;
 
     @Override
     public void onCreate(Bundle savedInstanceState) {
         setRetainInstance(true);
         super.onCreate(savedInstanceState);
     }
 
     @Override
     public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
-        geckoView = new GeckoView(getContext());
-        return geckoView;
+        mGeckoView = new GeckoView(getContext());
+        return mGeckoView;
     }
 
     @Override
     public void onResume() {
-        if (state != null && lastUsed != this) {
+        if (mSavedState != null && mLastUsed != this) {
             // "Restore" the window from the previously used GeckoView to this GeckoView and attach it
-            geckoView.onRestoreInstanceState(state);
-            state = null;
+            mGeckoView.onRestoreInstanceState(mSavedState);
+            mSavedState = null;
         }
         super.onResume();
     }
 
     @Override
     public void onPause() {
-        state = geckoView.onSaveInstanceState();
-        lastUsed = this;
+        mSavedState = mGeckoView.onSaveInstanceState();
+        mLastUsed = this;
         super.onPause();
     }
 }
--- a/mobile/android/modules/GeckoViewContent.jsm
+++ b/mobile/android/modules/GeckoViewContent.jsm
@@ -8,37 +8,38 @@ this.EXPORTED_SYMBOLS = ["GeckoViewConte
 
 const { classes: Cc, interfaces: Ci, utils: Cu, results: Cr } = Components;
 
 Cu.import("resource://gre/modules/GeckoViewModule.jsm");
 
 var dump = Cu.import("resource://gre/modules/AndroidLog.jsm", {})
            .AndroidLog.d.bind(null, "ViewContent");
 
-var DEBUG = false;
+function debug(aMsg) {
+  // dump(aMsg);
+}
 
 class GeckoViewContent extends GeckoViewModule {
   init() {
     this.window.QueryInterface(Ci.nsIDOMChromeWindow).browserDOMWindow = this;
 
     this.messageManager.loadFrameScript("chrome://browser/content/GeckoViewContent.js", true);
     this.messageManager.addMessageListener("GeckoView:DOMTitleChanged", this);
   }
 
-  handleEvent(event) {
-    if (DEBUG) {
-      dump("handleEvent: event.type=" + event.type);
-    }
+  handleEvent(aEvent) {
+    debug("handleEvent: aEvent.type=" + aEvent.type);
   }
 
   // Message manager event handler.
-  receiveMessage(msg) {
-    if (DEBUG) {
-      dump("receiveMessage " + msg.name);
-    }
+  receiveMessage(aMsg) {
+    debug("receiveMessage " + aMsg.name);
 
-    switch (msg.name) {
+    switch (aMsg.name) {
       case "GeckoView:DOMTitleChanged":
-        this.eventDispatcher.sendRequest({ type: "GeckoView:DOMTitleChanged", title: msg.data.title });
+        this.eventDispatcher.sendRequest({
+          type: "GeckoView:DOMTitleChanged",
+          title: aMsg.data.title
+        });
         break;
     }
   }
 }
--- a/mobile/android/modules/GeckoViewModule.jsm
+++ b/mobile/android/modules/GeckoViewModule.jsm
@@ -6,25 +6,25 @@
 
 this.EXPORTED_SYMBOLS = ["GeckoViewModule"];
 
 const { classes: Cc, interfaces: Ci, utils: Cu, results: Cr } = Components;
 
 var dump = Cu.import("resource://gre/modules/AndroidLog.jsm", {})
            .AndroidLog.d.bind(null, "ViewModule");
 
-function debug(msg) {
-  // dump(msg);
+function debug(aMsg) {
+  // dump(aMsg);
 }
 
 class GeckoViewModule {
-  constructor(window, browser, eventDispatcher) {
-    this.window = window;
-    this.browser = browser;
-    this.eventDispatcher = eventDispatcher;
+  constructor(aWindow, aBrowser, aEventDispatcher) {
+    this.window = aWindow;
+    this.browser = aBrowser;
+    this.eventDispatcher = aEventDispatcher;
 
     this.eventDispatcher.registerListener(
       () => this.onSettingsUpdate(),
       "GeckoView:UpdateSettings");
 
     this.init();
     this.onSettingsUpdate();
   }
--- a/mobile/android/modules/GeckoViewNavigation.jsm
+++ b/mobile/android/modules/GeckoViewNavigation.jsm
@@ -12,18 +12,18 @@ Cu.import("resource://gre/modules/GeckoV
 Cu.import("resource://gre/modules/XPCOMUtils.jsm");
 
 XPCOMUtils.defineLazyModuleGetter(this, "EventDispatcher",
   "resource://gre/modules/Messaging.jsm");
 
 var dump = Cu.import("resource://gre/modules/AndroidLog.jsm", {})
            .AndroidLog.d.bind(null, "ViewNavigation");
 
-function debug(msg) {
-  // dump(msg);
+function debug(aMsg) {
+  // dump(aMsg);
 }
 
 // Handles navigation requests between Gecko and a GeckoView.
 // Implements GeckoView.loadUri via openURI.
 // Handles GeckoView:GoBack and :GoForward requests dispatched by
 // GeckoView.goBack and .goForward.
 // Dispatches GeckoView:LocationChange to the GeckoView on location change when
 // active.
@@ -37,49 +37,53 @@ class GeckoViewNavigation extends GeckoV
     // event may be dispatched before this object is constructed.
     this.registerProgressListener();
 
     this.eventDispatcher.registerListener(this, [
       "GeckoViewNavigation:Active",
       "GeckoViewNavigation:Inactive",
       "GeckoView:GoBack",
       "GeckoView:GoForward",
+      "GeckoView:Reload",
     ]);
   }
 
   // Bundle event handler.
-  onEvent(event, data, callback) {
-    debug("onEvent: event=" + event + ", data=" + JSON.stringify(data));
+  onEvent(aEvent, aData, aCallback) {
+    debug("onEvent: aEvent=" + aEvent + ", aData=" + JSON.stringify(aData));
 
-    switch (event) {
+    switch (aEvent) {
       case "GeckoViewNavigation:Active":
         this.registerProgressListener();
         break;
       case "GeckoViewNavigation:Inactive":
         this.unregisterProgressListener();
         break;
       case "GeckoView:GoBack":
         this.browser.goBack();
         break;
       case "GeckoView:GoForward":
         this.browser.goForward();
         break;
+      case "GeckoView:Reload":
+        this.browser.reload();
+        break;
     }
   }
 
   // Message manager event handler.
-  receiveMessage(msg) {
-    debug("receiveMessage " + msg.name);
+  receiveMessage(aMsg) {
+    debug("receiveMessage " + aMsg.name);
   }
 
   // nsIBrowserDOMWindow::openURI implementation.
-  openURI(uri, opener, where, flags) {
-    debug("openURI: uri.spec=" + uri.spec);
+  openURI(aUri, aOpener, aWhere, aFlags) {
+    debug("openURI: aUri.spec=" + aUri.spec);
     // nsIWebNavigation::loadURI(URI, loadFlags, referrer, postData, headers).
-    this.browser.loadURI(uri.spec, null, null, null);
+    this.browser.loadURI(aUri.spec, null, null, null);
   }
 
   // nsIBrowserDOMWindow::canClose implementation.
   canClose() {
     debug("canClose");
     return false;
   }
 
@@ -98,23 +102,23 @@ class GeckoViewNavigation extends GeckoV
     if (!this.progressFilter) {
       return;
     }
     this.progressFilter.removeProgressListener(this);
     this.browser.removeProgressListener(this.progressFilter);
   }
 
   // WebProgress event handler.
-  onLocationChange(webProgress, request, locationURI, flags) {
+  onLocationChange(aWebProgress, aRequest, aLocationURI, aFlags) {
     debug("onLocationChange");
 
-    let fixedURI = locationURI;
+    let fixedURI = aLocationURI;
 
     try {
-      fixedURI = URIFixup.createExposableURI(locationURI);
+      fixedURI = URIFixup.createExposableURI(aLocationURI);
     } catch (ex) { }
 
     let message = {
       type: "GeckoView:LocationChange",
       uri: fixedURI.spec,
       canGoBack: this.browser.canGoBack,
       canGoForward: this.browser.canGoForward,
     };
--- a/mobile/android/modules/GeckoViewProgress.jsm
+++ b/mobile/android/modules/GeckoViewProgress.jsm
@@ -12,69 +12,66 @@ Cu.import("resource://gre/modules/GeckoV
 Cu.import("resource://gre/modules/XPCOMUtils.jsm");
 
 XPCOMUtils.defineLazyModuleGetter(this, "EventDispatcher",
   "resource://gre/modules/Messaging.jsm");
 
 var dump = Cu.import("resource://gre/modules/AndroidLog.jsm", {})
            .AndroidLog.d.bind(null, "ViewNavigation");
 
-var DEBUG = false;
+function debug(aMsg) {
+  // dump(aMsg);
+}
 
 class GeckoViewProgress extends GeckoViewModule {
   init() {
     this.window.QueryInterface(Ci.nsIDOMChromeWindow).browserDOMWindow = this;
 
     this.registerProgressListener();
   }
 
   registerProgressListener() {
-    if (DEBUG) {
-      dump("registerProgressListeners()");
-    }
+    debug("registerProgressListeners()");
 
     let flags = Ci.nsIWebProgress.NOTIFY_STATE_NETWORK | Ci.nsIWebProgress.NOTIFY_SECURITY;
     this.progressFilter =
       Cc["@mozilla.org/appshell/component/browser-status-filter;1"]
       .createInstance(Ci.nsIWebProgress);
     this.progressFilter.addProgressListener(this, flags);
     this.browser.addProgressListener(this.progressFilter, flags);
   }
 
   onStateChange(aWebProgress, aRequest, aStateFlags, aStatus) {
-    if (DEBUG) {
-      dump("onStateChange()");
-    }
+    debug("onStateChange()");
 
     if (!aWebProgress.isTopLevel) {
       return;
     }
 
     if (aStateFlags & Ci.nsIWebProgressListener.STATE_START) {
       let uri = aRequest.QueryInterface(Ci.nsIChannel).URI;
       let message = {
         type: "GeckoView:PageStart",
         uri: uri.spec,
       };
 
       this.eventDispatcher.sendRequest(message);
-    } else if ((aStateFlags & Ci.nsIWebProgressListener.STATE_STOP) && !aWebProgress.isLoadingDocument) {
+    } else if ((aStateFlags & Ci.nsIWebProgressListener.STATE_STOP) &&
+               !aWebProgress.isLoadingDocument) {
       let message = {
         type: "GeckoView:PageStop",
         success: aStatus ? false : true
       };
 
       this.eventDispatcher.sendRequest(message);
     }
   }
 
   onSecurityChange(aWebProgress, aRequest, aState) {
-    if (DEBUG) {
-      dump("onSecurityChange()");
-    }
+    debug("onSecurityChange()");
 
     let message = {
       type: "GeckoView:SecurityChanged",
       status: aState
     };
 
     this.eventDispatcher.sendRequest(message);
   }
--- a/mobile/android/modules/GeckoViewSettings.jsm
+++ b/mobile/android/modules/GeckoViewSettings.jsm
@@ -12,18 +12,18 @@ Cu.import("resource://gre/modules/GeckoV
 Cu.import("resource://gre/modules/XPCOMUtils.jsm");
 
 XPCOMUtils.defineLazyModuleGetter(this, "SafeBrowsing",
   "resource://gre/modules/SafeBrowsing.jsm");
 
 var dump = Cu.import("resource://gre/modules/AndroidLog.jsm", {})
            .AndroidLog.d.bind(null, "ViewSettings");
 
-function debug(msg) {
-  // dump(msg);
+function debug(aMsg) {
+  // dump(aMsg);
 }
 
 // Handles GeckoView settings including:
 // * tracking protection
 class GeckoViewSettings extends GeckoViewModule {
   init() {
     this._isSafeBrowsingInit = false;
     this._useTrackingProtection = false;
@@ -34,22 +34,22 @@ class GeckoViewSettings extends GeckoVie
 
     this.useTrackingProtection = !!this.settings.useTrackingProtection;
   }
 
   get useTrackingProtection() {
     return this._useTrackingProtection;
   }
 
-  set useTrackingProtection(use) {
-    if (use && !this._isSafeBrowsingInit) {
+  set useTrackingProtection(aUse) {
+    if (aUse && !this._isSafeBrowsingInit) {
       SafeBrowsing.init();
       this._isSafeBrowsingInit = true;
     }
-    if (use != this._useTrackingProtection) {
+    if (aUse != this._useTrackingProtection) {
       this.messageManager.loadFrameScript('data:,' +
-        'docShell.useTrackingProtection = ' + use,
+        'docShell.useTrackingProtection = ' + aUse,
         true
       );
-      this._useTrackingProtection = use;
+      this._useTrackingProtection = aUse;
     }
   }
 }
--- a/mobile/android/tests/background/junit4/src/org/mozilla/gecko/util/TestStringUtils.java
+++ b/mobile/android/tests/background/junit4/src/org/mozilla/gecko/util/TestStringUtils.java
@@ -53,16 +53,31 @@ public class TestStringUtils {
 
         assertEquals(StringUtils.stripRef("??AAABBBCCC"), "??AAABBBCCC");
         assertEquals(StringUtils.stripRef("https://mozilla.org"), "https://mozilla.org");
         assertEquals(StringUtils.stripRef("https://mozilla.org#BBBB"), "https://mozilla.org");
         assertEquals(StringUtils.stripRef("https://mozilla.org/#BBBB"), "https://mozilla.org/");
     }
 
     @Test
+    public void testStripScheme() {
+        assertEquals("mozilla.org", StringUtils.stripScheme("http://mozilla.org"));
+        assertEquals("mozilla.org", StringUtils.stripScheme("http://mozilla.org/"));
+        assertEquals("https://mozilla.org", StringUtils.stripScheme("https://mozilla.org"));
+        assertEquals("https://mozilla.org", StringUtils.stripScheme("https://mozilla.org/"));
+        assertEquals("mozilla.org", StringUtils.stripScheme("https://mozilla.org/", StringUtils.UrlFlags.STRIP_HTTPS));
+        assertEquals("mozilla.org", StringUtils.stripScheme("https://mozilla.org", StringUtils.UrlFlags.STRIP_HTTPS));
+        assertEquals("", StringUtils.stripScheme("http://"));
+        assertEquals("", StringUtils.stripScheme("https://", StringUtils.UrlFlags.STRIP_HTTPS));
+        // This edge case is not handled properly yet
+//        assertEquals(StringUtils.stripScheme("https://"), "");
+        assertEquals(null, StringUtils.stripScheme(null));
+    }
+
+    @Test
     public void testIsRTL() {
         assertFalse(StringUtils.isRTL("mozilla.org"));
         assertFalse(StringUtils.isRTL("something.عربي"));
 
         assertTrue(StringUtils.isRTL("عربي"));
         assertTrue(StringUtils.isRTL("عربي.org"));
 
         // Text with LTR mark
--- a/netwerk/protocol/http/Http2Stream.cpp
+++ b/netwerk/protocol/http/Http2Stream.cpp
@@ -1475,18 +1475,18 @@ Http2Stream::MapStreamToHttpConnection()
 // -----------------------------------------------------------------------------
 // mirror nsAHttpTransaction
 // -----------------------------------------------------------------------------
 
 bool
 Http2Stream::Do0RTT()
 {
   MOZ_ASSERT(mTransaction);
-  mAttempting0RTT = true;
-  return mTransaction->Do0RTT();
+  mAttempting0RTT = mTransaction->Do0RTT();
+  return mAttempting0RTT;
 }
 
 nsresult
 Http2Stream::Finish0RTT(bool aRestart, bool aAlpnChanged)
 {
   MOZ_ASSERT(mTransaction);
   mAttempting0RTT = false;
   return mTransaction->Finish0RTT(aRestart, aAlpnChanged);
rename from testing/mozharness/configs/partner_repacks/staging_release_mozilla-esr52_desktop.py
rename to testing/mozharness/configs/partner_repacks/release_mozilla-esr52_desktop.py
--- a/tools/profiler/core/ProfilerBacktrace.cpp
+++ b/tools/profiler/core/ProfilerBacktrace.cpp
@@ -14,19 +14,17 @@ ProfilerBacktrace::ProfilerBacktrace(Syn
 {
   MOZ_COUNT_CTOR(ProfilerBacktrace);
   MOZ_ASSERT(aProfile);
 }
 
 ProfilerBacktrace::~ProfilerBacktrace()
 {
   MOZ_COUNT_DTOR(ProfilerBacktrace);
-  if (mProfile->ShouldDestroy()) {
-    delete mProfile;
-  }
+  delete mProfile;
 }
 
 void
 ProfilerBacktrace::StreamJSON(SpliceableJSONWriter& aWriter,
                               UniqueStacks& aUniqueStacks)
 {
   mozilla::MutexAutoLock lock(mProfile->GetMutex());
   mProfile->StreamJSON(aWriter, aUniqueStacks);
--- a/tools/profiler/core/SyncProfile.cpp
+++ b/tools/profiler/core/SyncProfile.cpp
@@ -4,52 +4,25 @@
  * 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 "SyncProfile.h"
 
 SyncProfile::SyncProfile(int aThreadId, PseudoStack* aStack)
   : ThreadInfo("SyncProfile", aThreadId, /* isMainThread = */ false, aStack,
                /* stackTop = */ nullptr)
-  , mOwnerState(REFERENCED)
 {
   MOZ_COUNT_CTOR(SyncProfile);
   SetProfile(new ProfileBuffer(GET_BACKTRACE_DEFAULT_ENTRIES));
 }
 
 SyncProfile::~SyncProfile()
 {
   MOZ_COUNT_DTOR(SyncProfile);
 }
 
-bool
-SyncProfile::ShouldDestroy()
-{
-  mozilla::MutexAutoLock lock(GetMutex());
-  if (mOwnerState == OWNED) {
-    mOwnerState = OWNER_DESTROYING;
-    return true;
-  }
-  mOwnerState = ORPHANED;
-  return false;
-}
-
-void
-SyncProfile::EndUnwind()
-{
-  if (mOwnerState != ORPHANED) {
-    mOwnerState = OWNED;
-  }
-  // Save mOwnerState before we release the mutex
-  OwnerState ownerState = mOwnerState;
-  ThreadInfo::EndUnwind();
-  if (ownerState == ORPHANED) {
-    delete this;
-  }
-}
-
 // SyncProfiles' stacks are deduplicated in the context of the containing
 // profile in which the backtrace is as a marker payload.
 void
 SyncProfile::StreamJSON(SpliceableJSONWriter& aWriter, UniqueStacks& aUniqueStacks)
 {
   ThreadInfo::StreamSamplesAndMarkers(aWriter, /* aSinceTime = */ 0, aUniqueStacks);
 }
--- a/tools/profiler/core/SyncProfile.h
+++ b/tools/profiler/core/SyncProfile.h
@@ -14,28 +14,14 @@ class SyncProfile : public ThreadInfo
 public:
   SyncProfile(int aThreadId, PseudoStack* aStack);
   ~SyncProfile();
 
   // SyncProfiles' stacks are deduplicated in the context of the containing
   // profile in which the backtrace is as a marker payload.
   void StreamJSON(SpliceableJSONWriter& aWriter, UniqueStacks& aUniqueStacks);
 
-  virtual void EndUnwind();
-
 private:
   friend class ProfilerBacktrace;
-
-  enum OwnerState
-  {
-    REFERENCED,       // ProfilerBacktrace has a pointer to this but doesn't own
-    OWNED,            // ProfilerBacktrace is responsible for destroying this
-    OWNER_DESTROYING, // ProfilerBacktrace owns this and is destroying
-    ORPHANED          // No owner, we must destroy ourselves
-  };
-
-  bool ShouldDestroy();
-
-  OwnerState mOwnerState;
 };
 
 #endif // __SYNCPROFILE_H
 
--- a/tools/profiler/core/ThreadInfo.cpp
+++ b/tools/profiler/core/ThreadInfo.cpp
@@ -232,28 +232,16 @@ ThreadInfo::FlushSamplesAndMarkers()
     mSavedStreamedMarkers = b.WriteFunc()->CopyData();
   }
 
   // Reset the buffer. Attempting to symbolicate JS samples after mContext has
   // gone away will crash.
   mBuffer->reset();
 }
 
-void
-ThreadInfo::BeginUnwind()
-{
-  mMutex->Lock();
-}
-
-void
-ThreadInfo::EndUnwind()
-{
-  mMutex->Unlock();
-}
-
 mozilla::Mutex&
 ThreadInfo::GetMutex()
 {
   return *mMutex.get();
 }
 
 void
 ThreadInfo::DuplicateLastSample(const TimeStamp& aStartTime)
--- a/tools/profiler/core/ThreadInfo.h
+++ b/tools/profiler/core/ThreadInfo.h
@@ -65,19 +65,16 @@ public:
   void addStoredMarker(ProfilerMarker* aStoredMarker);
   mozilla::Mutex& GetMutex();
   void StreamJSON(SpliceableJSONWriter& aWriter, double aSinceTime = 0);
 
   // Call this method when the JS entries inside the buffer are about to
   // become invalid, i.e., just before JS shutdown.
   void FlushSamplesAndMarkers();
 
-  void BeginUnwind();
-  virtual void EndUnwind();
-
   void DuplicateLastSample(const mozilla::TimeStamp& aStartTime);
 
   ThreadResponsiveness* GetThreadResponsiveness() { return &mRespInfo; }
 
   void UpdateThreadResponsiveness() {
     mRespInfo.Update(mIsMainThread, mThread);
   }
 
--- a/tools/profiler/core/platform-linux-android.cpp
+++ b/tools/profiler/core/platform-linux-android.cpp
@@ -176,28 +176,27 @@ static void SetSampleContext(TickSample*
 }
 
 static void
 SigprofHandler(int signal, siginfo_t* info, void* context)
 {
   // Avoid TSan warning about clobbering errno.
   int savedErrno = errno;
 
-  TickSample sample_obj;
-  TickSample* sample = &sample_obj;
-  sample->context = context;
+  TickSample sample;
+  sample.context = context;
 
   // Extract the current pc and sp.
-  SetSampleContext(sample, context);
-  sample->threadInfo = gCurrentThreadInfo;
-  sample->timestamp = mozilla::TimeStamp::Now();
-  sample->rssMemory = gRssMemory;
-  sample->ussMemory = gUssMemory;
+  SetSampleContext(&sample, context);
+  sample.threadInfo = gCurrentThreadInfo;
+  sample.timestamp = mozilla::TimeStamp::Now();
+  sample.rssMemory = gRssMemory;
+  sample.ussMemory = gUssMemory;
 
-  Tick(sample);
+  Tick(&sample);
 
   sem_post(&gSignalHandlingDone);
   errno = savedErrno;
 }
 
 #if defined(GP_OS_android)
 #define SYS_tgkill __NR_tgkill
 #endif
--- a/tools/profiler/core/platform-macos.cpp
+++ b/tools/profiler/core/platform-macos.cpp
@@ -185,25 +185,24 @@ public:
     }
   }
 
   void SampleContext(ThreadInfo* aThreadInfo, bool isFirstProfiledThread)
   {
     thread_act_t profiled_thread =
       aThreadInfo->GetPlatformData()->profiled_thread();
 
-    TickSample sample_obj;
-    TickSample* sample = &sample_obj;
+    TickSample sample;
 
     // Unique Set Size is not supported on Mac.
-    sample->ussMemory = 0;
-    sample->rssMemory = 0;
+    sample.ussMemory = 0;
+    sample.rssMemory = 0;
 
     if (isFirstProfiledThread && gProfileMemory) {
-      sample->rssMemory = nsMemoryReporterManager::ResidentFast();
+      sample.rssMemory = nsMemoryReporterManager::ResidentFast();
     }
 
     // We're using thread_suspend on OS X because pthread_kill (which is what
     // we're using on Linux) has less consistent performance and causes
     // strange crashes, see bug 1166778 and bug 1166808.
 
     if (KERN_SUCCESS != thread_suspend(profiled_thread)) return;
 
@@ -228,25 +227,25 @@ public:
 #else
 #error Unsupported Mac OS X host architecture.
 #endif  // GP_ARCH_*
 
     if (thread_get_state(profiled_thread,
                          flavor,
                          reinterpret_cast<natural_t*>(&state),
                          &count) == KERN_SUCCESS) {
-      sample->pc = reinterpret_cast<Address>(state.REGISTER_FIELD(ip));
-      sample->sp = reinterpret_cast<Address>(state.REGISTER_FIELD(sp));
-      sample->fp = reinterpret_cast<Address>(state.REGISTER_FIELD(bp));
-      sample->timestamp = mozilla::TimeStamp::Now();
-      sample->threadInfo = aThreadInfo;
+      sample.pc = reinterpret_cast<Address>(state.REGISTER_FIELD(ip));
+      sample.sp = reinterpret_cast<Address>(state.REGISTER_FIELD(sp));
+      sample.fp = reinterpret_cast<Address>(state.REGISTER_FIELD(bp));
+      sample.timestamp = mozilla::TimeStamp::Now();
+      sample.threadInfo = aThreadInfo;
 
 #undef REGISTER_FIELD
 
-      Tick(sample);
+      Tick(&sample);
     }
     thread_resume(profiled_thread);
   }
 
 private:
   pthread_t mThread;
 
   int mIntervalMicro;
--- a/tools/profiler/core/platform-win32.cpp
+++ b/tools/profiler/core/platform-win32.cpp
@@ -197,31 +197,30 @@ class SamplerThread
     HANDLE profiled_thread = reinterpret_cast<HANDLE>(thread);
     if (profiled_thread == NULL)
       return;
 
     // Context used for sampling the register state of the profiled thread.
     CONTEXT context;
     memset(&context, 0, sizeof(context));
 
-    TickSample sample_obj;
-    TickSample* sample = &sample_obj;
+    TickSample sample;
 
     // Grab the timestamp before pausing the thread, to avoid deadlocks.
-    sample->timestamp = mozilla::TimeStamp::Now();
-    sample->threadInfo = aThreadInfo;
+    sample.timestamp = mozilla::TimeStamp::Now();
+    sample.threadInfo = aThreadInfo;
 
     if (isFirstProfiledThread && gProfileMemory) {
-      sample->rssMemory = nsMemoryReporterManager::ResidentFast();
+      sample.rssMemory = nsMemoryReporterManager::ResidentFast();
     } else {
-      sample->rssMemory = 0;
+      sample.rssMemory = 0;
     }
 
     // Unique Set Size is not supported on Windows.
-    sample->ussMemory = 0;
+    sample.ussMemory = 0;
 
     static const DWORD kSuspendFailed = static_cast<DWORD>(-1);
     if (SuspendThread(profiled_thread) == kSuspendFailed)
       return;
 
     // SuspendThread is asynchronous, so the thread may still be running.
     // Call GetThreadContext first to ensure the thread is really suspended.
     // See https://blogs.msdn.microsoft.com/oldnewthing/20150205-00/?p=44743.
@@ -234,28 +233,28 @@ class SamplerThread
     context.ContextFlags = CONTEXT_CONTROL;
 #endif
     if (!GetThreadContext(profiled_thread, &context)) {
       ResumeThread(profiled_thread);
       return;
     }
 
 #if defined(GP_ARCH_amd64)
-    sample->pc = reinterpret_cast<Address>(context.Rip);
-    sample->sp = reinterpret_cast<Address>(context.Rsp);
-    sample->fp = reinterpret_cast<Address>(context.Rbp);
+    sample.pc = reinterpret_cast<Address>(context.Rip);
+    sample.sp = reinterpret_cast<Address>(context.Rsp);
+    sample.fp = reinterpret_cast<Address>(context.Rbp);
 #else
-    sample->pc = reinterpret_cast<Address>(context.Eip);
-    sample->sp = reinterpret_cast<Address>(context.Esp);
-    sample->fp = reinterpret_cast<Address>(context.Ebp);
+    sample.pc = reinterpret_cast<Address>(context.Eip);
+    sample.sp = reinterpret_cast<Address>(context.Esp);
+    sample.fp = reinterpret_cast<Address>(context.Ebp);
 #endif
 
-    sample->context = &context;
+    sample.context = &context;
 
-    Tick(sample);
+    Tick(&sample);
 
     ResumeThread(profiled_thread);
   }
 
 private:
   HANDLE mThread;
   Thread::tid_t mThreadId;
 
--- a/tools/profiler/core/platform.cpp
+++ b/tools/profiler/core/platform.cpp
@@ -2454,19 +2454,17 @@ profiler_get_backtrace()
 #else
 # error "unknown platform"
 #endif
 #endif
 
   sample.isSamplingCurrentThread = true;
   sample.timestamp = mozilla::TimeStamp::Now();
 
-  profile->BeginUnwind();
   Tick(&sample);
-  profile->EndUnwind();
 
   return UniqueProfilerBacktrace(new ProfilerBacktrace(profile));
 }
 
 void
 ProfilerBacktraceDestructor::operator()(ProfilerBacktrace* aBacktrace)
 {
   delete aBacktrace;