Merge inbound to m-c
authorWes Kocher <wkocher@mozilla.com>
Thu, 13 Mar 2014 19:00:59 -0700
changeset 190641 76a24e33ec2ad06d945f93ba3b1885da2bca7969
parent 190630 9fce3f6a4f45387c4e8f2cd2917fcbdee82d834b (current diff)
parent 190640 5461dd604fcf44d0f3030e7fd7565afb779e1dec (diff)
child 190684 f073b3d6db1f8d02917a3361d641d523cc545673
push id3503
push userraliiev@mozilla.com
push dateMon, 28 Apr 2014 18:51:11 +0000
treeherdermozilla-beta@c95ac01e332e [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
milestone30.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Merge inbound to m-c
--- a/dom/base/nsGlobalWindow.cpp
+++ b/dom/base/nsGlobalWindow.cpp
@@ -12395,24 +12395,22 @@ nsGlobalWindow::GetScrollFrame()
   if (presShell) {
     return presShell->GetRootScrollFrameAsScrollable();
   }
   return nullptr;
 }
 
 nsresult
 nsGlobalWindow::BuildURIfromBase(const char *aURL, nsIURI **aBuiltURI,
-                                 bool *aFreeSecurityPass,
                                  JSContext **aCXused)
 {
   nsIScriptContext *scx = GetContextInternal();
   JSContext *cx = nullptr;
 
   *aBuiltURI = nullptr;
-  *aFreeSecurityPass = false;
   if (aCXused)
     *aCXused = nullptr;
 
   // get JSContext
   NS_ASSERTION(scx, "opening window missing its context");
   NS_ASSERTION(mDoc, "opening window missing its document");
   if (!scx || !mDoc)
     return NS_ERROR_FAILURE;
@@ -12443,47 +12441,49 @@ nsGlobalWindow::BuildURIfromBase(const c
   if (cx) {
     nsIScriptContext *scriptcx = nsJSUtils::GetDynamicScriptContext(cx);
     if (scriptcx)
       sourceWindow = do_QueryInterface(scriptcx->GetGlobalObject());
   }
 
   if (!sourceWindow) {
     sourceWindow = this;
-    *aFreeSecurityPass = true;
-  }
-
-  if (sourceWindow) {
-    nsCOMPtr<nsIDocument> doc = sourceWindow->GetDoc();
-    if (doc) {
-      baseURI = doc->GetDocBaseURI();
-      charset = doc->GetDocumentCharacterSet();
-    }
+  }
+
+  nsCOMPtr<nsIDocument> doc = sourceWindow->GetDoc();
+  if (doc) {
+    baseURI = doc->GetDocBaseURI();
+    charset = doc->GetDocumentCharacterSet();
   }
 
   if (aCXused)
     *aCXused = cx;
   return NS_NewURI(aBuiltURI, nsDependentCString(aURL), charset.get(), baseURI);
 }
 
 nsresult
 nsGlobalWindow::SecurityCheckURL(const char *aURL)
 {
   JSContext       *cxUsed;
-  bool             freePass;
   nsCOMPtr<nsIURI> uri;
 
-  if (NS_FAILED(BuildURIfromBase(aURL, getter_AddRefs(uri), &freePass, &cxUsed)))
+  if (NS_FAILED(BuildURIfromBase(aURL, getter_AddRefs(uri), &cxUsed))) {
     return NS_ERROR_FAILURE;
+  }
+
+  if (!cxUsed) {
+    return NS_OK;
+  }
 
   AutoPushJSContext cx(cxUsed);
 
-  if (!freePass && NS_FAILED(nsContentUtils::GetSecurityManager()->
-        CheckLoadURIFromScript(cx, uri)))
+  if (NS_FAILED(nsContentUtils::GetSecurityManager()->
+        CheckLoadURIFromScript(cx, uri))) {
     return NS_ERROR_FAILURE;
+  }
 
   return NS_OK;
 }
 
 void
 nsGlobalWindow::FlushPendingNotifications(mozFlushType aType)
 {
   if (mDoc) {
--- a/dom/base/nsGlobalWindow.h
+++ b/dom/base/nsGlobalWindow.h
@@ -1165,19 +1165,18 @@ protected:
   void InsertTimeoutIntoList(nsTimeout *aTimeout);
   static void TimerCallback(nsITimer *aTimer, void *aClosure);
 
   // Helper Functions
   already_AddRefed<nsIDocShellTreeOwner> GetTreeOwner();
   already_AddRefed<nsIBaseWindow> GetTreeOwnerWindow();
   already_AddRefed<nsIWebBrowserChrome> GetWebBrowserChrome();
   nsresult SecurityCheckURL(const char *aURL);
-  nsresult BuildURIfromBase(const char *aURL,
-                            nsIURI **aBuiltURI,
-                            bool *aFreeSecurityPass, JSContext **aCXused);
+  nsresult BuildURIfromBase(const char *aURL, nsIURI **aBuiltURI,
+                            JSContext **aCXused);
   bool PopupWhitelisted();
   PopupControlState RevisePopupAbuseLevel(PopupControlState);
   void     FireAbuseEvents(bool aBlocked, bool aWindow,
                            const nsAString &aPopupURL,
                            const nsAString &aPopupWindowName,
                            const nsAString &aPopupWindowFeatures);
   void FireOfflineStatusEvent();
 
--- a/gfx/layers/FrameMetrics.h
+++ b/gfx/layers/FrameMetrics.h
@@ -199,16 +199,22 @@ public:
     mScrollOffset += aPoint;
   }
 
   void ZoomBy(float aFactor)
   {
     mZoom.scale *= aFactor;
   }
 
+  void CopyScrollInfoFrom(const FrameMetrics& aOther)
+  {
+    mScrollOffset = aOther.mScrollOffset;
+    mScrollGeneration = aOther.mScrollGeneration;
+  }
+
   // ---------------------------------------------------------------------------
   // The following metrics are all in widget space/device pixels.
   //
 
   // This is the area within the widget that we're compositing to. It is relative
   // to the layer tree origin.
   //
   // This is useful because, on mobile, the viewport and composition dimensions
--- a/gfx/layers/ipc/AsyncPanZoomController.cpp
+++ b/gfx/layers/ipc/AsyncPanZoomController.cpp
@@ -62,17 +62,17 @@
 
 // #define APZC_ENABLE_RENDERTRACE
 
 #define APZC_LOG(...)
 // #define APZC_LOG(...) printf_stderr("APZC: " __VA_ARGS__)
 #define APZC_LOG_FM(fm, prefix, ...) \
   APZC_LOG(prefix ":" \
            " i=(%ld %lld) cb=(%d %d %d %d) dp=(%.3f %.3f %.3f %.3f) v=(%.3f %.3f %.3f %.3f) " \
-           "s=(%.3f %.3f) sr=(%.3f %.3f %.3f %.3f) z=(%.3f %.3f %.3f %.3f) u=(%d %llu)\n", \
+           "s=(%.3f %.3f) sr=(%.3f %.3f %.3f %.3f) z=(%.3f %.3f %.3f %.3f) u=(%d %lu)\n", \
            __VA_ARGS__, \
            fm.mPresShellId, fm.mScrollId, \
            fm.mCompositionBounds.x, fm.mCompositionBounds.y, fm.mCompositionBounds.width, fm.mCompositionBounds.height, \
            fm.mDisplayPort.x, fm.mDisplayPort.y, fm.mDisplayPort.width, fm.mDisplayPort.height, \
            fm.mViewport.x, fm.mViewport.y, fm.mViewport.width, fm.mViewport.height, \
            fm.mScrollOffset.x, fm.mScrollOffset.y, \
            fm.mScrollableRect.x, fm.mScrollableRect.y, fm.mScrollableRect.width, fm.mScrollableRect.height, \
            fm.mDevPixelsPerCSSPixel.scale, fm.mResolution.scale, fm.mCumulativeResolution.scale, fm.mZoom.scale, \
@@ -1713,16 +1713,23 @@ void AsyncPanZoomController::NotifyLayer
     // change, so we can accept the viewport it's calculated.
     if (mFrameMetrics.mViewport.width != aLayerMetrics.mViewport.width ||
         mFrameMetrics.mViewport.height != aLayerMetrics.mViewport.height) {
       needContentRepaint = true;
     }
     mFrameMetrics.mViewport = aLayerMetrics.mViewport;
   }
 
+  // If the layers update was not triggered by our own repaint request, then
+  // we want to take the new scroll offset. Check the scroll generation as well
+  // to filter duplicate calls to NotifyLayersUpdated with the same scroll offset
+  // update message.
+  bool scrollOffsetUpdated = aLayerMetrics.GetScrollOffsetUpdated()
+        && (aLayerMetrics.GetScrollGeneration() != mFrameMetrics.GetScrollGeneration());
+
   if (aIsFirstPaint || isDefault) {
     // Initialize our internal state to something sane when the content
     // that was just painted is something we knew nothing about previously
     mPaintThrottler.ClearHistory();
     mPaintThrottler.SetMaxDurations(gNumPaintDurationSamples);
 
     mX.CancelTouch();
     mY.CancelTouch();
@@ -1748,41 +1755,40 @@ void AsyncPanZoomController::NotifyLayer
       mFrameMetrics.mDevPixelsPerCSSPixel.scale = aLayerMetrics.mDevPixelsPerCSSPixel.scale;
     }
     mFrameMetrics.mScrollableRect = aLayerMetrics.mScrollableRect;
     mFrameMetrics.mCompositionBounds = aLayerMetrics.mCompositionBounds;
     mFrameMetrics.mResolution = aLayerMetrics.mResolution;
     mFrameMetrics.mCumulativeResolution = aLayerMetrics.mCumulativeResolution;
     mFrameMetrics.mHasScrollgrab = aLayerMetrics.mHasScrollgrab;
 
-    // If the layers update was not triggered by our own repaint request, then
-    // we want to take the new scroll offset.
-    if (aLayerMetrics.GetScrollOffsetUpdated()) {
+    if (scrollOffsetUpdated) {
       APZC_LOG("%p updating scroll offset from (%f, %f) to (%f, %f)\n", this,
         mFrameMetrics.mScrollOffset.x, mFrameMetrics.mScrollOffset.y,
         aLayerMetrics.mScrollOffset.x, aLayerMetrics.mScrollOffset.y);
 
-      mFrameMetrics.SetScrollOffset(aLayerMetrics.GetScrollOffset());
+      mFrameMetrics.CopyScrollInfoFrom(aLayerMetrics);
 
       // Because of the scroll offset update, any inflight paint requests are
       // going to be ignored by layout, and so mLastDispatchedPaintMetrics
       // becomes incorrect for the purposes of calculating the LD transform. To
       // correct this we need to update mLastDispatchedPaintMetrics to be the
       // last thing we know was painted by Gecko.
       mLastDispatchedPaintMetrics = aLayerMetrics;
     }
   }
 
-  if (aLayerMetrics.GetScrollOffsetUpdated()) {
+  if (scrollOffsetUpdated) {
     // Once layout issues a scroll offset update, it becomes impervious to
     // scroll offset updates from APZ until we acknowledge the update it sent.
     // This prevents APZ updates from clobbering scroll updates from other
     // more "legitimate" sources like content scripts.
     nsRefPtr<GeckoContentController> controller = GetGeckoContentController();
     if (controller) {
+      APZC_LOG("%p sending scroll update acknowledgement with gen %lu\n", this, aLayerMetrics.GetScrollGeneration());
       controller->AcknowledgeScrollUpdate(aLayerMetrics.mScrollId,
                                           aLayerMetrics.GetScrollGeneration());
     }
   }
 
   if (needContentRepaint) {
     RequestContentRepaint();
   }
--- a/gfx/layers/ipc/CompositorParent.cpp
+++ b/gfx/layers/ipc/CompositorParent.cpp
@@ -392,16 +392,21 @@ CompositorParent::RecvLeaveTestMode()
 {
   mIsTesting = false;
   return true;
 }
 
 void
 CompositorParent::ActorDestroy(ActorDestroyReason why)
 {
+  CancelCurrentCompositeTask();
+  if (mForceCompositionTask) {
+    mForceCompositionTask->Cancel();
+    mForceCompositionTask = nullptr;
+  }
   mPaused = true;
   RemoveCompositor(mCompositorID);
 
   if (mLayerManager) {
     mLayerManager->Destroy();
     mLayerManager = nullptr;
     sIndirectLayerTrees[mRootLayerTreeID].mLayerManager = nullptr;
     mCompositionManager = nullptr;
@@ -627,17 +632,20 @@ CompositorParent::CompositeToTarget(Draw
   TimeDuration scheduleDelta = TimeStamp::Now() - mExpectedComposeStartTime;
   if (scheduleDelta > TimeDuration::FromMilliseconds(2) ||
       scheduleDelta < TimeDuration::FromMilliseconds(-2)) {
     printf_stderr("Compositor: Compose starting off schedule by %4.1f ms\n",
                   scheduleDelta.ToMilliseconds());
   }
 #endif
 
-  mCurrentCompositeTask = nullptr;
+  if (mCurrentCompositeTask) {
+    mCurrentCompositeTask->Cancel();
+    mCurrentCompositeTask = nullptr;
+  }
 
   mLastCompose = TimeStamp::Now();
 
   if (!CanComposite()) {
     return;
   }
 
   AutoResolveRefLayers resolve(mCompositionManager);
--- a/js/src/jit-test/tests/debug/Source-introductionScript-02.js
+++ b/js/src/jit-test/tests/debug/Source-introductionScript-02.js
@@ -24,8 +24,21 @@ dbg.onDebuggerStatement = outerHandler;
 g.evaluate('debugger; ["debugger;"].map(eval)', { lineNumber: 1234 });
 assertEq(log, 'oi');
 
 log = '';
 dbg.onDebuggerStatement = outerHandler;
 g.evaluate('debugger; "debugger;".replace(/.*/, eval);',
            { lineNumber: 1234 });
 assertEq(log, 'oi');
+
+
+// If the call takes place in another global, however, we don't record the
+// introduction script.
+log = '';
+dbg.onDebuggerStatement = function (frame) {
+  log += 'd';
+  assertEq(frame.script.source.introductionScript, undefined);
+  assertEq(frame.script.source.introductionOffset, undefined);
+};
+["debugger;"].map(g.eval);
+"debugger;".replace(/.*/, g.eval);
+assertEq(log, 'dd');
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/debug/Source-introductionScript-03.js
@@ -0,0 +1,32 @@
+// We don't record introduction scripts in a different global from the
+// introduced script, even if they're both debuggees.
+
+var dbg = new Debugger;
+
+var g1 = newGlobal();
+g1.g1 = g1;
+var g1DO = dbg.addDebuggee(g1);
+
+var g2 = newGlobal();
+g2.g1 = g1;
+
+var log = '';
+dbg.onDebuggerStatement = function (frame) {
+  log += 'd';
+  assertEq(frame.script.source.introductionScript, undefined);
+  assertEq(frame.script.source.introductionOffset, undefined);
+};
+
+g2.eval('g1.eval("debugger;");');
+assertEq(log, 'd');
+
+// Just for sanity: when it's not cross-global, we do note the introducer.
+log = '';
+dbg.onDebuggerStatement = function (frame) {
+  log += 'd';
+  assertEq(frame.script.source.introductionScript instanceof Debugger.Script, true);
+  assertEq(typeof frame.script.source.introductionOffset, "number");
+};
+// Exactly as above, but with g1 instead of g2.
+g1.eval('g1.eval("debugger;");');
+assertEq(log, 'd');
--- a/layout/generic/nsGfxScrollFrame.cpp
+++ b/layout/generic/nsGfxScrollFrame.cpp
@@ -1547,17 +1547,17 @@ ScrollFrameHelper::ScrollFrameHelper(nsC
   : mHScrollbarBox(nullptr)
   , mVScrollbarBox(nullptr)
   , mScrolledFrame(nullptr)
   , mScrollCornerBox(nullptr)
   , mResizerBox(nullptr)
   , mOuter(aOuter)
   , mAsyncScroll(nullptr)
   , mOriginOfLastScroll(nsGkAtoms::other)
-  , mScrollGeneration(0)
+  , mScrollGeneration(1) // we start off pretending we scrolled to 0,0 to flush a notification to APZ
   , mDestination(0, 0)
   , mScrollPosAtLastPaint(0, 0)
   , mRestorePos(-1, -1)
   , mLastPos(-1, -1)
   , mScrollPosForLayerPixelAlignment(-1, -1)
   , mLastUpdateImagesPos(-1, -1)
   , mNeverHasVerticalScrollbar(false)
   , mNeverHasHorizontalScrollbar(false)
--- a/mfbt/TypeTraits.h
+++ b/mfbt/TypeTraits.h
@@ -471,16 +471,23 @@ struct IsUnsigned : detail::IsUnsignedHe
 template<typename T, typename U>
 struct IsSame : FalseType {};
 
 template<typename T>
 struct IsSame<T, T> : TrueType {};
 
 namespace detail {
 
+#if defined(__GNUC__) || defined(__clang__) || defined(_MSC_VER)
+
+template<class Base, class Derived>
+struct BaseOfTester : IntegralConstant<bool, __is_base_of(Base, Derived)> {};
+
+#else
+
 // The trickery used to implement IsBaseOf here makes it possible to use it for
 // the cases of private and multiple inheritance.  This code was inspired by the
 // sample code here:
 //
 // http://stackoverflow.com/questions/2910979/how-is-base-of-works
 template<class Base, class Derived>
 struct BaseOfHelper
 {
@@ -519,16 +526,18 @@ template<class Base, class Derived>
 struct BaseOfTester<Base&, Derived&> : FalseType {};
 
 template<class Type>
 struct BaseOfTester<Type, Type> : TrueType {};
 
 template<class Type>
 struct BaseOfTester<Type, const Type> : TrueType {};
 
+#endif
+
 } /* namespace detail */
 
 /*
  * IsBaseOf allows to know whether a given class is derived from another.
  *
  * Consider the following class definitions:
  *
  *   class A {};
--- a/mobile/android/base/webapp/EventListener.java
+++ b/mobile/android/base/webapp/EventListener.java
@@ -110,17 +110,17 @@ public class EventListener implements Ge
                 String origin = message.getString("origin");
 
                 JSONObject obj = new JSONObject();
                 obj.put("profile", preInstallWebapp(name, manifestURL, origin).toString());
                 EventDispatcher.sendResponse(message, obj);
             } else if (event.equals("Webapps:GetApkVersions")) {
                 JSONObject obj = new JSONObject();
                 obj.put("versions", getApkVersions(GeckoAppShell.getGeckoInterface().getActivity(),
-                                                   message.getJSONArray("packageNames")).toString());
+                                                   message.getJSONArray("packageNames")));
                 EventDispatcher.sendResponse(message, obj);
             }
         } catch (Exception e) {
             Log.e(LOGTAG, "Exception handling message \"" + event + "\":", e);
         }
     }
 
     // Not used by MOZ_ANDROID_SYNTHAPKS.
--- a/mobile/android/modules/WebappManager.jsm
+++ b/mobile/android/modules/WebappManager.jsm
@@ -270,28 +270,28 @@ this.WebappManager = {
     try {
       let installedApps = yield this._getInstalledApps();
       if (installedApps.length === 0) {
         return;
       }
 
       // Map APK names to APK versions.
       let apkNameToVersion = yield this._getAPKVersions(installedApps.map(app =>
-        app.packageName).filter(packageName => !!packageName)
+        app.apkPackageName).filter(apkPackageName => !!apkPackageName)
       );
 
       // Map manifest URLs to APK versions, which is what the service needs
       // in order to tell us which apps are outdated; and also map them to app
       // objects, which the downloader/installer uses to download/install APKs.
       // XXX Will this cause us to update apps without packages, and if so,
       // does that satisfy the legacy migration story?
       let manifestUrlToApkVersion = {};
       let manifestUrlToApp = {};
       for (let app of installedApps) {
-        manifestUrlToApkVersion[app.manifestURL] = apkNameToVersion[app.packageName] || 0;
+        manifestUrlToApkVersion[app.manifestURL] = apkNameToVersion[app.apkPackageName] || 0;
         manifestUrlToApp[app.manifestURL] = app;
       }
 
       let outdatedApps = yield this._getOutdatedApps(manifestUrlToApkVersion, userInitiated);
 
       if (outdatedApps.length === 0) {
         // If the user asked us to check for updates, tell 'em we came up empty.
         if (userInitiated) {
--- a/modules/libpref/src/init/all.js
+++ b/modules/libpref/src/init/all.js
@@ -3927,16 +3927,17 @@ pref("layers.acceleration.force-enabled"
 
 pref("layers.acceleration.draw-fps", false);
 
 pref("layers.dump", false);
 pref("layers.draw-borders", false);
 pref("layers.draw-tile-borders", false);
 pref("layers.draw-bigimage-borders", false);
 pref("layers.frame-counter", false);
+pref("layers.enable-tiles", false);
 // Max number of layers per container. See Overwrite in mobile prefs.
 pref("layers.max-active", -1);
 // When a layer is moving it will add a scroll graph to measure the smoothness
 // of the movement. NOTE: This pref triggers composites to refresh
 // the graph.
 pref("layers.scroll-graph", false);
 
 // Set the default values, and then override per-platform as needed
--- a/toolkit/xre/glxtest.cpp
+++ b/toolkit/xre/glxtest.cpp
@@ -255,21 +255,23 @@ bool fire_glxtest_process()
   }
   pid_t pid = fork();
   if (pid < 0) {
       perror("fork");
       close(pfd[0]);
       close(pfd[1]);
       return false;
   }
+  // The child exits early to avoid running the full shutdown sequence and avoid conflicting with threads 
+  // we have already spawned (like the profiler).
   if (pid == 0) {
       close(pfd[0]);
       write_end_of_the_pipe = pfd[1];
       glxtest();
       close(pfd[1]);
-      return true;
+      exit(0);
   }
 
   close(pfd[1]);
   mozilla::widget::glxtest_pipe = pfd[0];
   mozilla::widget::glxtest_pid = pid;
   return false;
 }
--- a/toolkit/xre/nsAppRunner.cpp
+++ b/toolkit/xre/nsAppRunner.cpp
@@ -2846,20 +2846,20 @@ XREMain::XRE_mainInit(bool* aExitFlag)
     NS_BREAK();
 #endif
 
 #ifdef USE_GLX_TEST
   // bug 639842 - it's very important to fire this process BEFORE we set up
   // error handling. indeed, this process is expected to be crashy, and we
   // don't want the user to see its crashes. That's the whole reason for
   // doing this in a separate process.
-  if (fire_glxtest_process()) {
-    *aExitFlag = true;
-    return 0;
-  }
+  //
+  // This call will cause a fork and the fork will terminate itself separately
+  // from the usual shutdown sequence
+  fire_glxtest_process();
 #endif
 
 #if defined(XP_WIN) && defined(MOZ_METRO)
   // Don't remove this arg, we want to pass it on to nsUpdateDriver 
   if (CheckArg("metro-update", false, nullptr, false) == ARG_FOUND ||
       XRE_GetWindowsEnvironment() == WindowsEnvironmentType_Metro) {
     // If we're doing a restart update that was initiated from metro land,
     // we'll be running desktop to handle the actual update. Request that
--- a/tools/profiler/platform-linux.cc
+++ b/tools/profiler/platform-linux.cc
@@ -130,18 +130,17 @@ static void paf_prepare(void) {
 
 // In the parent, just after the fork, return pausedness to the
 // pre-fork state.
 static void paf_parent(void) {
   if (Sampler::GetActiveSampler())
     Sampler::GetActiveSampler()->SetPaused(was_paused);
 }
 
-// Set up the fork handlers.  This is called just once, at the first
-// call to SenderEntry.
+// Set up the fork handlers.
 static void* setup_atfork() {
   pthread_atfork(paf_prepare, paf_parent, NULL);
   return NULL;
 }
 #endif /* !defined(ANDROID) */
 
 struct SamplerRegistry {
   static void AddActiveSampler(Sampler *sampler) {
@@ -257,24 +256,16 @@ Sampler::AllocPlatformData(int aThreadId
 Sampler::FreePlatformData(PlatformData* aData)
 {
   delete aData;
 }
 
 static void* SignalSender(void* arg) {
   // Taken from platform_thread_posix.cc
   prctl(PR_SET_NAME, "SamplerThread", 0, 0, 0);
-# if defined(ANDROID)
-  // pthread_atfork isn't available on Android.
-  void* initialize_atfork = NULL;
-# else
-  // This call is done just once, at the first call to SenderEntry.
-  // It returns NULL.
-  static void* initialize_atfork = setup_atfork();
-# endif
 
 #ifdef MOZ_NUWA_PROCESS
   // If the Nuwa process is enabled, we need to mark and freeze the sampler
   // thread in the Nuwa process and have this thread recreated in the spawned
   // child.
   if(IsNuwaProcess()) {
     NuwaMarkCurrentThread(nullptr, nullptr);
     // Freeze the thread here so the spawned child will get the correct tgid
@@ -323,17 +314,17 @@ static void* SignalSender(void* arg) {
     // occuring during signal delivery.
     // TODO measure and confirm this.
     int interval = floor(SamplerRegistry::sampler->interval() * 1000 + 0.5) - 100;
     if (interval <= 0) {
       interval = 1;
     }
     OS::SleepMicro(interval);
   }
-  return initialize_atfork; // which is guaranteed to be NULL
+  return 0;
 }
 
 Sampler::Sampler(double interval, bool profiling, int entrySize)
     : interval_(interval),
       profiling_(profiling),
       paused_(false),
       active_(false),
       entrySize_(entrySize) {
@@ -560,29 +551,39 @@ static void StartSignalHandler(int signa
   profiler_start(PROFILE_DEFAULT_ENTRY, 1,
       features, featureCount,
       threadNames, threadCount);
 
   freeArray(threadNames, threadCount);
   freeArray(features, featureCount);
 }
 
-void OS::RegisterStartHandler()
+void OS::Startup()
 {
   LOG("Registering start signal");
   struct sigaction sa;
   sa.sa_sigaction = StartSignalHandler;
   sigemptyset(&sa.sa_mask);
   sa.sa_flags = SA_RESTART | SA_SIGINFO;
   if (sigaction(SIGSTART, &sa, &old_sigstart_signal_handler) != 0) {
     LOG("Error installing signal");
   }
 }
+
+#else
+
+void OS::Startup() {
+  // Set up the fork handlers.
+  setup_atfork();
+}
+
 #endif
 
+
+
 void TickSample::PopulateContext(void* aContext)
 {
   MOZ_ASSERT(aContext);
   ucontext_t* pContext = reinterpret_cast<ucontext_t*>(aContext);
   if (!getcontext(pContext)) {
     context = pContext;
     SetSampleContext(this, aContext);
   }
--- a/tools/profiler/platform-macos.cc
+++ b/tools/profiler/platform-macos.cc
@@ -51,16 +51,19 @@ struct SamplerRegistry {
 };
 
 Sampler *SamplerRegistry::sampler = NULL;
 
 // 0 is never a valid thread id on MacOSX since a ptread_t is
 // a pointer.
 static const pthread_t kNoThread = (pthread_t) 0;
 
+void OS::Startup() {
+}
+
 void OS::Sleep(int milliseconds) {
   usleep(1000 * milliseconds);
 }
 
 void OS::SleepMicro(int microseconds) {
   usleep(microseconds);
 }
 
--- a/tools/profiler/platform-win32.cc
+++ b/tools/profiler/platform-win32.cc
@@ -263,16 +263,19 @@ void Thread::Join() {
 }
 
 /* static */ Thread::tid_t
 Thread::GetCurrentId()
 {
   return GetCurrentThreadId();
 }
 
+void OS::Startup() {
+}
+
 void OS::Sleep(int milliseconds) {
   ::Sleep(milliseconds);
 }
 
 bool Sampler::RegisterCurrentThread(const char* aName,
                                     PseudoStack* aPseudoStack,
                                     bool aIsMainThread, void* stackTop)
 {
--- a/tools/profiler/platform.cpp
+++ b/tools/profiler/platform.cpp
@@ -473,18 +473,18 @@ void mozilla_sampler_init(void* stackTop
                                    gGeckoThreadName : "Application Thread",
                                  stack, isMainThread, stackTop);
 
   // Read mode settings from MOZ_PROFILER_MODE and interval
   // settings from MOZ_PROFILER_INTERVAL and stack-scan threshhold
   // from MOZ_PROFILER_STACK_SCAN.
   read_profiler_env_vars();
 
-  // Allow the profiler to be started using signals
-  OS::RegisterStartHandler();
+  // platform specific initialization
+  OS::Startup();
 
   // Initialize I/O interposing
   mozilla::IOInterposer::Init();
   // Initialize NSPR I/O Interposing
   mozilla::InitNSPRIOInterposing();
 
   // We can't open pref so we use an environment variable
   // to know if we should trigger the profiler on startup
--- a/tools/profiler/platform.h
+++ b/tools/profiler/platform.h
@@ -119,23 +119,18 @@ class OS {
  public:
 
   // Sleep for a number of milliseconds.
   static void Sleep(const int milliseconds);
 
   // Sleep for a number of microseconds.
   static void SleepMicro(const int microseconds);
 
-  // On supported platforms, setup a signal handler which would start
-  // the profiler.
-#if defined(ANDROID)
-  static void RegisterStartHandler();
-#else
-  static void RegisterStartHandler() {}
-#endif
+  // Called on startup to initialize platform specific things
+  static void Startup();
 
  private:
   static const int msPerSecond = 1000;
 
 };