diff options
Diffstat (limited to 'src/platform-win32.cc')
-rw-r--r-- | src/platform-win32.cc | 252 |
1 files changed, 158 insertions, 94 deletions
diff --git a/src/platform-win32.cc b/src/platform-win32.cc index f24994b5..50a9e5b1 100644 --- a/src/platform-win32.cc +++ b/src/platform-win32.cc @@ -173,6 +173,10 @@ double ceiling(double x) { return ceil(x); } + +static Mutex* limit_mutex = NULL; + + #ifdef _WIN64 typedef double (*ModuloFunction)(double, double); @@ -540,6 +544,7 @@ void OS::Setup() { // call this setup code within the same millisecond. uint64_t seed = static_cast<uint64_t>(TimeCurrentMillis()); srand(static_cast<unsigned int>(seed)); + limit_mutex = CreateMutex(); } @@ -676,7 +681,7 @@ bool OS::Remove(const char* path) { // Open log file in binary mode to avoid /n -> /r/n conversion. -const char* OS::LogFileOpenMode = "wb"; +const char* const OS::LogFileOpenMode = "wb"; // Print (debug) message to console. @@ -749,9 +754,13 @@ char* OS::StrChr(char* str, int c) { void OS::StrNCpy(Vector<char> dest, const char* src, size_t n) { + // Use _TRUNCATE or strncpy_s crashes (by design) if buffer is too small. + size_t buffer_size = static_cast<size_t>(dest.length()); + if (n + 1 > buffer_size) // count for trailing '\0' + n = _TRUNCATE; int result = strncpy_s(dest.start(), dest.length(), src, n); USE(result); - ASSERT(result == 0); + ASSERT(result == 0 || (n == _TRUNCATE && result == STRUNCATE)); } @@ -765,6 +774,9 @@ static void* highest_ever_allocated = reinterpret_cast<void*>(0); static void UpdateAllocatedSpaceLimits(void* address, int size) { + ASSERT(limit_mutex != NULL); + ScopedLock lock(limit_mutex); + lowest_ever_allocated = Min(lowest_ever_allocated, address); highest_ever_allocated = Max(highest_ever_allocated, @@ -835,7 +847,7 @@ void* OS::Allocate(const size_t requested, // For exectutable pages try and randomize the allocation address if (prot == PAGE_EXECUTE_READWRITE && msize >= static_cast<size_t>(Page::kPageSize)) { - address = (V8::RandomPrivate() << kPageSizeBits) + address = (V8::RandomPrivate(Isolate::Current()) << kPageSizeBits) | kAllocationRandomAddressMin; address &= kAllocationRandomAddressMax; } @@ -848,7 +860,7 @@ void* OS::Allocate(const size_t requested, mbase = VirtualAlloc(NULL, msize, MEM_COMMIT | MEM_RESERVE, prot); if (mbase == NULL) { - LOG(StringEvent("OS::Allocate", "VirtualAlloc failed")); + LOG(ISOLATE, StringEvent("OS::Allocate", "VirtualAlloc failed")); return NULL; } @@ -1191,7 +1203,8 @@ static bool LoadSymbols(HANDLE process_handle) { if (err != ERROR_MOD_NOT_FOUND && err != ERROR_INVALID_HANDLE) return false; } - LOG(SharedLibraryEvent( + LOG(i::Isolate::Current(), + SharedLibraryEvent( module_entry.szExePath, reinterpret_cast<unsigned int>(module_entry.modBaseAddr), reinterpret_cast<unsigned int>(module_entry.modBaseAddr + @@ -1450,6 +1463,7 @@ static unsigned int __stdcall ThreadEntry(void* arg) { // don't know which thread will run first (the original thread or the new // one) so we initialize it here too. thread->thread_handle_data()->tid_ = GetCurrentThreadId(); + Thread::SetThreadLocal(Isolate::isolate_key(), thread->isolate()); thread->Run(); return 0; } @@ -1493,13 +1507,19 @@ class Thread::PlatformData : public Malloced { // Initialize a Win32 thread object. The thread has an invalid thread // handle until it is started. -Thread::Thread() : ThreadHandle(ThreadHandle::INVALID) { +Thread::Thread(Isolate* isolate, const Options& options) + : ThreadHandle(ThreadHandle::INVALID), + isolate_(isolate), + stack_size_(options.stack_size) { data_ = new PlatformData(kNoThread); - set_name("v8:<unknown>"); + set_name(options.name); } -Thread::Thread(const char* name) : ThreadHandle(ThreadHandle::INVALID) { +Thread::Thread(Isolate* isolate, const char* name) + : ThreadHandle(ThreadHandle::INVALID), + isolate_(isolate), + stack_size_(0) { data_ = new PlatformData(kNoThread); set_name(name); } @@ -1524,7 +1544,7 @@ Thread::~Thread() { void Thread::Start() { data_->thread_ = reinterpret_cast<HANDLE>( _beginthreadex(NULL, - 0, + static_cast<unsigned>(stack_size_), ThreadEntry, this, 0, @@ -1840,135 +1860,179 @@ Socket* OS::CreateSocket() { // ---------------------------------------------------------------------------- // Win32 profiler support. -// -// On win32 we use a sampler thread with high priority to sample the program -// counter for the profiled thread. class Sampler::PlatformData : public Malloced { public: - explicit PlatformData(Sampler* sampler) { - sampler_ = sampler; - sampler_thread_ = INVALID_HANDLE_VALUE; - profiled_thread_ = INVALID_HANDLE_VALUE; + // 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())) {} + + ~PlatformData() { + if (profiled_thread_ != NULL) { + CloseHandle(profiled_thread_); + profiled_thread_ = NULL; + } } - Sampler* sampler_; - HANDLE sampler_thread_; + HANDLE profiled_thread() { return profiled_thread_; } + + private: HANDLE profiled_thread_; - RuntimeProfilerRateLimiter rate_limiter_; +}; + + +class SamplerThread : public Thread { + public: + explicit SamplerThread(int interval) + : Thread(NULL, "SamplerThread"), + interval_(interval) {} + + static void AddActiveSampler(Sampler* sampler) { + ScopedLock lock(mutex_); + SamplerRegistry::AddActiveSampler(sampler); + if (instance_ == NULL) { + instance_ = new SamplerThread(sampler->interval()); + instance_->Start(); + } else { + ASSERT(instance_->interval_ == sampler->interval()); + } + } + + static void RemoveActiveSampler(Sampler* sampler) { + ScopedLock lock(mutex_); + SamplerRegistry::RemoveActiveSampler(sampler); + if (SamplerRegistry::GetState() == SamplerRegistry::HAS_NO_SAMPLERS) { + RuntimeProfiler::WakeUpRuntimeProfilerThreadBeforeShutdown(); + instance_->Join(); + delete instance_; + instance_ = NULL; + } + } - // Sampler thread handler. - void Runner() { - while (sampler_->IsActive()) { - if (rate_limiter_.SuspendIfNecessary()) continue; - Sample(); - Sleep(sampler_->interval_); + // Implement Thread::Run(). + virtual void Run() { + SamplerRegistry::State state; + while ((state = SamplerRegistry::GetState()) != + SamplerRegistry::HAS_NO_SAMPLERS) { + bool cpu_profiling_enabled = + (state == SamplerRegistry::HAS_CPU_PROFILING_SAMPLERS); + bool runtime_profiler_enabled = RuntimeProfiler::IsEnabled(); + // When CPU profiling is enabled both JavaScript and C++ code is + // profiled. We must not suspend. + if (!cpu_profiling_enabled) { + if (rate_limiter_.SuspendIfNecessary()) continue; + } + if (cpu_profiling_enabled) { + if (!SamplerRegistry::IterateActiveSamplers(&DoCpuProfile, this)) { + return; + } + } + if (runtime_profiler_enabled) { + if (!SamplerRegistry::IterateActiveSamplers(&DoRuntimeProfile, NULL)) { + return; + } + } + OS::Sleep(interval_); } } - void Sample() { - if (sampler_->IsProfiling()) { - // Context used for sampling the register state of the profiled thread. - CONTEXT context; - memset(&context, 0, sizeof(context)); + 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); + } + + static void DoRuntimeProfile(Sampler* sampler, void* ignored) { + if (!sampler->isolate()->IsInitialized()) return; + sampler->isolate()->runtime_profiler()->NotifyTick(); + } + + void SampleContext(Sampler* sampler) { + HANDLE profiled_thread = sampler->platform_data()->profiled_thread(); + if (profiled_thread == NULL) return; - TickSample sample_obj; - TickSample* sample = CpuProfiler::TickSampleEvent(); - if (sample == NULL) sample = &sample_obj; + // Context used for sampling the register state of the profiled thread. + CONTEXT context; + memset(&context, 0, sizeof(context)); - static const DWORD kSuspendFailed = static_cast<DWORD>(-1); - if (SuspendThread(profiled_thread_) == kSuspendFailed) return; - sample->state = Top::current_vm_state(); + TickSample sample_obj; + TickSample* sample = CpuProfiler::TickSampleEvent(sampler->isolate()); + if (sample == NULL) sample = &sample_obj; - context.ContextFlags = CONTEXT_FULL; - if (GetThreadContext(profiled_thread_, &context) != 0) { + static const DWORD kSuspendFailed = static_cast<DWORD>(-1); + if (SuspendThread(profiled_thread) == kSuspendFailed) return; + sample->state = sampler->isolate()->current_vm_state(); + + context.ContextFlags = CONTEXT_FULL; + if (GetThreadContext(profiled_thread, &context) != 0) { #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); + 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); + sample->pc = reinterpret_cast<Address>(context.Eip); + sample->sp = reinterpret_cast<Address>(context.Esp); + sample->fp = reinterpret_cast<Address>(context.Ebp); #endif - sampler_->SampleStack(sample); - sampler_->Tick(sample); - } - ResumeThread(profiled_thread_); + sampler->SampleStack(sample); + sampler->Tick(sample); } - if (RuntimeProfiler::IsEnabled()) RuntimeProfiler::NotifyTick(); + ResumeThread(profiled_thread); } + + const int interval_; + RuntimeProfilerRateLimiter rate_limiter_; + + // Protects the process wide state below. + static Mutex* mutex_; + static SamplerThread* instance_; + + DISALLOW_COPY_AND_ASSIGN(SamplerThread); }; -// Entry point for sampler thread. -static unsigned int __stdcall SamplerEntry(void* arg) { - Sampler::PlatformData* data = - reinterpret_cast<Sampler::PlatformData*>(arg); - data->Runner(); - return 0; -} +Mutex* SamplerThread::mutex_ = OS::CreateMutex(); +SamplerThread* SamplerThread::instance_ = NULL; -// Initialize a profile sampler. -Sampler::Sampler(int interval) - : interval_(interval), +Sampler::Sampler(Isolate* isolate, int interval) + : isolate_(isolate), + interval_(interval), profiling_(false), active_(false), samples_taken_(0) { - data_ = new PlatformData(this); + data_ = new PlatformData; } Sampler::~Sampler() { + ASSERT(!IsActive()); delete data_; } -// Start profiling. void Sampler::Start() { - // Do not start multiple threads for the same sampler. ASSERT(!IsActive()); - - // 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. - data_->profiled_thread_ = OpenThread(THREAD_GET_CONTEXT | - THREAD_SUSPEND_RESUME | - THREAD_QUERY_INFORMATION, - false, - GetCurrentThreadId()); - BOOL ok = data_->profiled_thread_ != NULL; - if (!ok) return; - - // Start sampler thread. - unsigned int tid; SetActive(true); - data_->sampler_thread_ = reinterpret_cast<HANDLE>( - _beginthreadex(NULL, 0, SamplerEntry, data_, 0, &tid)); - // Set thread to high priority to increase sampling accuracy. - SetThreadPriority(data_->sampler_thread_, THREAD_PRIORITY_TIME_CRITICAL); + SamplerThread::AddActiveSampler(this); } -// Stop profiling. void Sampler::Stop() { - // Seting active to false triggers termination of the sampler - // thread. + ASSERT(IsActive()); + SamplerThread::RemoveActiveSampler(this); SetActive(false); - - // Wait for sampler thread to terminate. - Top::WakeUpRuntimeProfilerThreadBeforeShutdown(); - WaitForSingleObject(data_->sampler_thread_, INFINITE); - - // Release the thread handles - CloseHandle(data_->sampler_thread_); - CloseHandle(data_->profiled_thread_); } - #endif // ENABLE_LOGGING_AND_PROFILING } } // namespace v8::internal |