| OLD | NEW | 
|    1 // Copyright 2006-2011 the V8 project authors. All rights reserved. |    1 // Copyright 2006-2011 the V8 project authors. All rights reserved. | 
|    2 // Redistribution and use in source and binary forms, with or without |    2 // Redistribution and use in source and binary forms, with or without | 
|    3 // modification, are permitted provided that the following conditions are |    3 // modification, are permitted provided that the following conditions are | 
|    4 // met: |    4 // met: | 
|    5 // |    5 // | 
|    6 //     * Redistributions of source code must retain the above copyright |    6 //     * Redistributions of source code must retain the above copyright | 
|    7 //       notice, this list of conditions and the following disclaimer. |    7 //       notice, this list of conditions and the following disclaimer. | 
|    8 //     * Redistributions in binary form must reproduce the above |    8 //     * Redistributions in binary form must reproduce the above | 
|    9 //       copyright notice, this list of conditions and the following |    9 //       copyright notice, this list of conditions and the following | 
|   10 //       disclaimer in the documentation and/or other materials provided |   10 //       disclaimer in the documentation and/or other materials provided | 
| (...skipping 24 matching lines...) Expand all  Loading... | 
|   35 #include <strings.h>    // index |   35 #include <strings.h>    // index | 
|   36 #include <sys/time.h> |   36 #include <sys/time.h> | 
|   37 #include <sys/mman.h>   // mmap & munmap |   37 #include <sys/mman.h>   // mmap & munmap | 
|   38 #include <unistd.h>     // sysconf |   38 #include <unistd.h>     // sysconf | 
|   39  |   39  | 
|   40 #undef MAP_TYPE |   40 #undef MAP_TYPE | 
|   41  |   41  | 
|   42 #include "v8.h" |   42 #include "v8.h" | 
|   43  |   43  | 
|   44 #include "platform.h" |   44 #include "platform.h" | 
|   45 #include "top.h" |  | 
|   46 #include "v8threads.h" |   45 #include "v8threads.h" | 
|   47 #include "vm-state-inl.h" |   46 #include "vm-state-inl.h" | 
|   48 #include "win32-headers.h" |   47 #include "win32-headers.h" | 
|   49  |   48  | 
|   50 namespace v8 { |   49 namespace v8 { | 
|   51 namespace internal { |   50 namespace internal { | 
|   52  |   51  | 
|   53 // 0 is never a valid thread id |   52 // 0 is never a valid thread id | 
|   54 static const pthread_t kNoThread = (pthread_t) 0; |   53 static const pthread_t kNoThread = (pthread_t) 0; | 
|   55  |   54  | 
|   56  |   55  | 
|   57 double ceiling(double x) { |   56 double ceiling(double x) { | 
|   58   return ceil(x); |   57   return ceil(x); | 
|   59 } |   58 } | 
|   60  |   59  | 
|   61  |   60  | 
 |   61 static Mutex* limit_mutex = NULL; | 
 |   62  | 
 |   63  | 
|   62 void OS::Setup() { |   64 void OS::Setup() { | 
|   63   // Seed the random number generator. |   65   // Seed the random number generator. | 
|   64   // Convert the current time to a 64-bit integer first, before converting it |   66   // Convert the current time to a 64-bit integer first, before converting it | 
|   65   // to an unsigned. Going directly can cause an overflow and the seed to be |   67   // to an unsigned. Going directly can cause an overflow and the seed to be | 
|   66   // set to all ones. The seed will be identical for different instances that |   68   // set to all ones. The seed will be identical for different instances that | 
|   67   // call this setup code within the same millisecond. |   69   // call this setup code within the same millisecond. | 
|   68   uint64_t seed = static_cast<uint64_t>(TimeCurrentMillis()); |   70   uint64_t seed = static_cast<uint64_t>(TimeCurrentMillis()); | 
|   69   srandom(static_cast<unsigned int>(seed)); |   71   srandom(static_cast<unsigned int>(seed)); | 
 |   72   limit_mutex = CreateMutex(); | 
|   70 } |   73 } | 
|   71  |   74  | 
|   72  |   75  | 
|   73 uint64_t OS::CpuFeaturesImpliedByPlatform() { |   76 uint64_t OS::CpuFeaturesImpliedByPlatform() { | 
|   74   return 0;  // Nothing special about Cygwin. |   77   return 0;  // Nothing special about Cygwin. | 
|   75 } |   78 } | 
|   76  |   79  | 
|   77  |   80  | 
|   78 int OS::ActivationFrameAlignment() { |   81 int OS::ActivationFrameAlignment() { | 
|   79   // With gcc 4.4 the tree vectorization optimizer can generate code |   82   // With gcc 4.4 the tree vectorization optimizer can generate code | 
| (...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
|  112 // We keep the lowest and highest addresses mapped as a quick way of |  115 // We keep the lowest and highest addresses mapped as a quick way of | 
|  113 // determining that pointers are outside the heap (used mostly in assertions |  116 // determining that pointers are outside the heap (used mostly in assertions | 
|  114 // and verification).  The estimate is conservative, ie, not all addresses in |  117 // and verification).  The estimate is conservative, ie, not all addresses in | 
|  115 // 'allocated' space are actually allocated to our heap.  The range is |  118 // 'allocated' space are actually allocated to our heap.  The range is | 
|  116 // [lowest, highest), inclusive on the low and and exclusive on the high end. |  119 // [lowest, highest), inclusive on the low and and exclusive on the high end. | 
|  117 static void* lowest_ever_allocated = reinterpret_cast<void*>(-1); |  120 static void* lowest_ever_allocated = reinterpret_cast<void*>(-1); | 
|  118 static void* highest_ever_allocated = reinterpret_cast<void*>(0); |  121 static void* highest_ever_allocated = reinterpret_cast<void*>(0); | 
|  119  |  122  | 
|  120  |  123  | 
|  121 static void UpdateAllocatedSpaceLimits(void* address, int size) { |  124 static void UpdateAllocatedSpaceLimits(void* address, int size) { | 
 |  125   ASSERT(limit_mutex != NULL); | 
 |  126   ScopedLock lock(limit_mutex); | 
 |  127  | 
|  122   lowest_ever_allocated = Min(lowest_ever_allocated, address); |  128   lowest_ever_allocated = Min(lowest_ever_allocated, address); | 
|  123   highest_ever_allocated = |  129   highest_ever_allocated = | 
|  124       Max(highest_ever_allocated, |  130       Max(highest_ever_allocated, | 
|  125           reinterpret_cast<void*>(reinterpret_cast<char*>(address) + size)); |  131           reinterpret_cast<void*>(reinterpret_cast<char*>(address) + size)); | 
|  126 } |  132 } | 
|  127  |  133  | 
|  128  |  134  | 
|  129 bool OS::IsOutsideAllocatedSpace(void* address) { |  135 bool OS::IsOutsideAllocatedSpace(void* address) { | 
|  130   return address < lowest_ever_allocated || address >= highest_ever_allocated; |  136   return address < lowest_ever_allocated || address >= highest_ever_allocated; | 
|  131 } |  137 } | 
| (...skipping 115 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
|  247   // This function assumes that the layout of the file is as follows: |  253   // This function assumes that the layout of the file is as follows: | 
|  248   // hex_start_addr-hex_end_addr rwxp <unused data> [binary_file_name] |  254   // hex_start_addr-hex_end_addr rwxp <unused data> [binary_file_name] | 
|  249   // If we encounter an unexpected situation we abort scanning further entries. |  255   // If we encounter an unexpected situation we abort scanning further entries. | 
|  250   FILE* fp = fopen("/proc/self/maps", "r"); |  256   FILE* fp = fopen("/proc/self/maps", "r"); | 
|  251   if (fp == NULL) return; |  257   if (fp == NULL) return; | 
|  252  |  258  | 
|  253   // Allocate enough room to be able to store a full file name. |  259   // Allocate enough room to be able to store a full file name. | 
|  254   const int kLibNameLen = FILENAME_MAX + 1; |  260   const int kLibNameLen = FILENAME_MAX + 1; | 
|  255   char* lib_name = reinterpret_cast<char*>(malloc(kLibNameLen)); |  261   char* lib_name = reinterpret_cast<char*>(malloc(kLibNameLen)); | 
|  256  |  262  | 
 |  263   i::Isolate* isolate = ISOLATE; | 
|  257   // This loop will terminate once the scanning hits an EOF. |  264   // This loop will terminate once the scanning hits an EOF. | 
|  258   while (true) { |  265   while (true) { | 
|  259     uintptr_t start, end; |  266     uintptr_t start, end; | 
|  260     char attr_r, attr_w, attr_x, attr_p; |  267     char attr_r, attr_w, attr_x, attr_p; | 
|  261     // Parse the addresses and permission bits at the beginning of the line. |  268     // Parse the addresses and permission bits at the beginning of the line. | 
|  262     if (fscanf(fp, "%" V8PRIxPTR "-%" V8PRIxPTR, &start, &end) != 2) break; |  269     if (fscanf(fp, "%" V8PRIxPTR "-%" V8PRIxPTR, &start, &end) != 2) break; | 
|  263     if (fscanf(fp, " %c%c%c%c", &attr_r, &attr_w, &attr_x, &attr_p) != 4) break; |  270     if (fscanf(fp, " %c%c%c%c", &attr_r, &attr_w, &attr_x, &attr_p) != 4) break; | 
|  264  |  271  | 
|  265     int c; |  272     int c; | 
|  266     if (attr_r == 'r' && attr_w != 'w' && attr_x == 'x') { |  273     if (attr_r == 'r' && attr_w != 'w' && attr_x == 'x') { | 
| (...skipping 13 matching lines...) Expand all  Loading... | 
|  280  |  287  | 
|  281         // Drop the newline character read by fgets. We do not need to check |  288         // Drop the newline character read by fgets. We do not need to check | 
|  282         // for a zero-length string because we know that we at least read the |  289         // for a zero-length string because we know that we at least read the | 
|  283         // '/' character. |  290         // '/' character. | 
|  284         lib_name[strlen(lib_name) - 1] = '\0'; |  291         lib_name[strlen(lib_name) - 1] = '\0'; | 
|  285       } else { |  292       } else { | 
|  286         // No library name found, just record the raw address range. |  293         // No library name found, just record the raw address range. | 
|  287         snprintf(lib_name, kLibNameLen, |  294         snprintf(lib_name, kLibNameLen, | 
|  288                  "%08" V8PRIxPTR "-%08" V8PRIxPTR, start, end); |  295                  "%08" V8PRIxPTR "-%08" V8PRIxPTR, start, end); | 
|  289       } |  296       } | 
|  290       LOG(SharedLibraryEvent(lib_name, start, end)); |  297       LOG(isolate, SharedLibraryEvent(lib_name, start, end)); | 
|  291     } else { |  298     } else { | 
|  292       // Entry not describing executable data. Skip to end of line to setup |  299       // Entry not describing executable data. Skip to end of line to setup | 
|  293       // reading the next entry. |  300       // reading the next entry. | 
|  294       do { |  301       do { | 
|  295         c = getc(fp); |  302         c = getc(fp); | 
|  296       } while ((c != EOF) && (c != '\n')); |  303       } while ((c != EOF) && (c != '\n')); | 
|  297       if (c == EOF) break; |  304       if (c == EOF) break; | 
|  298     } |  305     } | 
|  299   } |  306   } | 
|  300   free(lib_name); |  307   free(lib_name); | 
|  301   fclose(fp); |  308   fclose(fp); | 
|  302 #endif |  309 #endif | 
|  303 } |  310 } | 
|  304  |  311  | 
|  305  |  312  | 
|  306 void OS::SignalCodeMovingGC() { |  313 void OS::SignalCodeMovingGC() { | 
|  307   // Nothing to do on Cygwin. |  314   // Nothing to do on Cygwin. | 
|  308 } |  315 } | 
|  309  |  316  | 
|  310  |  317  | 
|  311 int OS::StackWalk(Vector<OS::StackFrame> frames) { |  318 int OS::StackWalk(Vector<OS::StackFrame> frames) { | 
|  312   // Not supported on Cygwin. |  319   // Not supported on Cygwin. | 
|  313   return 0; |  320   return 0; | 
|  314 } |  321 } | 
|  315  |  322  | 
|  316  |  323  | 
|  317 // Constants used for mmap. |  324 // The VirtualMemory implementation is taken from platform-win32.cc. | 
|  318 static const int kMmapFd = -1; |  325 // The mmap-based virtual memory implementation as it is used on most posix | 
|  319 static const int kMmapFdOffset = 0; |  326 // platforms does not work well because Cygwin does not support MAP_FIXED. | 
 |  327 // This causes VirtualMemory::Commit to not always commit the memory region | 
 |  328 // specified. | 
 |  329  | 
 |  330 bool VirtualMemory::IsReserved() { | 
 |  331   return address_ != NULL; | 
 |  332 } | 
|  320  |  333  | 
|  321  |  334  | 
|  322 VirtualMemory::VirtualMemory(size_t size) { |  335 VirtualMemory::VirtualMemory(size_t size) { | 
|  323   address_ = mmap(NULL, size, PROT_NONE, |  336   address_ = VirtualAlloc(NULL, size, MEM_RESERVE, PAGE_NOACCESS); | 
|  324                   MAP_PRIVATE | MAP_ANONYMOUS | MAP_NORESERVE, |  | 
|  325                   kMmapFd, kMmapFdOffset); |  | 
|  326   size_ = size; |  337   size_ = size; | 
|  327 } |  338 } | 
|  328  |  339  | 
|  329  |  340  | 
|  330 VirtualMemory::~VirtualMemory() { |  341 VirtualMemory::~VirtualMemory() { | 
|  331   if (IsReserved()) { |  342   if (IsReserved()) { | 
|  332     if (0 == munmap(address(), size())) address_ = MAP_FAILED; |  343     if (0 == VirtualFree(address(), 0, MEM_RELEASE)) address_ = NULL; | 
|  333   } |  344   } | 
|  334 } |  345 } | 
|  335  |  346  | 
|  336  |  347  | 
|  337 bool VirtualMemory::IsReserved() { |  | 
|  338   return address_ != MAP_FAILED; |  | 
|  339 } |  | 
|  340  |  | 
|  341  |  | 
|  342 bool VirtualMemory::Commit(void* address, size_t size, bool is_executable) { |  348 bool VirtualMemory::Commit(void* address, size_t size, bool is_executable) { | 
|  343   int prot = PROT_READ | PROT_WRITE | (is_executable ? PROT_EXEC : 0); |  349   int prot = is_executable ? PAGE_EXECUTE_READWRITE : PAGE_READWRITE; | 
|  344  |  350   if (NULL == VirtualAlloc(address, size, MEM_COMMIT, prot)) { | 
|  345   if (mprotect(address, size, prot) != 0) { |  | 
|  346     return false; |  351     return false; | 
|  347   } |  352   } | 
|  348  |  353  | 
|  349   UpdateAllocatedSpaceLimits(address, size); |  354   UpdateAllocatedSpaceLimits(address, static_cast<int>(size)); | 
|  350   return true; |  355   return true; | 
|  351 } |  356 } | 
|  352  |  357  | 
|  353  |  358  | 
|  354 bool VirtualMemory::Uncommit(void* address, size_t size) { |  359 bool VirtualMemory::Uncommit(void* address, size_t size) { | 
|  355   return mmap(address, size, PROT_NONE, |  360   ASSERT(IsReserved()); | 
|  356               MAP_PRIVATE | MAP_ANONYMOUS | MAP_NORESERVE, |  361   return VirtualFree(address, size, MEM_DECOMMIT) != false; | 
|  357               kMmapFd, kMmapFdOffset) != MAP_FAILED; |  | 
|  358 } |  362 } | 
|  359  |  363  | 
|  360  |  364  | 
|  361 class ThreadHandle::PlatformData : public Malloced { |  365 class ThreadHandle::PlatformData : public Malloced { | 
|  362  public: |  366  public: | 
|  363   explicit PlatformData(ThreadHandle::Kind kind) { |  367   explicit PlatformData(ThreadHandle::Kind kind) { | 
|  364     Initialize(kind); |  368     Initialize(kind); | 
|  365   } |  369   } | 
|  366  |  370  | 
|  367   void Initialize(ThreadHandle::Kind kind) { |  371   void Initialize(ThreadHandle::Kind kind) { | 
| (...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
|  420 } |  424 } | 
|  421  |  425  | 
|  422  |  426  | 
|  423 static void* ThreadEntry(void* arg) { |  427 static void* ThreadEntry(void* arg) { | 
|  424   Thread* thread = reinterpret_cast<Thread*>(arg); |  428   Thread* thread = reinterpret_cast<Thread*>(arg); | 
|  425   // This is also initialized by the first argument to pthread_create() but we |  429   // This is also initialized by the first argument to pthread_create() but we | 
|  426   // don't know which thread will run first (the original thread or the new |  430   // don't know which thread will run first (the original thread or the new | 
|  427   // one) so we initialize it here too. |  431   // one) so we initialize it here too. | 
|  428   thread->thread_handle_data()->thread_ = pthread_self(); |  432   thread->thread_handle_data()->thread_ = pthread_self(); | 
|  429   ASSERT(thread->IsValid()); |  433   ASSERT(thread->IsValid()); | 
 |  434   Thread::SetThreadLocal(Isolate::isolate_key(), thread->isolate()); | 
|  430   thread->Run(); |  435   thread->Run(); | 
|  431   return NULL; |  436   return NULL; | 
|  432 } |  437 } | 
|  433  |  438  | 
|  434  |  439  | 
|  435 void Thread::set_name(const char* name) { |  440 void Thread::set_name(const char* name) { | 
|  436   strncpy(name_, name, sizeof(name_)); |  441   strncpy(name_, name, sizeof(name_)); | 
|  437   name_[sizeof(name_) - 1] = '\0'; |  442   name_[sizeof(name_) - 1] = '\0'; | 
|  438 } |  443 } | 
|  439  |  444  | 
|  440  |  445  | 
|  441 void Thread::Start() { |  446 void Thread::Start() { | 
|  442   pthread_create(&thread_handle_data()->thread_, NULL, ThreadEntry, this); |  447   pthread_attr_t* attr_ptr = NULL; | 
 |  448   pthread_attr_t attr; | 
 |  449   if (stack_size_ > 0) { | 
 |  450     pthread_attr_init(&attr); | 
 |  451     pthread_attr_setstacksize(&attr, static_cast<size_t>(stack_size_)); | 
 |  452     attr_ptr = &attr; | 
 |  453   } | 
 |  454   pthread_create(&thread_handle_data()->thread_, attr_ptr, ThreadEntry, this); | 
|  443   ASSERT(IsValid()); |  455   ASSERT(IsValid()); | 
|  444 } |  456 } | 
|  445  |  457  | 
|  446  |  458  | 
|  447 void Thread::Join() { |  459 void Thread::Join() { | 
|  448   pthread_join(thread_handle_data()->thread_, NULL); |  460   pthread_join(thread_handle_data()->thread_, NULL); | 
|  449 } |  461 } | 
|  450  |  462  | 
|  451  |  463  | 
|  452 static inline Thread::LocalStorageKey PthreadKeyToLocalKey( |  464 static inline Thread::LocalStorageKey PthreadKeyToLocalKey( | 
| (...skipping 163 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
|  616  |  628  | 
|  617 #ifdef ENABLE_LOGGING_AND_PROFILING |  629 #ifdef ENABLE_LOGGING_AND_PROFILING | 
|  618  |  630  | 
|  619 // ---------------------------------------------------------------------------- |  631 // ---------------------------------------------------------------------------- | 
|  620 // Cygwin profiler support. |  632 // Cygwin profiler support. | 
|  621 // |  633 // | 
|  622 // On Cygwin we use the same sampler implementation as on win32. |  634 // On Cygwin we use the same sampler implementation as on win32. | 
|  623  |  635  | 
|  624 class Sampler::PlatformData : public Malloced { |  636 class Sampler::PlatformData : public Malloced { | 
|  625  public: |  637  public: | 
|  626   explicit PlatformData(Sampler* sampler) { |  | 
|  627     sampler_ = sampler; |  | 
|  628     sampler_thread_ = INVALID_HANDLE_VALUE; |  | 
|  629     profiled_thread_ = INVALID_HANDLE_VALUE; |  | 
|  630   } |  | 
|  631  |  | 
|  632   Sampler* sampler_; |  | 
|  633   HANDLE sampler_thread_; |  | 
|  634   HANDLE profiled_thread_; |  | 
|  635   RuntimeProfilerRateLimiter rate_limiter_; |  | 
|  636  |  | 
|  637   // Sampler thread handler. |  | 
|  638   void Runner() { |  | 
|  639     while (sampler_->IsActive()) { |  | 
|  640       if (rate_limiter_.SuspendIfNecessary()) continue; |  | 
|  641       Sample(); |  | 
|  642       Sleep(sampler_->interval_); |  | 
|  643     } |  | 
|  644   } |  | 
|  645  |  | 
|  646   void Sample() { |  | 
|  647     if (sampler_->IsProfiling()) { |  | 
|  648       // Context used for sampling the register state of the profiled thread. |  | 
|  649       CONTEXT context; |  | 
|  650       memset(&context, 0, sizeof(context)); |  | 
|  651  |  | 
|  652       TickSample sample_obj; |  | 
|  653       TickSample* sample = CpuProfiler::TickSampleEvent(); |  | 
|  654       if (sample == NULL) sample = &sample_obj; |  | 
|  655  |  | 
|  656       static const DWORD kSuspendFailed = static_cast<DWORD>(-1); |  | 
|  657       if (SuspendThread(profiled_thread_) == kSuspendFailed) return; |  | 
|  658       sample->state = Top::current_vm_state(); |  | 
|  659  |  | 
|  660       context.ContextFlags = CONTEXT_FULL; |  | 
|  661       if (GetThreadContext(profiled_thread_, &context) != 0) { |  | 
|  662 #if V8_HOST_ARCH_X64 |  | 
|  663         sample->pc = reinterpret_cast<Address>(context.Rip); |  | 
|  664         sample->sp = reinterpret_cast<Address>(context.Rsp); |  | 
|  665         sample->fp = reinterpret_cast<Address>(context.Rbp); |  | 
|  666 #else |  | 
|  667         sample->pc = reinterpret_cast<Address>(context.Eip); |  | 
|  668         sample->sp = reinterpret_cast<Address>(context.Esp); |  | 
|  669         sample->fp = reinterpret_cast<Address>(context.Ebp); |  | 
|  670 #endif |  | 
|  671         sampler_->SampleStack(sample); |  | 
|  672         sampler_->Tick(sample); |  | 
|  673       } |  | 
|  674       ResumeThread(profiled_thread_); |  | 
|  675     } |  | 
|  676     if (RuntimeProfiler::IsEnabled()) RuntimeProfiler::NotifyTick(); |  | 
|  677   } |  | 
|  678 }; |  | 
|  679  |  | 
|  680  |  | 
|  681 // Entry point for sampler thread. |  | 
|  682 static DWORD __stdcall SamplerEntry(void* arg) { |  | 
|  683   Sampler::PlatformData* data = |  | 
|  684       reinterpret_cast<Sampler::PlatformData*>(arg); |  | 
|  685   data->Runner(); |  | 
|  686   return 0; |  | 
|  687 } |  | 
|  688  |  | 
|  689  |  | 
|  690 // Initialize a profile sampler. |  | 
|  691 Sampler::Sampler(int interval) |  | 
|  692     : interval_(interval), |  | 
|  693       profiling_(false), |  | 
|  694       active_(false), |  | 
|  695       samples_taken_(0) { |  | 
|  696   data_ = new PlatformData(this); |  | 
|  697 } |  | 
|  698  |  | 
|  699  |  | 
|  700 Sampler::~Sampler() { |  | 
|  701   delete data_; |  | 
|  702 } |  | 
|  703  |  | 
|  704  |  | 
|  705 // Start profiling. |  | 
|  706 void Sampler::Start() { |  | 
|  707   // Do not start multiple threads for the same sampler. |  | 
|  708   ASSERT(!IsActive()); |  | 
|  709  |  | 
|  710   // Get a handle to the calling thread. This is the thread that we are |  638   // Get a handle to the calling thread. This is the thread that we are | 
|  711   // going to profile. We need to make a copy of the handle because we are |  639   // going to profile. We need to make a copy of the handle because we are | 
|  712   // going to use it in the sampler thread. Using GetThreadHandle() will |  640   // going to use it in the sampler thread. Using GetThreadHandle() will | 
|  713   // not work in this case. We're using OpenThread because DuplicateHandle |  641   // not work in this case. We're using OpenThread because DuplicateHandle | 
|  714   // for some reason doesn't work in Chrome's sandbox. |  642   // for some reason doesn't work in Chrome's sandbox. | 
|  715   data_->profiled_thread_ = OpenThread(THREAD_GET_CONTEXT | |  643   PlatformData() : profiled_thread_(OpenThread(THREAD_GET_CONTEXT | | 
|  716                                        THREAD_SUSPEND_RESUME | |  644                                                THREAD_SUSPEND_RESUME | | 
|  717                                        THREAD_QUERY_INFORMATION, |  645                                                THREAD_QUERY_INFORMATION, | 
|  718                                        false, |  646                                                false, | 
|  719                                        GetCurrentThreadId()); |  647                                                GetCurrentThreadId())) {} | 
|  720   BOOL ok = data_->profiled_thread_ != NULL; |  | 
|  721   if (!ok) return; |  | 
|  722  |  648  | 
|  723   // Start sampler thread. |  649   ~PlatformData() { | 
|  724   DWORD tid; |  650     if (profiled_thread_ != NULL) { | 
|  725   SetActive(true); |  651       CloseHandle(profiled_thread_); | 
|  726   data_->sampler_thread_ = CreateThread(NULL, 0, SamplerEntry, data_, 0, &tid); |  652       profiled_thread_ = NULL; | 
|  727   // Set thread to high priority to increase sampling accuracy. |  653     } | 
|  728   SetThreadPriority(data_->sampler_thread_, THREAD_PRIORITY_TIME_CRITICAL); |  654   } | 
 |  655  | 
 |  656   HANDLE profiled_thread() { return profiled_thread_; } | 
 |  657  | 
 |  658  private: | 
 |  659   HANDLE profiled_thread_; | 
 |  660 }; | 
 |  661  | 
 |  662  | 
 |  663 class SamplerThread : public Thread { | 
 |  664  public: | 
 |  665   explicit SamplerThread(int interval) | 
 |  666       : Thread(NULL, "SamplerThread"), | 
 |  667         interval_(interval) {} | 
 |  668  | 
 |  669   static void AddActiveSampler(Sampler* sampler) { | 
 |  670     ScopedLock lock(mutex_); | 
 |  671     SamplerRegistry::AddActiveSampler(sampler); | 
 |  672     if (instance_ == NULL) { | 
 |  673       instance_ = new SamplerThread(sampler->interval()); | 
 |  674       instance_->Start(); | 
 |  675     } else { | 
 |  676       ASSERT(instance_->interval_ == sampler->interval()); | 
 |  677     } | 
 |  678   } | 
 |  679  | 
 |  680   static void RemoveActiveSampler(Sampler* sampler) { | 
 |  681     ScopedLock lock(mutex_); | 
 |  682     SamplerRegistry::RemoveActiveSampler(sampler); | 
 |  683     if (SamplerRegistry::GetState() == SamplerRegistry::HAS_NO_SAMPLERS) { | 
 |  684       RuntimeProfiler::WakeUpRuntimeProfilerThreadBeforeShutdown(); | 
 |  685       instance_->Join(); | 
 |  686       delete instance_; | 
 |  687       instance_ = NULL; | 
 |  688     } | 
 |  689   } | 
 |  690  | 
 |  691   // Implement Thread::Run(). | 
 |  692   virtual void Run() { | 
 |  693     SamplerRegistry::State state; | 
 |  694     while ((state = SamplerRegistry::GetState()) != | 
 |  695            SamplerRegistry::HAS_NO_SAMPLERS) { | 
 |  696       bool cpu_profiling_enabled = | 
 |  697           (state == SamplerRegistry::HAS_CPU_PROFILING_SAMPLERS); | 
 |  698       bool runtime_profiler_enabled = RuntimeProfiler::IsEnabled(); | 
 |  699       // When CPU profiling is enabled both JavaScript and C++ code is | 
 |  700       // profiled. We must not suspend. | 
 |  701       if (!cpu_profiling_enabled) { | 
 |  702         if (rate_limiter_.SuspendIfNecessary()) continue; | 
 |  703       } | 
 |  704       if (cpu_profiling_enabled) { | 
 |  705         if (!SamplerRegistry::IterateActiveSamplers(&DoCpuProfile, this)) { | 
 |  706           return; | 
 |  707         } | 
 |  708       } | 
 |  709       if (runtime_profiler_enabled) { | 
 |  710         if (!SamplerRegistry::IterateActiveSamplers(&DoRuntimeProfile, NULL)) { | 
 |  711           return; | 
 |  712         } | 
 |  713       } | 
 |  714       OS::Sleep(interval_); | 
 |  715     } | 
 |  716   } | 
 |  717  | 
 |  718   static void DoCpuProfile(Sampler* sampler, void* raw_sampler_thread) { | 
 |  719     if (!sampler->isolate()->IsInitialized()) return; | 
 |  720     if (!sampler->IsProfiling()) return; | 
 |  721     SamplerThread* sampler_thread = | 
 |  722         reinterpret_cast<SamplerThread*>(raw_sampler_thread); | 
 |  723     sampler_thread->SampleContext(sampler); | 
 |  724   } | 
 |  725  | 
 |  726   static void DoRuntimeProfile(Sampler* sampler, void* ignored) { | 
 |  727     if (!sampler->isolate()->IsInitialized()) return; | 
 |  728     sampler->isolate()->runtime_profiler()->NotifyTick(); | 
 |  729   } | 
 |  730  | 
 |  731   void SampleContext(Sampler* sampler) { | 
 |  732     HANDLE profiled_thread = sampler->platform_data()->profiled_thread(); | 
 |  733     if (profiled_thread == NULL) return; | 
 |  734  | 
 |  735     // Context used for sampling the register state of the profiled thread. | 
 |  736     CONTEXT context; | 
 |  737     memset(&context, 0, sizeof(context)); | 
 |  738  | 
 |  739     TickSample sample_obj; | 
 |  740     TickSample* sample = CpuProfiler::TickSampleEvent(sampler->isolate()); | 
 |  741     if (sample == NULL) sample = &sample_obj; | 
 |  742  | 
 |  743     static const DWORD kSuspendFailed = static_cast<DWORD>(-1); | 
 |  744     if (SuspendThread(profiled_thread) == kSuspendFailed) return; | 
 |  745     sample->state = sampler->isolate()->current_vm_state(); | 
 |  746  | 
 |  747     context.ContextFlags = CONTEXT_FULL; | 
 |  748     if (GetThreadContext(profiled_thread, &context) != 0) { | 
 |  749 #if V8_HOST_ARCH_X64 | 
 |  750       sample->pc = reinterpret_cast<Address>(context.Rip); | 
 |  751       sample->sp = reinterpret_cast<Address>(context.Rsp); | 
 |  752       sample->fp = reinterpret_cast<Address>(context.Rbp); | 
 |  753 #else | 
 |  754       sample->pc = reinterpret_cast<Address>(context.Eip); | 
 |  755       sample->sp = reinterpret_cast<Address>(context.Esp); | 
 |  756       sample->fp = reinterpret_cast<Address>(context.Ebp); | 
 |  757 #endif | 
 |  758       sampler->SampleStack(sample); | 
 |  759       sampler->Tick(sample); | 
 |  760     } | 
 |  761     ResumeThread(profiled_thread); | 
 |  762   } | 
 |  763  | 
 |  764   const int interval_; | 
 |  765   RuntimeProfilerRateLimiter rate_limiter_; | 
 |  766  | 
 |  767   // Protects the process wide state below. | 
 |  768   static Mutex* mutex_; | 
 |  769   static SamplerThread* instance_; | 
 |  770  | 
 |  771   DISALLOW_COPY_AND_ASSIGN(SamplerThread); | 
 |  772 }; | 
 |  773  | 
 |  774  | 
 |  775 Mutex* SamplerThread::mutex_ = OS::CreateMutex(); | 
 |  776 SamplerThread* SamplerThread::instance_ = NULL; | 
 |  777  | 
 |  778  | 
 |  779 Sampler::Sampler(Isolate* isolate, int interval) | 
 |  780     : isolate_(isolate), | 
 |  781       interval_(interval), | 
 |  782       profiling_(false), | 
 |  783       active_(false), | 
 |  784       samples_taken_(0) { | 
 |  785   data_ = new PlatformData; | 
|  729 } |  786 } | 
|  730  |  787  | 
|  731  |  788  | 
|  732 // Stop profiling. |  789 Sampler::~Sampler() { | 
|  733 void Sampler::Stop() { |  790   ASSERT(!IsActive()); | 
|  734   // Seting active to false triggers termination of the sampler |  791   delete data_; | 
|  735   // thread. |  | 
|  736   SetActive(false); |  | 
|  737  |  | 
|  738   // Wait for sampler thread to terminate. |  | 
|  739   Top::WakeUpRuntimeProfilerThreadBeforeShutdown(); |  | 
|  740   WaitForSingleObject(data_->sampler_thread_, INFINITE); |  | 
|  741  |  | 
|  742   // Release the thread handles |  | 
|  743   CloseHandle(data_->sampler_thread_); |  | 
|  744   CloseHandle(data_->profiled_thread_); |  | 
|  745 } |  792 } | 
|  746  |  793  | 
|  747  |  794  | 
 |  795 void Sampler::Start() { | 
 |  796   ASSERT(!IsActive()); | 
 |  797   SetActive(true); | 
 |  798   SamplerThread::AddActiveSampler(this); | 
 |  799 } | 
 |  800  | 
 |  801  | 
 |  802 void Sampler::Stop() { | 
 |  803   ASSERT(IsActive()); | 
 |  804   SamplerThread::RemoveActiveSampler(this); | 
 |  805   SetActive(false); | 
 |  806 } | 
 |  807  | 
|  748 #endif  // ENABLE_LOGGING_AND_PROFILING |  808 #endif  // ENABLE_LOGGING_AND_PROFILING | 
|  749  |  809  | 
|  750 } }  // namespace v8::internal |  810 } }  // namespace v8::internal | 
|  751  |  811  | 
| OLD | NEW |