| OLD | NEW | 
|---|
| 1 // Copyright 2013 the V8 project authors. All rights reserved. | 1 // Copyright 2016 the V8 project authors. All rights reserved. | 
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be | 
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. | 
| 4 | 4 | 
| 5 #include "src/profiler/sampler.h" | 5 #include "src/libsampler/v8-sampler.h" | 
| 6 | 6 | 
| 7 #if V8_OS_POSIX && !V8_OS_CYGWIN | 7 #if V8_OS_POSIX && !V8_OS_CYGWIN | 
| 8 | 8 | 
| 9 #define USE_SIGNALS | 9 #define USE_SIGNALS | 
| 10 | 10 | 
| 11 #include <errno.h> | 11 #include <errno.h> | 
| 12 #include <pthread.h> | 12 #include <pthread.h> | 
| 13 #include <signal.h> | 13 #include <signal.h> | 
| 14 #include <sys/time.h> | 14 #include <sys/time.h> | 
| 15 | 15 | 
| (...skipping 19 matching lines...) Expand all  Loading... | 
| 35     !defined(__BIONIC_HAVE_STRUCT_SIGCONTEXT) | 35     !defined(__BIONIC_HAVE_STRUCT_SIGCONTEXT) | 
| 36 #include <asm/sigcontext.h>  // NOLINT | 36 #include <asm/sigcontext.h>  // NOLINT | 
| 37 #endif | 37 #endif | 
| 38 | 38 | 
| 39 #elif V8_OS_WIN || V8_OS_CYGWIN | 39 #elif V8_OS_WIN || V8_OS_CYGWIN | 
| 40 | 40 | 
| 41 #include "src/base/win32-headers.h" | 41 #include "src/base/win32-headers.h" | 
| 42 | 42 | 
| 43 #endif | 43 #endif | 
| 44 | 44 | 
|  | 45 #include <algorithm> | 
|  | 46 #include <list> | 
|  | 47 #include <map> | 
|  | 48 | 
| 45 #include "src/base/atomic-utils.h" | 49 #include "src/base/atomic-utils.h" | 
| 46 #include "src/base/platform/platform.h" | 50 #include "src/base/platform/platform.h" | 
| 47 #include "src/flags.h" |  | 
| 48 #include "src/frames-inl.h" |  | 
| 49 #include "src/log.h" |  | 
| 50 #include "src/profiler/cpu-profiler-inl.h" |  | 
| 51 #include "src/simulator.h" |  | 
| 52 #include "src/v8threads.h" |  | 
| 53 #include "src/vm-state-inl.h" |  | 
| 54 | 51 | 
| 55 | 52 | 
| 56 #if V8_OS_ANDROID && !defined(__BIONIC_HAVE_UCONTEXT_T) | 53 #if V8_OS_ANDROID && !defined(__BIONIC_HAVE_UCONTEXT_T) | 
| 57 | 54 | 
| 58 // Not all versions of Android's C library provide ucontext_t. | 55 // Not all versions of Android's C library provide ucontext_t. | 
| 59 // Detect this and provide custom but compatible definitions. Note that these | 56 // Detect this and provide custom but compatible definitions. Note that these | 
| 60 // follow the GLibc naming convention to access register values from | 57 // follow the GLibc naming convention to access register values from | 
| 61 // mcontext_t. | 58 // mcontext_t. | 
| 62 // | 59 // | 
| 63 // See http://code.google.com/p/android/issues/detail?id=34784 | 60 // See http://code.google.com/p/android/issues/detail?id=34784 | 
| (...skipping 87 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
| 151   mcontext_t uc_mcontext; | 148   mcontext_t uc_mcontext; | 
| 152   // Other fields are not used by V8, don't define them here. | 149   // Other fields are not used by V8, don't define them here. | 
| 153 } ucontext_t; | 150 } ucontext_t; | 
| 154 enum { REG_RBP = 10, REG_RSP = 15, REG_RIP = 16 }; | 151 enum { REG_RBP = 10, REG_RSP = 15, REG_RIP = 16 }; | 
| 155 #endif | 152 #endif | 
| 156 | 153 | 
| 157 #endif  // V8_OS_ANDROID && !defined(__BIONIC_HAVE_UCONTEXT_T) | 154 #endif  // V8_OS_ANDROID && !defined(__BIONIC_HAVE_UCONTEXT_T) | 
| 158 | 155 | 
| 159 | 156 | 
| 160 namespace v8 { | 157 namespace v8 { | 
| 161 namespace internal { | 158 namespace sampler { | 
| 162 | 159 | 
| 163 namespace { | 160 namespace { | 
| 164 | 161 | 
| 165 class PlatformDataCommon : public Malloced { | 162 #if defined(USE_SIGNALS) | 
| 166  public: | 163 typedef std::list<Sampler*> SamplerList; | 
| 167   PlatformDataCommon() : profiled_thread_id_(ThreadId::Current()) {} | 164 typedef SamplerList::iterator SamplerListIterator; | 
| 168   ThreadId profiled_thread_id() { return profiled_thread_id_; } | 165 typedef std::map<pthread_t, SamplerList*> SamplerMap; | 
|  | 166 typedef SamplerMap::iterator SamplerMapIterator; | 
| 169 | 167 | 
| 170  protected: |  | 
| 171   ~PlatformDataCommon() {} |  | 
| 172 |  | 
| 173  private: |  | 
| 174   ThreadId profiled_thread_id_; |  | 
| 175 }; |  | 
| 176 |  | 
| 177 |  | 
| 178 bool IsSamePage(byte* ptr1, byte* ptr2) { |  | 
| 179   const uint32_t kPageSize = 4096; |  | 
| 180   uintptr_t mask = ~static_cast<uintptr_t>(kPageSize - 1); |  | 
| 181   return (reinterpret_cast<uintptr_t>(ptr1) & mask) == |  | 
| 182          (reinterpret_cast<uintptr_t>(ptr2) & mask); |  | 
| 183 } |  | 
| 184 |  | 
| 185 |  | 
| 186 // Check if the code at specified address could potentially be a |  | 
| 187 // frame setup code. |  | 
| 188 bool IsNoFrameRegion(Address address) { |  | 
| 189   struct Pattern { |  | 
| 190     int bytes_count; |  | 
| 191     byte bytes[8]; |  | 
| 192     int offsets[4]; |  | 
| 193   }; |  | 
| 194   byte* pc = reinterpret_cast<byte*>(address); |  | 
| 195   static Pattern patterns[] = { |  | 
| 196 #if V8_HOST_ARCH_IA32 |  | 
| 197     // push %ebp |  | 
| 198     // mov %esp,%ebp |  | 
| 199     {3, {0x55, 0x89, 0xe5}, {0, 1, -1}}, |  | 
| 200     // pop %ebp |  | 
| 201     // ret N |  | 
| 202     {2, {0x5d, 0xc2}, {0, 1, -1}}, |  | 
| 203     // pop %ebp |  | 
| 204     // ret |  | 
| 205     {2, {0x5d, 0xc3}, {0, 1, -1}}, |  | 
| 206 #elif V8_HOST_ARCH_X64 |  | 
| 207     // pushq %rbp |  | 
| 208     // movq %rsp,%rbp |  | 
| 209     {4, {0x55, 0x48, 0x89, 0xe5}, {0, 1, -1}}, |  | 
| 210     // popq %rbp |  | 
| 211     // ret N |  | 
| 212     {2, {0x5d, 0xc2}, {0, 1, -1}}, |  | 
| 213     // popq %rbp |  | 
| 214     // ret |  | 
| 215     {2, {0x5d, 0xc3}, {0, 1, -1}}, |  | 
| 216 #endif |  | 
| 217     {0, {}, {}} |  | 
| 218   }; |  | 
| 219   for (Pattern* pattern = patterns; pattern->bytes_count; ++pattern) { |  | 
| 220     for (int* offset_ptr = pattern->offsets; *offset_ptr != -1; ++offset_ptr) { |  | 
| 221       int offset = *offset_ptr; |  | 
| 222       if (!offset || IsSamePage(pc, pc - offset)) { |  | 
| 223         MSAN_MEMORY_IS_INITIALIZED(pc - offset, pattern->bytes_count); |  | 
| 224         if (!memcmp(pc - offset, pattern->bytes, pattern->bytes_count)) |  | 
| 225           return true; |  | 
| 226       } else { |  | 
| 227         // It is not safe to examine bytes on another page as it might not be |  | 
| 228         // allocated thus causing a SEGFAULT. |  | 
| 229         // Check the pattern part that's on the same page and |  | 
| 230         // pessimistically assume it could be the entire pattern match. |  | 
| 231         MSAN_MEMORY_IS_INITIALIZED(pc, pattern->bytes_count - offset); |  | 
| 232         if (!memcmp(pc, pattern->bytes + offset, pattern->bytes_count - offset)) |  | 
| 233           return true; |  | 
| 234       } |  | 
| 235     } |  | 
| 236   } |  | 
| 237   return false; |  | 
| 238 } |  | 
| 239 |  | 
| 240 typedef List<Sampler*> SamplerList; |  | 
| 241 |  | 
| 242 #if defined(USE_SIGNALS) |  | 
| 243 class AtomicGuard { | 168 class AtomicGuard { | 
| 244  public: | 169  public: | 
| 245   explicit AtomicGuard(base::AtomicValue<int>* atomic, bool is_block = true) | 170   explicit AtomicGuard(base::AtomicValue<int>* atomic, bool is_block = true) | 
| 246       : atomic_(atomic), | 171       : atomic_(atomic), | 
| 247         is_success_(false) { | 172         is_success_(false) { | 
| 248     do { | 173     do { | 
| 249       // Use Acquire_Load to gain mutual exclusion. | 174       // Use Acquire_Load to gain mutual exclusion. | 
| 250       USE(atomic_->Value()); | 175       USE(atomic_->Value()); | 
| 251       is_success_ = atomic_->TrySetValue(0, 1); | 176       is_success_ = atomic_->TrySetValue(0, 1); | 
| 252     } while (is_block && !is_success_); | 177     } while (is_block && !is_success_); | 
| 253   } | 178   } | 
| 254 | 179 | 
| 255   bool is_success() { return is_success_; } | 180   bool is_success() { return is_success_; } | 
| 256 | 181 | 
| 257   ~AtomicGuard() { | 182   ~AtomicGuard() { | 
| 258     if (is_success_) { | 183     if (is_success_) { | 
| 259       atomic_->SetValue(0); | 184       atomic_->SetValue(0); | 
| 260     } | 185     } | 
| 261     atomic_ = NULL; | 186     atomic_ = NULL; | 
| 262   } | 187   } | 
| 263 | 188 | 
| 264  private: | 189  private: | 
| 265   base::AtomicValue<int>* atomic_; | 190   base::AtomicValue<int>* atomic_; | 
| 266   bool is_success_; | 191   bool is_success_; | 
| 267 }; | 192 }; | 
| 268 | 193 | 
| 269 |  | 
| 270 // Returns key for hash map. |  | 
| 271 void* ThreadKey(pthread_t thread_id) { |  | 
| 272   return reinterpret_cast<void*>(thread_id); |  | 
| 273 } |  | 
| 274 |  | 
| 275 |  | 
| 276 // Returns hash value for hash map. |  | 
| 277 uint32_t ThreadHash(pthread_t thread_id) { |  | 
| 278 #if V8_OS_MACOSX |  | 
| 279   return static_cast<uint32_t>(reinterpret_cast<intptr_t>(thread_id)); |  | 
| 280 #else |  | 
| 281   return static_cast<uint32_t>(thread_id); |  | 
| 282 #endif |  | 
| 283 } |  | 
| 284 #endif  // USE_SIGNALS | 194 #endif  // USE_SIGNALS | 
| 285 | 195 | 
| 286 }  // namespace | 196 }  // namespace | 
| 287 | 197 | 
| 288 #if defined(USE_SIGNALS) | 198 #if defined(USE_SIGNALS) | 
| 289 | 199 | 
| 290 class Sampler::PlatformData : public PlatformDataCommon { | 200 class Sampler::PlatformData { | 
| 291  public: | 201  public: | 
| 292   PlatformData() : vm_tid_(pthread_self()) {} | 202   PlatformData() : vm_tid_(pthread_self()) {} | 
| 293   pthread_t vm_tid() const { return vm_tid_; } | 203   pthread_t vm_tid() const { return vm_tid_; } | 
| 294 | 204 | 
| 295  private: | 205  private: | 
| 296   pthread_t vm_tid_; | 206   pthread_t vm_tid_; | 
| 297 }; | 207 }; | 
| 298 | 208 | 
|  | 209 | 
|  | 210 class SamplerManager { | 
|  | 211  public: | 
|  | 212   static void AddSampler(Sampler* sampler) { | 
|  | 213     AtomicGuard atomic_guard(&samplers_access_counter_); | 
|  | 214     DCHECK(sampler->IsActive()); | 
|  | 215     // Add sampler into map if needed. | 
|  | 216     pthread_t thread_id = sampler->platform_data()->vm_tid(); | 
|  | 217     SamplerMapIterator sampler_entry = sampler_map_.find(thread_id); | 
|  | 218     if (sampler_entry == sampler_map_.end()) { | 
|  | 219       SamplerList* samplers = new SamplerList(); | 
|  | 220       samplers->push_back(sampler); | 
|  | 221       sampler_map_[thread_id] = samplers; | 
|  | 222     } else { | 
|  | 223       SamplerList* samplers = sampler_entry->second; | 
|  | 224       if (std::find(samplers->begin(), samplers->end(), sampler) == | 
|  | 225           samplers->end()) { | 
|  | 226         samplers->push_back(sampler); | 
|  | 227       } | 
|  | 228     } | 
|  | 229   } | 
|  | 230 | 
|  | 231   static void RemoveSampler(Sampler* sampler) { | 
|  | 232     AtomicGuard atomic_guard(&samplers_access_counter_); | 
|  | 233     DCHECK(sampler->IsActive()); | 
|  | 234     // Remove sampler from map. | 
|  | 235     pthread_t thread_id = sampler->platform_data()->vm_tid(); | 
|  | 236     SamplerMapIterator sampler_entry = sampler_map_.find(thread_id); | 
|  | 237     DCHECK(sampler_entry != sampler_map_.end()); | 
|  | 238     SamplerList* samplers = sampler_entry->second; | 
|  | 239     samplers->remove(sampler); | 
|  | 240     if (samplers->empty()) { | 
|  | 241       sampler_map_.erase(thread_id); | 
|  | 242       delete samplers; | 
|  | 243     } | 
|  | 244   } | 
|  | 245 | 
|  | 246  private: | 
|  | 247   friend class SignalHandler; | 
|  | 248   static SamplerMap sampler_map_; | 
|  | 249   static base::AtomicValue<int> samplers_access_counter_; | 
|  | 250 }; | 
|  | 251 | 
|  | 252 | 
|  | 253 SamplerMap SamplerManager::sampler_map_; | 
|  | 254 base::AtomicValue<int> SamplerManager::samplers_access_counter_(0); | 
|  | 255 | 
|  | 256 | 
| 299 #elif V8_OS_WIN || V8_OS_CYGWIN | 257 #elif V8_OS_WIN || V8_OS_CYGWIN | 
| 300 | 258 | 
| 301 // ---------------------------------------------------------------------------- | 259 // ---------------------------------------------------------------------------- | 
| 302 // Win32 profiler support. On Cygwin we use the same sampler implementation as | 260 // Win32 profiler support. On Cygwin we use the same sampler implementation as | 
| 303 // on Win32. | 261 // on Win32. | 
| 304 | 262 | 
| 305 class Sampler::PlatformData : public PlatformDataCommon { | 263 class Sampler::PlatformData { | 
| 306  public: | 264  public: | 
| 307   // Get a handle to the calling thread. This is the thread that we are | 265   // Get a handle to the calling thread. This is the thread that we are | 
| 308   // going to profile. We need to make a copy of the handle because we are | 266   // going to profile. We need to make a copy of the handle because we are | 
| 309   // going to use it in the sampler thread. Using GetThreadHandle() will | 267   // going to use it in the sampler thread. Using GetThreadHandle() will | 
| 310   // not work in this case. We're using OpenThread because DuplicateHandle | 268   // not work in this case. We're using OpenThread because DuplicateHandle | 
| 311   // for some reason doesn't work in Chrome's sandbox. | 269   // for some reason doesn't work in Chrome's sandbox. | 
| 312   PlatformData() | 270   PlatformData() | 
| 313       : profiled_thread_(OpenThread(THREAD_GET_CONTEXT | | 271       : profiled_thread_(OpenThread(THREAD_GET_CONTEXT | | 
| 314                                     THREAD_SUSPEND_RESUME | | 272                                     THREAD_SUSPEND_RESUME | | 
| 315                                     THREAD_QUERY_INFORMATION, | 273                                     THREAD_QUERY_INFORMATION, | 
| 316                                     false, | 274                                     false, | 
| 317                                     GetCurrentThreadId())) {} | 275                                     GetCurrentThreadId())) {} | 
| 318 | 276 | 
| 319   ~PlatformData() { | 277   ~PlatformData() { | 
| 320     if (profiled_thread_ != NULL) { | 278     if (profiled_thread_ != NULL) { | 
| 321       CloseHandle(profiled_thread_); | 279       CloseHandle(profiled_thread_); | 
| 322       profiled_thread_ = NULL; | 280       profiled_thread_ = NULL; | 
| 323     } | 281     } | 
| 324   } | 282   } | 
| 325 | 283 | 
| 326   HANDLE profiled_thread() { return profiled_thread_; } | 284   HANDLE profiled_thread() { return profiled_thread_; } | 
| 327 | 285 | 
| 328  private: | 286  private: | 
| 329   HANDLE profiled_thread_; | 287   HANDLE profiled_thread_; | 
| 330 }; | 288 }; | 
| 331 #endif | 289 #endif  // USE_SIGNALS | 
| 332 |  | 
| 333 |  | 
| 334 #if defined(USE_SIMULATOR) |  | 
| 335 bool SimulatorHelper::FillRegisters(Isolate* isolate, |  | 
| 336                                     v8::RegisterState* state) { |  | 
| 337   Simulator *simulator = isolate->thread_local_top()->simulator_; |  | 
| 338   // Check if there is active simulator. |  | 
| 339   if (simulator == NULL) return false; |  | 
| 340 #if V8_TARGET_ARCH_ARM |  | 
| 341   if (!simulator->has_bad_pc()) { |  | 
| 342     state->pc = reinterpret_cast<Address>(simulator->get_pc()); |  | 
| 343   } |  | 
| 344   state->sp = reinterpret_cast<Address>(simulator->get_register(Simulator::sp)); |  | 
| 345   state->fp = reinterpret_cast<Address>(simulator->get_register( |  | 
| 346       Simulator::r11)); |  | 
| 347 #elif V8_TARGET_ARCH_ARM64 |  | 
| 348   state->pc = reinterpret_cast<Address>(simulator->pc()); |  | 
| 349   state->sp = reinterpret_cast<Address>(simulator->sp()); |  | 
| 350   state->fp = reinterpret_cast<Address>(simulator->fp()); |  | 
| 351 #elif V8_TARGET_ARCH_MIPS || V8_TARGET_ARCH_MIPS64 |  | 
| 352   if (!simulator->has_bad_pc()) { |  | 
| 353     state->pc = reinterpret_cast<Address>(simulator->get_pc()); |  | 
| 354   } |  | 
| 355   state->sp = reinterpret_cast<Address>(simulator->get_register(Simulator::sp)); |  | 
| 356   state->fp = reinterpret_cast<Address>(simulator->get_register(Simulator::fp)); |  | 
| 357 #elif V8_TARGET_ARCH_PPC |  | 
| 358   if (!simulator->has_bad_pc()) { |  | 
| 359     state->pc = reinterpret_cast<Address>(simulator->get_pc()); |  | 
| 360   } |  | 
| 361   state->sp = reinterpret_cast<Address>(simulator->get_register(Simulator::sp)); |  | 
| 362   state->fp = reinterpret_cast<Address>(simulator->get_register(Simulator::fp)); |  | 
| 363 #elif V8_TARGET_ARCH_S390 |  | 
| 364   if (!simulator->has_bad_pc()) { |  | 
| 365     state->pc = reinterpret_cast<Address>(simulator->get_pc()); |  | 
| 366   } |  | 
| 367   state->sp = reinterpret_cast<Address>(simulator->get_register(Simulator::sp)); |  | 
| 368   state->fp = reinterpret_cast<Address>(simulator->get_register(Simulator::fp)); |  | 
| 369 #endif |  | 
| 370   if (state->sp == 0 || state->fp == 0) { |  | 
| 371     // It possible that the simulator is interrupted while it is updating |  | 
| 372     // the sp or fp register. ARM64 simulator does this in two steps: |  | 
| 373     // first setting it to zero and then setting it to the new value. |  | 
| 374     // Bailout if sp/fp doesn't contain the new value. |  | 
| 375     // |  | 
| 376     // FIXME: The above doesn't really solve the issue. |  | 
| 377     // If a 64-bit target is executed on a 32-bit host even the final |  | 
| 378     // write is non-atomic, so it might obtain a half of the result. |  | 
| 379     // Moreover as long as the register set code uses memcpy (as of now), |  | 
| 380     // it is not guaranteed to be atomic even when both host and target |  | 
| 381     // are of same bitness. |  | 
| 382     return false; |  | 
| 383   } |  | 
| 384   return true; |  | 
| 385 } |  | 
| 386 #endif  // USE_SIMULATOR |  | 
| 387 | 290 | 
| 388 | 291 | 
| 389 #if defined(USE_SIGNALS) | 292 #if defined(USE_SIGNALS) | 
| 390 | 293 class SignalHandler { | 
| 391 class SignalHandler : public AllStatic { |  | 
| 392  public: | 294  public: | 
| 393   static void SetUp() { if (!mutex_) mutex_ = new base::Mutex(); } | 295   static void SetUp() { if (!mutex_) mutex_ = new base::Mutex(); } | 
| 394   static void TearDown() { delete mutex_; mutex_ = NULL; } | 296   static void TearDown() { delete mutex_; mutex_ = NULL; } | 
| 395 | 297 | 
| 396   static void IncreaseSamplerCount() { | 298   static void IncreaseSamplerCount() { | 
| 397     base::LockGuard<base::Mutex> lock_guard(mutex_); | 299     base::LockGuard<base::Mutex> lock_guard(mutex_); | 
| 398     if (++client_count_ == 1) Install(); | 300     if (++client_count_ == 1) Install(); | 
| 399   } | 301   } | 
| 400 | 302 | 
| 401   static void DecreaseSamplerCount() { | 303   static void DecreaseSamplerCount() { | 
| 402     base::LockGuard<base::Mutex> lock_guard(mutex_); | 304     base::LockGuard<base::Mutex> lock_guard(mutex_); | 
| 403     if (--client_count_ == 0) Restore(); | 305     if (--client_count_ == 0) Restore(); | 
| 404   } | 306   } | 
| 405 | 307 | 
| 406   static bool Installed() { | 308   static bool Installed() { | 
| 407     return signal_handler_installed_; | 309     return signal_handler_installed_; | 
| 408   } | 310   } | 
| 409 | 311 | 
| 410 #if !V8_OS_NACL |  | 
| 411   static void CollectSample(void* context, Sampler* sampler); |  | 
| 412 #endif |  | 
| 413 |  | 
| 414  private: | 312  private: | 
| 415   static void Install() { | 313   static void Install() { | 
| 416 #if !V8_OS_NACL | 314 #if !V8_OS_NACL | 
| 417     struct sigaction sa; | 315     struct sigaction sa; | 
| 418     sa.sa_sigaction = &HandleProfilerSignal; | 316     sa.sa_sigaction = &HandleProfilerSignal; | 
| 419     sigemptyset(&sa.sa_mask); | 317     sigemptyset(&sa.sa_mask); | 
| 420 #if V8_OS_QNX | 318 #if V8_OS_QNX | 
| 421     sa.sa_flags = SA_SIGINFO; | 319     sa.sa_flags = SA_SIGINFO; | 
| 422 #else | 320 #else | 
| 423     sa.sa_flags = SA_RESTART | SA_SIGINFO; | 321     sa.sa_flags = SA_RESTART | SA_SIGINFO; | 
| 424 #endif | 322 #endif | 
| 425     signal_handler_installed_ = | 323     signal_handler_installed_ = | 
| 426         (sigaction(SIGPROF, &sa, &old_signal_handler_) == 0); | 324         (sigaction(SIGPROF, &sa, &old_signal_handler_) == 0); | 
| 427 #endif | 325 #endif  // !V8_OS_NACL | 
| 428   } | 326   } | 
| 429 | 327 | 
| 430   static void Restore() { | 328   static void Restore() { | 
| 431 #if !V8_OS_NACL | 329 #if !V8_OS_NACL | 
| 432     if (signal_handler_installed_) { | 330     if (signal_handler_installed_) { | 
| 433       sigaction(SIGPROF, &old_signal_handler_, 0); | 331       sigaction(SIGPROF, &old_signal_handler_, 0); | 
| 434       signal_handler_installed_ = false; | 332       signal_handler_installed_ = false; | 
| 435     } | 333     } | 
| 436 #endif | 334 #endif | 
| 437   } | 335   } | 
| 438 | 336 | 
| 439 #if !V8_OS_NACL | 337 #if !V8_OS_NACL | 
|  | 338   static void FillRegisterState(void* context, RegisterState* regs); | 
| 440   static void HandleProfilerSignal(int signal, siginfo_t* info, void* context); | 339   static void HandleProfilerSignal(int signal, siginfo_t* info, void* context); | 
| 441 #endif | 340 #endif | 
| 442   // Protects the process wide state below. | 341   // Protects the process wide state below. | 
| 443   static base::Mutex* mutex_; | 342   static base::Mutex* mutex_; | 
| 444   static int client_count_; | 343   static int client_count_; | 
| 445   static bool signal_handler_installed_; | 344   static bool signal_handler_installed_; | 
| 446   static struct sigaction old_signal_handler_; | 345   static struct sigaction old_signal_handler_; | 
| 447 }; | 346 }; | 
| 448 | 347 | 
| 449 | 348 | 
| 450 base::Mutex* SignalHandler::mutex_ = NULL; | 349 base::Mutex* SignalHandler::mutex_ = NULL; | 
| 451 int SignalHandler::client_count_ = 0; | 350 int SignalHandler::client_count_ = 0; | 
| 452 struct sigaction SignalHandler::old_signal_handler_; | 351 struct sigaction SignalHandler::old_signal_handler_; | 
| 453 bool SignalHandler::signal_handler_installed_ = false; | 352 bool SignalHandler::signal_handler_installed_ = false; | 
| 454 | 353 | 
| 455 | 354 | 
| 456 // As Native Client does not support signal handling, profiling is disabled. | 355 // As Native Client does not support signal handling, profiling is disabled. | 
| 457 #if !V8_OS_NACL | 356 #if !V8_OS_NACL | 
| 458 void SignalHandler::CollectSample(void* context, Sampler* sampler) { | 357 void SignalHandler::HandleProfilerSignal(int signal, siginfo_t* info, | 
| 459   if (sampler == NULL || (!sampler->IsProfiling() && | 358                                          void* context) { | 
| 460                           !sampler->IsRegistered())) { | 359   USE(info); | 
| 461     return; | 360   if (signal != SIGPROF) return; | 
| 462   } | 361   AtomicGuard atomic_guard(&SamplerManager::samplers_access_counter_, false); | 
| 463   Isolate* isolate = sampler->isolate(); | 362   if (!atomic_guard.is_success()) return; | 
| 464 | 363   pthread_t thread_id = pthread_self(); | 
| 465   // We require a fully initialized and entered isolate. | 364   SamplerMapIterator sampler_entry = | 
| 466   if (isolate == NULL || !isolate->IsInUse()) return; | 365       SamplerManager::sampler_map_.find(thread_id); | 
| 467 | 366   if (sampler_entry == SamplerManager::sampler_map_.end()) return; | 
| 468   if (v8::Locker::IsActive() && | 367   SamplerList* samplers = sampler_entry->second; | 
| 469       !isolate->thread_manager()->IsLockedByCurrentThread()) { |  | 
| 470     return; |  | 
| 471   } |  | 
| 472 | 368 | 
| 473   v8::RegisterState state; | 369   v8::RegisterState state; | 
|  | 370   SignalHandler::FillRegisterState(context, &state); | 
| 474 | 371 | 
| 475 #if defined(USE_SIMULATOR) | 372   for (SamplerListIterator iter = samplers->begin(); iter != samplers->end(); | 
| 476   if (!SimulatorHelper::FillRegisters(isolate, &state)) return; | 373        ++iter) { | 
| 477 #else | 374     Sampler* sampler = *iter; | 
|  | 375     if (sampler == NULL || !sampler->IsProfiling()) return; | 
|  | 376 | 
|  | 377     Isolate* isolate = sampler->isolate(); | 
|  | 378 | 
|  | 379     // We require a fully initialized and entered isolate. | 
|  | 380     if (isolate == NULL || !isolate->IsInUse()) return; | 
|  | 381 | 
|  | 382     if (v8::Locker::IsActive() && !Locker::IsLocked(isolate)) return; | 
|  | 383 | 
|  | 384     sampler->SampleStack(state); | 
|  | 385   } | 
|  | 386 } | 
|  | 387 | 
|  | 388 void SignalHandler::FillRegisterState(void* context, RegisterState* state) { | 
| 478   // Extracting the sample from the context is extremely machine dependent. | 389   // Extracting the sample from the context is extremely machine dependent. | 
| 479   ucontext_t* ucontext = reinterpret_cast<ucontext_t*>(context); | 390   ucontext_t* ucontext = reinterpret_cast<ucontext_t*>(context); | 
| 480 #if !(V8_OS_OPENBSD || (V8_OS_LINUX && (V8_HOST_ARCH_PPC || V8_HOST_ARCH_S390))) | 391 #if !(V8_OS_OPENBSD || (V8_OS_LINUX && (V8_HOST_ARCH_PPC || V8_HOST_ARCH_S390))) | 
| 481   mcontext_t& mcontext = ucontext->uc_mcontext; | 392   mcontext_t& mcontext = ucontext->uc_mcontext; | 
| 482 #endif | 393 #endif | 
| 483 #if V8_OS_LINUX | 394 #if V8_OS_LINUX | 
| 484 #if V8_HOST_ARCH_IA32 | 395 #if V8_HOST_ARCH_IA32 | 
| 485   state.pc = reinterpret_cast<Address>(mcontext.gregs[REG_EIP]); | 396   state->pc = reinterpret_cast<void*>(mcontext.gregs[REG_EIP]); | 
| 486   state.sp = reinterpret_cast<Address>(mcontext.gregs[REG_ESP]); | 397   state->sp = reinterpret_cast<void*>(mcontext.gregs[REG_ESP]); | 
| 487   state.fp = reinterpret_cast<Address>(mcontext.gregs[REG_EBP]); | 398   state->fp = reinterpret_cast<void*>(mcontext.gregs[REG_EBP]); | 
| 488 #elif V8_HOST_ARCH_X64 | 399 #elif V8_HOST_ARCH_X64 | 
| 489   state.pc = reinterpret_cast<Address>(mcontext.gregs[REG_RIP]); | 400   state->pc = reinterpret_cast<void*>(mcontext.gregs[REG_RIP]); | 
| 490   state.sp = reinterpret_cast<Address>(mcontext.gregs[REG_RSP]); | 401   state->sp = reinterpret_cast<void*>(mcontext.gregs[REG_RSP]); | 
| 491   state.fp = reinterpret_cast<Address>(mcontext.gregs[REG_RBP]); | 402   state->fp = reinterpret_cast<void*>(mcontext.gregs[REG_RBP]); | 
| 492 #elif V8_HOST_ARCH_ARM | 403 #elif V8_HOST_ARCH_ARM | 
| 493 #if V8_LIBC_GLIBC && !V8_GLIBC_PREREQ(2, 4) | 404 #if V8_LIBC_GLIBC && !V8_GLIBC_PREREQ(2, 4) | 
| 494   // Old GLibc ARM versions used a gregs[] array to access the register | 405   // Old GLibc ARM versions used a gregs[] array to access the register | 
| 495   // values from mcontext_t. | 406   // values from mcontext_t. | 
| 496   state.pc = reinterpret_cast<Address>(mcontext.gregs[R15]); | 407   state->pc = reinterpret_cast<void*>(mcontext.gregs[R15]); | 
| 497   state.sp = reinterpret_cast<Address>(mcontext.gregs[R13]); | 408   state->sp = reinterpret_cast<void*>(mcontext.gregs[R13]); | 
| 498   state.fp = reinterpret_cast<Address>(mcontext.gregs[R11]); | 409   state->fp = reinterpret_cast<void*>(mcontext.gregs[R11]); | 
| 499 #else | 410 #else | 
| 500   state.pc = reinterpret_cast<Address>(mcontext.arm_pc); | 411   state->pc = reinterpret_cast<void*>(mcontext.arm_pc); | 
| 501   state.sp = reinterpret_cast<Address>(mcontext.arm_sp); | 412   state->sp = reinterpret_cast<void*>(mcontext.arm_sp); | 
| 502   state.fp = reinterpret_cast<Address>(mcontext.arm_fp); | 413   state->fp = reinterpret_cast<void*>(mcontext.arm_fp); | 
| 503 #endif  // V8_LIBC_GLIBC && !V8_GLIBC_PREREQ(2, 4) | 414 #endif  // V8_LIBC_GLIBC && !V8_GLIBC_PREREQ(2, 4) | 
| 504 #elif V8_HOST_ARCH_ARM64 | 415 #elif V8_HOST_ARCH_ARM64 | 
| 505   state.pc = reinterpret_cast<Address>(mcontext.pc); | 416   state->pc = reinterpret_cast<void*>(mcontext.pc); | 
| 506   state.sp = reinterpret_cast<Address>(mcontext.sp); | 417   state->sp = reinterpret_cast<void*>(mcontext.sp); | 
| 507   // FP is an alias for x29. | 418   // FP is an alias for x29. | 
| 508   state.fp = reinterpret_cast<Address>(mcontext.regs[29]); | 419   state->fp = reinterpret_cast<void*>(mcontext.regs[29]); | 
| 509 #elif V8_HOST_ARCH_MIPS | 420 #elif V8_HOST_ARCH_MIPS | 
| 510   state.pc = reinterpret_cast<Address>(mcontext.pc); | 421   state->pc = reinterpret_cast<void*>(mcontext.pc); | 
| 511   state.sp = reinterpret_cast<Address>(mcontext.gregs[29]); | 422   state->sp = reinterpret_cast<void*>(mcontext.gregs[29]); | 
| 512   state.fp = reinterpret_cast<Address>(mcontext.gregs[30]); | 423   state->fp = reinterpret_cast<void*>(mcontext.gregs[30]); | 
| 513 #elif V8_HOST_ARCH_MIPS64 | 424 #elif V8_HOST_ARCH_MIPS64 | 
| 514   state.pc = reinterpret_cast<Address>(mcontext.pc); | 425   state->pc = reinterpret_cast<void*>(mcontext.pc); | 
| 515   state.sp = reinterpret_cast<Address>(mcontext.gregs[29]); | 426   state->sp = reinterpret_cast<void*>(mcontext.gregs[29]); | 
| 516   state.fp = reinterpret_cast<Address>(mcontext.gregs[30]); | 427   state->fp = reinterpret_cast<void*>(mcontext.gregs[30]); | 
| 517 #elif V8_HOST_ARCH_PPC | 428 #elif V8_HOST_ARCH_PPC | 
| 518   state.pc = reinterpret_cast<Address>(ucontext->uc_mcontext.regs->nip); | 429   state->pc = reinterpret_cast<void*>(ucontext->uc_mcontext.regs->nip); | 
| 519   state.sp = reinterpret_cast<Address>(ucontext->uc_mcontext.regs->gpr[PT_R1]); | 430   state->sp = | 
| 520   state.fp = reinterpret_cast<Address>(ucontext->uc_mcontext.regs->gpr[PT_R31]); | 431       reinterpret_cast<void*>(ucontext->uc_mcontext.regs->gpr[PT_R1]); | 
|  | 432   state->fp = | 
|  | 433       reinterpret_cast<void*>(ucontext->uc_mcontext.regs->gpr[PT_R31]); | 
| 521 #elif V8_HOST_ARCH_S390 | 434 #elif V8_HOST_ARCH_S390 | 
| 522 #if V8_TARGET_ARCH_32_BIT | 435 #if V8_TARGET_ARCH_32_BIT | 
| 523   // 31-bit target will have bit 0 (MSB) of the PSW set to denote addressing | 436   // 31-bit target will have bit 0 (MSB) of the PSW set to denote addressing | 
| 524   // mode.  This bit needs to be masked out to resolve actual address. | 437   // mode.  This bit needs to be masked out to resolve actual address. | 
| 525   state.pc = | 438   state->pc = | 
| 526       reinterpret_cast<Address>(ucontext->uc_mcontext.psw.addr & 0x7FFFFFFF); | 439       reinterpret_cast<void*>(ucontext->uc_mcontext.psw.addr & 0x7FFFFFFF); | 
| 527 #else | 440 #else | 
| 528   state.pc = reinterpret_cast<Address>(ucontext->uc_mcontext.psw.addr); | 441   state->pc = reinterpret_cast<void*>(ucontext->uc_mcontext.psw.addr); | 
| 529 #endif  // V8_TARGET_ARCH_32_BIT | 442 #endif  // V8_TARGET_ARCH_32_BIT | 
| 530   state.sp = reinterpret_cast<Address>(ucontext->uc_mcontext.gregs[15]); | 443   state->sp = reinterpret_cast<void*>(ucontext->uc_mcontext.gregs[15]); | 
| 531   state.fp = reinterpret_cast<Address>(ucontext->uc_mcontext.gregs[11]); | 444   state->fp = reinterpret_cast<void*>(ucontext->uc_mcontext.gregs[11]); | 
| 532 #endif  // V8_HOST_ARCH_* | 445 #endif  // V8_HOST_ARCH_* | 
| 533 #elif V8_OS_MACOSX | 446 #elif V8_OS_MACOSX | 
| 534 #if V8_HOST_ARCH_X64 | 447 #if V8_HOST_ARCH_X64 | 
| 535 #if __DARWIN_UNIX03 | 448 #if __DARWIN_UNIX03 | 
| 536   state.pc = reinterpret_cast<Address>(mcontext->__ss.__rip); | 449   state->pc = reinterpret_cast<void*>(mcontext->__ss.__rip); | 
| 537   state.sp = reinterpret_cast<Address>(mcontext->__ss.__rsp); | 450   state->sp = reinterpret_cast<void*>(mcontext->__ss.__rsp); | 
| 538   state.fp = reinterpret_cast<Address>(mcontext->__ss.__rbp); | 451   state->fp = reinterpret_cast<void*>(mcontext->__ss.__rbp); | 
| 539 #else  // !__DARWIN_UNIX03 | 452 #else  // !__DARWIN_UNIX03 | 
| 540   state.pc = reinterpret_cast<Address>(mcontext->ss.rip); | 453   state->pc = reinterpret_cast<void*>(mcontext->ss.rip); | 
| 541   state.sp = reinterpret_cast<Address>(mcontext->ss.rsp); | 454   state->sp = reinterpret_cast<void*>(mcontext->ss.rsp); | 
| 542   state.fp = reinterpret_cast<Address>(mcontext->ss.rbp); | 455   state->fp = reinterpret_cast<void*>(mcontext->ss.rbp); | 
| 543 #endif  // __DARWIN_UNIX03 | 456 #endif  // __DARWIN_UNIX03 | 
| 544 #elif V8_HOST_ARCH_IA32 | 457 #elif V8_HOST_ARCH_IA32 | 
| 545 #if __DARWIN_UNIX03 | 458 #if __DARWIN_UNIX03 | 
| 546   state.pc = reinterpret_cast<Address>(mcontext->__ss.__eip); | 459   state->pc = reinterpret_cast<void*>(mcontext->__ss.__eip); | 
| 547   state.sp = reinterpret_cast<Address>(mcontext->__ss.__esp); | 460   state->sp = reinterpret_cast<void*>(mcontext->__ss.__esp); | 
| 548   state.fp = reinterpret_cast<Address>(mcontext->__ss.__ebp); | 461   state->fp = reinterpret_cast<void*>(mcontext->__ss.__ebp); | 
| 549 #else  // !__DARWIN_UNIX03 | 462 #else  // !__DARWIN_UNIX03 | 
| 550   state.pc = reinterpret_cast<Address>(mcontext->ss.eip); | 463   state->pc = reinterpret_cast<void*>(mcontext->ss.eip); | 
| 551   state.sp = reinterpret_cast<Address>(mcontext->ss.esp); | 464   state->sp = reinterpret_cast<void*>(mcontext->ss.esp); | 
| 552   state.fp = reinterpret_cast<Address>(mcontext->ss.ebp); | 465   state->fp = reinterpret_cast<void*>(mcontext->ss.ebp); | 
| 553 #endif  // __DARWIN_UNIX03 | 466 #endif  // __DARWIN_UNIX03 | 
| 554 #endif  // V8_HOST_ARCH_IA32 | 467 #endif  // V8_HOST_ARCH_IA32 | 
| 555 #elif V8_OS_FREEBSD | 468 #elif V8_OS_FREEBSD | 
| 556 #if V8_HOST_ARCH_IA32 | 469 #if V8_HOST_ARCH_IA32 | 
| 557   state.pc = reinterpret_cast<Address>(mcontext.mc_eip); | 470   state->pc = reinterpret_cast<void*>(mcontext.mc_eip); | 
| 558   state.sp = reinterpret_cast<Address>(mcontext.mc_esp); | 471   state->sp = reinterpret_cast<void*>(mcontext.mc_esp); | 
| 559   state.fp = reinterpret_cast<Address>(mcontext.mc_ebp); | 472   state->fp = reinterpret_cast<void*>(mcontext.mc_ebp); | 
| 560 #elif V8_HOST_ARCH_X64 | 473 #elif V8_HOST_ARCH_X64 | 
| 561   state.pc = reinterpret_cast<Address>(mcontext.mc_rip); | 474   state->pc = reinterpret_cast<void*>(mcontext.mc_rip); | 
| 562   state.sp = reinterpret_cast<Address>(mcontext.mc_rsp); | 475   state->sp = reinterpret_cast<void*>(mcontext.mc_rsp); | 
| 563   state.fp = reinterpret_cast<Address>(mcontext.mc_rbp); | 476   state->fp = reinterpret_cast<void*>(mcontext.mc_rbp); | 
| 564 #elif V8_HOST_ARCH_ARM | 477 #elif V8_HOST_ARCH_ARM | 
| 565   state.pc = reinterpret_cast<Address>(mcontext.mc_r15); | 478   state->pc = reinterpret_cast<void*>(mcontext.mc_r15); | 
| 566   state.sp = reinterpret_cast<Address>(mcontext.mc_r13); | 479   state->sp = reinterpret_cast<void*>(mcontext.mc_r13); | 
| 567   state.fp = reinterpret_cast<Address>(mcontext.mc_r11); | 480   state->fp = reinterpret_cast<void*>(mcontext.mc_r11); | 
| 568 #endif  // V8_HOST_ARCH_* | 481 #endif  // V8_HOST_ARCH_* | 
| 569 #elif V8_OS_NETBSD | 482 #elif V8_OS_NETBSD | 
| 570 #if V8_HOST_ARCH_IA32 | 483 #if V8_HOST_ARCH_IA32 | 
| 571   state.pc = reinterpret_cast<Address>(mcontext.__gregs[_REG_EIP]); | 484   state->pc = reinterpret_cast<void*>(mcontext.__gregs[_REG_EIP]); | 
| 572   state.sp = reinterpret_cast<Address>(mcontext.__gregs[_REG_ESP]); | 485   state->sp = reinterpret_cast<void*>(mcontext.__gregs[_REG_ESP]); | 
| 573   state.fp = reinterpret_cast<Address>(mcontext.__gregs[_REG_EBP]); | 486   state->fp = reinterpret_cast<void*>(mcontext.__gregs[_REG_EBP]); | 
| 574 #elif V8_HOST_ARCH_X64 | 487 #elif V8_HOST_ARCH_X64 | 
| 575   state.pc = reinterpret_cast<Address>(mcontext.__gregs[_REG_RIP]); | 488   state->pc = reinterpret_cast<void*>(mcontext.__gregs[_REG_RIP]); | 
| 576   state.sp = reinterpret_cast<Address>(mcontext.__gregs[_REG_RSP]); | 489   state->sp = reinterpret_cast<void*>(mcontext.__gregs[_REG_RSP]); | 
| 577   state.fp = reinterpret_cast<Address>(mcontext.__gregs[_REG_RBP]); | 490   state->fp = reinterpret_cast<void*>(mcontext.__gregs[_REG_RBP]); | 
| 578 #endif  // V8_HOST_ARCH_* | 491 #endif  // V8_HOST_ARCH_* | 
| 579 #elif V8_OS_OPENBSD | 492 #elif V8_OS_OPENBSD | 
| 580 #if V8_HOST_ARCH_IA32 | 493 #if V8_HOST_ARCH_IA32 | 
| 581   state.pc = reinterpret_cast<Address>(ucontext->sc_eip); | 494   state->pc = reinterpret_cast<void*>(ucontext->sc_eip); | 
| 582   state.sp = reinterpret_cast<Address>(ucontext->sc_esp); | 495   state->sp = reinterpret_cast<void*>(ucontext->sc_esp); | 
| 583   state.fp = reinterpret_cast<Address>(ucontext->sc_ebp); | 496   state->fp = reinterpret_cast<void*>(ucontext->sc_ebp); | 
| 584 #elif V8_HOST_ARCH_X64 | 497 #elif V8_HOST_ARCH_X64 | 
| 585   state.pc = reinterpret_cast<Address>(ucontext->sc_rip); | 498   state->pc = reinterpret_cast<void*>(ucontext->sc_rip); | 
| 586   state.sp = reinterpret_cast<Address>(ucontext->sc_rsp); | 499   state->sp = reinterpret_cast<void*>(ucontext->sc_rsp); | 
| 587   state.fp = reinterpret_cast<Address>(ucontext->sc_rbp); | 500   state->fp = reinterpret_cast<void*>(ucontext->sc_rbp); | 
| 588 #endif  // V8_HOST_ARCH_* | 501 #endif  // V8_HOST_ARCH_* | 
| 589 #elif V8_OS_SOLARIS | 502 #elif V8_OS_SOLARIS | 
| 590   state.pc = reinterpret_cast<Address>(mcontext.gregs[REG_PC]); | 503   state->pc = reinterpret_cast<void*>(mcontext.gregs[REG_PC]); | 
| 591   state.sp = reinterpret_cast<Address>(mcontext.gregs[REG_SP]); | 504   state->sp = reinterpret_cast<void*>(mcontext.gregs[REG_SP]); | 
| 592   state.fp = reinterpret_cast<Address>(mcontext.gregs[REG_FP]); | 505   state->fp = reinterpret_cast<void*>(mcontext.gregs[REG_FP]); | 
| 593 #elif V8_OS_QNX | 506 #elif V8_OS_QNX | 
| 594 #if V8_HOST_ARCH_IA32 | 507 #if V8_HOST_ARCH_IA32 | 
| 595   state.pc = reinterpret_cast<Address>(mcontext.cpu.eip); | 508   state->pc = reinterpret_cast<void*>(mcontext.cpu.eip); | 
| 596   state.sp = reinterpret_cast<Address>(mcontext.cpu.esp); | 509   state->sp = reinterpret_cast<void*>(mcontext.cpu.esp); | 
| 597   state.fp = reinterpret_cast<Address>(mcontext.cpu.ebp); | 510   state->fp = reinterpret_cast<void*>(mcontext.cpu.ebp); | 
| 598 #elif V8_HOST_ARCH_ARM | 511 #elif V8_HOST_ARCH_ARM | 
| 599   state.pc = reinterpret_cast<Address>(mcontext.cpu.gpr[ARM_REG_PC]); | 512   state->pc = reinterpret_cast<void*>(mcontext.cpu.gpr[ARM_REG_PC]); | 
| 600   state.sp = reinterpret_cast<Address>(mcontext.cpu.gpr[ARM_REG_SP]); | 513   state->sp = reinterpret_cast<void*>(mcontext.cpu.gpr[ARM_REG_SP]); | 
| 601   state.fp = reinterpret_cast<Address>(mcontext.cpu.gpr[ARM_REG_FP]); | 514   state->fp = reinterpret_cast<void*>(mcontext.cpu.gpr[ARM_REG_FP]); | 
| 602 #endif  // V8_HOST_ARCH_* | 515 #endif  // V8_HOST_ARCH_* | 
| 603 #elif V8_OS_AIX | 516 #elif V8_OS_AIX | 
| 604   state.pc = reinterpret_cast<Address>(mcontext.jmp_context.iar); | 517   state->pc = reinterpret_cast<void*>(mcontext.jmp_context.iar); | 
| 605   state.sp = reinterpret_cast<Address>(mcontext.jmp_context.gpr[1]); | 518   state->sp = reinterpret_cast<void*>(mcontext.jmp_context.gpr[1]); | 
| 606   state.fp = reinterpret_cast<Address>(mcontext.jmp_context.gpr[31]); | 519   state->fp = reinterpret_cast<void*>(mcontext.jmp_context.gpr[31]); | 
| 607 #endif  // V8_OS_AIX | 520 #endif  // V8_OS_AIX | 
| 608 #endif  // USE_SIMULATOR |  | 
| 609   sampler->SampleStack(state); |  | 
| 610 } | 521 } | 
| 611 #endif  // V8_OS_NACL | 522 | 
|  | 523 #endif  // !V8_OS_NACL | 
| 612 | 524 | 
| 613 #endif  // USE_SIGNALS | 525 #endif  // USE_SIGNALS | 
| 614 | 526 | 
| 615 | 527 | 
| 616 class SamplerThread : public base::Thread { |  | 
| 617  public: |  | 
| 618   static const int kSamplerThreadStackSize = 64 * KB; |  | 
| 619 |  | 
| 620   explicit SamplerThread(int interval) |  | 
| 621       : Thread(base::Thread::Options("SamplerThread", kSamplerThreadStackSize)), |  | 
| 622         interval_(interval) {} |  | 
| 623 |  | 
| 624   static void SetUp() { if (!mutex_) mutex_ = new base::Mutex(); } |  | 
| 625   static void TearDown() { delete mutex_; mutex_ = NULL; } |  | 
| 626 |  | 
| 627   static void AddActiveSampler(Sampler* sampler) { |  | 
| 628     bool need_to_start = false; |  | 
| 629     base::LockGuard<base::Mutex> lock_guard(mutex_); |  | 
| 630     if (instance_ == NULL) { |  | 
| 631       // Start a thread that will send SIGPROF signal to VM threads, |  | 
| 632       // when CPU profiling will be enabled. |  | 
| 633       instance_ = new SamplerThread(sampler->interval()); |  | 
| 634       need_to_start = true; |  | 
| 635     } |  | 
| 636 |  | 
| 637     DCHECK(sampler->IsActive()); |  | 
| 638     DCHECK(instance_->interval_ == sampler->interval()); |  | 
| 639 |  | 
| 640 #if defined(USE_SIGNALS) |  | 
| 641     AddSampler(sampler); |  | 
| 642 #else |  | 
| 643     DCHECK(!instance_->active_samplers_.Contains(sampler)); |  | 
| 644     instance_->active_samplers_.Add(sampler); |  | 
| 645 #endif  // USE_SIGNALS |  | 
| 646 |  | 
| 647     if (need_to_start) instance_->StartSynchronously(); |  | 
| 648   } |  | 
| 649 |  | 
| 650   static void RemoveSampler(Sampler* sampler) { |  | 
| 651     SamplerThread* instance_to_remove = NULL; |  | 
| 652     { |  | 
| 653       base::LockGuard<base::Mutex> lock_guard(mutex_); |  | 
| 654 |  | 
| 655       DCHECK(sampler->IsActive() || sampler->IsRegistered()); |  | 
| 656 #if defined(USE_SIGNALS) |  | 
| 657       { |  | 
| 658         AtomicGuard atomic_guard(&sampler_list_access_counter_); |  | 
| 659         // Remove sampler from map. |  | 
| 660         pthread_t thread_id = sampler->platform_data()->vm_tid(); |  | 
| 661         void* thread_key = ThreadKey(thread_id); |  | 
| 662         uint32_t thread_hash = ThreadHash(thread_id); |  | 
| 663         HashMap::Entry* entry = |  | 
| 664             thread_id_to_samplers_.Get().Lookup(thread_key, thread_hash); |  | 
| 665         DCHECK(entry != NULL); |  | 
| 666         SamplerList* samplers = reinterpret_cast<SamplerList*>(entry->value); |  | 
| 667         samplers->RemoveElement(sampler); |  | 
| 668         if (samplers->is_empty()) { |  | 
| 669           thread_id_to_samplers_.Pointer()->Remove(thread_key, thread_hash); |  | 
| 670           delete samplers; |  | 
| 671         } |  | 
| 672         if (thread_id_to_samplers_.Get().occupancy() == 0) { |  | 
| 673           instance_to_remove = instance_; |  | 
| 674           instance_ = NULL; |  | 
| 675         } |  | 
| 676       } |  | 
| 677 #else |  | 
| 678       bool removed = instance_->active_samplers_.RemoveElement(sampler); |  | 
| 679       DCHECK(removed); |  | 
| 680       USE(removed); |  | 
| 681 |  | 
| 682       // We cannot delete the instance immediately as we need to Join() the |  | 
| 683       // thread but we are holding mutex_ and the thread may try to acquire it. |  | 
| 684       if (instance_->active_samplers_.is_empty()) { |  | 
| 685         instance_to_remove = instance_; |  | 
| 686         instance_ = NULL; |  | 
| 687       } |  | 
| 688 #endif  // USE_SIGNALS |  | 
| 689     } |  | 
| 690 |  | 
| 691     if (!instance_to_remove) return; |  | 
| 692     instance_to_remove->Join(); |  | 
| 693     delete instance_to_remove; |  | 
| 694   } |  | 
| 695 |  | 
| 696   // Unlike AddActiveSampler, this method only adds a sampler, |  | 
| 697   // but won't start the sampler thread. |  | 
| 698   static void RegisterSampler(Sampler* sampler) { |  | 
| 699     base::LockGuard<base::Mutex> lock_guard(mutex_); |  | 
| 700 #if defined(USE_SIGNALS) |  | 
| 701     AddSampler(sampler); |  | 
| 702 #endif  // USE_SIGNALS |  | 
| 703   } |  | 
| 704 |  | 
| 705   // Implement Thread::Run(). |  | 
| 706   virtual void Run() { |  | 
| 707     while (true) { |  | 
| 708       { |  | 
| 709         base::LockGuard<base::Mutex> lock_guard(mutex_); |  | 
| 710 #if defined(USE_SIGNALS) |  | 
| 711         if (thread_id_to_samplers_.Get().occupancy() == 0) break; |  | 
| 712         if (SignalHandler::Installed()) { |  | 
| 713           for (HashMap::Entry *p = thread_id_to_samplers_.Get().Start(); |  | 
| 714                p != NULL; p = thread_id_to_samplers_.Get().Next(p)) { |  | 
| 715 #if V8_OS_AIX && V8_TARGET_ARCH_PPC64 |  | 
| 716             // on AIX64, cannot cast (void *) to pthread_t which is |  | 
| 717             // of type unsigned int (4bytes) |  | 
| 718             pthread_t thread_id = reinterpret_cast<intptr_t>(p->key); |  | 
| 719 #else |  | 
| 720             pthread_t thread_id = reinterpret_cast<pthread_t>(p->key); |  | 
| 721 #endif |  | 
| 722             pthread_kill(thread_id, SIGPROF); |  | 
| 723           } |  | 
| 724         } |  | 
| 725 #else |  | 
| 726         if (active_samplers_.is_empty()) break; |  | 
| 727         // When CPU profiling is enabled both JavaScript and C++ code is |  | 
| 728         // profiled. We must not suspend. |  | 
| 729         for (int i = 0; i < active_samplers_.length(); ++i) { |  | 
| 730           Sampler* sampler = active_samplers_.at(i); |  | 
| 731           if (!sampler->IsProfiling()) continue; |  | 
| 732           sampler->DoSample(); |  | 
| 733         } |  | 
| 734 #endif  // USE_SIGNALS |  | 
| 735       } |  | 
| 736       base::OS::Sleep(base::TimeDelta::FromMilliseconds(interval_)); |  | 
| 737     } |  | 
| 738   } |  | 
| 739 |  | 
| 740  private: |  | 
| 741   // Protects the process wide state below. |  | 
| 742   static base::Mutex* mutex_; |  | 
| 743   static SamplerThread* instance_; |  | 
| 744 |  | 
| 745   const int interval_; |  | 
| 746 |  | 
| 747 #if defined(USE_SIGNALS) |  | 
| 748   struct HashMapCreateTrait { |  | 
| 749     static void Construct(HashMap* allocated_ptr) { |  | 
| 750       new (allocated_ptr) HashMap(HashMap::PointersMatch); |  | 
| 751     } |  | 
| 752   }; |  | 
| 753   friend class SignalHandler; |  | 
| 754   static base::LazyInstance<HashMap, HashMapCreateTrait>::type |  | 
| 755       thread_id_to_samplers_; |  | 
| 756   static base::AtomicValue<int> sampler_list_access_counter_; |  | 
| 757   static void AddSampler(Sampler* sampler) { |  | 
| 758     AtomicGuard atomic_guard(&sampler_list_access_counter_); |  | 
| 759     // Add sampler into map if needed. |  | 
| 760     pthread_t thread_id = sampler->platform_data()->vm_tid(); |  | 
| 761     HashMap::Entry *entry = |  | 
| 762         thread_id_to_samplers_.Pointer()->LookupOrInsert(ThreadKey(thread_id), |  | 
| 763                                                          ThreadHash(thread_id)); |  | 
| 764     if (entry->value == NULL) { |  | 
| 765       SamplerList* samplers = new SamplerList(); |  | 
| 766       samplers->Add(sampler); |  | 
| 767       entry->value = samplers; |  | 
| 768     } else { |  | 
| 769       SamplerList* samplers = reinterpret_cast<SamplerList*>(entry->value); |  | 
| 770       if (!samplers->Contains(sampler)) { |  | 
| 771         samplers->Add(sampler); |  | 
| 772       } |  | 
| 773     } |  | 
| 774   } |  | 
| 775 #else |  | 
| 776   SamplerList active_samplers_; |  | 
| 777 #endif  // USE_SIGNALS |  | 
| 778 |  | 
| 779   DISALLOW_COPY_AND_ASSIGN(SamplerThread); |  | 
| 780 }; |  | 
| 781 |  | 
| 782 |  | 
| 783 base::Mutex* SamplerThread::mutex_ = NULL; |  | 
| 784 SamplerThread* SamplerThread::instance_ = NULL; |  | 
| 785 #if defined(USE_SIGNALS) |  | 
| 786 base::LazyInstance<HashMap, SamplerThread::HashMapCreateTrait>::type |  | 
| 787     SamplerThread::thread_id_to_samplers_ = LAZY_INSTANCE_INITIALIZER; |  | 
| 788 base::AtomicValue<int> SamplerThread::sampler_list_access_counter_(0); |  | 
| 789 |  | 
| 790 // As Native Client does not support signal handling, profiling is disabled. |  | 
| 791 #if !V8_OS_NACL |  | 
| 792 void SignalHandler::HandleProfilerSignal(int signal, siginfo_t* info, |  | 
| 793                                          void* context) { |  | 
| 794   USE(info); |  | 
| 795   if (signal != SIGPROF) return; |  | 
| 796   AtomicGuard atomic_guard(&SamplerThread::sampler_list_access_counter_, false); |  | 
| 797   if (!atomic_guard.is_success()) return; |  | 
| 798   pthread_t thread_id = pthread_self(); |  | 
| 799   HashMap::Entry* entry = |  | 
| 800       SamplerThread::thread_id_to_samplers_.Pointer()->Lookup( |  | 
| 801           ThreadKey(thread_id), ThreadHash(thread_id)); |  | 
| 802   if (entry == NULL) |  | 
| 803     return; |  | 
| 804   SamplerList* samplers = reinterpret_cast<SamplerList*>(entry->value); |  | 
| 805   for (int i = 0; i < samplers->length(); ++i) { |  | 
| 806     Sampler* sampler = samplers->at(i); |  | 
| 807     CollectSample(context, sampler); |  | 
| 808   } |  | 
| 809 } |  | 
| 810 #endif  // !V8_OS_NACL |  | 
| 811 #endif  // USE_SIGNALs |  | 
| 812 |  | 
| 813 |  | 
| 814 // |  | 
| 815 // StackTracer implementation |  | 
| 816 // |  | 
| 817 DISABLE_ASAN void TickSample::Init(Isolate* isolate, |  | 
| 818                                    const v8::RegisterState& regs, |  | 
| 819                                    RecordCEntryFrame record_c_entry_frame, |  | 
| 820                                    bool update_stats) { |  | 
| 821   timestamp = base::TimeTicks::HighResolutionNow(); |  | 
| 822   pc = reinterpret_cast<Address>(regs.pc); |  | 
| 823   state = isolate->current_vm_state(); |  | 
| 824   this->update_stats = update_stats; |  | 
| 825 |  | 
| 826   // Avoid collecting traces while doing GC. |  | 
| 827   if (state == GC) return; |  | 
| 828 |  | 
| 829   Address js_entry_sp = isolate->js_entry_sp(); |  | 
| 830   if (js_entry_sp == 0) return;  // Not executing JS now. |  | 
| 831 |  | 
| 832   if (pc && IsNoFrameRegion(pc)) { |  | 
| 833     // Can't collect stack. Mark the sample as spoiled. |  | 
| 834     timestamp = base::TimeTicks(); |  | 
| 835     pc = 0; |  | 
| 836     return; |  | 
| 837   } |  | 
| 838 |  | 
| 839   ExternalCallbackScope* scope = isolate->external_callback_scope(); |  | 
| 840   Address handler = Isolate::handler(isolate->thread_local_top()); |  | 
| 841   // If there is a handler on top of the external callback scope then |  | 
| 842   // we have already entrered JavaScript again and the external callback |  | 
| 843   // is not the top function. |  | 
| 844   if (scope && scope->scope_address() < handler) { |  | 
| 845     external_callback_entry = *scope->callback_entrypoint_address(); |  | 
| 846     has_external_callback = true; |  | 
| 847   } else { |  | 
| 848     // sp register may point at an arbitrary place in memory, make |  | 
| 849     // sure MSAN doesn't complain about it. |  | 
| 850     MSAN_MEMORY_IS_INITIALIZED(regs.sp, sizeof(Address)); |  | 
| 851     // Sample potential return address value for frameless invocation of |  | 
| 852     // stubs (we'll figure out later, if this value makes sense). |  | 
| 853     tos = Memory::Address_at(reinterpret_cast<Address>(regs.sp)); |  | 
| 854     has_external_callback = false; |  | 
| 855   } |  | 
| 856 |  | 
| 857   SafeStackFrameIterator it(isolate, reinterpret_cast<Address>(regs.fp), |  | 
| 858                             reinterpret_cast<Address>(regs.sp), js_entry_sp); |  | 
| 859   top_frame_type = it.top_frame_type(); |  | 
| 860 |  | 
| 861   SampleInfo info; |  | 
| 862   GetStackSample(isolate, regs, record_c_entry_frame, |  | 
| 863                  reinterpret_cast<void**>(&stack[0]), kMaxFramesCount, &info); |  | 
| 864   frames_count = static_cast<unsigned>(info.frames_count); |  | 
| 865   if (!frames_count) { |  | 
| 866     // It is executing JS but failed to collect a stack trace. |  | 
| 867     // Mark the sample as spoiled. |  | 
| 868     timestamp = base::TimeTicks(); |  | 
| 869     pc = 0; |  | 
| 870   } |  | 
| 871 } |  | 
| 872 |  | 
| 873 |  | 
| 874 void TickSample::GetStackSample(Isolate* isolate, const v8::RegisterState& regs, |  | 
| 875                                 RecordCEntryFrame record_c_entry_frame, |  | 
| 876                                 void** frames, size_t frames_limit, |  | 
| 877                                 v8::SampleInfo* sample_info) { |  | 
| 878   sample_info->frames_count = 0; |  | 
| 879   sample_info->vm_state = isolate->current_vm_state(); |  | 
| 880   if (sample_info->vm_state == GC) return; |  | 
| 881 |  | 
| 882   Address js_entry_sp = isolate->js_entry_sp(); |  | 
| 883   if (js_entry_sp == 0) return;  // Not executing JS now. |  | 
| 884 |  | 
| 885   SafeStackFrameIterator it(isolate, reinterpret_cast<Address>(regs.fp), |  | 
| 886                             reinterpret_cast<Address>(regs.sp), js_entry_sp); |  | 
| 887   size_t i = 0; |  | 
| 888   if (record_c_entry_frame == kIncludeCEntryFrame && !it.done() && |  | 
| 889       it.top_frame_type() == StackFrame::EXIT) { |  | 
| 890     frames[i++] = isolate->c_function(); |  | 
| 891   } |  | 
| 892   while (!it.done() && i < frames_limit) { |  | 
| 893     if (it.frame()->is_interpreted()) { |  | 
| 894       // For interpreted frames use the bytecode array pointer as the pc. |  | 
| 895       InterpretedFrame* frame = static_cast<InterpretedFrame*>(it.frame()); |  | 
| 896       // Since the sampler can interrupt execution at any point the |  | 
| 897       // bytecode_array might be garbage, so don't dereference it. |  | 
| 898       Address bytecode_array = |  | 
| 899           reinterpret_cast<Address>(frame->GetBytecodeArray()) - kHeapObjectTag; |  | 
| 900       frames[i++] = bytecode_array + BytecodeArray::kHeaderSize + |  | 
| 901                     frame->GetBytecodeOffset(); |  | 
| 902     } else { |  | 
| 903       frames[i++] = it.frame()->pc(); |  | 
| 904     } |  | 
| 905     it.Advance(); |  | 
| 906   } |  | 
| 907   sample_info->frames_count = i; |  | 
| 908 } |  | 
| 909 |  | 
| 910 |  | 
| 911 void Sampler::SetUp() { | 528 void Sampler::SetUp() { | 
| 912 #if defined(USE_SIGNALS) | 529 #if defined(USE_SIGNALS) | 
| 913   SignalHandler::SetUp(); | 530   SignalHandler::SetUp(); | 
| 914 #endif | 531 #endif | 
| 915   SamplerThread::SetUp(); |  | 
| 916 } | 532 } | 
| 917 | 533 | 
| 918 | 534 | 
| 919 void Sampler::TearDown() { | 535 void Sampler::TearDown() { | 
| 920   SamplerThread::TearDown(); |  | 
| 921 #if defined(USE_SIGNALS) | 536 #if defined(USE_SIGNALS) | 
| 922   SignalHandler::TearDown(); | 537   SignalHandler::TearDown(); | 
| 923 #endif | 538 #endif | 
| 924 } | 539 } | 
| 925 | 540 | 
| 926 Sampler::Sampler(Isolate* isolate, int interval) | 541 Sampler::Sampler(Isolate* isolate) | 
| 927     : isolate_(isolate), | 542     : is_counting_samples_(false), | 
| 928       interval_(interval), | 543       js_sample_count_(0), | 
|  | 544       external_sample_count_(0), | 
|  | 545       isolate_(isolate), | 
| 929       profiling_(false), | 546       profiling_(false), | 
| 930       has_processing_thread_(false), | 547       active_(false) { | 
| 931       active_(false), |  | 
| 932       registered_(false), |  | 
| 933       is_counting_samples_(false), |  | 
| 934       js_sample_count_(0), |  | 
| 935       external_sample_count_(0) { |  | 
| 936   data_ = new PlatformData; | 548   data_ = new PlatformData; | 
| 937 } | 549 } | 
| 938 | 550 | 
| 939 Sampler::~Sampler() { | 551 Sampler::~Sampler() { | 
| 940   DCHECK(!IsActive()); | 552   DCHECK(!IsActive()); | 
| 941   if (IsRegistered()) { |  | 
| 942     SamplerThread::RemoveSampler(this); |  | 
| 943   } |  | 
| 944   delete data_; | 553   delete data_; | 
| 945 } | 554 } | 
| 946 | 555 | 
| 947 void Sampler::Start() { | 556 void Sampler::Start() { | 
| 948   DCHECK(!IsActive()); | 557   DCHECK(!IsActive()); | 
| 949   SetActive(true); | 558   SetActive(true); | 
| 950   SamplerThread::AddActiveSampler(this); | 559   SamplerManager::AddSampler(this); | 
| 951 } | 560 } | 
| 952 | 561 | 
| 953 | 562 | 
| 954 void Sampler::Stop() { | 563 void Sampler::Stop() { | 
|  | 564   SamplerManager::RemoveSampler(this); | 
| 955   DCHECK(IsActive()); | 565   DCHECK(IsActive()); | 
| 956   SamplerThread::RemoveSampler(this); |  | 
| 957   SetActive(false); | 566   SetActive(false); | 
| 958   SetRegistered(false); |  | 
| 959 } | 567 } | 
| 960 | 568 | 
| 961 | 569 | 
| 962 void Sampler::IncreaseProfilingDepth() { | 570 void Sampler::IncreaseProfilingDepth() { | 
| 963   base::NoBarrier_AtomicIncrement(&profiling_, 1); | 571   base::NoBarrier_AtomicIncrement(&profiling_, 1); | 
| 964 #if defined(USE_SIGNALS) | 572 #if defined(USE_SIGNALS) | 
| 965   SignalHandler::IncreaseSamplerCount(); | 573   SignalHandler::IncreaseSamplerCount(); | 
| 966 #endif | 574 #endif | 
| 967 } | 575 } | 
| 968 | 576 | 
| 969 | 577 | 
| 970 void Sampler::DecreaseProfilingDepth() { | 578 void Sampler::DecreaseProfilingDepth() { | 
| 971 #if defined(USE_SIGNALS) | 579 #if defined(USE_SIGNALS) | 
| 972   SignalHandler::DecreaseSamplerCount(); | 580   SignalHandler::DecreaseSamplerCount(); | 
| 973 #endif | 581 #endif | 
| 974   base::NoBarrier_AtomicIncrement(&profiling_, -1); | 582   base::NoBarrier_AtomicIncrement(&profiling_, -1); | 
| 975 } | 583 } | 
| 976 | 584 | 
| 977 | 585 | 
| 978 void Sampler::SampleStack(const v8::RegisterState& state) { |  | 
| 979   TickSample* sample = isolate_->cpu_profiler()->StartTickSample(); |  | 
| 980   TickSample sample_obj; |  | 
| 981   if (sample == NULL) sample = &sample_obj; |  | 
| 982   sample->Init(isolate_, state, TickSample::kIncludeCEntryFrame, true); |  | 
| 983   if (is_counting_samples_ && !sample->timestamp.IsNull()) { |  | 
| 984     if (sample->state == JS) ++js_sample_count_; |  | 
| 985     if (sample->state == EXTERNAL) ++external_sample_count_; |  | 
| 986   } |  | 
| 987   Tick(sample); |  | 
| 988   if (sample != &sample_obj) { |  | 
| 989     isolate_->cpu_profiler()->FinishTickSample(); |  | 
| 990   } |  | 
| 991 } |  | 
| 992 |  | 
| 993 |  | 
| 994 #if defined(USE_SIGNALS) | 586 #if defined(USE_SIGNALS) | 
| 995 | 587 | 
| 996 void Sampler::DoSample() { | 588 void Sampler::DoSample() { | 
| 997   if (!SignalHandler::Installed()) return; | 589   if (!SignalHandler::Installed()) return; | 
| 998   if (!IsActive() && !IsRegistered()) { |  | 
| 999     SamplerThread::RegisterSampler(this); |  | 
| 1000     SetRegistered(true); |  | 
| 1001   } |  | 
| 1002   pthread_kill(platform_data()->vm_tid(), SIGPROF); | 590   pthread_kill(platform_data()->vm_tid(), SIGPROF); | 
| 1003 } | 591 } | 
| 1004 | 592 | 
| 1005 #elif V8_OS_WIN || V8_OS_CYGWIN | 593 #elif V8_OS_WIN || V8_OS_CYGWIN | 
| 1006 | 594 | 
| 1007 void Sampler::DoSample() { | 595 void Sampler::DoSample() { | 
| 1008   HANDLE profiled_thread = platform_data()->profiled_thread(); | 596   HANDLE profiled_thread = platform_data()->profiled_thread(); | 
| 1009   if (profiled_thread == NULL) return; | 597   if (profiled_thread == NULL) return; | 
| 1010 | 598 | 
| 1011   const DWORD kSuspendFailed = static_cast<DWORD>(-1); | 599   const DWORD kSuspendFailed = static_cast<DWORD>(-1); | 
| 1012   if (SuspendThread(profiled_thread) == kSuspendFailed) return; | 600   if (SuspendThread(profiled_thread) == kSuspendFailed) return; | 
| 1013 | 601 | 
| 1014   // Context used for sampling the register state of the profiled thread. | 602   // Context used for sampling the register state of the profiled thread. | 
| 1015   CONTEXT context; | 603   CONTEXT context; | 
| 1016   memset(&context, 0, sizeof(context)); | 604   memset(&context, 0, sizeof(context)); | 
| 1017   context.ContextFlags = CONTEXT_FULL; | 605   context.ContextFlags = CONTEXT_FULL; | 
| 1018   if (GetThreadContext(profiled_thread, &context) != 0) { | 606   if (GetThreadContext(profiled_thread, &context) != 0) { | 
| 1019     v8::RegisterState state; | 607     v8::RegisterState state; | 
| 1020 #if defined(USE_SIMULATOR) | 608 #if V8_HOST_ARCH_X64 | 
| 1021     if (!SimulatorHelper::FillRegisters(isolate(), &state)) { | 609     state.pc = reinterpret_cast<void*>(context.Rip); | 
| 1022       ResumeThread(profiled_thread); | 610     state.sp = reinterpret_cast<void*>(context.Rsp); | 
| 1023       return; | 611     state.fp = reinterpret_cast<void*>(context.Rbp); | 
| 1024     } |  | 
| 1025 #else | 612 #else | 
| 1026 #if V8_HOST_ARCH_X64 | 613     state.pc = reinterpret_cast<void*>(context.Eip); | 
| 1027     state.pc = reinterpret_cast<Address>(context.Rip); | 614     state.sp = reinterpret_cast<void*>(context.Esp); | 
| 1028     state.sp = reinterpret_cast<Address>(context.Rsp); | 615     state.fp = reinterpret_cast<void*>(context.Ebp); | 
| 1029     state.fp = reinterpret_cast<Address>(context.Rbp); |  | 
| 1030 #else |  | 
| 1031     state.pc = reinterpret_cast<Address>(context.Eip); |  | 
| 1032     state.sp = reinterpret_cast<Address>(context.Esp); |  | 
| 1033     state.fp = reinterpret_cast<Address>(context.Ebp); |  | 
| 1034 #endif | 616 #endif | 
| 1035 #endif  // USE_SIMULATOR |  | 
| 1036     SampleStack(state); | 617     SampleStack(state); | 
| 1037   } | 618   } | 
| 1038   ResumeThread(profiled_thread); | 619   ResumeThread(profiled_thread); | 
| 1039 } | 620 } | 
| 1040 | 621 | 
| 1041 #endif  // USE_SIGNALS | 622 #endif  // USE_SIGNALS | 
| 1042 | 623 | 
| 1043 | 624 }  // namespace sampler | 
| 1044 }  // namespace internal |  | 
| 1045 }  // namespace v8 | 625 }  // namespace v8 | 
| OLD | NEW | 
|---|