Bug 851611 - Part 4: Split out GeckoProfilerFunc.h & PseudoStack.h. r=jrmuizel
authorBenoit Girard <b56girard@gmail.com>
Fri, 15 Mar 2013 20:48:56 -0400
changeset 126128 a428deb3fa9ac24ed35ccbb4b4888a630a733255
parent 126127 bf04a3230bfe14735b7c569df6591a011b573b89
child 126129 3a2dd29511b5e6887d0a09dc4b47fe5b184412c0
push id24475
push userphilringnalda@gmail.com
push dateTue, 26 Mar 2013 04:34:11 +0000
treeherdermozilla-central@456cb08f8509 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjrmuizel
bugs851611
milestone22.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
Bug 851611 - Part 4: Split out GeckoProfilerFunc.h & PseudoStack.h. r=jrmuizel
gfx/gl/SurfaceStream.cpp
gfx/layers/basic/BasicCanvasLayer.cpp
gfx/layers/basic/BasicLayerManager.cpp
tools/profiler/GeckoProfiler.h
tools/profiler/GeckoProfilerFunc.h
tools/profiler/GeckoProfilerImpl.h
tools/profiler/Makefile.in
tools/profiler/PseudoStack.h
--- a/gfx/gl/SurfaceStream.cpp
+++ b/gfx/gl/SurfaceStream.cpp
@@ -3,17 +3,17 @@
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "SurfaceStream.h"
 
 #include "gfxPoint.h"
 #include "SharedSurface.h"
 #include "SurfaceFactory.h"
-#include "sampler.h"
+#include "GeckoProfiler.h"
 
 namespace mozilla {
 namespace gfx {
 
 SurfaceStreamType
 SurfaceStream::ChooseGLStreamType(SurfaceStream::OMTC omtc,
                                   bool preserveBuffer)
 {
@@ -390,17 +390,17 @@ SurfaceStream_TripleBuffer::SurrenderSur
     if (!consumer)
         consumer = Surrender(mStaging);
 }
 
 SharedSurface*
 SurfaceStream_TripleBuffer::SwapProducer(SurfaceFactory* factory,
                                          const gfxIntSize& size)
 {
-    SAMPLE_LABEL("SurfaceStream_TripleBuffer", "SwapProducer");
+    PROFILER_LABEL("SurfaceStream_TripleBuffer", "SwapProducer");
 
     MonitorAutoLock lock(mMonitor);
     if (mProducer) {
         RecycleScraps(factory);
 
         // If WaitForCompositor succeeds, mStaging has moved to mConsumer.
         // If it failed, we might have to scrap it.
         if (mStaging && !WaitForCompositor())
@@ -437,17 +437,17 @@ SurfaceStream_TripleBuffer_Async::Surfac
 
 SurfaceStream_TripleBuffer_Async::~SurfaceStream_TripleBuffer_Async()
 {
 }
 
 bool
 SurfaceStream_TripleBuffer_Async::WaitForCompositor()
 {
-    SAMPLE_LABEL("SurfaceStream_TripleBuffer_Async", "WaitForCompositor");
+    PROFILER_LABEL("SurfaceStream_TripleBuffer_Async", "WaitForCompositor");
 
     // We are assumed to be locked
     while (mStaging)
         mMonitor.Wait();
 
     return true;
 }
 
--- a/gfx/layers/basic/BasicCanvasLayer.cpp
+++ b/gfx/layers/basic/BasicCanvasLayer.cpp
@@ -7,17 +7,17 @@
 #include "gfxImageSurface.h"
 #include "GLContext.h"
 #include "gfxUtils.h"
 #include "gfxPlatform.h"
 #include "mozilla/Preferences.h"
 #include "SurfaceStream.h"
 #include "SharedSurfaceGL.h"
 #include "SharedSurfaceEGL.h"
-#include "sampler.h"
+#include "GeckoProfiler.h"
 
 #include "BasicLayersImpl.h"
 #include "nsXULAppAPI.h"
 
 using namespace mozilla::gfx;
 using namespace mozilla::gl;
 
 namespace mozilla {
@@ -407,17 +407,17 @@ BasicShadowableCanvasLayer::Initialize(c
       DestroyBackBuffer();
     }
   }
 }
 
 void
 BasicShadowableCanvasLayer::Paint(gfxContext* aContext, Layer* aMaskLayer)
 {
-  SAMPLE_LABEL("BasicShadowableCanvasLayer", "Paint");
+  PROFILER_LABEL("BasicShadowableCanvasLayer", "Paint");
   if (!HasShadow()) {
     BasicCanvasLayer::Paint(aContext, aMaskLayer);
     return;
   }
 
   if (!IsDirty())
     return;
 
--- a/gfx/layers/basic/BasicLayerManager.cpp
+++ b/gfx/layers/basic/BasicLayerManager.cpp
@@ -866,17 +866,17 @@ BasicLayerManager::FlushGroup(PaintConte
 
 void
 BasicLayerManager::PaintLayer(gfxContext* aTarget,
                               Layer* aLayer,
                               DrawThebesLayerCallback aCallback,
                               void* aCallbackData,
                               ReadbackProcessor* aReadback)
 {
-  SAMPLE_LABEL("BasicLayerManager", "PaintLayer");
+  PROFILER_LABEL("BasicLayerManager", "PaintLayer");
   PaintContext paintContext(aTarget, aLayer, aCallback, aCallbackData, aReadback);
 
   // Don't attempt to paint layers with a singular transform, cairo will
   // just throw an error.
   if (aLayer->GetEffectiveTransform().IsSingular()) {
     return;
   }
 
new file mode 100644
--- /dev/null
+++ b/tools/profiler/GeckoProfilerFunc.h
@@ -0,0 +1,79 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* 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/. */
+
+#ifndef PROFILER_FUNCS_H
+#define PROFILER_FUNCS_H
+
+#include "mozilla/NullPtr.h"
+#include "mozilla/StandardInteger.h"
+#include "mozilla/TimeStamp.h"
+#include "jsfriendapi.h"
+
+using mozilla::TimeStamp;
+using mozilla::TimeDuration;
+
+// Returns a handle to pass on exit. This can check that we are popping the
+// correct callstack.
+inline void* mozilla_sampler_call_enter(const char *aInfo, void *aFrameAddress = NULL,
+                                        bool aCopy = false, uint32_t line = 0);
+inline void  mozilla_sampler_call_exit(void* handle);
+inline void  mozilla_sampler_add_marker(const char *aInfo);
+
+void mozilla_sampler_start1(int aEntries, int aInterval, const char** aFeatures,
+                            uint32_t aFeatureCount);
+void mozilla_sampler_start2(int aEntries, int aInterval, const char** aFeatures,
+                            uint32_t aFeatureCount);
+
+void mozilla_sampler_stop1();
+void mozilla_sampler_stop2();
+
+bool mozilla_sampler_is_active1();
+bool mozilla_sampler_is_active2();
+
+void mozilla_sampler_responsiveness1(const TimeStamp& time);
+void mozilla_sampler_responsiveness2(const TimeStamp& time);
+
+void mozilla_sampler_frame_number1(int frameNumber);
+void mozilla_sampler_frame_number2(int frameNumber);
+
+const double* mozilla_sampler_get_responsiveness1();
+const double* mozilla_sampler_get_responsiveness2();
+
+void mozilla_sampler_save1();
+void mozilla_sampler_save2();
+
+char* mozilla_sampler_get_profile1();
+char* mozilla_sampler_get_profile2();
+
+JSObject *mozilla_sampler_get_profile_data1(JSContext *aCx);
+JSObject *mozilla_sampler_get_profile_data2(JSContext *aCx);
+
+const char** mozilla_sampler_get_features1();
+const char** mozilla_sampler_get_features2();
+
+void mozilla_sampler_init1();
+void mozilla_sampler_init2();
+
+void mozilla_sampler_shutdown1();
+void mozilla_sampler_shutdown2();
+
+void mozilla_sampler_print_location1();
+void mozilla_sampler_print_location2();
+
+// Lock the profiler. When locked the profiler is (1) stopped,
+// (2) profile data is cleared, (3) profiler-locked is fired.
+// This is used to lock down the profiler during private browsing
+void mozilla_sampler_lock1();
+void mozilla_sampler_lock2();
+
+// Unlock the profiler, leaving it stopped and fires profiler-unlocked.
+void mozilla_sampler_unlock1();
+void mozilla_sampler_unlock2();
+
+/* Returns true if env var SPS_NEW is set to anything, else false. */
+extern bool sps_version2();
+
+#endif
+
--- a/tools/profiler/GeckoProfilerImpl.h
+++ b/tools/profiler/GeckoProfilerImpl.h
@@ -4,41 +4,40 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef TOOLS_SPS_SAMPLER_H_
 #define TOOLS_SPS_SAMPLER_H_
 
 #include <stdlib.h>
 #include <signal.h>
 #include <stdarg.h>
+#include <algorithm>
 #include "mozilla/ThreadLocal.h"
-#include "nscore.h"
 #include "mozilla/Assertions.h"
 #include "mozilla/TimeStamp.h"
 #include "mozilla/Util.h"
 #include "nsAlgorithm.h"
-#include <algorithm>
+#include "nscore.h"
+#include "jsfriendapi.h"
+#include "GeckoProfilerFunc.h"
+#include "PseudoStack.h"
 
 
 /* QT has a #define for the word "slots" and jsfriendapi.h has a struct with
  * this variable name, causing compilation problems. Alleviate this for now by
  * removing this #define */
 #ifdef MOZ_WIDGET_QT
 #undef slots
 #endif
-#include "jsfriendapi.h"
 
 // Make sure that we can use std::min here without the Windows headers messing with us.
 #ifdef min
 #undef min
 #endif
 
-using mozilla::TimeStamp;
-using mozilla::TimeDuration;
-
 struct PseudoStack;
 class TableTicker;
 class JSCustomObject;
 
 extern mozilla::ThreadLocal<PseudoStack *> tlsPseudoStack;
 extern bool stack_key_initialized;
 
 #ifndef SAMPLE_FUNCTION_NAME
@@ -46,77 +45,16 @@ extern bool stack_key_initialized;
 #  define SAMPLE_FUNCTION_NAME __FUNCTION__
 # elif defined(_MSC_VER)
 #  define SAMPLE_FUNCTION_NAME __FUNCTION__
 # else
 #  define SAMPLE_FUNCTION_NAME __func__  // defined in C99, supported in various C++ compilers. Just raw function name.
 # endif
 #endif
 
-// Returns a handle to pass on exit. This can check that we are popping the
-// correct callstack.
-inline void* mozilla_sampler_call_enter(const char *aInfo, void *aFrameAddress = NULL,
-                                        bool aCopy = false, uint32_t line = 0);
-inline void  mozilla_sampler_call_exit(void* handle);
-inline void  mozilla_sampler_add_marker(const char *aInfo);
-
-void mozilla_sampler_start1(int aEntries, int aInterval, const char** aFeatures,
-                            uint32_t aFeatureCount);
-void mozilla_sampler_start2(int aEntries, int aInterval, const char** aFeatures,
-                            uint32_t aFeatureCount);
-
-void mozilla_sampler_stop1();
-void mozilla_sampler_stop2();
-
-bool mozilla_sampler_is_active1();
-bool mozilla_sampler_is_active2();
-
-void mozilla_sampler_responsiveness1(const TimeStamp& time);
-void mozilla_sampler_responsiveness2(const TimeStamp& time);
-
-void mozilla_sampler_frame_number1(int frameNumber);
-void mozilla_sampler_frame_number2(int frameNumber);
-
-const double* mozilla_sampler_get_responsiveness1();
-const double* mozilla_sampler_get_responsiveness2();
-
-void mozilla_sampler_save1();
-void mozilla_sampler_save2();
-
-char* mozilla_sampler_get_profile1();
-char* mozilla_sampler_get_profile2();
-
-JSObject *mozilla_sampler_get_profile_data1(JSContext *aCx);
-JSObject *mozilla_sampler_get_profile_data2(JSContext *aCx);
-
-const char** mozilla_sampler_get_features1();
-const char** mozilla_sampler_get_features2();
-
-void mozilla_sampler_init1();
-void mozilla_sampler_init2();
-
-void mozilla_sampler_shutdown1();
-void mozilla_sampler_shutdown2();
-
-void mozilla_sampler_print_location1();
-void mozilla_sampler_print_location2();
-
-// Lock the profiler. When locked the profiler is (1) stopped,
-// (2) profile data is cleared, (3) profiler-locked is fired.
-// This is used to lock down the profiler during private browsing
-void mozilla_sampler_lock1();
-void mozilla_sampler_lock2();
-
-// Unlock the profiler, leaving it stopped and fires profiler-unlocked.
-void mozilla_sampler_unlock1();
-void mozilla_sampler_unlock2();
-
-/* Returns true if env var SPS_NEW is set to anything, else false. */
-extern bool sps_version2();
-
 static inline
 void profiler_init()
 {
   if (!sps_version2()) {
     mozilla_sampler_init1();
   } else {
     mozilla_sampler_init2();
   }
@@ -262,28 +200,16 @@ void profiler_unlock()
 
 #define PROFILER_LABEL(name_space, info) mozilla::SamplerStackFrameRAII SAMPLER_APPEND_LINE_NUMBER(sampler_raii)(name_space "::" info, __LINE__)
 #define PROFILER_LABEL_PRINTF(name_space, info, ...) mozilla::SamplerStackFramePrintfRAII SAMPLER_APPEND_LINE_NUMBER(sampler_raii)(name_space "::" info, __LINE__, __VA_ARGS__)
 #define PROFILER_MARKER(info) mozilla_sampler_add_marker(info)
 #define PROFILER_MAIN_THREAD_LABEL(name_space, info)  MOZ_ASSERT(NS_IsMainThread(), "This can only be called on the main thread"); mozilla::SamplerStackFrameRAII SAMPLER_APPEND_LINE_NUMBER(sampler_raii)(name_space "::" info, __LINE__)
 #define PROFILER_MAIN_THREAD_LABEL_PRINTF(name_space, info, ...)  MOZ_ASSERT(NS_IsMainThread(), "This can only be called on the main thread"); mozilla::SamplerStackFramePrintfRAII SAMPLER_APPEND_LINE_NUMBER(sampler_raii)(name_space "::" info, __LINE__, __VA_ARGS__)
 #define PROFILER_MAIN_THREAD_MARKER(info)  MOZ_ASSERT(NS_IsMainThread(), "This can only be called on the main thread"); mozilla_sampler_add_marker(info)
 
-/* we duplicate this code here to avoid header dependencies
- * which make it more difficult to include in other places */
-#if defined(_M_X64) || defined(__x86_64__)
-#define V8_HOST_ARCH_X64 1
-#elif defined(_M_IX86) || defined(__i386__) || defined(__i386)
-#define V8_HOST_ARCH_IA32 1
-#elif defined(__ARMEL__)
-#define V8_HOST_ARCH_ARM 1
-#else
-#warning Please add support for your architecture in chromium_types.h
-#endif
-
 /* FIXME/bug 789667: memory constraints wouldn't much of a problem for
  * this small a sample buffer size, except that serializing the
  * profile data is extremely, unnecessarily memory intensive. */
 #ifdef MOZ_WIDGET_GONK
 # define PLATFORM_LIKELY_MEMORY_CONSTRAINED
 #endif
 
 #if !defined(PLATFORM_LIKELY_MEMORY_CONSTRAINED) && !defined(ARCH_ARMV6)
@@ -311,60 +237,16 @@ void profiler_unlock()
 // enough.
 #define PROFILE_DEFAULT_INTERVAL 1
 #else
 #define PROFILE_DEFAULT_INTERVAL 1
 #endif
 #define PROFILE_DEFAULT_FEATURES NULL
 #define PROFILE_DEFAULT_FEATURE_COUNT 0
 
-// STORE_SEQUENCER: Because signals can interrupt our profile modification
-//                  we need to make stores are not re-ordered by the compiler
-//                  or hardware to make sure the profile is consistent at
-//                  every point the signal can fire.
-#ifdef V8_HOST_ARCH_ARM
-// TODO Is there something cheaper that will prevent
-//      memory stores from being reordered
-
-typedef void (*LinuxKernelMemoryBarrierFunc)(void);
-LinuxKernelMemoryBarrierFunc pLinuxKernelMemoryBarrier __attribute__((weak)) =
-    (LinuxKernelMemoryBarrierFunc) 0xffff0fa0;
-
-# define STORE_SEQUENCER() pLinuxKernelMemoryBarrier()
-#elif defined(V8_HOST_ARCH_IA32) || defined(V8_HOST_ARCH_X64)
-# if defined(_MSC_VER)
-#if _MSC_VER > 1400
-#  include <intrin.h>
-#else // _MSC_VER > 1400
-    // MSVC2005 has a name collision bug caused when both <intrin.h> and <winnt.h> are included together.
-#ifdef _WINNT_
-#  define _interlockedbittestandreset _interlockedbittestandreset_NAME_CHANGED_TO_AVOID_MSVS2005_ERROR
-#  define _interlockedbittestandset _interlockedbittestandset_NAME_CHANGED_TO_AVOID_MSVS2005_ERROR
-#  include <intrin.h>
-#else
-#  include <intrin.h>
-#  define _interlockedbittestandreset _interlockedbittestandreset_NAME_CHANGED_TO_AVOID_MSVS2005_ERROR
-#  define _interlockedbittestandset _interlockedbittestandset_NAME_CHANGED_TO_AVOID_MSVS2005_ERROR
-#endif
-   // Even though MSVC2005 has the intrinsic _ReadWriteBarrier, it fails to link to it when it's
-   // not explicitly declared.
-#  pragma intrinsic(_ReadWriteBarrier)
-#endif // _MSC_VER > 1400
-#  define STORE_SEQUENCER() _ReadWriteBarrier();
-# elif defined(__INTEL_COMPILER)
-#  define STORE_SEQUENCER() __memory_barrier();
-# elif __GNUC__
-#  define STORE_SEQUENCER() asm volatile("" ::: "memory");
-# else
-#  error "Memory clobber not supported for your compiler."
-# endif
-#else
-# error "Memory clobber not supported for your platform."
-#endif
-
 namespace mozilla {
 
 class NS_STACK_CLASS SamplerStackFrameRAII {
 public:
   // we only copy the strings at save time, so to take multiple parameters we'd need to copy them then.
   SamplerStackFrameRAII(const char *aInfo, uint32_t line) {
     mHandle = mozilla_sampler_call_enter(aInfo, this, false, line);
   }
@@ -405,196 +287,16 @@ public:
   }
 private:
   char mDest[SAMPLER_MAX_STRING];
   void* mHandle;
 };
 
 } //mozilla
 
-// A stack entry exists to allow the JS engine to inform SPS of the current
-// backtrace, but also to instrument particular points in C++ in case stack
-// walking is not available on the platform we are running on.
-//
-// Each entry has a descriptive string, a relevant stack address, and some extra
-// information the JS engine might want to inform SPS of. This class inherits
-// from the JS engine's version of the entry to ensure that the size and layout
-// of the two representations are consistent.
-class StackEntry : public js::ProfileEntry
-{
-public:
-
-  bool isCopyLabel() volatile {
-    return !((uintptr_t)stackAddress() & 0x1);
-  }
-
-  void setStackAddressCopy(void *sparg, bool copy) volatile {
-    // Tagged pointer. Less significant bit used to track if mLabel needs a
-    // copy. Note that we don't need the last bit of the stack address for
-    // proper ordering. This is optimized for encoding within the JS engine's
-    // instrumentation, so we do the extra work here of encoding a bit.
-    // Last bit 1 = Don't copy, Last bit 0 = Copy.
-    if (copy) {
-      setStackAddress(reinterpret_cast<void*>(
-                        reinterpret_cast<uintptr_t>(sparg) & ~0x1));
-    } else {
-      setStackAddress(reinterpret_cast<void*>(
-                        reinterpret_cast<uintptr_t>(sparg) | 0x1));
-    }
-  }
-};
-
-// the PseudoStack members are read by signal
-// handlers, so the mutation of them needs to be signal-safe.
-struct PseudoStack
-{
-public:
-  PseudoStack()
-    : mStackPointer(0)
-    , mSignalLock(false)
-    , mMarkerPointer(0)
-    , mQueueClearMarker(false)
-    , mRuntime(NULL)
-    , mStartJSSampling(false)
-  { }
-
-  void addMarker(const char *aMarker)
-  {
-    char* markerCopy = strdup(aMarker);
-    mSignalLock = true;
-    STORE_SEQUENCER();
-
-    if (mQueueClearMarker) {
-      clearMarkers();
-    }
-    if (!aMarker) {
-      return; //discard
-    }
-    if (size_t(mMarkerPointer) == mozilla::ArrayLength(mMarkers)) {
-      return; //array full, silently drop
-    }
-    mMarkers[mMarkerPointer] = markerCopy;
-    mMarkerPointer++;
-
-    mSignalLock = false;
-    STORE_SEQUENCER();
-  }
-
-  // called within signal. Function must be reentrant
-  const char* getMarker(int aMarkerId)
-  {
-    // if mSignalLock then the stack is inconsistent because it's being
-    // modified by the profiled thread. Post pone these markers
-    // for the next sample. The odds of a livelock are nearly impossible
-    // and would show up in a profile as many sample in 'addMarker' thus
-    // we ignore this scenario.
-    // if mQueueClearMarker then we've the sampler thread has already
-    // thread the markers then they are pending deletion.
-    if (mSignalLock || mQueueClearMarker || aMarkerId < 0 ||
-      static_cast<mozilla::sig_safe_t>(aMarkerId) >= mMarkerPointer) {
-      return NULL;
-    }
-    return mMarkers[aMarkerId];
-  }
-
-  // called within signal. Function must be reentrant
-  void clearMarkers()
-  {
-    for (mozilla::sig_safe_t i = 0; i < mMarkerPointer; i++) {
-      free(mMarkers[i]);
-    }
-    mMarkerPointer = 0;
-    mQueueClearMarker = false;
-  }
-
-  void push(const char *aName, uint32_t line)
-  {
-    push(aName, NULL, false, line);
-  }
-
-  void push(const char *aName, void *aStackAddress, bool aCopy, uint32_t line)
-  {
-    if (size_t(mStackPointer) >= mozilla::ArrayLength(mStack)) {
-      mStackPointer++;
-      return;
-    }
-
-    // Make sure we increment the pointer after the name has
-    // been written such that mStack is always consistent.
-    mStack[mStackPointer].setLabel(aName);
-    mStack[mStackPointer].setStackAddressCopy(aStackAddress, aCopy);
-    mStack[mStackPointer].setLine(line);
-
-    // Prevent the optimizer from re-ordering these instructions
-    STORE_SEQUENCER();
-    mStackPointer++;
-  }
-  void pop()
-  {
-    mStackPointer--;
-  }
-  bool isEmpty()
-  {
-    return mStackPointer == 0;
-  }
-  uint32_t stackSize() const
-  {
-    return std::min<uint32_t>(mStackPointer, mozilla::ArrayLength(mStack));
-  }
-
-  void sampleRuntime(JSRuntime *runtime) {
-    mRuntime = runtime;
-    if (!runtime) {
-      // JS shut down
-      return;
-    }
-
-    JS_STATIC_ASSERT(sizeof(mStack[0]) == sizeof(js::ProfileEntry));
-    js::SetRuntimeProfilingStack(runtime,
-                                 (js::ProfileEntry*) mStack,
-                                 (uint32_t*) &mStackPointer,
-                                 mozilla::ArrayLength(mStack));
-    if (mStartJSSampling)
-      enableJSSampling();
-  }
-  void enableJSSampling() {
-    if (mRuntime) {
-      js::EnableRuntimeProfilingStack(mRuntime, true);
-      mStartJSSampling = false;
-    } else {
-      mStartJSSampling = true;
-    }
-  }
-  void disableJSSampling() {
-    mStartJSSampling = false;
-    if (mRuntime)
-      js::EnableRuntimeProfilingStack(mRuntime, false);
-  }
-
-  // Keep a list of active checkpoints
-  StackEntry volatile mStack[1024];
-  // Keep a list of active markers to be applied to the next sample taken
-  char* mMarkers[1024];
- private:
-  // This may exceed the length of mStack, so instead use the stackSize() method
-  // to determine the number of valid samples in mStack
-  mozilla::sig_safe_t mStackPointer;
-  // If this is set then it's not safe to read mStackPointer from the signal handler
-  volatile bool mSignalLock;
- public:
-  volatile mozilla::sig_safe_t mMarkerPointer;
-  // We don't want to modify _markers from within the signal so we allow
-  // it to queue a clear operation.
-  volatile mozilla::sig_safe_t mQueueClearMarker;
-  // The runtime which is being sampled
-  JSRuntime *mRuntime;
-  // Start JS Profiling when possible
-  bool mStartJSSampling;
-};
-
 inline PseudoStack* mozilla_get_pseudo_stack(void)
 {
   if (!stack_key_initialized)
     return NULL;
   return tlsPseudoStack.get();
 }
 
 inline void* mozilla_sampler_call_enter(const char *aInfo, void *aFrameAddress,
--- a/tools/profiler/Makefile.in
+++ b/tools/profiler/Makefile.in
@@ -14,16 +14,18 @@ XPCSHELL_TESTS = tests
 
 include $(DEPTH)/config/autoconf.mk
 
 EXPORTS = GeckoProfiler.h
 
 ifdef MOZ_ENABLE_PROFILER_SPS
 EXPORTS += \
   GeckoProfilerImpl.h \
+  GeckoProfilerFunc.h \
+  PseudoStack.h \
   shared-libraries.h \
   $(NULL)
 
 LOCAL_INCLUDES += \
   -I$(topsrcdir)/mozglue/linker \
   -I$(topsrcdir)/ipc/chromium/src \
   -I$(topsrcdir)/toolkit/crashreporter/google-breakpad/src \
   $(NULL)
new file mode 100644
--- /dev/null
+++ b/tools/profiler/PseudoStack.h
@@ -0,0 +1,251 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* 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/. */
+
+#ifndef PROFILER_PSEUDO_STACK_H_
+#define PROFILER_PSEUDO_STACK_H_
+
+#include "mozilla/NullPtr.h"
+#include "mozilla/StandardInteger.h"
+#include "jsfriendapi.h"
+#include <stdlib.h>
+
+/* we duplicate this code here to avoid header dependencies
+ * which make it more difficult to include in other places */
+#if defined(_M_X64) || defined(__x86_64__)
+#define V8_HOST_ARCH_X64 1
+#elif defined(_M_IX86) || defined(__i386__) || defined(__i386)
+#define V8_HOST_ARCH_IA32 1
+#elif defined(__ARMEL__)
+#define V8_HOST_ARCH_ARM 1
+#else
+#warning Please add support for your architecture in chromium_types.h
+#endif
+
+// STORE_SEQUENCER: Because signals can interrupt our profile modification
+//                  we need to make stores are not re-ordered by the compiler
+//                  or hardware to make sure the profile is consistent at
+//                  every point the signal can fire.
+#ifdef V8_HOST_ARCH_ARM
+// TODO Is there something cheaper that will prevent
+//      memory stores from being reordered
+
+typedef void (*LinuxKernelMemoryBarrierFunc)(void);
+LinuxKernelMemoryBarrierFunc pLinuxKernelMemoryBarrier __attribute__((weak)) =
+    (LinuxKernelMemoryBarrierFunc) 0xffff0fa0;
+
+# define STORE_SEQUENCER() pLinuxKernelMemoryBarrier()
+#elif defined(V8_HOST_ARCH_IA32) || defined(V8_HOST_ARCH_X64)
+# if defined(_MSC_VER)
+#if _MSC_VER > 1400
+#  include <intrin.h>
+#else // _MSC_VER > 1400
+    // MSVC2005 has a name collision bug caused when both <intrin.h> and <winnt.h> are included together.
+#ifdef _WINNT_
+#  define _interlockedbittestandreset _interlockedbittestandreset_NAME_CHANGED_TO_AVOID_MSVS2005_ERROR
+#  define _interlockedbittestandset _interlockedbittestandset_NAME_CHANGED_TO_AVOID_MSVS2005_ERROR
+#  include <intrin.h>
+#else
+#  include <intrin.h>
+#  define _interlockedbittestandreset _interlockedbittestandreset_NAME_CHANGED_TO_AVOID_MSVS2005_ERROR
+#  define _interlockedbittestandset _interlockedbittestandset_NAME_CHANGED_TO_AVOID_MSVS2005_ERROR
+#endif
+   // Even though MSVC2005 has the intrinsic _ReadWriteBarrier, it fails to link to it when it's
+   // not explicitly declared.
+#  pragma intrinsic(_ReadWriteBarrier)
+#endif // _MSC_VER > 1400
+#  define STORE_SEQUENCER() _ReadWriteBarrier();
+# elif defined(__INTEL_COMPILER)
+#  define STORE_SEQUENCER() __memory_barrier();
+# elif __GNUC__
+#  define STORE_SEQUENCER() asm volatile("" ::: "memory");
+# else
+#  error "Memory clobber not supported for your compiler."
+# endif
+#else
+# error "Memory clobber not supported for your platform."
+#endif
+
+// A stack entry exists to allow the JS engine to inform SPS of the current
+// backtrace, but also to instrument particular points in C++ in case stack
+// walking is not available on the platform we are running on.
+//
+// Each entry has a descriptive string, a relevant stack address, and some extra
+// information the JS engine might want to inform SPS of. This class inherits
+// from the JS engine's version of the entry to ensure that the size and layout
+// of the two representations are consistent.
+class StackEntry : public js::ProfileEntry
+{
+public:
+
+  bool isCopyLabel() volatile {
+    return !((uintptr_t)stackAddress() & 0x1);
+  }
+
+  void setStackAddressCopy(void *sparg, bool copy) volatile {
+    // Tagged pointer. Less significant bit used to track if mLabel needs a
+    // copy. Note that we don't need the last bit of the stack address for
+    // proper ordering. This is optimized for encoding within the JS engine's
+    // instrumentation, so we do the extra work here of encoding a bit.
+    // Last bit 1 = Don't copy, Last bit 0 = Copy.
+    if (copy) {
+      setStackAddress(reinterpret_cast<void*>(
+                        reinterpret_cast<uintptr_t>(sparg) & ~0x1));
+    } else {
+      setStackAddress(reinterpret_cast<void*>(
+                        reinterpret_cast<uintptr_t>(sparg) | 0x1));
+    }
+  }
+};
+
+// the PseudoStack members are read by signal
+// handlers, so the mutation of them needs to be signal-safe.
+struct PseudoStack
+{
+public:
+  PseudoStack()
+    : mStackPointer(0)
+    , mSignalLock(false)
+    , mMarkerPointer(0)
+    , mQueueClearMarker(false)
+    , mRuntime(nullptr)
+    , mStartJSSampling(false)
+  { }
+
+  void addMarker(const char *aMarker)
+  {
+    char* markerCopy = strdup(aMarker);
+    mSignalLock = true;
+    STORE_SEQUENCER();
+
+    if (mQueueClearMarker) {
+      clearMarkers();
+    }
+    if (!aMarker) {
+      return; //discard
+    }
+    if (size_t(mMarkerPointer) == mozilla::ArrayLength(mMarkers)) {
+      return; //array full, silently drop
+    }
+    mMarkers[mMarkerPointer] = markerCopy;
+    mMarkerPointer++;
+
+    mSignalLock = false;
+    STORE_SEQUENCER();
+  }
+
+  // called within signal. Function must be reentrant
+  const char* getMarker(int aMarkerId)
+  {
+    // if mSignalLock then the stack is inconsistent because it's being
+    // modified by the profiled thread. Post pone these markers
+    // for the next sample. The odds of a livelock are nearly impossible
+    // and would show up in a profile as many sample in 'addMarker' thus
+    // we ignore this scenario.
+    // if mQueueClearMarker then we've the sampler thread has already
+    // thread the markers then they are pending deletion.
+    if (mSignalLock || mQueueClearMarker || aMarkerId < 0 ||
+      static_cast<mozilla::sig_safe_t>(aMarkerId) >= mMarkerPointer) {
+      return nullptr;
+    }
+    return mMarkers[aMarkerId];
+  }
+
+  // called within signal. Function must be reentrant
+  void clearMarkers()
+  {
+    for (mozilla::sig_safe_t i = 0; i < mMarkerPointer; i++) {
+      free(mMarkers[i]);
+    }
+    mMarkerPointer = 0;
+    mQueueClearMarker = false;
+  }
+
+  void push(const char *aName, uint32_t line)
+  {
+    push(aName, nullptr, false, line);
+  }
+
+  void push(const char *aName, void *aStackAddress, bool aCopy, uint32_t line)
+  {
+    if (size_t(mStackPointer) >= mozilla::ArrayLength(mStack)) {
+      mStackPointer++;
+      return;
+    }
+
+    // Make sure we increment the pointer after the name has
+    // been written such that mStack is always consistent.
+    mStack[mStackPointer].setLabel(aName);
+    mStack[mStackPointer].setStackAddressCopy(aStackAddress, aCopy);
+    mStack[mStackPointer].setLine(line);
+
+    // Prevent the optimizer from re-ordering these instructions
+    STORE_SEQUENCER();
+    mStackPointer++;
+  }
+  void pop()
+  {
+    mStackPointer--;
+  }
+  bool isEmpty()
+  {
+    return mStackPointer == 0;
+  }
+  uint32_t stackSize() const
+  {
+    return std::min<uint32_t>(mStackPointer, mozilla::ArrayLength(mStack));
+  }
+
+  void sampleRuntime(JSRuntime *runtime) {
+    mRuntime = runtime;
+    if (!runtime) {
+      // JS shut down
+      return;
+    }
+
+    JS_STATIC_ASSERT(sizeof(mStack[0]) == sizeof(js::ProfileEntry));
+    js::SetRuntimeProfilingStack(runtime,
+                                 (js::ProfileEntry*) mStack,
+                                 (uint32_t*) &mStackPointer,
+                                 mozilla::ArrayLength(mStack));
+    if (mStartJSSampling)
+      enableJSSampling();
+  }
+  void enableJSSampling() {
+    if (mRuntime) {
+      js::EnableRuntimeProfilingStack(mRuntime, true);
+      mStartJSSampling = false;
+    } else {
+      mStartJSSampling = true;
+    }
+  }
+  void disableJSSampling() {
+    mStartJSSampling = false;
+    if (mRuntime)
+      js::EnableRuntimeProfilingStack(mRuntime, false);
+  }
+
+  // Keep a list of active checkpoints
+  StackEntry volatile mStack[1024];
+  // Keep a list of active markers to be applied to the next sample taken
+  char* mMarkers[1024];
+ private:
+  // This may exceed the length of mStack, so instead use the stackSize() method
+  // to determine the number of valid samples in mStack
+  mozilla::sig_safe_t mStackPointer;
+  // If this is set then it's not safe to read mStackPointer from the signal handler
+  volatile bool mSignalLock;
+ public:
+  volatile mozilla::sig_safe_t mMarkerPointer;
+  // We don't want to modify _markers from within the signal so we allow
+  // it to queue a clear operation.
+  volatile mozilla::sig_safe_t mQueueClearMarker;
+  // The runtime which is being sampled
+  JSRuntime *mRuntime;
+  // Start JS Profiling when possible
+  bool mStartJSSampling;
+};
+
+#endif
+