Backed out 3 changesets (bug 734691, bug 862500) for leaks.
authorRyan VanderMeulen <ryanvm@gmail.com>
Thu, 18 Apr 2013 08:15:09 -0400
changeset 129174 fa5d5fccbc11ffdac6707e14fa45cfb8da2c987c
parent 129173 caf3832d2066f8a9610cf382b8733fc0f8f095dc
child 129187 032e5c11a9e6da533ffa50dbc4c8328764530a7c
child 129193 25d7bd2fd8d932411d3e21dbbef604cbea5e7219
push id24559
push userryanvm@gmail.com
push dateThu, 18 Apr 2013 14:56:46 +0000
treeherdermozilla-central@fa5d5fccbc11 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
bugs734691, 862500
milestone23.0a1
backs out4444510d672f82f2d8ea7f7a62e43953401e427d
5c321bc4dc63920768a3aac5cf784904494100dc
e045934f78bee59b6dc7ff64d90b5a66e1cc2268
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
Backed out 3 changesets (bug 734691, bug 862500) for leaks. Backed out changeset 4444510d672f (bug 862500) Backed out changeset 5c321bc4dc63 (bug 734691) Backed out changeset e045934f78be (bug 734691)
dom/workers/RuntimeService.cpp
ipc/chromium/src/base/thread.cc
toolkit/xre/nsAppRunner.cpp
toolkit/xre/nsEmbedFunctions.cpp
tools/profiler/BreakpadSampler.cpp
tools/profiler/GeckoProfiler.h
tools/profiler/GeckoProfilerFunc.h
tools/profiler/GeckoProfilerImpl.h
tools/profiler/Makefile.in
tools/profiler/ProfileEntry.cpp
tools/profiler/ProfileEntry.h
tools/profiler/PseudoStack.h
tools/profiler/TableTicker.cpp
tools/profiler/TableTicker.h
tools/profiler/platform-linux.cc
tools/profiler/platform-macos.cc
tools/profiler/platform-win32.cc
tools/profiler/platform.cpp
tools/profiler/platform.h
xpcom/build/nsXPComInit.cpp
--- a/dom/workers/RuntimeService.cpp
+++ b/dom/workers/RuntimeService.cpp
@@ -37,18 +37,16 @@
 
 #include "Events.h"
 #include "Worker.h"
 #include "WorkerPrivate.h"
 
 #include "OSFileConstants.h"
 #include <algorithm>
 
-#include "GeckoProfiler.h"
-
 using namespace mozilla;
 using namespace mozilla::dom;
 
 USING_WORKERS_NAMESPACE
 
 using mozilla::MutexAutoLock;
 using mozilla::MutexAutoUnlock;
 using mozilla::Preferences;
@@ -260,20 +258,16 @@ ErrorReporter(JSContext* aCx, const char
   WorkerPrivate* worker = GetWorkerPrivateFromContext(aCx);
   return worker->ReportError(aCx, aMessage, aReport);
 }
 
 JSBool
 OperationCallback(JSContext* aCx)
 {
   WorkerPrivate* worker = GetWorkerPrivateFromContext(aCx);
-
-  // Now is a good time to turn on profiling if it's pending.
-  profiler_js_operation_callback();
-
   return worker->OperationCallback(aCx);
 }
 
 class LogViolationDetailsRunnable : public nsRunnable
 {
   WorkerPrivate* mWorkerPrivate;
   nsString mFileName;
   uint32_t mLineNum;
@@ -516,29 +510,23 @@ public:
 
     JSContext* cx = CreateJSContextForWorker(workerPrivate);
     if (!cx) {
       // XXX need to fire an error at parent.
       NS_ERROR("Failed to create runtime and context!");
       return NS_ERROR_FAILURE;
     }
 
-    JSRuntime* rt = JS_GetRuntime(cx);
-
-    profiler_register_thread("WebWorker");
-#ifdef MOZ_ENABLE_PROFILER_SPS
-    if (PseudoStack* stack = mozilla_get_pseudo_stack())
-      stack->sampleRuntime(rt);
-#endif
-
     {
       JSAutoRequest ar(cx);
       workerPrivate->DoRunLoop(cx);
     }
 
+    JSRuntime* rt = JS_GetRuntime(cx);
+
     // XXX Bug 666963 - CTypes can create another JSContext for use with
     // closures, and then it holds that context in a reserved slot on the CType
     // prototype object. We have to destroy that context before we can destroy
     // the runtime, and we also have to make sure that it isn't the last context
     // to be destroyed (otherwise it will assert). To accomplish this we create
     // an unused dummy context, destroy our real context, and then destroy the
     // dummy. Once this bug is resolved we can remove this nastiness and simply
     // call JS_DestroyContextNoGC on our context.
@@ -547,24 +535,19 @@ public:
       JS_DestroyContext(cx);
       JS_DestroyContext(dummyCx);
     }
     else {
       NS_WARNING("Failed to create dummy context!");
       JS_DestroyContext(cx);
     }
 
-#ifdef MOZ_ENABLE_PROFILER_SPS
-    if (PseudoStack* stack = mozilla_get_pseudo_stack())
-      stack->sampleRuntime(nullptr);
-#endif
     JS_DestroyRuntime(rt);
 
     workerPrivate->ScheduleDeletion(false);
-    profiler_unregister_thread();
     return NS_OK;
   }
 };
 
 } /* anonymous namespace */
 
 BEGIN_WORKERS_NAMESPACE
 
--- a/ipc/chromium/src/base/thread.cc
+++ b/ipc/chromium/src/base/thread.cc
@@ -3,17 +3,16 @@
 // found in the LICENSE file.
 
 #include "base/thread.h"
 
 #include "base/lazy_instance.h"
 #include "base/string_util.h"
 #include "base/thread_local.h"
 #include "base/waitable_event.h"
-#include "GeckoProfiler.h"
 
 namespace base {
 
 // This task is used to trigger the message loop to exit.
 class ThreadQuitTask : public Task {
  public:
   virtual void Run() {
     MessageLoop::current()->Quit();
@@ -132,18 +131,16 @@ void Thread::StopSoon() {
   // most likely means that the thread terminated unexpectedly, probably due
   // to someone calling Quit() on our message loop directly.
   DCHECK(message_loop_);
 
   message_loop_->PostTask(FROM_HERE, new ThreadQuitTask());
 }
 
 void Thread::ThreadMain() {
-  profiler_register_thread(name_.c_str());
-
   // The message loop for this thread.
   MessageLoop message_loop(startup_data_->options.message_loop_type);
 
   // Complete the initialization of our Thread object.
   thread_id_ = PlatformThread::CurrentId();
   PlatformThread::SetName(name_.c_str());
   message_loop.set_thread_name(name_);
   message_loop_ = &message_loop;
@@ -159,16 +156,14 @@ void Thread::ThreadMain() {
   message_loop.Run();
 
   // Let the thread do extra cleanup.
   CleanUp();
 
   // Assert that MessageLoop::Quit was called by ThreadQuitTask.
   DCHECK(GetThreadWasQuitProperly());
 
-  profiler_unregister_thread();
-
   // We can't receive messages anymore.
   message_loop_ = NULL;
   thread_id_ = 0;
 }
 
 }  // namespace base
--- a/toolkit/xre/nsAppRunner.cpp
+++ b/toolkit/xre/nsAppRunner.cpp
@@ -3889,17 +3889,17 @@ XREMain::XRE_mainRun()
 }
 
 /*
  * XRE_main - A class based main entry point used by most platforms.
  */
 int
 XREMain::XRE_main(int argc, char* argv[], const nsXREAppData* aAppData)
 {
-  GeckoProfilerInitRAII profilerGuard;
+  profiler_init();
   PROFILER_LABEL("Startup", "XRE_Main");
 
   nsresult rv = NS_OK;
 
   gArgc = argc;
   gArgv = argv;
 
   NS_ENSURE_TRUE(aAppData, 2);
@@ -3990,16 +3990,17 @@ XREMain::XRE_main(int argc, char* argv[]
     SaveFileToEnvIfUnset("XRE_PROFILE_PATH", mProfD);
     SaveFileToEnvIfUnset("XRE_PROFILE_LOCAL_PATH", mProfLD);
     SaveWordToEnvIfUnset("XRE_PROFILE_NAME", mProfileName);
 
 #ifdef MOZ_WIDGET_GTK
     MOZ_gdk_display_close(mGdkDisplay);
 #endif
 
+    profiler_shutdown();
     rv = LaunchChild(mNativeApp, true);
 
 #ifdef MOZ_CRASHREPORTER
     if (mAppData->flags & NS_XRE_ENABLE_CRASH_REPORTER)
       CrashReporter::UnsetExceptionHandler();
 #endif
     return rv == NS_ERROR_LAUNCHED_CHILD_PROCESS ? 0 : 1;
   }
@@ -4012,16 +4013,18 @@ XREMain::XRE_main(int argc, char* argv[]
 
 #ifdef MOZ_CRASHREPORTER
   if (mAppData->flags & NS_XRE_ENABLE_CRASH_REPORTER)
       CrashReporter::UnsetExceptionHandler();
 #endif
 
   XRE_DeinitCommandLine();
 
+  profiler_shutdown();
+
   return NS_FAILED(rv) ? 1 : 0;
 }
 
 #if defined(MOZ_METRO) && defined(XP_WIN)
 extern bool XRE_MetroCoreApplicationRun();
 static XREMain* xreMainPtr;
 
 // must be called by the thread we want as the main thread
@@ -4084,17 +4087,17 @@ public:
     }
   }
   HRESULT mResult;
 };
 
 int
 XRE_mainMetro(int argc, char* argv[], const nsXREAppData* aAppData)
 {
-  GeckoProfilerInitRAII profilerGuard;
+  profiler_init();
   PROFILER_LABEL("Startup", "XRE_Main");
 
   nsresult rv = NS_OK;
 
   xreMainPtr = new XREMain();
   if (!xreMainPtr) {
     return 1;
   }
@@ -4125,16 +4128,17 @@ XRE_mainMetro(int argc, char* argv[], co
   if (!XRE_MetroCoreApplicationRun()) {
     return 1;
   }
 
   // XRE_metroShutdown should have already been called on the worker
   // thread that called XRE_metroStartup.
   NS_ASSERTION(!xreMainPtr->mScopedXPCom,
                "XPCOM Shutdown hasn't occured, and we are exiting.");
+  profiler_shutdown();
   return 0;
 }
 
 void SetWindowsEnvironment(WindowsEnvironmentType aEnvID);
 #endif // MOZ_METRO || !defined(XP_WIN)
 
 void
 XRE_DisableWritePoisoning(void) {
--- a/toolkit/xre/nsEmbedFunctions.cpp
+++ b/toolkit/xre/nsEmbedFunctions.cpp
@@ -277,17 +277,17 @@ SetTaskbarGroupId(const nsString& aId)
 nsresult
 XRE_InitChildProcess(int aArgc,
                      char* aArgv[],
                      GeckoProcessType aProcess)
 {
   NS_ENSURE_ARG_MIN(aArgc, 2);
   NS_ENSURE_ARG_POINTER(aArgv);
   NS_ENSURE_ARG_POINTER(aArgv[0]);
-  GeckoProfilerInitRAII profilerGuard;
+  profiler_init();
   PROFILER_LABEL("Startup", "XRE_InitChildProcess");
 
   sChildProcessType = aProcess;
 
   // Complete 'task_t' exchange for Mac OS X. This structure has the same size
   // regardless of architecture so we don't have any cross-arch issues here.
 #ifdef XP_MACOSX
   if (aArgc < 1)
--- a/tools/profiler/BreakpadSampler.cpp
+++ b/tools/profiler/BreakpadSampler.cpp
@@ -153,52 +153,45 @@ void genPseudoBacktraceEntries(/*MODIFIE
 #   endif
   }
 # endif
 }
 
 // RUNS IN SIGHANDLER CONTEXT
 void BreakpadSampler::Tick(TickSample* sample)
 {
-  if (!sample->threadProfile) {
-    // Platform doesn't support multithread, so use the main thread profile we created
-    sample->threadProfile = GetPrimaryThreadProfile();
-  }
-
-  ThreadProfile& currThreadProfile = *sample->threadProfile;
-
   /* Get hold of an empty inter-thread buffer into which to park
      the ProfileEntries for this sample. */
   UnwinderThreadBuffer* utb = uwt__acquire_empty_buffer();
 
   /* This could fail, if no buffers are currently available, in which
      case we must give up right away.  We cannot wait for a buffer to
      become available, as that risks deadlock. */
   if (!utb)
     return;
 
   /* Manufacture the ProfileEntries that we will give to the unwinder
      thread, and park them in |utb|. */
 
   // Marker(s) come before the sample
-  PseudoStack* stack = currThreadProfile.GetPseudoStack();
+  PseudoStack* stack = mPrimaryThreadProfile.GetPseudoStack();
   for (int i = 0; stack->getMarker(i) != NULL; i++) {
     utb__addEntry( utb, ProfileEntry('m', stack->getMarker(i)) );
   }
   stack->mQueueClearMarker = true;
 
   bool recordSample = true;
   if (mJankOnly) {
     // if we are on a different event we can discard any temporary samples
     // we've kept around
     if (sLastSampledEventGeneration != sCurrentEventGeneration) {
       // XXX: we also probably want to add an entry to the profile to help
       // distinguish which samples are part of the same event. That, or record
       // the event generation in each sample
-      currThreadProfile.erase();
+      mPrimaryThreadProfile.erase();
     }
     sLastSampledEventGeneration = sCurrentEventGeneration;
 
     recordSample = false;
     // only record the events when we have a we haven't seen a tracer
     // event for 100ms
     if (!sLastTracerEvent.IsNull()) {
       TimeDuration delta = sample->timestamp - sLastTracerEvent;
@@ -295,17 +288,17 @@ void BreakpadSampler::Tick(TickSample* s
     void* ucV = (void*)&uc;
 #   elif defined(SPS_OS_windows)
     /* Totally fake this up so it at least builds.  No idea if we can
        even ever get here on Windows. */
     void* ucV = NULL;
 #   else
 #     error "Unsupported platform"
 #   endif
-    uwt__release_full_buffer(&currThreadProfile, utb, ucV);
+    uwt__release_full_buffer(&mPrimaryThreadProfile, utb, ucV);
   } else {
-    uwt__release_full_buffer(&currThreadProfile, utb, NULL);
+    uwt__release_full_buffer(&mPrimaryThreadProfile, utb, NULL);
   }
 }
 
 // END take samples
 ////////////////////////////////////////////////////////////////////////
 
--- a/tools/profiler/GeckoProfiler.h
+++ b/tools/profiler/GeckoProfiler.h
@@ -130,32 +130,15 @@ static inline void profiler_print_locati
 // Discard the profile, throw away the profile and notify 'profiler-locked'.
 // This function is to be used when entering private browsing to prevent
 // the profiler from collecting sensitive data.
 static inline void profiler_lock() {}
 
 // Re-enable the profiler and notify 'profiler-unlocked'.
 static inline void profiler_unlock() {}
 
-static inline void profiler_register_thread(const char* name) {}
-static inline void profiler_unregister_thread() {}
-
-// Call by the JSRuntime's operation callback. This is used to enable
-// profiling on auxilerary threads.
-static inline void profiler_js_operation_callback() {}
-
 #else
 
 #include "GeckoProfilerImpl.h"
 
 #endif
 
-class GeckoProfilerInitRAII {
-public:
-  GeckoProfilerInitRAII() {
-    profiler_init();
-  }
-  ~GeckoProfilerInitRAII() {
-    profiler_shutdown();
-  }
-};
-
 #endif // ifndef SAMPLER_H
--- a/tools/profiler/GeckoProfilerFunc.h
+++ b/tools/profiler/GeckoProfilerFunc.h
@@ -52,17 +52,13 @@ 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_lock();
 
 // Unlock the profiler, leaving it stopped and fires profiler-unlocked.
 void mozilla_sampler_unlock();
 
-// Register/unregister threads with the profiler
-bool mozilla_sampler_register_thread(const char* name);
-void mozilla_sampler_unregister_thread();
-
 /* 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
@@ -135,54 +135,30 @@ void profiler_lock()
 }
 
 static inline
 void profiler_unlock()
 {
   return mozilla_sampler_unlock();
 }
 
-static inline
-void profiler_register_thread(const char* name)
-{
-  mozilla_sampler_register_thread(name);
-}
-
-static inline
-void profiler_unregister_thread()
-{
-  mozilla_sampler_unregister_thread();
-}
-
-static inline
-void profiler_js_operation_callback()
-{
-  PseudoStack *stack = tlsPseudoStack.get();
-  if (!stack) {
-    return;
-  }
-
-  stack->jsOperationCallback();
-}
-
 // we want the class and function name but can't easily get that using preprocessor macros
 // __func__ doesn't have the class name and __PRETTY_FUNCTION__ has the parameters
 
 #define SAMPLER_APPEND_LINE_NUMBER_PASTE(id, line) id ## line
 #define SAMPLER_APPEND_LINE_NUMBER_EXPAND(id, line) SAMPLER_APPEND_LINE_NUMBER_PASTE(id, line)
 #define SAMPLER_APPEND_LINE_NUMBER(id) SAMPLER_APPEND_LINE_NUMBER_EXPAND(id, __LINE__)
 
 #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)
 
-
 /* 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)
--- a/tools/profiler/Makefile.in
+++ b/tools/profiler/Makefile.in
@@ -29,19 +29,16 @@ MODULE_NAME     = nsProfilerModule
 LIBRARY_NAME    = profiler
 EXPORT_LIBRARY  = 1
 LIBXUL_LIBRARY  = 1
 IS_COMPONENT    = 1
 ifndef _MSC_VER
 FAIL_ON_WARNINGS = 1
 endif # !_MSC_VER
 
-# Uncomment for better debugging in opt builds
-#MOZ_OPTIMIZE_FLAGS += -O0 -g
-
 CPPSRCS		= \
   platform.cpp \
   nsProfilerFactory.cpp \
   nsProfiler.cpp \
   TableTicker.cpp \
   BreakpadSampler.cpp \
   UnwinderThread2.cpp \
   ProfileEntry.cpp \
--- a/tools/profiler/ProfileEntry.cpp
+++ b/tools/profiler/ProfileEntry.cpp
@@ -129,37 +129,29 @@ std::ostream& operator<<(std::ostream& s
 ////////////////////////////////////////////////////////////////////////
 
 
 ////////////////////////////////////////////////////////////////////////
 // BEGIN ThreadProfile
 
 #define DYNAMIC_MAX_STRING 512
 
-ThreadProfile::ThreadProfile(const char* aName, int aEntrySize,
-                             PseudoStack *aStack, int aThreadId,
-                             PlatformData* aPlatform,
-                             bool aIsMainThread)
+ThreadProfile::ThreadProfile(int aEntrySize, PseudoStack *aStack)
   : mWritePos(0)
   , mLastFlushPos(0)
   , mReadPos(0)
   , mEntrySize(aEntrySize)
   , mPseudoStack(aStack)
   , mMutex("ThreadProfile::mMutex")
-  , mName(strdup(aName))
-  , mThreadId(aThreadId)
-  , mIsMainThread(aIsMainThread)
-  , mPlatformData(aPlatform)
 {
   mEntries = new ProfileEntry[mEntrySize];
 }
 
 ThreadProfile::~ThreadProfile()
 {
-  free(mName);
   delete[] mEntries;
 }
 
 void ThreadProfile::addTag(ProfileEntry aTag)
 {
   // Called from signal, call only reentrant functions
   mEntries[mWritePos] = aTag;
   mWritePos = (mWritePos + 1) % mEntrySize;
@@ -302,20 +294,16 @@ JSCustomObject* ThreadProfile::ToJSObjec
   JSObjectBuilder b(aCx);
   JSCustomObject *profile = b.CreateObject();
   BuildJSObject(b, profile);
 
   return profile;
 }
 
 void ThreadProfile::BuildJSObject(JSAObjectBuilder& b, JSCustomObject* profile) {
-  // Thread meta data
-  b.DefineProperty(profile, "name", mName);
-  b.DefineProperty(profile, "tid", mThreadId);
-
   JSCustomArray *samples = b.CreateArray();
   b.DefineProperty(profile, "samples", samples);
 
   JSCustomObject *sample = nullptr;
   JSCustomArray *frames = nullptr;
   JSCustomArray *marker = nullptr;
 
   int readPos = mReadPos;
--- a/tools/profiler/ProfileEntry.h
+++ b/tools/profiler/ProfileEntry.h
@@ -1,23 +1,23 @@
 /* -*- 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 MOZ_PROFILE_ENTRY_H
 #define MOZ_PROFILE_ENTRY_H
 
-#include <ostream>
 #include "GeckoProfilerImpl.h"
 #include "JSAObjectBuilder.h"
 #include "platform.h"
 #include "mozilla/Mutex.h"
 
 class ThreadProfile;
+class ThreadProfile;
 
 class ProfileEntry
 {
 public:
   ProfileEntry();
 
   // aTagData must not need release (i.e. be a string from the text segment)
   ProfileEntry(char aTagName, const char *aTagData);
@@ -51,49 +51,37 @@ private:
   char mTagName;
 };
 
 typedef void (*IterateTagsCallback)(const ProfileEntry& entry, const char* tagStringData);
 
 class ThreadProfile
 {
 public:
-  ThreadProfile(const char* aName, int aEntrySize, PseudoStack *aStack,
-                int aThreadId, PlatformData* aPlatformData,
-                bool aIsMainThread);
+  ThreadProfile(int aEntrySize, PseudoStack *aStack);
   ~ThreadProfile();
   void addTag(ProfileEntry aTag);
   void flush();
   void erase();
   char* processDynamicTag(int readPos, int* tagsConsumed, char* tagBuff);
   void IterateTags(IterateTagsCallback aCallback);
   friend std::ostream& operator<<(std::ostream& stream,
                                   const ThreadProfile& profile);
   void ToStreamAsJSON(std::ostream& stream);
   JSCustomObject *ToJSObject(JSContext *aCx);
   PseudoStack* GetPseudoStack();
   mozilla::Mutex* GetMutex();
   void BuildJSObject(JSAObjectBuilder& b, JSCustomObject* profile);
-
-  bool IsMainThread() const { return mIsMainThread; }
-  const char* Name() const { return mName; }
-  int ThreadId() const { return mThreadId; }
-
-  PlatformData* GetPlatformData() { return mPlatformData; }
 private:
   // Circular buffer 'Keep One Slot Open' implementation
   // for simplicity
   ProfileEntry* mEntries;
   int            mWritePos; // points to the next entry we will write to
   int            mLastFlushPos; // points to the next entry since the last flush()
   int            mReadPos;  // points to the next entry we will read to
   int            mEntrySize;
   PseudoStack*   mPseudoStack;
   mozilla::Mutex mMutex;
-  char*          mName;
-  int            mThreadId;
-  bool           mIsMainThread;
-  PlatformData*  mPlatformData;  // Platform specific data.
 };
 
 std::ostream& operator<<(std::ostream& stream, const ThreadProfile& profile);
 
 #endif /* ndef MOZ_PROFILE_ENTRY_H */
--- a/tools/profiler/PseudoStack.h
+++ b/tools/profiler/PseudoStack.h
@@ -215,20 +215,16 @@ public:
   void enableJSSampling() {
     if (mRuntime) {
       js::EnableRuntimeProfilingStack(mRuntime, true);
       mStartJSSampling = false;
     } else {
       mStartJSSampling = true;
     }
   }
-  void jsOperationCallback() {
-    if (mStartJSSampling)
-      enableJSSampling();
-  }
   void disableJSSampling() {
     mStartJSSampling = false;
     if (mRuntime)
       js::EnableRuntimeProfilingStack(mRuntime, false);
   }
 
   // Keep a list of active checkpoints
   StackEntry volatile mStack[1024];
--- a/tools/profiler/TableTicker.cpp
+++ b/tools/profiler/TableTicker.cpp
@@ -168,36 +168,26 @@ void TableTicker::BuildJSObject(JSAObjec
   // Put meta data
   JSCustomObject *meta = GetMetaJSCustomObject(b);
   b.DefineProperty(profile, "meta", meta);
 
   // Lists the samples for each ThreadProfile
   JSCustomArray *threads = b.CreateArray();
   b.DefineProperty(profile, "threads", threads);
 
+  // For now we only have one thread
   SetPaused(true);
-
-  {
-    mozilla::MutexAutoLock lock(*sRegisteredThreadsMutex);
-
-    for (size_t i = 0; i < sRegisteredThreads->size(); i++) {
-      // Thread not being profiled, skip it
-      if (!sRegisteredThreads->at(i)->Profile())
-        continue;
-
-      MutexAutoLock lock(*sRegisteredThreads->at(i)->Profile()->GetMutex());
-
-      JSCustomObject* threadSamples = b.CreateObject();
-      sRegisteredThreads->at(i)->Profile()->BuildJSObject(b, threadSamples);
-      b.ArrayPush(threads, threadSamples);
-    }
-  }
-
+  ThreadProfile* prof = GetPrimaryThreadProfile();
+  prof->GetMutex()->Lock();
+  JSCustomObject* threadSamples = b.CreateObject();
+  prof->BuildJSObject(b, threadSamples);
+  b.ArrayPush(threads, threadSamples);
+  prof->GetMutex()->Unlock();
   SetPaused(false);
-} 
+}
 
 // END SaveProfileTask et al
 ////////////////////////////////////////////////////////////////////////
 
 static
 void addDynamicTag(ThreadProfile &aProfile, char aTagName, const char *aStr)
 {
   aProfile.addTag(ProfileEntry(aTagName, ""));
@@ -290,34 +280,34 @@ void StackWalkCallback(void* aPC, void* 
   array->sp_array[array->count] = aSP;
   array->array[array->count] = aPC;
   array->count++;
 }
 
 void TableTicker::doNativeBacktrace(ThreadProfile &aProfile, TickSample* aSample)
 {
 #ifndef XP_MACOSX
-  uintptr_t thread = GetThreadHandle(aSample->threadProfile->GetPlatformData());
+  uintptr_t thread = GetThreadHandle(platform_data());
   MOZ_ASSERT(thread);
 #endif
   void* pc_array[1000];
   void* sp_array[1000];
   PCArray array = {
     pc_array,
     sp_array,
     mozilla::ArrayLength(pc_array),
     0
   };
 
   // Start with the current function.
   StackWalkCallback(aSample->pc, aSample->sp, &array);
 
   uint32_t maxFrames = uint32_t(array.size - array.count);
 #ifdef XP_MACOSX
-  pthread_t pt = GetProfiledThread(aSample->threadProfile->GetPlatformData());
+  pthread_t pt = GetProfiledThread(platform_data());
   void *stackEnd = reinterpret_cast<void*>(-1);
   if (pt)
     stackEnd = static_cast<char*>(pthread_get_stackaddr_np(pt));
   nsresult rv = NS_OK;
   if (aSample->fp >= aSample->sp && aSample->fp <= stackEnd)
     rv = FramePointerStackWalk(StackWalkCallback, /* skipFrames */ 0,
                                maxFrames, &array,
                                reinterpret_cast<void**>(aSample->fp), stackEnd);
@@ -388,72 +378,70 @@ void doSampleStackTrace(PseudoStack *aSt
     aProfile.addTag(ProfileEntry('L', (void*)sample->lr));
 #endif
   }
 #endif
 }
 
 void TableTicker::Tick(TickSample* sample)
 {
-  ThreadProfile& currThreadProfile = *sample->threadProfile;
-
   // Marker(s) come before the sample
-  PseudoStack* stack = currThreadProfile.GetPseudoStack();
+  PseudoStack* stack = mPrimaryThreadProfile.GetPseudoStack();
   for (int i = 0; stack->getMarker(i) != NULL; i++) {
-    addDynamicTag(currThreadProfile, 'm', stack->getMarker(i));
+    addDynamicTag(mPrimaryThreadProfile, 'm', stack->getMarker(i));
   }
   stack->mQueueClearMarker = true;
 
   bool recordSample = true;
   if (mJankOnly) {
     // if we are on a different event we can discard any temporary samples
     // we've kept around
     if (sLastSampledEventGeneration != sCurrentEventGeneration) {
       // XXX: we also probably want to add an entry to the profile to help
       // distinguish which samples are part of the same event. That, or record
       // the event generation in each sample
-      currThreadProfile.erase();
+      mPrimaryThreadProfile.erase();
     }
     sLastSampledEventGeneration = sCurrentEventGeneration;
 
     recordSample = false;
     // only record the events when we have a we haven't seen a tracer event for 100ms
     if (!sLastTracerEvent.IsNull()) {
       TimeDuration delta = sample->timestamp - sLastTracerEvent;
       if (delta.ToMilliseconds() > 100.0) {
           recordSample = true;
       }
     }
   }
 
 #if defined(USE_BACKTRACE) || defined(USE_NS_STACKWALK)
   if (mUseStackWalk) {
-    doNativeBacktrace(currThreadProfile, sample);
+    doNativeBacktrace(mPrimaryThreadProfile, sample);
   } else {
-    doSampleStackTrace(stack, currThreadProfile, mAddLeafAddresses ? sample : nullptr);
+    doSampleStackTrace(stack, mPrimaryThreadProfile, mAddLeafAddresses ? sample : nullptr);
   }
 #else
-  doSampleStackTrace(stack, currThreadProfile, mAddLeafAddresses ? sample : nullptr);
+  doSampleStackTrace(stack, mPrimaryThreadProfile, mAddLeafAddresses ? sample : nullptr);
 #endif
 
   if (recordSample)
-    currThreadProfile.flush();
+    mPrimaryThreadProfile.flush();
 
-  if (!sLastTracerEvent.IsNull() && sample && currThreadProfile.IsMainThread()) {
+  if (!sLastTracerEvent.IsNull() && sample) {
     TimeDuration delta = sample->timestamp - sLastTracerEvent;
-    currThreadProfile.addTag(ProfileEntry('r', delta.ToMilliseconds()));
+    mPrimaryThreadProfile.addTag(ProfileEntry('r', delta.ToMilliseconds()));
   }
 
   if (sample) {
     TimeDuration delta = sample->timestamp - mStartTime;
-    currThreadProfile.addTag(ProfileEntry('t', delta.ToMilliseconds()));
+    mPrimaryThreadProfile.addTag(ProfileEntry('t', delta.ToMilliseconds()));
   }
 
   if (sLastFrameNumber != sFrameNumber) {
-    currThreadProfile.addTag(ProfileEntry('f', sFrameNumber));
+    mPrimaryThreadProfile.addTag(ProfileEntry('f', sFrameNumber));
     sLastFrameNumber = sFrameNumber;
   }
 }
 
 static void print_callback(const ProfileEntry& entry, const char* tagStringData) {
   switch (entry.getTagName()) {
     case 's':
     case 'c':
@@ -467,18 +455,17 @@ void mozilla_sampler_print_location1()
     profiler_init();
 
   PseudoStack *stack = tlsPseudoStack.get();
   if (!stack) {
     MOZ_ASSERT(false);
     return;
   }
 
-  ThreadProfile threadProfile("Temp", PROFILE_DEFAULT_ENTRY, stack,
-                              0, Sampler::AllocPlatformData(0), false);
+  ThreadProfile threadProfile(1000, stack);
   doSampleStackTrace(stack, threadProfile, NULL);
 
   threadProfile.flush();
 
   printf_stderr("Backtrace:\n");
   threadProfile.IterateTags(print_callback);
 }
 
--- a/tools/profiler/TableTicker.h
+++ b/tools/profiler/TableTicker.h
@@ -1,16 +1,15 @@
 /* -*- 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/. */
 
 #include "platform.h"
 #include "ProfileEntry.h"
-#include "mozilla/Mutex.h"
 
 static bool
 hasFeature(const char** aFeatures, uint32_t aFeatureCount, const char* aFeature) {
   for(size_t i = 0; i < aFeatureCount; i++) {
     if (strcmp(aFeatures[i], aFeature) == 0)
       return true;
   }
   return false;
@@ -21,136 +20,81 @@ extern int sFrameNumber;
 extern int sLastFrameNumber;
 extern unsigned int sCurrentEventGeneration;
 extern unsigned int sLastSampledEventGeneration;
 
 class BreakpadSampler;
 
 class TableTicker: public Sampler {
  public:
-  TableTicker(int aInterval, int aEntrySize,
+  TableTicker(int aInterval, int aEntrySize, PseudoStack *aStack,
               const char** aFeatures, uint32_t aFeatureCount)
-    : Sampler(aInterval, true, aEntrySize)
-    , mPrimaryThreadProfile(nullptr)
+    : Sampler(aInterval, true)
+    , mPrimaryThreadProfile(aEntrySize, aStack)
     , mStartTime(TimeStamp::Now())
     , mSaveRequested(false)
   {
     mUseStackWalk = hasFeature(aFeatures, aFeatureCount, "stackwalk");
 
     //XXX: It's probably worth splitting the jank profiler out from the regular profiler at some point
     mJankOnly = hasFeature(aFeatures, aFeatureCount, "jank");
     mProfileJS = hasFeature(aFeatures, aFeatureCount, "js");
-    mProfileThreads = true || hasFeature(aFeatures, aFeatureCount, "threads");
     mAddLeafAddresses = hasFeature(aFeatures, aFeatureCount, "leaf");
-
-    {
-      mozilla::MutexAutoLock lock(*sRegisteredThreadsMutex);
-
-      // Create ThreadProfile for each registered thread
-      for (uint32_t i = 0; i < sRegisteredThreads->size(); i++) {
-        ThreadInfo* info = sRegisteredThreads->at(i);
-
-        if (!info->IsMainThread() && !mProfileThreads)
-          continue;
-
-        ThreadProfile* profile = new ThreadProfile(info->Name(),
-                                                   aEntrySize,
-                                                   info->Stack(),
-                                                   info->ThreadId(),
-                                                   info->GetPlatformData(),
-                                                   info->IsMainThread());
-        profile->addTag(ProfileEntry('m', "Start"));
-
-        info->SetProfile(profile);
-      }
-
-      SetActiveSampler(this);
-    }
+    mPrimaryThreadProfile.addTag(ProfileEntry('m', "Start"));
   }
 
-  ~TableTicker() {
-    if (IsActive())
-      Stop();
-
-    SetActiveSampler(nullptr);
-
-    // Destroy ThreadProfile for all threads
-    {
-      mozilla::MutexAutoLock lock(*sRegisteredThreadsMutex);
+  ~TableTicker() { if (IsActive()) Stop(); }
 
-      for (uint32_t i = 0; i < sRegisteredThreads->size(); i++) {
-        ThreadInfo* info = sRegisteredThreads->at(i);
-        ThreadProfile* profile = info->Profile();
-        if (profile) {
-          delete profile;
-          info->SetProfile(nullptr);
-        }
-      }
-    }
-  }
+  virtual void SampleStack(TickSample* sample) {}
 
   // Called within a signal. This function must be reentrant
   virtual void Tick(TickSample* sample);
 
   // Called within a signal. This function must be reentrant
   virtual void RequestSave()
   {
     mSaveRequested = true;
   }
 
   virtual void HandleSaveRequest();
 
   ThreadProfile* GetPrimaryThreadProfile()
   {
-    if (!mPrimaryThreadProfile) {
-      mozilla::MutexAutoLock lock(*sRegisteredThreadsMutex);
-
-      for (uint32_t i = 0; i < sRegisteredThreads->size(); i++) {
-        ThreadInfo* info = sRegisteredThreads->at(i);
-        if (info->IsMainThread()) {
-          mPrimaryThreadProfile = info->Profile();
-          break;
-        }
-      }
-    }
-
-    return mPrimaryThreadProfile;
+    return &mPrimaryThreadProfile;
   }
 
   void ToStreamAsJSON(std::ostream& stream);
   virtual JSObject *ToJSObject(JSContext *aCx);
   JSCustomObject *GetMetaJSCustomObject(JSAObjectBuilder& b);
 
-  bool ProfileJS() const { return mProfileJS; }
-  bool ProfileThreads() const { return mProfileThreads; }
+  const bool ProfileJS() { return mProfileJS; }
 
   virtual BreakpadSampler* AsBreakpadSampler() { return nullptr; }
 
 protected:
   // Not implemented on platforms which do not support backtracing
   void doNativeBacktrace(ThreadProfile &aProfile, TickSample* aSample);
 
   void BuildJSObject(JSAObjectBuilder& b, JSCustomObject* profile);
 
   // This represent the application's main thread (SAMPLER_INIT)
-  ThreadProfile* mPrimaryThreadProfile;
+  ThreadProfile mPrimaryThreadProfile;
   TimeStamp mStartTime;
   bool mSaveRequested;
   bool mAddLeafAddresses;
   bool mUseStackWalk;
   bool mJankOnly;
   bool mProfileJS;
-  bool mProfileThreads;
 };
 
 class BreakpadSampler: public TableTicker {
  public:
-  BreakpadSampler(int aInterval, int aEntrySize,
+  BreakpadSampler(int aInterval, int aEntrySize, PseudoStack *aStack,
               const char** aFeatures, uint32_t aFeatureCount)
-    : TableTicker(aInterval, aEntrySize, aFeatures, aFeatureCount)
+    : TableTicker(aInterval, aEntrySize, aStack, aFeatures, aFeatureCount)
   {}
 
   // Called within a signal. This function must be reentrant
   virtual void Tick(TickSample* sample);
 
   virtual BreakpadSampler* AsBreakpadSampler() { return this; }
 };
 
--- a/tools/profiler/platform-linux.cc
+++ b/tools/profiler/platform-linux.cc
@@ -34,17 +34,16 @@
 #include <pthread.h>
 #include <semaphore.h>
 #include <signal.h>
 #include <sys/time.h>
 #include <sys/resource.h>
 #include <sys/syscall.h>
 #include <sys/types.h>
 #include <stdlib.h>
-#include <sched.h>
 #ifdef ANDROID
 #include <android/log.h>
 #else
 #define __android_log_print(a, ...)
 #endif
 // Ubuntu Dapper requires memory pages to be marked as
 // executable. Otherwise, OS raises an exception when executing code
 // in that page.
@@ -56,36 +55,34 @@
 #ifdef __GLIBC__
 #include <execinfo.h>   // backtrace, backtrace_symbols
 #endif  // def __GLIBC__
 #include <strings.h>    // index
 #include <errno.h>
 #include <stdarg.h>
 #include "platform.h"
 #include "GeckoProfilerImpl.h"
-#include "mozilla/Mutex.h"
-#include "ProfileEntry.h"
-#include "nsThreadUtils.h"
-#include "TableTicker.h"
 
 #include <string.h>
 #include <stdio.h>
-#include <list>
 
 #define SIGNAL_SAVE_PROFILE SIGUSR2
 
 #if defined(__GLIBC__)
 // glibc doesn't implement gettid(2).
 #include <sys/syscall.h>
 pid_t gettid()
 {
   return (pid_t) syscall(SYS_gettid);
 }
 #endif
 
+static Sampler* sActiveSampler = NULL;
+
+
 #if !defined(ANDROID)
 // Keep track of when any of our threads calls fork(), so we can
 // temporarily disable signal delivery during the fork() call.  Not
 // doing so appears to cause a kind of race, in which signals keep
 // getting delivered to the thread doing fork(), which keeps causing
 // it to fail and be restarted; hence forward progress is delayed a
 // great deal.  A side effect of this is to permanently disable
 // sampling in the child process.  See bug 837390.
@@ -94,80 +91,65 @@ pid_t gettid()
 // doesn't have pthread_atfork.
 
 // This records the current state at the time we paused it.
 static bool was_paused = false;
 
 // In the parent, just before the fork, record the pausedness state,
 // and then pause.
 static void paf_prepare(void) {
-  if (Sampler::GetActiveSampler()) {
-    was_paused = Sampler::GetActiveSampler()->IsPaused();
-    Sampler::GetActiveSampler()->SetPaused(true);
+  if (sActiveSampler) {
+    was_paused = sActiveSampler->IsPaused();
+    sActiveSampler->SetPaused(true);
   } else {
     was_paused = false;
   }
 }
 
 // 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);
+  if (sActiveSampler)
+    sActiveSampler->SetPaused(was_paused);
 }
 
 // Set up the fork handlers.  This is called just once, at the first
 // call to SenderEntry.
 static void* setup_atfork() {
   pthread_atfork(paf_prepare, paf_parent, NULL);
   return NULL;
 }
 #endif /* !defined(ANDROID) */
 
 #ifdef ANDROID
 #include "android-signal-defs.h"
 #endif
 
-struct SamplerRegistry {
-  static void AddActiveSampler(Sampler *sampler) {
-    ASSERT(!SamplerRegistry::sampler);
-    SamplerRegistry::sampler = sampler;
-  }
-  static void RemoveActiveSampler(Sampler *sampler) {
-    SamplerRegistry::sampler = NULL;
-  }
-  static Sampler *sampler;
-};
-
-Sampler *SamplerRegistry::sampler = NULL;
-
-static ThreadProfile* sCurrentThreadProfile = NULL;
-
 static void ProfilerSaveSignalHandler(int signal, siginfo_t* info, void* context) {
-  Sampler::GetActiveSampler()->RequestSave();
+  sActiveSampler->RequestSave();
 }
 
 #ifdef ANDROID
 #define V8_HOST_ARCH_ARM 1
 #define SYS_gettid __NR_gettid
 #define SYS_tgkill __NR_tgkill
 #else
 #define V8_HOST_ARCH_X64 1
 #endif
 static void ProfilerSignalHandler(int signal, siginfo_t* info, void* context) {
-  if (!Sampler::GetActiveSampler())
+  if (!sActiveSampler)
     return;
 
   TickSample sample_obj;
   TickSample* sample = &sample_obj;
   sample->context = context;
 
 #ifdef ENABLE_SPS_LEAF_DATA
   // If profiling, we extract the current pc and sp.
-  if (Sampler::GetActiveSampler()->IsProfiling()) {
+  if (sActiveSampler->IsProfiling()) {
     // Extracting the sample from the context is extremely machine dependent.
     ucontext_t* ucontext = reinterpret_cast<ucontext_t*>(context);
     mcontext_t& mcontext = ucontext->uc_mcontext;
 #if V8_HOST_ARCH_IA32
     sample->pc = reinterpret_cast<Address>(mcontext.gregs[REG_EIP]);
     sample->sp = reinterpret_cast<Address>(mcontext.gregs[REG_ESP]);
     sample->fp = reinterpret_cast<Address>(mcontext.gregs[REG_EBP]);
 #elif V8_HOST_ARCH_X64
@@ -192,224 +174,170 @@ static void ProfilerSignalHandler(int si
 #endif
 #endif
 #elif V8_HOST_ARCH_MIPS
     // Implement this on MIPS.
     UNIMPLEMENTED();
 #endif
   }
 #endif
-  sample->threadProfile = sCurrentThreadProfile;
   sample->timestamp = mozilla::TimeStamp::Now();
 
-  Sampler::GetActiveSampler()->Tick(sample);
-
-  sCurrentThreadProfile = NULL;
-}
-
-int tgkill(pid_t tgid, pid_t tid, int signalno) {
-  return syscall(SYS_tgkill, tgid, tid, signalno);
+  sActiveSampler->Tick(sample);
 }
 
-class PlatformData : public Malloced {
+#ifndef XP_MACOSX
+void tgkill(pid_t tgid, pid_t tid, int signalno) {
+  syscall(SYS_tgkill, tgid, tid, signalno);
+}
+#endif
+
+class Sampler::PlatformData : public Malloced {
  public:
-  PlatformData()
-  {}
+  explicit PlatformData(Sampler* sampler)
+      : sampler_(sampler),
+        signal_handler_installed_(false),
+        vm_tgid_(getpid()),
+#ifndef XP_MACOSX
+        vm_tid_(gettid()),
+#endif
+        signal_sender_launched_(false)
+#ifdef XP_MACOSX
+        , signal_receiver_(pthread_self())
+#endif
+  {
+  }
+
+  void SignalSender() {
+    while (sampler_->IsActive()) {
+      sampler_->HandleSaveRequest();
+
+      if (!sampler_->IsPaused()) {
+#ifdef XP_MACOSX
+        pthread_kill(signal_receiver_, SIGPROF);
+#else
+        // Glibc doesn't provide a wrapper for tgkill(2).
+        tgkill(vm_tgid_, vm_tid_, SIGPROF);
+#endif
+      }
+
+      // Convert ms to us and subtract 100 us to compensate delays
+      // occuring during signal delivery.
+      // TODO measure and confirm this.
+      const useconds_t interval = sampler_->interval_ * 1000 - 100;
+      //int result = usleep(interval);
+      usleep(interval);
+    }
+  }
+
+  Sampler* sampler_;
+  bool signal_handler_installed_;
+  struct sigaction old_sigprof_signal_handler_;
+  struct sigaction old_sigsave_signal_handler_;
+  pid_t vm_tgid_;
+  pid_t vm_tid_;
+  bool signal_sender_launched_;
+  pthread_t signal_sender_thread_;
+#ifdef XP_MACOSX
+  pthread_t signal_receiver_;
+#endif
 };
 
-/* static */ PlatformData*
-Sampler::AllocPlatformData(int aThreadId)
-{
-  return new PlatformData;
-}
 
-/* static */ void
-Sampler::FreePlatformData(PlatformData* aData)
-{
-  delete aData;
-}
-
-static void* SignalSender(void* arg) {
+static void* SenderEntry(void* arg) {
 # 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
-
-  int vm_tgid_ = getpid();
-
-  while (SamplerRegistry::sampler->IsActive()) {
-    SamplerRegistry::sampler->HandleSaveRequest();
-
-    if (!SamplerRegistry::sampler->IsPaused()) {
-      mozilla::MutexAutoLock lock(*Sampler::sRegisteredThreadsMutex);
-      std::vector<ThreadInfo*> threads =
-        SamplerRegistry::sampler->GetRegisteredThreads();
-
-      for (uint32_t i = 0; i < threads.size(); i++) {
-        ThreadInfo* info = threads[i];
-
-        // This will be null if we're not interested in profiling this thread.
-        if (!info->Profile())
-          continue;
-
-        // We use sCurrentThreadProfile the ThreadProfile for the
-        // thread we're profiling to the signal handler
-        sCurrentThreadProfile = info->Profile();
-
-        int threadId = info->ThreadId();
-
-        if (tgkill(vm_tgid_, threadId, SIGPROF) != 0) {
-          printf_stderr("profiler failed to signal tid=%d\n", threadId);
-#ifdef DEBUG
-          abort();
-#endif
-          continue;
-        }
-
-        // Wait for the signal handler to run before moving on to the next one
-        while (sCurrentThreadProfile)
-          sched_yield();
-      }
-    }
-
-    // Convert ms to us and subtract 100 us to compensate delays
-    // occuring during signal delivery.
-    // TODO measure and confirm this.
-    const useconds_t interval =
-      SamplerRegistry::sampler->interval() * 1000 - 100;
-    //int result = usleep(interval);
-    usleep(interval);
-  }
+  Sampler::PlatformData* data =
+      reinterpret_cast<Sampler::PlatformData*>(arg);
+  data->SignalSender();
   return initialize_atfork; // which is guaranteed to be NULL
 }
 
-Sampler::Sampler(int interval, bool profiling, int entrySize)
+
+Sampler::Sampler(int interval, bool profiling)
     : interval_(interval),
       profiling_(profiling),
       paused_(false),
-      active_(false),
-      entrySize_(entrySize) {
+      active_(false) {
+  data_ = new PlatformData(this);
 }
 
 Sampler::~Sampler() {
-  ASSERT(!signal_sender_launched_);
+  ASSERT(!data_->signal_sender_launched_);
+  delete data_;
 }
 
 
 void Sampler::Start() {
   LOG("Sampler started");
-
-  SamplerRegistry::AddActiveSampler(this);
+  if (sActiveSampler != NULL) return;
 
   // Request profiling signals.
   LOG("Request signal");
   struct sigaction sa;
   sa.sa_sigaction = ProfilerSignalHandler;
   sigemptyset(&sa.sa_mask);
   sa.sa_flags = SA_RESTART | SA_SIGINFO;
-  if (sigaction(SIGPROF, &sa, &old_sigprof_signal_handler_) != 0) {
+  if (sigaction(SIGPROF, &sa, &data_->old_sigprof_signal_handler_) != 0) {
     LOG("Error installing signal");
     return;
   }
 
   // Request save profile signals
   struct sigaction sa2;
   sa2.sa_sigaction = ProfilerSaveSignalHandler;
   sigemptyset(&sa2.sa_mask);
   sa2.sa_flags = SA_RESTART | SA_SIGINFO;
-  if (sigaction(SIGNAL_SAVE_PROFILE, &sa2, &old_sigsave_signal_handler_) != 0) {
+  if (sigaction(SIGNAL_SAVE_PROFILE, &sa2, &data_->old_sigsave_signal_handler_) != 0) {
     LOG("Error installing start signal");
     return;
   }
   LOG("Signal installed");
-  signal_handler_installed_ = true;
+  data_->signal_handler_installed_ = true;
 
   // Start a thread that sends SIGPROF signal to VM thread.
   // Sending the signal ourselves instead of relying on itimer provides
   // much better accuracy.
   SetActive(true);
   if (pthread_create(
-        &signal_sender_thread_, NULL, SignalSender, NULL) == 0) {
-    signal_sender_launched_ = true;
+          &data_->signal_sender_thread_, NULL, SenderEntry, data_) == 0) {
+    data_->signal_sender_launched_ = true;
   }
   LOG("Profiler thread started");
+
+  // Set this sampler as the active sampler.
+  sActiveSampler = this;
 }
 
 
 void Sampler::Stop() {
   SetActive(false);
 
   // Wait for signal sender termination (it will exit after setting
   // active_ to false).
-  if (signal_sender_launched_) {
-    pthread_join(signal_sender_thread_, NULL);
-    signal_sender_launched_ = false;
+  if (data_->signal_sender_launched_) {
+    pthread_join(data_->signal_sender_thread_, NULL);
+    data_->signal_sender_launched_ = false;
   }
 
-  SamplerRegistry::RemoveActiveSampler(this);
-
   // Restore old signal handler
-  if (signal_handler_installed_) {
-    sigaction(SIGNAL_SAVE_PROFILE, &old_sigsave_signal_handler_, 0);
-    sigaction(SIGPROF, &old_sigprof_signal_handler_, 0);
-    signal_handler_installed_ = false;
-  }
-}
-
-bool Sampler::RegisterCurrentThread(const char* aName, PseudoStack* aPseudoStack, bool aIsMainThread)
-{
-  if (!Sampler::sRegisteredThreadsMutex)
-    return false;
-
-  mozilla::MutexAutoLock lock(*Sampler::sRegisteredThreadsMutex);
-
-  ThreadInfo* info = new ThreadInfo(aName, gettid(),
-    aIsMainThread, aPseudoStack);
-
-  bool profileThread = sActiveSampler &&
-    (aIsMainThread || sActiveSampler->ProfileThreads());
-
-  if (profileThread) {
-    // We need to create the ThreadProfile now
-    info->SetProfile(new ThreadProfile(info->Name(),
-                                       sActiveSampler->EntrySize(),
-                                       info->Stack(),
-                                       info->ThreadId(),
-                                       info->GetPlatformData(),
-                                       aIsMainThread));
-    if (sActiveSampler->ProfileJS()) {
-      info->Profile()->GetPseudoStack()->enableJSSampling();
-    }
+  if (data_->signal_handler_installed_) {
+    sigaction(SIGNAL_SAVE_PROFILE, &data_->old_sigsave_signal_handler_, 0);
+    sigaction(SIGPROF, &data_->old_sigprof_signal_handler_, 0);
+    data_->signal_handler_installed_ = false;
   }
 
-  sRegisteredThreads->push_back(info);
-  return true;
-}
-
-void Sampler::UnregisterCurrentThread()
-{
-  if (!Sampler::sRegisteredThreadsMutex)
-    return;
-
-  mozilla::MutexAutoLock lock(*Sampler::sRegisteredThreadsMutex);
-
-  int id = gettid();
-
-  for (uint32_t i = 0; i < sRegisteredThreads->size(); i++) {
-    ThreadInfo* info = sRegisteredThreads->at(i);
-    if (info->ThreadId() == id) {
-      delete info;
-      sRegisteredThreads->erase(sRegisteredThreads->begin() + i);
-      break;
-    }
-  }
+  // This sampler is no longer the active sampler.
+  sActiveSampler = NULL;
 }
 
 #ifdef ANDROID
 static struct sigaction old_sigstart_signal_handler;
 const int SIGSTART = SIGUSR1;
 
 static void StartSignalHandler(int signal, siginfo_t* info, void* context) {
   profiler_start(PROFILE_DEFAULT_ENTRY, PROFILE_DEFAULT_INTERVAL,
@@ -423,9 +351,8 @@ void OS::RegisterStartHandler()
   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");
   }
 }
 #endif
-
--- a/tools/profiler/platform-macos.cc
+++ b/tools/profiler/platform-macos.cc
@@ -23,20 +23,17 @@
 #include <sys/resource.h>
 #include <sys/types.h>
 #include <sys/sysctl.h>
 #include <stdarg.h>
 #include <stdlib.h>
 #include <string.h>
 #include <errno.h>
 
-#include "nsThreadUtils.h"
-
 #include "platform.h"
-#include "TableTicker.h"
 #include "UnwinderThread2.h"  /* uwt__register_thread_for_profiling */
 
 // this port is based off of v8 svn revision 9837
 
 // XXX: this is a very stubbed out implementation
 // that only supports a single Sampler
 struct SamplerRegistry {
   static void AddActiveSampler(Sampler *sampler) {
@@ -87,23 +84,31 @@ class MacOSMutex : public Mutex {
 Mutex* OS::CreateMutex() {
   return new MacOSMutex();
 }
 
 void OS::Sleep(int milliseconds) {
   usleep(1000 * milliseconds);
 }
 
+class Thread::PlatformData : public Malloced {
+ public:
+  PlatformData() : thread_(kNoThread) {}
+  pthread_t thread_;  // Thread handle for pthread.
+};
+
 Thread::Thread(const char* name)
-    : stack_size_(0) {
+    : data_(new PlatformData),
+      stack_size_(0) {
   set_name(name);
 }
 
 
 Thread::~Thread() {
+  delete data_;
 }
 
 
 static void SetThreadName(const char* name) {
   // pthread_setname_np is only available in 10.6 or later, so test
   // for it at runtime.
   int (*dynamic_pthread_setname_np)(const char*);
   *reinterpret_cast<void**>(&dynamic_pthread_setname_np) =
@@ -129,19 +134,19 @@ static void* ThreadEntry(void* arg) {
   extern bool sps_version2();
   if (sps_version2()) {
     // Register this thread for profiling.
     int aLocal;
     uwt__register_thread_for_profiling( &aLocal );
   }
   // END temp hack for SPS v1-vs-v2
 
-  thread->thread_ = pthread_self();
+  thread->data()->thread_ = pthread_self();
   SetThreadName(thread->name());
-  ASSERT(thread->thread_ != kNoThread);
+  ASSERT(thread->data()->thread_ != kNoThread);
   thread->Run();
   return NULL;
 }
 
 
 void Thread::set_name(const char* name) {
   strncpy(name_, name, sizeof(name_));
   name_[sizeof(name_) - 1] = '\0';
@@ -151,25 +156,25 @@ void Thread::set_name(const char* name) 
 void Thread::Start() {
   pthread_attr_t* attr_ptr = NULL;
   pthread_attr_t attr;
   if (stack_size_ > 0) {
     pthread_attr_init(&attr);
     pthread_attr_setstacksize(&attr, static_cast<size_t>(stack_size_));
     attr_ptr = &attr;
   }
-  pthread_create(&thread_, attr_ptr, ThreadEntry, this);
-  ASSERT(thread_ != kNoThread);
+  pthread_create(&data_->thread_, attr_ptr, ThreadEntry, this);
+  ASSERT(data_->thread_ != kNoThread);
 }
 
 void Thread::Join() {
-  pthread_join(thread_, NULL);
+  pthread_join(data_->thread_, NULL);
 }
 
-class PlatformData : public Malloced {
+class Sampler::PlatformData : public Malloced {
  public:
   PlatformData() : profiled_thread_(mach_thread_self())
   {
     profiled_pthread_ = pthread_from_mach_thread_np(profiled_thread_);
   }
 
   ~PlatformData() {
     // Deallocate Mach port for thread.
@@ -185,85 +190,66 @@ class PlatformData : public Malloced {
   // For details, consult "Mac OS X Internals" book, Section 7.3.
   thread_act_t profiled_thread_;
   // we also store the pthread because Mach threads have no concept of stack
   // and we want to be able to get the stack size when we need to unwind the
   // stack using frame pointers.
   pthread_t profiled_pthread_;
 };
 
-/* static */ PlatformData*
-Sampler::AllocPlatformData(int aThreadId)
-{
-  return new PlatformData;
-}
-
-/* static */ void
-Sampler::FreePlatformData(PlatformData* aData)
-{
-  delete aData;
-}
 
 class SamplerThread : public Thread {
  public:
   explicit SamplerThread(int interval)
-      : Thread("SamplerThread")
-      , interval_(interval) {}
+      : Thread("SamplerThread"),
+        interval_(interval) {}
 
   static void AddActiveSampler(Sampler* sampler) {
-    mozilla::MutexAutoLock lock(*Sampler::sRegisteredThreadsMutex);
+    ScopedLock lock(mutex_);
     SamplerRegistry::AddActiveSampler(sampler);
     if (instance_ == NULL) {
       instance_ = new SamplerThread(sampler->interval());
       instance_->Start();
     } else {
       ASSERT(instance_->interval_ == sampler->interval());
     }
   }
 
   static void RemoveActiveSampler(Sampler* sampler) {
-    mozilla::MutexAutoLock lock(*Sampler::sRegisteredThreadsMutex);
+    ScopedLock lock(mutex_);
     instance_->Join();
     //XXX: unlike v8 we need to remove the active sampler after doing the Join
     // because we drop the sampler immediately
     SamplerRegistry::RemoveActiveSampler(sampler);
     delete instance_;
     instance_ = NULL;
+    /*
+    if (SamplerRegistry::GetState() == SamplerRegistry::HAS_NO_SAMPLERS) {
+      RuntimeProfiler::StopRuntimeProfilerThreadBeforeShutdown(instance_);
+      delete instance_;
+      instance_ = NULL;
+    }
+    */
   }
 
   // Implement Thread::Run().
   virtual void Run() {
     while (SamplerRegistry::sampler->IsActive()) {
-      {
-        mozilla::MutexAutoLock lock(*Sampler::sRegisteredThreadsMutex);
-        std::vector<ThreadInfo*> threads =
-          SamplerRegistry::sampler->GetRegisteredThreads();
-        for (uint32_t i = 0; i < threads.size(); i++) {
-          ThreadInfo* info = threads[i];
-
-          // This will be null if we're not interested in profiling this thread.
-          if (!info->Profile())
-            continue;
-
-          ThreadProfile* thread_profile = info->Profile();
-
-          if (!SamplerRegistry::sampler->IsPaused())
-            SampleContext(SamplerRegistry::sampler, thread_profile);
-        }
-      }
+      if (!SamplerRegistry::sampler->IsPaused())
+        SampleContext(SamplerRegistry::sampler);
       OS::Sleep(interval_);
     }
   }
 
-  void SampleContext(Sampler* sampler, ThreadProfile* thread_profile) {
-    thread_act_t profiled_thread =
-      thread_profile->GetPlatformData()->profiled_thread();
-
+  void SampleContext(Sampler* sampler) {
+    thread_act_t profiled_thread = sampler->platform_data()->profiled_thread();
     TickSample sample_obj;
     TickSample* sample = &sample_obj;
+    //TickSample* sample = CpuProfiler::TickSampleEvent(sampler->isolate());
+    //if (sample == NULL) sample = &sample_obj;
 
     if (KERN_SUCCESS != thread_suspend(profiled_thread)) return;
 
 #if V8_HOST_ARCH_X64
     thread_state_flavor_t flavor = x86_THREAD_STATE64;
     x86_thread_state64_t state;
     mach_msg_type_number_t count = x86_THREAD_STATE64_COUNT;
 #if __DARWIN_UNIX03
@@ -283,21 +269,22 @@ class SamplerThread : public Thread {
 #else
 #error Unsupported Mac OS X host architecture.
 #endif  // V8_HOST_ARCH
 
     if (thread_get_state(profiled_thread,
                          flavor,
                          reinterpret_cast<natural_t*>(&state),
                          &count) == KERN_SUCCESS) {
+      //sample->state = sampler->isolate()->current_vm_state();
       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->threadProfile = thread_profile;
+      sampler->SampleStack(sample);
       sampler->Tick(sample);
     }
     thread_resume(profiled_thread);
   }
 
   const int interval_;
   //RuntimeProfilerRateLimiter rate_limiter_;
 
@@ -305,31 +292,35 @@ class SamplerThread : public Thread {
   static Mutex* mutex_;
   static SamplerThread* instance_;
 
   DISALLOW_COPY_AND_ASSIGN(SamplerThread);
 };
 
 #undef REGISTER_FIELD
 
+
+Mutex* SamplerThread::mutex_ = OS::CreateMutex();
 SamplerThread* SamplerThread::instance_ = NULL;
 
-Sampler::Sampler(int interval, bool profiling, int entrySize)
+
+Sampler::Sampler(int interval, bool profiling)
     : // isolate_(isolate),
       interval_(interval),
       profiling_(profiling),
       paused_(false),
-      active_(false),
-      entrySize_(entrySize) /*,
+      active_(false) /*,
       samples_taken_(0)*/ {
+  data_ = new PlatformData;
 }
 
 
 Sampler::~Sampler() {
   ASSERT(!IsActive());
+  delete data_;
 }
 
 
 void Sampler::Start() {
   ASSERT(!IsActive());
   SetActive(true);
   SamplerThread::AddActiveSampler(this);
 }
@@ -337,67 +328,12 @@ void Sampler::Start() {
 
 void Sampler::Stop() {
   ASSERT(IsActive());
   SetActive(false);
   SamplerThread::RemoveActiveSampler(this);
 }
 
 pthread_t
-Sampler::GetProfiledThread(PlatformData* aData)
+Sampler::GetProfiledThread(Sampler::PlatformData* aData)
 {
   return aData->profiled_pthread();
 }
-
-#include <sys/syscall.h>
-pid_t gettid()
-{
-  return (pid_t) syscall(SYS_thread_selfid);
-}
-
-bool Sampler::RegisterCurrentThread(const char* aName, PseudoStack* aPseudoStack, bool aIsMainThread)
-{
-  if (!Sampler::sRegisteredThreadsMutex)
-    return false;
-
-  mozilla::MutexAutoLock lock(*Sampler::sRegisteredThreadsMutex);
-
-  ThreadInfo* info = new ThreadInfo(aName, gettid(),
-    aIsMainThread, aPseudoStack);
-
-  bool profileThread = sActiveSampler &&
-    (aIsMainThread || sActiveSampler->ProfileThreads());
-
-  if (profileThread) {
-    // We need to create the ThreadProfile now
-    info->SetProfile(new ThreadProfile(info->Name(),
-                                       sActiveSampler->EntrySize(),
-                                       info->Stack(),
-                                       info->ThreadId(),
-                                       info->GetPlatformData(),
-                                       aIsMainThread));
-    if (sActiveSampler->ProfileJS()) {
-      info->Profile()->GetPseudoStack()->enableJSSampling();
-    }
-  }
-
-  sRegisteredThreads->push_back(info);
-  return true;
-}
-
-void Sampler::UnregisterCurrentThread()
-{
-  if (!Sampler::sRegisteredThreadsMutex)
-    return;
-
-  mozilla::MutexAutoLock lock(*Sampler::sRegisteredThreadsMutex);
-
-  int id = gettid();
-
-  for (uint32_t i = 0; i < sRegisteredThreads->size(); i++) {
-    ThreadInfo* info = sRegisteredThreads->at(i);
-    if (info->ThreadId() == id) {
-      delete info;
-      sRegisteredThreads->erase(sRegisteredThreads->begin() + i);
-      break;
-    }
-  }
-}
--- a/tools/profiler/platform-win32.cc
+++ b/tools/profiler/platform-win32.cc
@@ -23,71 +23,58 @@
 // OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
 // AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
 // OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
 // OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 // SUCH DAMAGE.
 
 #include <windows.h>
 #include <mmsystem.h>
+#include "platform.h"
 #include <process.h>
-#include "platform.h"
-#include "TableTicker.h"
-#include "ProfileEntry.h"
+
 
-class PlatformData : public Malloced {
+class Sampler::PlatformData : public Malloced {
  public:
   // Get a handle to the calling thread. This is the thread that we are
   // going to profile. We need to make a copy of the handle because we are
   // going to use it in the sampler thread. Using GetThreadHandle() will
   // not work in this case. We're using OpenThread because DuplicateHandle
   // for some reason doesn't work in Chrome's sandbox.
-  PlatformData(int aThreadId) : profiled_thread_(OpenThread(THREAD_GET_CONTEXT |
+  PlatformData() : profiled_thread_(OpenThread(THREAD_GET_CONTEXT |
                                                THREAD_SUSPEND_RESUME |
                                                THREAD_QUERY_INFORMATION,
                                                false,
-                                               aThreadId)) {}
+                                               GetCurrentThreadId())) {}
 
   ~PlatformData() {
     if (profiled_thread_ != NULL) {
       CloseHandle(profiled_thread_);
       profiled_thread_ = NULL;
     }
   }
 
   HANDLE profiled_thread() { return profiled_thread_; }
 
  private:
   HANDLE profiled_thread_;
 };
 
-/* static */ PlatformData*
-Sampler::AllocPlatformData(int aThreadId)
-{
-  return new PlatformData(aThreadId);
-}
-
-/* static */ void
-Sampler::FreePlatformData(PlatformData* aData)
-{
-  delete aData;
-}
-
 uintptr_t
-Sampler::GetThreadHandle(PlatformData* aData)
+Sampler::GetThreadHandle(Sampler::PlatformData* aData)
 {
   return (uintptr_t) aData->profiled_thread();
 }
 
 class SamplerThread : public Thread {
  public:
   SamplerThread(int interval, Sampler* sampler)
-      : Thread("SamplerThread")
-      , interval_(interval)
-      , sampler_(sampler) {}
+      : Thread("SamplerThread"),
+        interval_(interval),
+        sampler_(sampler) {}
 
   static void StartSampler(Sampler* sampler) {
     if (instance_ == NULL) {
       instance_ = new SamplerThread(sampler->interval(), sampler);
       instance_->Start();
     } else {
       ASSERT(instance_->interval_ == sampler->interval());
     }
@@ -104,59 +91,40 @@ class SamplerThread : public Thread {
 
     // By default we'll not adjust the timer resolution which tends to be around
     // 16ms. However, if the requested interval is sufficiently low we'll try to
     // adjust the resolution to match.
     if (interval_ < 10)
         ::timeBeginPeriod(interval_);
 
     while (sampler_->IsActive()) {
-      {
-        mozilla::MutexAutoLock lock(*Sampler::sRegisteredThreadsMutex);
-        std::vector<ThreadInfo*> threads =
-          sampler_->GetRegisteredThreads();
-        for (uint32_t i = 0; i < threads.size(); i++) {
-          ThreadInfo* info = threads[i];
-
-          // This will be null if we're not interested in profiling this thread.
-          if (!info->Profile())
-            continue;
-
-          ThreadProfile* thread_profile = info->Profile();
-
-          if (!sampler_->IsPaused()) {
-            SampleContext(sampler_, thread_profile);
-          }
-        }
-      }
+      if (!sampler_->IsPaused())
+        SampleContext(sampler_);
       OS::Sleep(interval_);
     }
 
     // disable any timer resolution changes we've made
     if (interval_ < 10)
         ::timeEndPeriod(interval_);
   }
 
-  void SampleContext(Sampler* sampler, ThreadProfile* thread_profile) {
-    uintptr_t thread = Sampler::GetThreadHandle(
-                               thread_profile->GetPlatformData());
-    HANDLE profiled_thread = reinterpret_cast<HANDLE>(thread);
+  void SampleContext(Sampler* sampler) {
+    HANDLE profiled_thread = sampler->platform_data()->profiled_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;
 
     // Grab the timestamp before pausing the thread, to avoid deadlocks.
     sample->timestamp = mozilla::TimeStamp::Now();
-    sample->threadProfile = thread_profile;
 
     static const DWORD kSuspendFailed = static_cast<DWORD>(-1);
     if (SuspendThread(profiled_thread) == kSuspendFailed)
       return;
 
     context.ContextFlags = CONTEXT_CONTROL;
     if (GetThreadContext(profiled_thread, &context) != 0) {
 #if V8_HOST_ARCH_X64
@@ -164,16 +132,17 @@ class SamplerThread : public Thread {
       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);
 #endif
       sample->context = &context;
+      sampler->SampleStack(sample);
       sampler->Tick(sample);
     }
     ResumeThread(profiled_thread);
   }
 
   Sampler* sampler_;
   const int interval_;
 
@@ -181,26 +150,27 @@ class SamplerThread : public Thread {
   static SamplerThread* instance_;
 
   DISALLOW_COPY_AND_ASSIGN(SamplerThread);
 };
 
 SamplerThread* SamplerThread::instance_ = NULL;
 
 
-Sampler::Sampler(int interval, bool profiling, int entrySize)
+Sampler::Sampler(int interval, bool profiling)
     : interval_(interval),
       profiling_(profiling),
       paused_(false),
       active_(false),
-      entrySize_(entrySize) {
+      data_(new PlatformData) {
 }
 
 Sampler::~Sampler() {
   ASSERT(!IsActive());
+  delete data_;
 }
 
 void Sampler::Start() {
   ASSERT(!IsActive());
   SetActive(true);
   SamplerThread::StartSampler(this);
 }
 
@@ -214,98 +184,57 @@ void Sampler::Stop() {
 static const HANDLE kNoThread = INVALID_HANDLE_VALUE;
 
 static unsigned int __stdcall ThreadEntry(void* arg) {
   Thread* thread = reinterpret_cast<Thread*>(arg);
   thread->Run();
   return 0;
 }
 
+class Thread::PlatformData : public Malloced {
+ public:
+  explicit PlatformData(HANDLE thread) : thread_(thread) {}
+  HANDLE thread_;
+  unsigned thread_id_;
+};
+
 // Initialize a Win32 thread object. The thread has an invalid thread
 // handle until it is started.
 Thread::Thread(const char* name)
     : stack_size_(0) {
-  thread_ = kNoThread;
+  data_ = new PlatformData(kNoThread);
   set_name(name);
 }
 
 void Thread::set_name(const char* name) {
   strncpy(name_, name, sizeof(name_));
   name_[sizeof(name_) - 1] = '\0';
 }
 
 // Close our own handle for the thread.
 Thread::~Thread() {
-  if (thread_ != kNoThread) CloseHandle(thread_);
+  if (data_->thread_ != kNoThread) CloseHandle(data_->thread_);
+  delete data_;
 }
 
 // Create a new thread. It is important to use _beginthreadex() instead of
 // the Win32 function CreateThread(), because the CreateThread() does not
 // initialize thread specific structures in the C runtime library.
 void Thread::Start() {
-  thread_ = reinterpret_cast<HANDLE>(
+  data_->thread_ = reinterpret_cast<HANDLE>(
       _beginthreadex(NULL,
                      static_cast<unsigned>(stack_size_),
                      ThreadEntry,
                      this,
                      0,
-                     &thread_id_));
+                     &data_->thread_id_));
 }
 
 // Wait for thread to terminate.
 void Thread::Join() {
-  if (thread_id_ != GetCurrentThreadId()) {
-    WaitForSingleObject(thread_, INFINITE);
+  if (data_->thread_id_ != GetCurrentThreadId()) {
+    WaitForSingleObject(data_->thread_, INFINITE);
   }
 }
 
 void OS::Sleep(int milliseconds) {
   ::Sleep(milliseconds);
 }
-
-bool Sampler::RegisterCurrentThread(const char* aName, PseudoStack* aPseudoStack, bool aIsMainThread)
-{
-  if (!Sampler::sRegisteredThreadsMutex)
-    return false;
-
-  mozilla::MutexAutoLock lock(*Sampler::sRegisteredThreadsMutex);
-
-  ThreadInfo* info = new ThreadInfo(aName, GetCurrentThreadId(),
-    aIsMainThread, aPseudoStack);
-
-  bool profileThread = sActiveSampler &&
-    (aIsMainThread || sActiveSampler->ProfileThreads());
-
-  if (profileThread) {
-    // We need to create the ThreadProfile now
-    info->SetProfile(new ThreadProfile(info->Name(),
-                                       sActiveSampler->EntrySize(),
-                                       info->Stack(),
-                                       GetCurrentThreadId(),
-                                       info->GetPlatformData(),
-                                       aIsMainThread));
-    if (sActiveSampler->ProfileJS()) {
-      info->Profile()->GetPseudoStack()->enableJSSampling();
-    }
-  }
-
-  sRegisteredThreads->push_back(info);
-  return true;
-}
-
-void Sampler::UnregisterCurrentThread()
-{
-  if (!Sampler::sRegisteredThreadsMutex)
-    return;
-
-  mozilla::MutexAutoLock lock(*Sampler::sRegisteredThreadsMutex);
-
-  int id = GetCurrentThreadId();
-
-  for (uint32_t i = 0; i < sRegisteredThreads->size(); i++) {
-    ThreadInfo* info = sRegisteredThreads->at(i);
-    if (info->ThreadId() == id) {
-      delete info;
-      sRegisteredThreads->erase(sRegisteredThreads->begin() + i);
-      break;
-    }
-  }
-}
--- a/tools/profiler/platform.cpp
+++ b/tools/profiler/platform.cpp
@@ -13,78 +13,41 @@
 #include "mozilla/ThreadLocal.h"
 #include "PseudoStack.h"
 #include "TableTicker.h"
 #include "UnwinderThread2.h"
 #include "nsIObserverService.h"
 #include "nsDirectoryServiceUtils.h"
 #include "nsDirectoryServiceDefs.h"
 #include "mozilla/Services.h"
-#include "nsThreadUtils.h"
 
 mozilla::ThreadLocal<PseudoStack *> tlsPseudoStack;
 mozilla::ThreadLocal<TableTicker *> tlsTicker;
 // We need to track whether we've been initialized otherwise
 // we end up using tlsStack without initializing it.
 // Because tlsStack is totally opaque to us we can't reuse
 // it as the flag itself.
 bool stack_key_initialized;
 
-TimeStamp   sLastTracerEvent; // is raced on
-int         sFrameNumber = 0;
-int         sLastFrameNumber = 0;
-int         sInitCount = 0; // Each init must have a matched shutdown.
-static bool sIsProfiling = false; // is raced on
+TimeStamp sLastTracerEvent; // is raced on
+int       sFrameNumber = 0;
+int       sLastFrameNumber = 0;
 
 /* used to keep track of the last event that we sampled during */
 unsigned int sLastSampledEventGeneration = 0;
 
 /* a counter that's incremented everytime we get responsiveness event
- * note: it might also be worth trackplaing everytime we go around
+ * note: it might also be worth tracking everytime we go around
  * the event loop */
 unsigned int sCurrentEventGeneration = 0;
 /* we don't need to worry about overflow because we only treat the
  * case of them being the same as special. i.e. we only run into
  * a problem if 2^32 events happen between samples that we need
  * to know are associated with different events */
 
-std::vector<ThreadInfo*>* Sampler::sRegisteredThreads = nullptr;
-mozilla::Mutex* Sampler::sRegisteredThreadsMutex = nullptr;
-
-TableTicker* Sampler::sActiveSampler;
-
-void Sampler::Startup() {
-  sRegisteredThreads = new std::vector<ThreadInfo*>();
-  sRegisteredThreadsMutex = new mozilla::Mutex("sRegisteredThreads mutex");
-}
-
-void Sampler::Shutdown() {
-  while (sRegisteredThreads->size() > 0) {
-    delete sRegisteredThreads->back();
-    sRegisteredThreads->pop_back();
-  }
-
-  delete sRegisteredThreadsMutex;
-  delete sRegisteredThreads;
-
-  // UnregisterThread can be called after shutdown in XPCShell. Thus
-  // we need to point to null to ignore such a call after shutdown.
-  sRegisteredThreadsMutex = nullptr;
-  sRegisteredThreads = nullptr;
-}
-
-ThreadInfo::~ThreadInfo() {
-  free(mName);
-
-  if (mProfile)
-    delete mProfile;
-
-  Sampler::FreePlatformData(mPlatformData);
-}
-
 bool sps_version2()
 {
   static int version = 0; // Raced on, potentially
 
   if (version == 0) {
     bool allow2 = false; // Is v2 allowable on this platform?
 #   if defined(SPS_PLAT_amd64_linux) || defined(SPS_PLAT_arm_android) \
        || defined(SPS_PLAT_x86_linux)
@@ -244,35 +207,29 @@ void read_profiler_env_vars()
   return;
 }
 
 ////////////////////////////////////////////////////////////////////////
 // BEGIN externally visible functions
 
 void mozilla_sampler_init()
 {
-  sInitCount++;
-
   if (stack_key_initialized)
     return;
 
   LOG("BEGIN mozilla_sampler_init");
   if (!tlsPseudoStack.init() || !tlsTicker.init()) {
     LOG("Failed to init.");
     return;
   }
   stack_key_initialized = true;
 
-  Sampler::Startup();
-
   PseudoStack *stack = new PseudoStack();
   tlsPseudoStack.set(stack);
 
-  Sampler::RegisterCurrentThread("Gecko", stack, true);
-
   if (sps_version2()) {
     // 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();
 
     // Create the unwinder thread.  ATM there is only one.
     uwt__init();
@@ -309,21 +266,16 @@ void mozilla_sampler_init()
                          };
   profiler_start(PROFILE_DEFAULT_ENTRY, PROFILE_DEFAULT_INTERVAL,
                          features, sizeof(features)/sizeof(const char*));
   LOG("END   mozilla_sampler_init");
 }
 
 void mozilla_sampler_shutdown()
 {
-  sInitCount--;
-
-  if (sInitCount > 0)
-    return;
-
   // Save the profile on shutdown if requested.
   TableTicker *t = tlsTicker.get();
   if (t) {
     const char *val = PR_GetEnv("MOZ_PROFILER_SHUTDOWN");
     if (val) {
       std::ofstream stream;
       stream.open(val);
       if (stream.is_open()) {
@@ -337,19 +289,16 @@ void mozilla_sampler_shutdown()
   // before stopping the sampler, so as to guarantee that the unwinder
   // thread doesn't try to access memory that the subsequent call to
   // mozilla_sampler_stop causes to be freed.
   if (sps_version2()) {
     uwt__deinit();
   }
 
   profiler_stop();
-
-  Sampler::Shutdown();
-
   // We can't delete the Stack because we can be between a
   // sampler call_enter/call_exit point.
   // TODO Need to find a safe time to delete Stack
 }
 
 void mozilla_sampler_save()
 {
   TableTicker *t = tlsTicker.get();
@@ -398,17 +347,16 @@ const char** mozilla_sampler_get_feature
 #if defined(MOZ_PROFILING) && defined(HAVE_NATIVE_UNWIND)
     "stackwalk",
 #endif
 #if defined(ENABLE_SPS_LEAF_DATA)
     "leaf",
 #endif
     "jank",
     "js",
-    "threads",
     NULL
   };
 
   return features;
 }
 
 // Values are only honored on the first start
 void mozilla_sampler_start(int aProfileEntries, int aInterval,
@@ -430,39 +378,26 @@ void mozilla_sampler_start(int aProfileE
 
   // Reset the current state if the profiler is running
   profiler_stop();
 
   TableTicker* t;
   if (sps_version2()) {
     t = new BreakpadSampler(aInterval ? aInterval : PROFILE_DEFAULT_INTERVAL,
                            aProfileEntries ? aProfileEntries : PROFILE_DEFAULT_ENTRY,
-                           aFeatures, aFeatureCount);
+                           stack, aFeatures, aFeatureCount);
   } else {
     t = new TableTicker(aInterval ? aInterval : PROFILE_DEFAULT_INTERVAL,
                         aProfileEntries ? aProfileEntries : PROFILE_DEFAULT_ENTRY,
-                        aFeatures, aFeatureCount);
+                        stack, aFeatures, aFeatureCount);
   }
   tlsTicker.set(t);
   t->Start();
-  if (t->ProfileJS()) {
-      mozilla::MutexAutoLock lock(*Sampler::sRegisteredThreadsMutex);
-      std::vector<ThreadInfo*> threads = t->GetRegisteredThreads();
-
-      for (uint32_t i = 0; i < threads.size(); i++) {
-        ThreadInfo* info = threads[i];
-        ThreadProfile* thread_profile = info->Profile();
-        if (!thread_profile) {
-          continue;
-        }
-        thread_profile->GetPseudoStack()->enableJSSampling();
-      }
-  }
-
-  sIsProfiling = true;
+  if (t->ProfileJS())
+      stack->enableJSSampling();
 
   nsCOMPtr<nsIObserverService> os = mozilla::services::GetObserverService();
   if (os)
     os->NotifyObservers(nullptr, "profiler-started", nullptr);
 }
 
 void mozilla_sampler_stop()
 {
@@ -480,26 +415,32 @@ void mozilla_sampler_stop()
   delete t;
   tlsTicker.set(NULL);
   PseudoStack *stack = tlsPseudoStack.get();
   ASSERT(stack != NULL);
 
   if (disableJS)
     stack->disableJSSampling();
 
-  sIsProfiling = false;
-
   nsCOMPtr<nsIObserverService> os = mozilla::services::GetObserverService();
   if (os)
     os->NotifyObservers(nullptr, "profiler-stopped", nullptr);
 }
 
 bool mozilla_sampler_is_active()
 {
-  return sIsProfiling;
+  if (!stack_key_initialized)
+    profiler_init();
+
+  TableTicker *t = tlsTicker.get();
+  if (!t) {
+    return false;
+  }
+
+  return t->IsActive();
 }
 
 static double sResponsivenessTimes[100];
 static unsigned int sResponsivenessLoc = 0;
 void mozilla_sampler_responsiveness(const TimeStamp& aTime)
 {
   if (!sLastTracerEvent.IsNull()) {
     if (sResponsivenessLoc == 100) {
@@ -541,25 +482,11 @@ void mozilla_sampler_lock()
 
 void mozilla_sampler_unlock()
 {
   nsCOMPtr<nsIObserverService> os = mozilla::services::GetObserverService();
   if (os)
     os->NotifyObservers(nullptr, "profiler-unlocked", nullptr);
 }
 
-bool mozilla_sampler_register_thread(const char* aName)
-{
-  PseudoStack* stack = new PseudoStack();
-  tlsPseudoStack.set(stack);
-
-  return Sampler::RegisterCurrentThread(aName, stack, false);
-}
-
-void mozilla_sampler_unregister_thread()
-{
-  Sampler::UnregisterCurrentThread();
-}
-
 // END externally visible functions
 ////////////////////////////////////////////////////////////////////////
 
-
--- a/tools/profiler/platform.h
+++ b/tools/profiler/platform.h
@@ -30,33 +30,24 @@
 #define TOOLS_PLATFORM_H_
 
 #ifdef ANDROID
 #include <android/log.h>
 #else
 #define __android_log_print(a, ...)
 #endif
 
-#ifdef XP_UNIX
-#include <pthread.h>
-#endif
-
 #include "mozilla/StandardInteger.h"
 #include "mozilla/Util.h"
 #include "mozilla/unused.h"
 #include "mozilla/TimeStamp.h"
-#include "mozilla/Mutex.h"
 #include "PlatformMacros.h"
 #include "v8-support.h"
 #include <vector>
 
-#ifdef XP_WIN
-#include <windows.h>
-#endif
-
 #define ASSERT(a) MOZ_ASSERT(a)
 
 #ifdef ANDROID
 # if defined(__arm__) || defined(__thumb__)
 #  define ENABLE_SPS_LEAF_DATA
 #  define ENABLE_ARM_LR_SAVING
 # endif
 # define LOG(text) \
@@ -187,27 +178,24 @@ class Thread {
 
   // Abstract method for run handler.
   virtual void Run() = 0;
 
   // The thread name length is limited to 16 based on Linux's implementation of
   // prctl().
   static const int kMaxThreadNameLength = 16;
 
-#ifdef XP_WIN
-  HANDLE thread_;
-  unsigned thread_id_;
-#endif
-#if defined(XP_MACOSX)
-  pthread_t thread_;
-#endif
+  class PlatformData;
+  PlatformData* data() { return data_; }
 
  private:
   void set_name(const char *name);
 
+  PlatformData* data_;
+
   char name_[kMaxThreadNameLength];
   int stack_size_;
 
   DISALLOW_COPY_AND_ASSIGN(Thread);
 };
 
 // ----------------------------------------------------------------------------
 // HAVE_NATIVE_UNWIND
@@ -239,19 +227,16 @@ extern int     sUnwindStackScan;  /* max
 
 // ----------------------------------------------------------------------------
 // Sampler
 //
 // A sampler periodically samples the state of the VM and optionally
 // (if used for profiling) the program counter and stack pointer for
 // the thread that created it.
 
-class PseudoStack;
-class ThreadProfile;
-
 // TickSample captures the information collected for each sample.
 class TickSample {
  public:
   TickSample()
       :
         pc(NULL),
         sp(NULL),
         fp(NULL),
@@ -265,33 +250,33 @@ class TickSample {
   Address sp;  // Stack pointer.
   Address fp;  // Frame pointer.
 #ifdef ENABLE_ARM_LR_SAVING
   Address lr;  // ARM link register
 #endif
   Address function;  // The last called JS function.
   void*   context;   // The context from the signal handler, if available. On
                      // Win32 this may contain the windows thread context.
-  ThreadProfile* threadProfile;
   static const int kMaxFramesCount = 64;
+  Address stack[kMaxFramesCount];  // Call stack.
   int frames_count;  // Number of captured frames.
   mozilla::TimeStamp timestamp;
 };
 
-class ThreadInfo;
-class PlatformData;
-class TableTicker;
 class Sampler {
  public:
   // Initialize sampler.
-  explicit Sampler(int interval, bool profiling, int entrySize);
+  explicit Sampler(int interval, bool profiling);
   virtual ~Sampler();
 
   int interval() const { return interval_; }
 
+  // Performs stack sampling.
+  virtual void SampleStack(TickSample* sample) = 0;
+
   // This method is called for each sampling period with the current
   // program counter.
   virtual void Tick(TickSample* sample) = 0;
 
   // Request a save from a signal handler
   virtual void RequestSave() = 0;
   // Process any outstanding request outside a signal handler.
   virtual void HandleSaveRequest() = 0;
@@ -305,97 +290,32 @@ class Sampler {
 
   // Whether the sampler is running (that is, consumes resources).
   bool IsActive() const { return active_; }
 
   // Low overhead way to stop the sampler from ticking
   bool IsPaused() const { return paused_; }
   void SetPaused(bool value) { NoBarrier_Store(&paused_, value); }
 
-  virtual bool ProfileThreads() const = 0;
-
-  int EntrySize() { return entrySize_; }
+  class PlatformData;
 
-  // We can't new/delete the type safely without defining it
-  // (-Wdelete-incomplete). Use these Alloc/Free functions instead.
-  static PlatformData* AllocPlatformData(int aThreadId);
-  static void FreePlatformData(PlatformData*);
+  PlatformData* platform_data() { return data_; }
 
   // If we move the backtracing code into the platform files we won't
   // need to have these hacks
 #ifdef XP_WIN
   // xxxehsan sucky hack :(
   static uintptr_t GetThreadHandle(PlatformData*);
 #endif
 #ifdef XP_MACOSX
   static pthread_t GetProfiledThread(PlatformData*);
 #endif
-
-  static std::vector<ThreadInfo*> GetRegisteredThreads() {
-    return *sRegisteredThreads;
-  }
-
-  static bool RegisterCurrentThread(const char* aName, PseudoStack* aPseudoStack, bool aIsMainThread);
-  static void UnregisterCurrentThread();
-
-  static void Startup();
-  // Should only be called on shutdown
-  static void Shutdown();
-
-  static TableTicker* GetActiveSampler() { return sActiveSampler; }
-  static void SetActiveSampler(TableTicker* sampler) { sActiveSampler = sampler; }
-
-  static mozilla::Mutex* sRegisteredThreadsMutex;
- protected:
-  static std::vector<ThreadInfo*>* sRegisteredThreads;
-  static TableTicker* sActiveSampler;
-
  private:
   void SetActive(bool value) { NoBarrier_Store(&active_, value); }
 
   const int interval_;
   const bool profiling_;
   Atomic32 paused_;
   Atomic32 active_;
-  const int entrySize_;
-
-  // Refactor me!
-#if defined(SPS_OS_linux) || defined(SPS_OS_android)
-  bool signal_handler_installed_;
-  struct sigaction old_sigprof_signal_handler_;
-  struct sigaction old_sigsave_signal_handler_;
-  bool signal_sender_launched_;
-  pthread_t signal_sender_thread_;
-#endif
-};
-
-class ThreadInfo {
- public:
-  ThreadInfo(const char* aName, int aThreadId, bool aIsMainThread, PseudoStack* aPseudoStack)
-    : mName(strdup(aName))
-    , mThreadId(aThreadId)
-    , mIsMainThread(aIsMainThread)
-    , mPseudoStack(aPseudoStack)
-    , mPlatformData(Sampler::AllocPlatformData(aThreadId))
-    , mProfile(NULL) {}
-
-  virtual ~ThreadInfo();
-
-  const char* Name() const { return mName; }
-  int ThreadId() const { return mThreadId; }
-
-  bool IsMainThread() const { return mIsMainThread; }
-  PseudoStack* Stack() const { return mPseudoStack; }
-  
-  void SetProfile(ThreadProfile* aProfile) { mProfile = aProfile; }
-  ThreadProfile* Profile() const { return mProfile; }
-
-  PlatformData* GetPlatformData() const { return mPlatformData; }
- private:
-  char* mName;
-  int mThreadId;
-  const bool mIsMainThread;
-  PseudoStack* mPseudoStack;
-  PlatformData* mPlatformData;
-  ThreadProfile* mProfile;
+  PlatformData* data_;  // Platform specific data.
 };
 
 #endif /* ndef TOOLS_PLATFORM_H_ */
--- a/xpcom/build/nsXPComInit.cpp
+++ b/xpcom/build/nsXPComInit.cpp
@@ -728,14 +728,12 @@ ShutdownXPCOM(nsIServiceManager* servMgr
     HangMonitor::Shutdown();
 
 #ifdef MOZ_VISUAL_EVENT_TRACER
     eventtracer::Shutdown();
 #endif
 
     NS_LogTerm();
 
-    profiler_shutdown();
-
     return NS_OK;
 }
 
 } // namespace mozilla