vendor/v8/src/platform-win32.cc in mustang-0.0.1 vs vendor/v8/src/platform-win32.cc in mustang-0.1.0

- old
+ new

@@ -171,19 +171,57 @@ double ceiling(double x) { return ceil(x); } + +static Mutex* limit_mutex = NULL; + +#if defined(V8_TARGET_ARCH_IA32) +static OS::MemCopyFunction memcopy_function = NULL; +static Mutex* memcopy_function_mutex = OS::CreateMutex(); +// Defined in codegen-ia32.cc. +OS::MemCopyFunction CreateMemCopyFunction(); + +// Copy memory area to disjoint memory area. +void OS::MemCopy(void* dest, const void* src, size_t size) { + if (memcopy_function == NULL) { + ScopedLock lock(memcopy_function_mutex); + if (memcopy_function == NULL) { + OS::MemCopyFunction temp = CreateMemCopyFunction(); + MemoryBarrier(); + memcopy_function = temp; + } + } + // Note: here we rely on dependent reads being ordered. This is true + // on all architectures we currently support. + (*memcopy_function)(dest, src, size); +#ifdef DEBUG + CHECK_EQ(0, memcmp(dest, src, size)); +#endif +} +#endif // V8_TARGET_ARCH_IA32 + #ifdef _WIN64 typedef double (*ModuloFunction)(double, double); - +static ModuloFunction modulo_function = NULL; +static Mutex* modulo_function_mutex = OS::CreateMutex(); // Defined in codegen-x64.cc. ModuloFunction CreateModuloFunction(); double modulo(double x, double y) { - static ModuloFunction function = CreateModuloFunction(); - return function(x, y); + if (modulo_function == NULL) { + ScopedLock lock(modulo_function_mutex); + if (modulo_function == NULL) { + ModuloFunction temp = CreateModuloFunction(); + MemoryBarrier(); + modulo_function = temp; + } + } + // Note: here we rely on dependent reads being ordered. This is true + // on all architectures we currently support. + return (*modulo_function)(x, y); } #else // Win32 double modulo(double x, double y) { // Workaround MS fmod bugs. ECMA-262 says: @@ -538,10 +576,11 @@ // to an unsigned. Going directly can cause an overflow and the seed to be // set to all ones. The seed will be identical for different instances that // 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(); } // Returns the accumulated user time for thread. int OS::GetUserTime(uint32_t* secs, uint32_t* usecs) { @@ -674,11 +713,11 @@ return (DeleteFileA(path) != 0); } // 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. void OS::Print(const char* format, ...) { va_list args; @@ -747,13 +786,17 @@ return const_cast<char*>(strchr(str, 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)); } // We keep the lowest and highest addresses mapped as a quick way of // determining that pointers are outside the heap (used mostly in assertions @@ -763,10 +806,13 @@ static void* lowest_ever_allocated = reinterpret_cast<void*>(-1); 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, reinterpret_cast<void*>(reinterpret_cast<char*>(address) + size)); } @@ -833,11 +879,11 @@ int prot = is_executable ? PAGE_EXECUTE_READWRITE : PAGE_READWRITE; // 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; } LPVOID mbase = VirtualAlloc(reinterpret_cast<void *>(address), @@ -846,11 +892,11 @@ prot); if (mbase == NULL && address != 0) 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; } ASSERT(IsAligned(reinterpret_cast<size_t>(mbase), OS::AllocateAlignment())); @@ -1189,11 +1235,12 @@ if (base == 0) { int err = GetLastError(); 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 + module_entry.modBaseSize))); cont = _Module32NextW(snapshot, &module_entry); @@ -1448,10 +1495,11 @@ Thread* thread = reinterpret_cast<Thread*>(arg); // This is also initialized by the last parameter to _beginthreadex() but we // 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; } @@ -1491,17 +1539,23 @@ // 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); } @@ -1522,11 +1576,11 @@ // the Win32 function CreateThread(), because the CreateThread() does not // initialize thread specific structures in the C runtime library. void Thread::Start() { data_->thread_ = reinterpret_cast<HANDLE>( _beginthreadex(NULL, - 0, + static_cast<unsigned>(stack_size_), ThreadEntry, this, 0, reinterpret_cast<unsigned int*>( &thread_handle_data()->tid_))); @@ -1838,137 +1892,181 @@ #ifdef ENABLE_LOGGING_AND_PROFILING // ---------------------------------------------------------------------------- // 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_; +}; - // Sampler thread handler. - void Runner() { - while (sampler_->IsActive()) { - if (rate_limiter_.SuspendIfNecessary()) continue; - Sample(); - Sleep(sampler_->interval_); + +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()); } } - 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 RemoveActiveSampler(Sampler* sampler) { + ScopedLock lock(mutex_); + SamplerRegistry::RemoveActiveSampler(sampler); + if (SamplerRegistry::GetState() == SamplerRegistry::HAS_NO_SAMPLERS) { + RuntimeProfiler::WakeUpRuntimeProfilerThreadBeforeShutdown(); + instance_->Join(); + delete instance_; + instance_ = NULL; + } + } - TickSample sample_obj; - TickSample* sample = CpuProfiler::TickSampleEvent(); - if (sample == NULL) sample = &sample_obj; + // 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_); + } + } - static const DWORD kSuspendFailed = static_cast<DWORD>(-1); - if (SuspendThread(profiled_thread_) == kSuspendFailed) return; - sample->state = Top::current_vm_state(); + 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); + } - context.ContextFlags = CONTEXT_FULL; - if (GetThreadContext(profiled_thread_, &context) != 0) { + 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; + + // Context used for sampling the register state of the profiled thread. + CONTEXT context; + memset(&context, 0, sizeof(context)); + + TickSample sample_obj; + TickSample* sample = CpuProfiler::TickSampleEvent(sampler->isolate()); + if (sample == NULL) sample = &sample_obj; + + 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