This change is a continuation of the refactoring started in r14265.
authoryurys@chromium.org <yurys@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Tue, 16 Apr 2013 08:54:33 +0000 (08:54 +0000)
committeryurys@chromium.org <yurys@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Tue, 16 Apr 2013 08:54:33 +0000 (08:54 +0000)
Renamed SignalSender to SamplerThread to match platforms that don't support signal sending.

Cygwin and Windows implementations are almost identical. Mac OS X uses different API to suspend thread but apart from that it is very similar to Windows implenenation.

BUG=None

Review URL: https://codereview.chromium.org/14264009

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@14272 ce2b1a6d-e550-0410-aec6-3dcde31c8c00

src/isolate.cc
src/platform-cygwin.cc
src/platform-macos.cc
src/platform-win32.cc
src/sampler.cc

index cd6ee47..fc5a225 100644 (file)
@@ -1841,11 +1841,6 @@ void Isolate::Deinit() {
     preallocated_message_space_ = NULL;
     PreallocatedMemoryThreadStop();
 
-    delete heap_profiler_;
-    heap_profiler_ = NULL;
-    delete cpu_profiler_;
-    cpu_profiler_ = NULL;
-
     if (runtime_profiler_ != NULL) {
       runtime_profiler_->TearDown();
       delete runtime_profiler_;
@@ -1854,6 +1849,11 @@ void Isolate::Deinit() {
     heap_.TearDown();
     logger_->TearDown();
 
+    delete heap_profiler_;
+    heap_profiler_ = NULL;
+    delete cpu_profiler_;
+    cpu_profiler_ = NULL;
+
     // The default isolate is re-initializable due to legacy API.
     state_ = UNINITIALIZED;
   }
@@ -2070,13 +2070,12 @@ bool Isolate::Init(Deserializer* des) {
   date_cache_ = new DateCache();
   code_stub_interface_descriptors_ =
       new CodeStubInterfaceDescriptor[CodeStub::NUMBER_OF_IDS];
+  cpu_profiler_ = new CpuProfiler(this);
+  heap_profiler_ = new HeapProfiler(heap());
 
   // Enable logging before setting up the heap
   logger_->SetUp();
 
-  cpu_profiler_ = new CpuProfiler(this);
-  heap_profiler_ = new HeapProfiler(heap());
-
   // Initialize other runtime facilities
 #if defined(USE_SIMULATOR)
 #if defined(V8_TARGET_ARCH_ARM) || defined(V8_TARGET_ARCH_MIPS)
index 418a05e..e13a3a6 100644 (file)
@@ -623,168 +623,6 @@ Semaphore* OS::CreateSemaphore(int count) {
 }
 
 
-// ----------------------------------------------------------------------------
-// Cygwin profiler support.
-//
-// On Cygwin we use the same sampler implementation as on win32.
-
-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()
-      : profiled_thread_(OpenThread(THREAD_GET_CONTEXT |
-                                    THREAD_SUSPEND_RESUME |
-                                    THREAD_QUERY_INFORMATION,
-                                    false,
-                                    GetCurrentThreadId())),
-        profiled_thread_id_(ThreadId::Current()) {}
-
-  ~PlatformData() {
-    if (profiled_thread_ != NULL) {
-      CloseHandle(profiled_thread_);
-      profiled_thread_ = NULL;
-    }
-  }
-
-  HANDLE profiled_thread() { return profiled_thread_; }
-  ThreadId profiled_thread_id() { return profiled_thread_id_; }
-
- private:
-  HANDLE profiled_thread_;
-  ThreadId profiled_thread_id_;
-};
-
-
-class SamplerThread : public Thread {
- public:
-  static const int kSamplerThreadStackSize = 64 * KB;
-
-  explicit SamplerThread(int interval)
-      : Thread(Thread::Options("SamplerThread", kSamplerThreadStackSize)),
-        interval_(interval) {}
-
-  static void SetUp() { if (!mutex_) mutex_ = OS::CreateMutex(); }
-  static void TearDown() { delete mutex_; }
-
-  static void AddActiveSampler(Sampler* sampler) {
-    ScopedLock lock(mutex_);
-    SamplerRegistry::AddActiveSampler(sampler);
-    if (instance_ == NULL) {
-      instance_ = new SamplerThread(sampler->interval());
-      instance_->StartSynchronously();
-    } else {
-      ASSERT(instance_->interval_ == sampler->interval());
-    }
-  }
-
-  static void RemoveActiveSampler(Sampler* sampler) {
-    ScopedLock lock(mutex_);
-    SamplerRegistry::RemoveActiveSampler(sampler);
-    if (SamplerRegistry::GetState() == SamplerRegistry::HAS_NO_SAMPLERS) {
-      instance_->Join();
-      delete instance_;
-      instance_ = NULL;
-    }
-  }
-
-  // Implement Thread::Run().
-  virtual void Run() {
-    SamplerRegistry::State state;
-    while ((state = SamplerRegistry::GetState()) !=
-           SamplerRegistry::HAS_NO_SAMPLERS) {
-      // When CPU profiling is enabled both JavaScript and C++ code is
-      // profiled. We must not suspend.
-      if (state == SamplerRegistry::HAS_CPU_PROFILING_SAMPLERS) {
-        SamplerRegistry::IterateActiveSamplers(&DoCpuProfile, this);
-      }
-      OS::Sleep(interval_);
-    }
-  }
-
-  static void DoCpuProfile(Sampler* sampler, void* raw_sampler_thread) {
-    if (!sampler->isolate()->IsInitialized()) return;
-    if (!sampler->IsProfiling()) return;
-    SamplerThread* sampler_thread =
-        reinterpret_cast<SamplerThread*>(raw_sampler_thread);
-    sampler_thread->SampleContext(sampler);
-  }
-
-  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));
-
-    Isolate* isolate = sampler->isolate();
-#if defined(USE_SIMULATOR)
-#if V8_TARGET_ARCH_ARM || V8_TARGET_ARCH_MIPS
-    ThreadId thread_id = sampler->platform_data()->profiled_thread_id();
-    Isolate::PerIsolateThreadData* per_thread_data = isolate->
-        FindPerThreadDataForThread(thread_id);
-    if (!per_thread_data) return;
-    Simulator* sim = per_thread_data->simulator();
-    // Check if there is active simulator before allocating TickSample.
-    if (!sim) return;
-#endif
-#endif  // USE_SIMULATOR
-    TickSample sample_obj;
-    TickSample* sample = isolate->cpu_profiler()->TickSampleEvent();
-    if (sample == NULL) sample = &sample_obj;
-
-    static const DWORD kSuspendFailed = static_cast<DWORD>(-1);
-    if (SuspendThread(profiled_thread) == kSuspendFailed) return;
-    sample->state = isolate->current_vm_state();
-
-    context.ContextFlags = CONTEXT_FULL;
-    if (GetThreadContext(profiled_thread, &context) != 0) {
-#if defined(USE_SIMULATOR)
-#if V8_TARGET_ARCH_ARM
-      sample->pc = reinterpret_cast<Address>(sim->get_register(Simulator::pc));
-      sample->sp = reinterpret_cast<Address>(sim->get_register(Simulator::sp));
-      sample->fp = reinterpret_cast<Address>(sim->get_register(Simulator::r11));
-#elif V8_TARGET_ARCH_MIPS
-      sample->pc = reinterpret_cast<Address>(sim->get_register(Simulator::pc));
-      sample->sp = reinterpret_cast<Address>(sim->get_register(Simulator::sp));
-      sample->fp = reinterpret_cast<Address>(sim->get_register(Simulator::fp));
-#endif
-#else
-#if V8_HOST_ARCH_X64
-      sample->pc = reinterpret_cast<Address>(context.Rip);
-      sample->sp = reinterpret_cast<Address>(context.Rsp);
-      sample->fp = reinterpret_cast<Address>(context.Rbp);
-#else
-      sample->pc = reinterpret_cast<Address>(context.Eip);
-      sample->sp = reinterpret_cast<Address>(context.Esp);
-      sample->fp = reinterpret_cast<Address>(context.Ebp);
-#endif
-#endif  // USE_SIMULATOR
-      sampler->SampleStack(sample);
-      sampler->Tick(sample);
-    }
-    ResumeThread(profiled_thread);
-  }
-
-  const int interval_;
-
-  // Protects the process wide state below.
-  static Mutex* mutex_;
-  static SamplerThread* instance_;
-
- private:
-  DISALLOW_COPY_AND_ASSIGN(SamplerThread);
-};
-
-
-Mutex* SamplerThread::mutex_ = NULL;
-SamplerThread* SamplerThread::instance_ = NULL;
-
-
 void OS::SetUp() {
   // Seed the random number generator.
   // Convert the current time to a 64-bit integer first, before converting it
@@ -794,44 +632,12 @@ void OS::SetUp() {
   uint64_t seed = static_cast<uint64_t>(TimeCurrentMillis());
   srandom(static_cast<unsigned int>(seed));
   limit_mutex = CreateMutex();
-  SamplerThread::SetUp();
 }
 
 
 void OS::TearDown() {
-  SamplerThread::TearDown();
   delete limit_mutex;
 }
 
 
-Sampler::Sampler(Isolate* isolate, int interval)
-    : isolate_(isolate),
-      interval_(interval),
-      profiling_(false),
-      active_(false),
-      samples_taken_(0) {
-  data_ = new PlatformData;
-}
-
-
-Sampler::~Sampler() {
-  ASSERT(!IsActive());
-  delete data_;
-}
-
-
-void Sampler::Start() {
-  ASSERT(!IsActive());
-  SetActive(true);
-  SamplerThread::AddActiveSampler(this);
-}
-
-
-void Sampler::Stop() {
-  ASSERT(IsActive());
-  SamplerThread::RemoveActiveSampler(this);
-  SetActive(false);
-}
-
-
 } }  // namespace v8::internal
index 8327acf..9bb4dbd 100644 (file)
@@ -743,211 +743,17 @@ Semaphore* OS::CreateSemaphore(int count) {
 }
 
 
-class Sampler::PlatformData : public Malloced {
- public:
-  PlatformData()
-      : profiled_thread_(mach_thread_self()),
-        profiled_thread_id_(ThreadId::Current()) {}
-
-  ~PlatformData() {
-    // Deallocate Mach port for thread.
-    mach_port_deallocate(mach_task_self(), profiled_thread_);
-  }
-
-  thread_act_t profiled_thread() { return profiled_thread_; }
-  ThreadId profiled_thread_id() { return profiled_thread_id_; }
-
- private:
-  // Note: for profiled_thread_ Mach primitives are used instead of PThread's
-  // because the latter doesn't provide thread manipulation primitives required.
-  // For details, consult "Mac OS X Internals" book, Section 7.3.
-  thread_act_t profiled_thread_;
-  ThreadId profiled_thread_id_;
-};
-
-
-class SamplerThread : public Thread {
- public:
-  static const int kSamplerThreadStackSize = 64 * KB;
-
-  explicit SamplerThread(int interval)
-      : Thread(Thread::Options("SamplerThread", kSamplerThreadStackSize)),
-        interval_(interval) {}
-
-  static void SetUp() { if (!mutex_) mutex_ = OS::CreateMutex(); }
-  static void TearDown() { delete mutex_; }
-
-  static void AddActiveSampler(Sampler* sampler) {
-    ScopedLock lock(mutex_);
-    SamplerRegistry::AddActiveSampler(sampler);
-    if (instance_ == NULL) {
-      instance_ = new SamplerThread(sampler->interval());
-      instance_->StartSynchronously();
-    } else {
-      ASSERT(instance_->interval_ == sampler->interval());
-    }
-  }
-
-  static void RemoveActiveSampler(Sampler* sampler) {
-    ScopedLock lock(mutex_);
-    SamplerRegistry::RemoveActiveSampler(sampler);
-    if (SamplerRegistry::GetState() == SamplerRegistry::HAS_NO_SAMPLERS) {
-      instance_->Join();
-      delete instance_;
-      instance_ = NULL;
-    }
-  }
-
-  // Implement Thread::Run().
-  virtual void Run() {
-    SamplerRegistry::State state;
-    while ((state = SamplerRegistry::GetState()) !=
-           SamplerRegistry::HAS_NO_SAMPLERS) {
-      // When CPU profiling is enabled both JavaScript and C++ code is
-      // profiled. We must not suspend.
-      if (state == SamplerRegistry::HAS_CPU_PROFILING_SAMPLERS) {
-        SamplerRegistry::IterateActiveSamplers(&DoCpuProfile, this);
-      }
-      OS::Sleep(interval_);
-    }
-  }
-
-  static void DoCpuProfile(Sampler* sampler, void* raw_sampler_thread) {
-    if (!sampler->isolate()->IsInitialized()) return;
-    if (!sampler->IsProfiling()) return;
-    SamplerThread* sampler_thread =
-        reinterpret_cast<SamplerThread*>(raw_sampler_thread);
-    sampler_thread->SampleContext(sampler);
-  }
-
-  void SampleContext(Sampler* sampler) {
-    thread_act_t profiled_thread = sampler->platform_data()->profiled_thread();
-    Isolate* isolate = sampler->isolate();
-#if defined(USE_SIMULATOR)
-#if V8_TARGET_ARCH_ARM || V8_TARGET_ARCH_MIPS
-    ThreadId thread_id = sampler->platform_data()->profiled_thread_id();
-    Isolate::PerIsolateThreadData* per_thread_data = isolate->
-        FindPerThreadDataForThread(thread_id);
-    if (!per_thread_data) return;
-    Simulator* sim = per_thread_data->simulator();
-    // Check if there is active simulator before allocating TickSample.
-    if (!sim) return;
-#endif
-#endif  // USE_SIMULATOR
-    TickSample sample_obj;
-    TickSample* sample = isolate->cpu_profiler()->TickSampleEvent();
-    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
-#define REGISTER_FIELD(name) __r ## name
-#else
-#define REGISTER_FIELD(name) r ## name
-#endif  // __DARWIN_UNIX03
-#elif V8_HOST_ARCH_IA32
-    thread_state_flavor_t flavor = i386_THREAD_STATE;
-    i386_thread_state_t state;
-    mach_msg_type_number_t count = i386_THREAD_STATE_COUNT;
-#if __DARWIN_UNIX03
-#define REGISTER_FIELD(name) __e ## name
-#else
-#define REGISTER_FIELD(name) e ## name
-#endif  // __DARWIN_UNIX03
-#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 = isolate->current_vm_state();
-#if defined(USE_SIMULATOR)
-#if V8_TARGET_ARCH_ARM
-      sample->pc = reinterpret_cast<Address>(sim->get_register(Simulator::pc));
-      sample->sp = reinterpret_cast<Address>(sim->get_register(Simulator::sp));
-      sample->fp = reinterpret_cast<Address>(sim->get_register(Simulator::r11));
-#elif V8_TARGET_ARCH_MIPS
-      sample->pc = reinterpret_cast<Address>(sim->get_register(Simulator::pc));
-      sample->sp = reinterpret_cast<Address>(sim->get_register(Simulator::sp));
-      sample->fp = reinterpret_cast<Address>(sim->get_register(Simulator::fp));
-#endif
-#else
-      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));
-#endif  // USE_SIMULATOR
-      sampler->SampleStack(sample);
-      sampler->Tick(sample);
-    }
-    thread_resume(profiled_thread);
-  }
-
-  const int interval_;
-
-  // Protects the process wide state below.
-  static Mutex* mutex_;
-  static SamplerThread* instance_;
-
- private:
-  DISALLOW_COPY_AND_ASSIGN(SamplerThread);
-};
-
-#undef REGISTER_FIELD
-
-
-Mutex* SamplerThread::mutex_ = NULL;
-SamplerThread* SamplerThread::instance_ = NULL;
-
-
 void OS::SetUp() {
   // Seed the random number generator. We preserve microsecond resolution.
   uint64_t seed = Ticks() ^ (getpid() << 16);
   srandom(static_cast<unsigned int>(seed));
   limit_mutex = CreateMutex();
-  SamplerThread::SetUp();
 }
 
 
 void OS::TearDown() {
-  SamplerThread::TearDown();
   delete limit_mutex;
 }
 
 
-Sampler::Sampler(Isolate* isolate, int interval)
-    : isolate_(isolate),
-      interval_(interval),
-      profiling_(false),
-      active_(false),
-      samples_taken_(0) {
-  data_ = new PlatformData;
-}
-
-
-Sampler::~Sampler() {
-  ASSERT(!IsActive());
-  delete data_;
-}
-
-
-void Sampler::Start() {
-  ASSERT(!IsActive());
-  SetActive(true);
-  SamplerThread::AddActiveSampler(this);
-}
-
-
-void Sampler::Stop() {
-  ASSERT(IsActive());
-  SamplerThread::RemoveActiveSampler(this);
-  SetActive(false);
-}
-
-
 } }  // namespace v8::internal
index f9c2ce7..78d1ac5 100644 (file)
@@ -1968,166 +1968,6 @@ Socket* OS::CreateSocket() {
 }
 
 
-// ----------------------------------------------------------------------------
-// Win32 profiler support.
-
-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()
-      : profiled_thread_(OpenThread(THREAD_GET_CONTEXT |
-                                    THREAD_SUSPEND_RESUME |
-                                    THREAD_QUERY_INFORMATION,
-                                    false,
-                                    GetCurrentThreadId())),
-        profiled_thread_id_(ThreadId::Current()) {}
-
-  ~PlatformData() {
-    if (profiled_thread_ != NULL) {
-      CloseHandle(profiled_thread_);
-      profiled_thread_ = NULL;
-    }
-  }
-
-  HANDLE profiled_thread() { return profiled_thread_; }
-  ThreadId profiled_thread_id() { return profiled_thread_id_; }
-
- private:
-  HANDLE profiled_thread_;
-  ThreadId profiled_thread_id_;
-};
-
-
-class SamplerThread : public Thread {
- public:
-  static const int kSamplerThreadStackSize = 64 * KB;
-
-  explicit SamplerThread(int interval)
-      : Thread(Thread::Options("SamplerThread", kSamplerThreadStackSize)),
-        interval_(interval) {}
-
-  static void SetUp() { if (!mutex_) mutex_ = OS::CreateMutex(); }
-  static void TearDown() { delete mutex_; }
-
-  static void AddActiveSampler(Sampler* sampler) {
-    ScopedLock lock(mutex_);
-    SamplerRegistry::AddActiveSampler(sampler);
-    if (instance_ == NULL) {
-      instance_ = new SamplerThread(sampler->interval());
-      instance_->StartSynchronously();
-    } else {
-      ASSERT(instance_->interval_ == sampler->interval());
-    }
-  }
-
-  static void RemoveActiveSampler(Sampler* sampler) {
-    ScopedLock lock(mutex_);
-    SamplerRegistry::RemoveActiveSampler(sampler);
-    if (SamplerRegistry::GetState() == SamplerRegistry::HAS_NO_SAMPLERS) {
-      instance_->Join();
-      delete instance_;
-      instance_ = NULL;
-    }
-  }
-
-  // Implement Thread::Run().
-  virtual void Run() {
-    SamplerRegistry::State state;
-    while ((state = SamplerRegistry::GetState()) !=
-           SamplerRegistry::HAS_NO_SAMPLERS) {
-      // When CPU profiling is enabled both JavaScript and C++ code is
-      // profiled. We must not suspend.
-      if (state == SamplerRegistry::HAS_CPU_PROFILING_SAMPLERS) {
-        SamplerRegistry::IterateActiveSamplers(&DoCpuProfile, this);
-      }
-      OS::Sleep(interval_);
-    }
-  }
-
-  static void DoCpuProfile(Sampler* sampler, void* raw_sampler_thread) {
-    if (!sampler->isolate()->IsInitialized()) return;
-    if (!sampler->IsProfiling()) return;
-    SamplerThread* sampler_thread =
-        reinterpret_cast<SamplerThread*>(raw_sampler_thread);
-    sampler_thread->SampleContext(sampler);
-  }
-
-  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));
-
-    Isolate* isolate = sampler->isolate();
-#if defined(USE_SIMULATOR)
-#if V8_TARGET_ARCH_ARM || V8_TARGET_ARCH_MIPS
-    ThreadId thread_id = sampler->platform_data()->profiled_thread_id();
-    Isolate::PerIsolateThreadData* per_thread_data = isolate->
-        FindPerThreadDataForThread(thread_id);
-    if (!per_thread_data) return;
-    Simulator* sim = per_thread_data->simulator();
-    // Check if there is active simulator before allocating TickSample.
-    if (!sim) return;
-#endif
-#endif  // USE_SIMULATOR
-    TickSample sample_obj;
-    TickSample* sample = isolate->cpu_profiler()->TickSampleEvent();
-    if (sample == NULL) sample = &sample_obj;
-
-    static const DWORD kSuspendFailed = static_cast<DWORD>(-1);
-    if (SuspendThread(profiled_thread) == kSuspendFailed) return;
-    sample->state = isolate->current_vm_state();
-
-    context.ContextFlags = CONTEXT_FULL;
-    if (GetThreadContext(profiled_thread, &context) != 0) {
-#if defined(USE_SIMULATOR)
-#if V8_TARGET_ARCH_ARM
-      sample->pc = reinterpret_cast<Address>(sim->get_register(Simulator::pc));
-      sample->sp = reinterpret_cast<Address>(sim->get_register(Simulator::sp));
-      sample->fp = reinterpret_cast<Address>(sim->get_register(Simulator::r11));
-#elif V8_TARGET_ARCH_MIPS
-      sample->pc = reinterpret_cast<Address>(sim->get_register(Simulator::pc));
-      sample->sp = reinterpret_cast<Address>(sim->get_register(Simulator::sp));
-      sample->fp = reinterpret_cast<Address>(sim->get_register(Simulator::fp));
-#endif
-#else
-#if V8_HOST_ARCH_X64
-      sample->pc = reinterpret_cast<Address>(context.Rip);
-      sample->sp = reinterpret_cast<Address>(context.Rsp);
-      sample->fp = reinterpret_cast<Address>(context.Rbp);
-#else
-      sample->pc = reinterpret_cast<Address>(context.Eip);
-      sample->sp = reinterpret_cast<Address>(context.Esp);
-      sample->fp = reinterpret_cast<Address>(context.Ebp);
-#endif
-#endif  // USE_SIMULATOR
-      sampler->SampleStack(sample);
-      sampler->Tick(sample);
-    }
-    ResumeThread(profiled_thread);
-  }
-
-  const int interval_;
-
-  // Protects the process wide state below.
-  static Mutex* mutex_;
-  static SamplerThread* instance_;
-
- private:
-  DISALLOW_COPY_AND_ASSIGN(SamplerThread);
-};
-
-
-Mutex* SamplerThread::mutex_ = NULL;
-SamplerThread* SamplerThread::instance_ = NULL;
-
-
 void OS::SetUp() {
   // Seed the random number generator.
   // Convert the current time to a 64-bit integer first, before converting it
@@ -2137,44 +1977,12 @@ void OS::SetUp() {
   uint64_t seed = static_cast<uint64_t>(TimeCurrentMillis());
   srand(static_cast<unsigned int>(seed));
   limit_mutex = CreateMutex();
-  SamplerThread::SetUp();
 }
 
 
 void OS::TearDown() {
-  SamplerThread::TearDown();
   delete limit_mutex;
 }
 
 
-Sampler::Sampler(Isolate* isolate, int interval)
-    : isolate_(isolate),
-      interval_(interval),
-      profiling_(false),
-      active_(false),
-      samples_taken_(0) {
-  data_ = new PlatformData;
-}
-
-
-Sampler::~Sampler() {
-  ASSERT(!IsActive());
-  delete data_;
-}
-
-
-void Sampler::Start() {
-  ASSERT(!IsActive());
-  SetActive(true);
-  SamplerThread::AddActiveSampler(this);
-}
-
-
-void Sampler::Stop() {
-  ASSERT(IsActive());
-  SamplerThread::RemoveActiveSampler(this);
-  SetActive(false);
-}
-
-
 } }  // namespace v8::internal
index 446f996..55b943c 100644 (file)
 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
 #if defined(__linux__) || defined(__FreeBSD__) || defined(__OpenBSD__) \
-    || defined(__NetBSD__) || defined(__sun)
+    || defined(__NetBSD__) || defined(__sun) || defined(__ANDROID__)
+
+#define USE_SIGNALS
 
 #include <errno.h>
 #include <pthread.h>
 #include <signal.h>
 #include <sys/time.h>
 #include <sys/syscall.h>
+#if !defined(__ANDROID__) || defined(__BIONIC_HAVE_UCONTEXT_T)
 #include <ucontext.h>
-#include <unistd.h>
-
 #endif
+#include <unistd.h>
 
 // GLibc on ARM defines mcontext_t has a typedef for 'struct sigcontext'.
 // Old versions of the C library <signal.h> didn't define the type.
 #include <asm/sigcontext.h>
 #endif
 
+#elif defined(__MACH__)
+
+#include <mach/mach.h>
+
+#elif defined(_WIN32) || defined(_WIN64) || defined(__CYGWIN__)
+
+#include "win32-headers.h"
+
+#endif
+
 #include "v8.h"
 
 #include "log.h"
@@ -58,7 +70,7 @@ namespace internal {
 
 
 #if defined(__linux__) || defined(__FreeBSD__) || defined(__OpenBSD__) \
-    || defined(__NetBSD__) || defined(__sun)
+    || defined(__NetBSD__) || defined(__sun) || defined(__ANDROID__)
 
 #if defined(__ANDROID__) && !defined(__BIONIC_HAVE_UCONTEXT_T)
 
@@ -153,13 +165,16 @@ class Sampler::PlatformData : public Malloced {
  public:
   PlatformData()
       : vm_tid_(GetThreadID()),
+        vm_tgid_(getpid()),
         profiled_thread_id_(ThreadId::Current()) {}
 
   pthread_t vm_tid() const { return vm_tid_; }
+  int vm_tgid() const { return vm_tgid_; }
   ThreadId profiled_thread_id() { return profiled_thread_id_; }
 
  private:
   pthread_t vm_tid_;
+  const int vm_tgid_;
   ThreadId profiled_thread_id_;
 };
 
@@ -216,7 +231,7 @@ static void ProfilerSignalHandler(int signal, siginfo_t* info, void* context) {
   ucontext_t* ucontext = reinterpret_cast<ucontext_t*>(context);
   mcontext_t& mcontext = ucontext->uc_mcontext;
   sample->state = isolate->current_vm_state();
-#if defined(__linux__)
+#if defined(__linux__) || defined(__ANDROID__)
 #if V8_HOST_ARCH_IA32
   sample->pc = reinterpret_cast<Address>(mcontext.gregs[REG_EIP]);
   sample->sp = reinterpret_cast<Address>(mcontext.gregs[REG_ESP]);
@@ -291,19 +306,80 @@ static void ProfilerSignalHandler(int signal, siginfo_t* info, void* context) {
 #endif  // __native_client__
 }
 
+#elif defined(__MACH__)
+class Sampler::PlatformData : public Malloced {
+ public:
+  PlatformData()
+      : profiled_thread_(mach_thread_self()),
+        profiled_thread_id_(ThreadId::Current()) {}
+
+  ~PlatformData() {
+    // Deallocate Mach port for thread.
+    mach_port_deallocate(mach_task_self(), profiled_thread_);
+  }
 
-class SignalSender : public Thread {
+  thread_act_t profiled_thread() { return profiled_thread_; }
+  ThreadId profiled_thread_id() { return profiled_thread_id_; }
+
+ private:
+  // Note: for profiled_thread_ Mach primitives are used instead of PThread's
+  // because the latter doesn't provide thread manipulation primitives required.
+  // For details, consult "Mac OS X Internals" book, Section 7.3.
+  thread_act_t profiled_thread_;
+  ThreadId profiled_thread_id_;
+};
+
+#elif defined(_WIN32) || defined(_WIN64) || defined(__CYGWIN__)
+
+// ----------------------------------------------------------------------------
+// Win32 profiler support. On Cygwin we use the same sampler implementation as
+// on Win32.
+
+class Sampler::PlatformData : public Malloced {
  public:
-  static const int kSignalSenderStackSize = 64 * KB;
+  // 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()
+      : profiled_thread_(OpenThread(THREAD_GET_CONTEXT |
+                                    THREAD_SUSPEND_RESUME |
+                                    THREAD_QUERY_INFORMATION,
+                                    false,
+                                    GetCurrentThreadId())),
+        profiled_thread_id_(ThreadId::Current()) {}
 
-  explicit SignalSender(int interval)
-      : Thread(Thread::Options("SignalSender", kSignalSenderStackSize)),
-        vm_tgid_(getpid()),
+  ~PlatformData() {
+    if (profiled_thread_ != NULL) {
+      CloseHandle(profiled_thread_);
+      profiled_thread_ = NULL;
+    }
+  }
+
+  HANDLE profiled_thread() { return profiled_thread_; }
+  ThreadId profiled_thread_id() { return profiled_thread_id_; }
+
+ private:
+  HANDLE profiled_thread_;
+  ThreadId profiled_thread_id_;
+};
+
+#endif
+
+
+class SamplerThread : public Thread {
+ public:
+  static const int kSamplerThreadStackSize = 64 * KB;
+
+  explicit SamplerThread(int interval)
+      : Thread(Thread::Options("SamplerThread", kSamplerThreadStackSize)),
         interval_(interval) {}
 
   static void SetUp() { if (!mutex_) mutex_ = OS::CreateMutex(); }
   static void TearDown() { delete mutex_; }
 
+#if defined(USE_SIGNALS)
   static void InstallSignalHandler() {
     struct sigaction sa;
     sa.sa_sigaction = ProfilerSignalHandler;
@@ -319,6 +395,7 @@ class SignalSender : public Thread {
       signal_handler_installed_ = false;
     }
   }
+#endif
 
   static void AddActiveSampler(Sampler* sampler) {
     ScopedLock lock(mutex_);
@@ -326,7 +403,7 @@ class SignalSender : public Thread {
     if (instance_ == NULL) {
       // Start a thread that will send SIGPROF signal to VM threads,
       // when CPU profiling will be enabled.
-      instance_ = new SignalSender(sampler->interval());
+      instance_ = new SamplerThread(sampler->interval());
       instance_->StartSynchronously();
     } else {
       ASSERT(instance_->interval_ == sampler->interval());
@@ -340,7 +417,9 @@ class SignalSender : public Thread {
       instance_->Join();
       delete instance_;
       instance_ = NULL;
+#if defined(USE_SIGNALS)
       RestoreSignalHandler();
+#endif
     }
   }
 
@@ -352,31 +431,39 @@ class SignalSender : public Thread {
       // When CPU profiling is enabled both JavaScript and C++ code is
       // profiled. We must not suspend.
       if (state == SamplerRegistry::HAS_CPU_PROFILING_SAMPLERS) {
+#if defined(USE_SIGNALS)
         if (!signal_handler_installed_) InstallSignalHandler();
+#endif
         SamplerRegistry::IterateActiveSamplers(&DoCpuProfile, this);
       } else {
+#if defined(USE_SIGNALS)
         if (signal_handler_installed_) RestoreSignalHandler();
+#endif
       }
       Sleep();  // TODO(svenpanne) Figure out if OS:Sleep(interval_) is enough.
     }
   }
 
   static void DoCpuProfile(Sampler* sampler, void* raw_sender) {
+    if (!sampler->isolate()->IsInitialized()) return;
     if (!sampler->IsProfiling()) return;
-    SignalSender* sender = reinterpret_cast<SignalSender*>(raw_sender);
-    sender->SendProfilingSignal(sampler->platform_data()->vm_tid());
+    SamplerThread* sender = reinterpret_cast<SamplerThread*>(raw_sender);
+    sender->SampleContext(sampler);
   }
 
-  void SendProfilingSignal(int tid) {
+#if defined(USE_SIGNALS)
+  void SampleContext(Sampler* sampler) {
     if (!signal_handler_installed_) return;
+    Sampler::PlatformData* platform_data = sampler->platform_data();
+    int tid = platform_data->vm_tid();
     // Glibc doesn't provide a wrapper for tgkill(2).
 #if defined(ANDROID)
-    syscall(__NR_tgkill, vm_tgid_, tid, SIGPROF);
+    syscall(__NR_tgkill, platform_data->vm_tgid(), tid, SIGPROF);
 #elif defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__NetBSD__) \
     || defined(__sun)
     pthread_kill(tid, SIGPROF);
 #else
-    int result = syscall(SYS_tgkill, vm_tgid_, tid, SIGPROF);
+    int result = syscall(SYS_tgkill, platform_data->vm_tgid(), tid, SIGPROF);
     USE(result);
     ASSERT(result == 0);
 #endif
@@ -393,7 +480,7 @@ class SignalSender : public Thread {
 #ifdef DEBUG
     if (result != 0 && errno != EINTR) {
       fprintf(stderr,
-              "SignalSender usleep error; interval = %u, errno = %d\n",
+              "SamplerThread usleep error; interval = %u, errno = %d\n",
               interval,
               errno);
       ASSERT(result == 0 || errno == EINTR);
@@ -403,33 +490,176 @@ class SignalSender : public Thread {
 #endif  // ANDROID
   }
 
-  const int vm_tgid_;
+#elif defined(__MACH__)
+
+  void SampleContext(Sampler* sampler) {
+    thread_act_t profiled_thread = sampler->platform_data()->profiled_thread();
+    Isolate* isolate = sampler->isolate();
+#if defined(USE_SIMULATOR)
+#if V8_TARGET_ARCH_ARM || V8_TARGET_ARCH_MIPS
+    ThreadId thread_id = sampler->platform_data()->profiled_thread_id();
+    Isolate::PerIsolateThreadData* per_thread_data = isolate->
+        FindPerThreadDataForThread(thread_id);
+    if (!per_thread_data) return;
+    Simulator* sim = per_thread_data->simulator();
+    // Check if there is active simulator before allocating TickSample.
+    if (!sim) return;
+#endif
+#endif  // USE_SIMULATOR
+    TickSample sample_obj;
+    TickSample* sample = isolate->cpu_profiler()->TickSampleEvent();
+    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
+#define REGISTER_FIELD(name) __r ## name
+#else
+#define REGISTER_FIELD(name) r ## name
+#endif  // __DARWIN_UNIX03
+#elif V8_HOST_ARCH_IA32
+    thread_state_flavor_t flavor = i386_THREAD_STATE;
+    i386_thread_state_t state;
+    mach_msg_type_number_t count = i386_THREAD_STATE_COUNT;
+#if __DARWIN_UNIX03
+#define REGISTER_FIELD(name) __e ## name
+#else
+#define REGISTER_FIELD(name) e ## name
+#endif  // __DARWIN_UNIX03
+#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 = isolate->current_vm_state();
+#if defined(USE_SIMULATOR)
+#if V8_TARGET_ARCH_ARM
+      sample->pc = reinterpret_cast<Address>(sim->get_register(Simulator::pc));
+      sample->sp = reinterpret_cast<Address>(sim->get_register(Simulator::sp));
+      sample->fp = reinterpret_cast<Address>(sim->get_register(Simulator::r11));
+#elif V8_TARGET_ARCH_MIPS
+      sample->pc = reinterpret_cast<Address>(sim->get_register(Simulator::pc));
+      sample->sp = reinterpret_cast<Address>(sim->get_register(Simulator::sp));
+      sample->fp = reinterpret_cast<Address>(sim->get_register(Simulator::fp));
+#endif
+#else
+      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));
+#endif  // USE_SIMULATOR
+#undef REGISTER_FIELD
+      sampler->SampleStack(sample);
+      sampler->Tick(sample);
+    }
+    thread_resume(profiled_thread);
+  }
+
+  void Sleep() {
+    OS::Sleep(interval_);
+  }
+
+#elif defined(_WIN32) || defined(_WIN64) || defined(__CYGWIN__)
+
+  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));
+
+    Isolate* isolate = sampler->isolate();
+#if defined(USE_SIMULATOR)
+#if V8_TARGET_ARCH_ARM || V8_TARGET_ARCH_MIPS
+    ThreadId thread_id = sampler->platform_data()->profiled_thread_id();
+    Isolate::PerIsolateThreadData* per_thread_data = isolate->
+        FindPerThreadDataForThread(thread_id);
+    if (!per_thread_data) return;
+    Simulator* sim = per_thread_data->simulator();
+    // Check if there is active simulator before allocating TickSample.
+    if (!sim) return;
+#endif
+#endif  // USE_SIMULATOR
+    TickSample sample_obj;
+    TickSample* sample = isolate->cpu_profiler()->TickSampleEvent();
+    if (sample == NULL) sample = &sample_obj;
+
+    static const DWORD kSuspendFailed = static_cast<DWORD>(-1);
+    if (SuspendThread(profiled_thread) == kSuspendFailed) return;
+    sample->state = isolate->current_vm_state();
+
+    context.ContextFlags = CONTEXT_FULL;
+    if (GetThreadContext(profiled_thread, &context) != 0) {
+#if defined(USE_SIMULATOR)
+#if V8_TARGET_ARCH_ARM
+      sample->pc = reinterpret_cast<Address>(sim->get_register(Simulator::pc));
+      sample->sp = reinterpret_cast<Address>(sim->get_register(Simulator::sp));
+      sample->fp = reinterpret_cast<Address>(sim->get_register(Simulator::r11));
+#elif V8_TARGET_ARCH_MIPS
+      sample->pc = reinterpret_cast<Address>(sim->get_register(Simulator::pc));
+      sample->sp = reinterpret_cast<Address>(sim->get_register(Simulator::sp));
+      sample->fp = reinterpret_cast<Address>(sim->get_register(Simulator::fp));
+#endif
+#else
+#if V8_HOST_ARCH_X64
+      sample->pc = reinterpret_cast<Address>(context.Rip);
+      sample->sp = reinterpret_cast<Address>(context.Rsp);
+      sample->fp = reinterpret_cast<Address>(context.Rbp);
+#else
+      sample->pc = reinterpret_cast<Address>(context.Eip);
+      sample->sp = reinterpret_cast<Address>(context.Esp);
+      sample->fp = reinterpret_cast<Address>(context.Ebp);
+#endif
+#endif  // USE_SIMULATOR
+      sampler->SampleStack(sample);
+      sampler->Tick(sample);
+    }
+    ResumeThread(profiled_thread);
+  }
+
+  void Sleep() {
+    OS::Sleep(interval_);
+  }
+
+#endif  // USE_SIGNALS
+
   const int interval_;
 
   // Protects the process wide state below.
   static Mutex* mutex_;
-  static SignalSender* instance_;
+  static SamplerThread* instance_;
+#if defined(USE_SIGNALS)
   static bool signal_handler_installed_;
   static struct sigaction old_signal_handler_;
+#endif
 
  private:
-  DISALLOW_COPY_AND_ASSIGN(SignalSender);
+  DISALLOW_COPY_AND_ASSIGN(SamplerThread);
 };
 
 
-Mutex* SignalSender::mutex_ = NULL;
-SignalSender* SignalSender::instance_ = NULL;
-struct sigaction SignalSender::old_signal_handler_;
-bool SignalSender::signal_handler_installed_ = false;
+Mutex* SamplerThread::mutex_ = NULL;
+SamplerThread* SamplerThread::instance_ = NULL;
+#if defined(USE_SIGNALS)
+struct sigaction SamplerThread::old_signal_handler_;
+bool SamplerThread::signal_handler_installed_ = false;
+#endif
 
 
 void Sampler::SetUp() {
-  SignalSender::SetUp();
+  SamplerThread::SetUp();
 }
 
 
 void Sampler::TearDown() {
-  SignalSender::TearDown();
+  SamplerThread::TearDown();
 }
 
 
@@ -451,27 +681,16 @@ Sampler::~Sampler() {
 void Sampler::Start() {
   ASSERT(!IsActive());
   SetActive(true);
-  SignalSender::AddActiveSampler(this);
+  SamplerThread::AddActiveSampler(this);
 }
 
 
 void Sampler::Stop() {
   ASSERT(IsActive());
-  SignalSender::RemoveActiveSampler(this);
+  SamplerThread::RemoveActiveSampler(this);
   SetActive(false);
 }
 
-#else
-
-void Sampler::SetUp() {
-}
-
-
-void Sampler::TearDown() {
-}
-
-#endif  // __linux__ || _*BSD__ || __sun
-
 void Sampler::SampleStack(TickSample* sample) {
   StackTracer::Trace(isolate_, sample);
   if (++samples_taken_ < 0) samples_taken_ = 0;