| OLD | NEW |
| 1 // Copyright 2006-2008 the V8 project authors. All rights reserved. | 1 // Copyright 2006-2008 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 |
| 11 // with the distribution. | 11 // with the distribution. |
| 12 // * Neither the name of Google Inc. nor the names of its | 12 // * Neither the name of Google Inc. nor the names of its |
| 13 // contributors may be used to endorse or promote products derived | 13 // contributors may be used to endorse or promote products derived |
| 14 // from this software without specific prior written permission. | 14 // from this software without specific prior written permission. |
| 15 // | 15 // |
| 16 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | 16 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
| 17 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | 17 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
| 18 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | 18 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
| 19 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | 19 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
| 20 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | 20 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
| 21 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | 21 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
| 22 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | 22 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
| 23 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | 23 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
| 24 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | 24 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
| 25 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | 25 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
| 26 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | 26 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| 27 | 27 |
| 28 // Platform specific code for Win32. | 28 // Platform specific code for Win32. |
| 29 #ifndef WIN32_LEAN_AND_MEAN | |
| 30 // WIN32_LEAN_AND_MEAN implies NOCRYPT and NOGDI. | |
| 31 #define WIN32_LEAN_AND_MEAN | |
| 32 #endif | |
| 33 #ifndef NOMINMAX | |
| 34 #define NOMINMAX | |
| 35 #endif | |
| 36 #ifndef NOKERNEL | |
| 37 #define NOKERNEL | |
| 38 #endif | |
| 39 #ifndef NOUSER | |
| 40 #define NOUSER | |
| 41 #endif | |
| 42 #ifndef NOSERVICE | |
| 43 #define NOSERVICE | |
| 44 #endif | |
| 45 #ifndef NOSOUND | |
| 46 #define NOSOUND | |
| 47 #endif | |
| 48 #ifndef NOMCX | |
| 49 #define NOMCX | |
| 50 #endif | |
| 51 // Require Windows XP or higher (this is required for the RtlCaptureContext | |
| 52 // function to be present). | |
| 53 #ifndef _WIN32_WINNT | |
| 54 #define _WIN32_WINNT 0x501 | |
| 55 #endif | |
| 56 | 29 |
| 57 #include <windows.h> | 30 #define V8_WIN32_HEADERS_FULL |
| 58 | 31 #include "win32-headers.h" |
| 59 #include <time.h> // For LocalOffset() implementation. | |
| 60 #include <mmsystem.h> // For timeGetTime(). | |
| 61 #ifdef __MINGW32__ | |
| 62 // Require Windows XP or higher when compiling with MinGW. This is for MinGW | |
| 63 // header files to expose getaddrinfo. | |
| 64 #undef _WIN32_WINNT | |
| 65 #define _WIN32_WINNT 0x501 | |
| 66 #endif // __MINGW32__ | |
| 67 #ifndef __MINGW32__ | |
| 68 #include <dbghelp.h> // For SymLoadModule64 and al. | |
| 69 #endif // __MINGW32__ | |
| 70 #include <limits.h> // For INT_MAX and al. | |
| 71 #include <tlhelp32.h> // For Module32First and al. | |
| 72 | |
| 73 // These additional WIN32 includes have to be right here as the #undef's below | |
| 74 // makes it impossible to have them elsewhere. | |
| 75 #include <winsock2.h> | |
| 76 #include <ws2tcpip.h> | |
| 77 #include <process.h> // for _beginthreadex() | |
| 78 #include <stdlib.h> | |
| 79 | |
| 80 #undef VOID | |
| 81 #undef DELETE | |
| 82 #undef IN | |
| 83 #undef THIS | |
| 84 #undef CONST | |
| 85 #undef NAN | |
| 86 #undef GetObject | |
| 87 #undef CreateMutex | |
| 88 #undef CreateSemaphore | |
| 89 | 32 |
| 90 #include "v8.h" | 33 #include "v8.h" |
| 91 | 34 |
| 92 #include "platform.h" | 35 #include "platform.h" |
| 36 #include "vm-state-inl.h" |
| 93 | 37 |
| 94 // Extra POSIX/ANSI routines for Win32 when when using Visual Studio C++. Please | 38 // Extra POSIX/ANSI routines for Win32 when when using Visual Studio C++. Please |
| 95 // refer to The Open Group Base Specification for specification of the correct | 39 // refer to The Open Group Base Specification for specification of the correct |
| 96 // semantics for these functions. | 40 // semantics for these functions. |
| 97 // (http://www.opengroup.org/onlinepubs/000095399/) | 41 // (http://www.opengroup.org/onlinepubs/000095399/) |
| 98 #ifdef _MSC_VER | 42 #ifdef _MSC_VER |
| 99 | 43 |
| 100 namespace v8 { | 44 namespace v8 { |
| 101 namespace internal { | 45 namespace internal { |
| 102 | 46 |
| (...skipping 1060 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1163 static bool LoadSymbols(HANDLE process_handle) { | 1107 static bool LoadSymbols(HANDLE process_handle) { |
| 1164 static bool symbols_loaded = false; | 1108 static bool symbols_loaded = false; |
| 1165 | 1109 |
| 1166 if (symbols_loaded) return true; | 1110 if (symbols_loaded) return true; |
| 1167 | 1111 |
| 1168 BOOL ok; | 1112 BOOL ok; |
| 1169 | 1113 |
| 1170 // Initialize the symbol engine. | 1114 // Initialize the symbol engine. |
| 1171 ok = _SymInitialize(process_handle, // hProcess | 1115 ok = _SymInitialize(process_handle, // hProcess |
| 1172 NULL, // UserSearchPath | 1116 NULL, // UserSearchPath |
| 1173 FALSE); // fInvadeProcess | 1117 false); // fInvadeProcess |
| 1174 if (!ok) return false; | 1118 if (!ok) return false; |
| 1175 | 1119 |
| 1176 DWORD options = _SymGetOptions(); | 1120 DWORD options = _SymGetOptions(); |
| 1177 options |= SYMOPT_LOAD_LINES; | 1121 options |= SYMOPT_LOAD_LINES; |
| 1178 options |= SYMOPT_FAIL_CRITICAL_ERRORS; | 1122 options |= SYMOPT_FAIL_CRITICAL_ERRORS; |
| 1179 options = _SymSetOptions(options); | 1123 options = _SymSetOptions(options); |
| 1180 | 1124 |
| 1181 char buf[OS::kStackWalkMaxNameLen] = {0}; | 1125 char buf[OS::kStackWalkMaxNameLen] = {0}; |
| 1182 ok = _SymGetSearchPath(process_handle, buf, OS::kStackWalkMaxNameLen); | 1126 ok = _SymGetSearchPath(process_handle, buf, OS::kStackWalkMaxNameLen); |
| 1183 if (!ok) { | 1127 if (!ok) { |
| (...skipping 239 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1423 return false; | 1367 return false; |
| 1424 } | 1368 } |
| 1425 | 1369 |
| 1426 UpdateAllocatedSpaceLimits(address, static_cast<int>(size)); | 1370 UpdateAllocatedSpaceLimits(address, static_cast<int>(size)); |
| 1427 return true; | 1371 return true; |
| 1428 } | 1372 } |
| 1429 | 1373 |
| 1430 | 1374 |
| 1431 bool VirtualMemory::Uncommit(void* address, size_t size) { | 1375 bool VirtualMemory::Uncommit(void* address, size_t size) { |
| 1432 ASSERT(IsReserved()); | 1376 ASSERT(IsReserved()); |
| 1433 return VirtualFree(address, size, MEM_DECOMMIT) != FALSE; | 1377 return VirtualFree(address, size, MEM_DECOMMIT) != false; |
| 1434 } | 1378 } |
| 1435 | 1379 |
| 1436 | 1380 |
| 1437 // ---------------------------------------------------------------------------- | 1381 // ---------------------------------------------------------------------------- |
| 1438 // Win32 thread support. | 1382 // Win32 thread support. |
| 1439 | 1383 |
| 1440 // Definition of invalid thread handle and id. | 1384 // Definition of invalid thread handle and id. |
| 1441 static const HANDLE kNoThread = INVALID_HANDLE_VALUE; | 1385 static const HANDLE kNoThread = INVALID_HANDLE_VALUE; |
| 1442 static const DWORD kNoThreadId = 0; | 1386 static const DWORD kNoThreadId = 0; |
| 1443 | 1387 |
| (...skipping 142 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1586 // On Win32 mutexes are implemented using CRITICAL_SECTION objects. These are | 1530 // On Win32 mutexes are implemented using CRITICAL_SECTION objects. These are |
| 1587 // faster than Win32 Mutex objects because they are implemented using user mode | 1531 // faster than Win32 Mutex objects because they are implemented using user mode |
| 1588 // atomic instructions. Therefore we only do ring transitions if there is lock | 1532 // atomic instructions. Therefore we only do ring transitions if there is lock |
| 1589 // contention. | 1533 // contention. |
| 1590 | 1534 |
| 1591 class Win32Mutex : public Mutex { | 1535 class Win32Mutex : public Mutex { |
| 1592 public: | 1536 public: |
| 1593 | 1537 |
| 1594 Win32Mutex() { InitializeCriticalSection(&cs_); } | 1538 Win32Mutex() { InitializeCriticalSection(&cs_); } |
| 1595 | 1539 |
| 1596 ~Win32Mutex() { DeleteCriticalSection(&cs_); } | 1540 virtual ~Win32Mutex() { DeleteCriticalSection(&cs_); } |
| 1597 | 1541 |
| 1598 int Lock() { | 1542 virtual int Lock() { |
| 1599 EnterCriticalSection(&cs_); | 1543 EnterCriticalSection(&cs_); |
| 1600 return 0; | 1544 return 0; |
| 1601 } | 1545 } |
| 1602 | 1546 |
| 1603 int Unlock() { | 1547 virtual int Unlock() { |
| 1604 LeaveCriticalSection(&cs_); | 1548 LeaveCriticalSection(&cs_); |
| 1605 return 0; | 1549 return 0; |
| 1606 } | 1550 } |
| 1607 | 1551 |
| 1552 |
| 1553 virtual bool TryLock() { |
| 1554 // Returns non-zero if critical section is entered successfully entered. |
| 1555 return TryEnterCriticalSection(&cs_); |
| 1556 } |
| 1557 |
| 1608 private: | 1558 private: |
| 1609 CRITICAL_SECTION cs_; // Critical section used for mutex | 1559 CRITICAL_SECTION cs_; // Critical section used for mutex |
| 1610 }; | 1560 }; |
| 1611 | 1561 |
| 1612 | 1562 |
| 1613 Mutex* OS::CreateMutex() { | 1563 Mutex* OS::CreateMutex() { |
| 1614 return new Win32Mutex(); | 1564 return new Win32Mutex(); |
| 1615 } | 1565 } |
| 1616 | 1566 |
| 1617 | 1567 |
| (...skipping 162 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1780 } | 1730 } |
| 1781 | 1731 |
| 1782 | 1732 |
| 1783 int Win32Socket::Receive(char* data, int len) const { | 1733 int Win32Socket::Receive(char* data, int len) const { |
| 1784 int status = recv(socket_, data, len, 0); | 1734 int status = recv(socket_, data, len, 0); |
| 1785 return status; | 1735 return status; |
| 1786 } | 1736 } |
| 1787 | 1737 |
| 1788 | 1738 |
| 1789 bool Win32Socket::SetReuseAddress(bool reuse_address) { | 1739 bool Win32Socket::SetReuseAddress(bool reuse_address) { |
| 1790 BOOL on = reuse_address ? TRUE : FALSE; | 1740 BOOL on = reuse_address ? true : false; |
| 1791 int status = setsockopt(socket_, SOL_SOCKET, SO_REUSEADDR, | 1741 int status = setsockopt(socket_, SOL_SOCKET, SO_REUSEADDR, |
| 1792 reinterpret_cast<char*>(&on), sizeof(on)); | 1742 reinterpret_cast<char*>(&on), sizeof(on)); |
| 1793 return status == SOCKET_ERROR; | 1743 return status == SOCKET_ERROR; |
| 1794 } | 1744 } |
| 1795 | 1745 |
| 1796 | 1746 |
| 1797 bool Socket::Setup() { | 1747 bool Socket::Setup() { |
| 1798 // Initialize Winsock32 | 1748 // Initialize Winsock32 |
| 1799 int err; | 1749 int err; |
| 1800 WSADATA winsock_data; | 1750 WSADATA winsock_data; |
| (...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1835 | 1785 |
| 1836 Socket* OS::CreateSocket() { | 1786 Socket* OS::CreateSocket() { |
| 1837 return new Win32Socket(); | 1787 return new Win32Socket(); |
| 1838 } | 1788 } |
| 1839 | 1789 |
| 1840 | 1790 |
| 1841 #ifdef ENABLE_LOGGING_AND_PROFILING | 1791 #ifdef ENABLE_LOGGING_AND_PROFILING |
| 1842 | 1792 |
| 1843 // ---------------------------------------------------------------------------- | 1793 // ---------------------------------------------------------------------------- |
| 1844 // Win32 profiler support. | 1794 // Win32 profiler support. |
| 1845 // | |
| 1846 // On win32 we use a sampler thread with high priority to sample the program | |
| 1847 // counter for the profiled thread. | |
| 1848 | 1795 |
| 1849 class Sampler::PlatformData : public Malloced { | 1796 class Sampler::PlatformData : public Malloced { |
| 1850 public: | 1797 public: |
| 1851 explicit PlatformData(Sampler* sampler) { | 1798 // Get a handle to the calling thread. This is the thread that we are |
| 1852 sampler_ = sampler; | 1799 // going to profile. We need to make a copy of the handle because we are |
| 1853 sampler_thread_ = INVALID_HANDLE_VALUE; | 1800 // going to use it in the sampler thread. Using GetThreadHandle() will |
| 1854 profiled_thread_ = INVALID_HANDLE_VALUE; | 1801 // not work in this case. We're using OpenThread because DuplicateHandle |
| 1802 // for some reason doesn't work in Chrome's sandbox. |
| 1803 PlatformData() : profiled_thread_(OpenThread(THREAD_GET_CONTEXT | |
| 1804 THREAD_SUSPEND_RESUME | |
| 1805 THREAD_QUERY_INFORMATION, |
| 1806 false, |
| 1807 GetCurrentThreadId())) {} |
| 1808 |
| 1809 ~PlatformData() { |
| 1810 if (profiled_thread_ != NULL) { |
| 1811 CloseHandle(profiled_thread_); |
| 1812 profiled_thread_ = NULL; |
| 1813 } |
| 1855 } | 1814 } |
| 1856 | 1815 |
| 1857 Sampler* sampler_; | 1816 HANDLE profiled_thread() { return profiled_thread_; } |
| 1858 HANDLE sampler_thread_; | 1817 |
| 1818 private: |
| 1859 HANDLE profiled_thread_; | 1819 HANDLE profiled_thread_; |
| 1820 }; |
| 1860 | 1821 |
| 1861 // Sampler thread handler. | 1822 |
| 1862 void Runner() { | 1823 class SamplerThread : public Thread { |
| 1824 public: |
| 1825 explicit SamplerThread(int interval) : Thread(NULL), interval_(interval) {} |
| 1826 |
| 1827 static void AddActiveSampler(Sampler* sampler) { |
| 1828 ScopedLock lock(mutex_); |
| 1829 SamplerRegistry::AddActiveSampler(sampler); |
| 1830 if (instance_ == NULL) { |
| 1831 instance_ = new SamplerThread(sampler->interval()); |
| 1832 instance_->Start(); |
| 1833 } else { |
| 1834 ASSERT(instance_->interval_ == sampler->interval()); |
| 1835 } |
| 1836 } |
| 1837 |
| 1838 static void RemoveActiveSampler(Sampler* sampler) { |
| 1839 ScopedLock lock(mutex_); |
| 1840 SamplerRegistry::RemoveActiveSampler(sampler); |
| 1841 if (SamplerRegistry::GetState() == SamplerRegistry::HAS_NO_SAMPLERS) { |
| 1842 RuntimeProfiler::WakeUpRuntimeProfilerThreadBeforeShutdown(); |
| 1843 instance_->Join(); |
| 1844 delete instance_; |
| 1845 instance_ = NULL; |
| 1846 } |
| 1847 } |
| 1848 |
| 1849 // Implement Thread::Run(). |
| 1850 virtual void Run() { |
| 1851 SamplerRegistry::State state = SamplerRegistry::GetState(); |
| 1852 while (state != SamplerRegistry::HAS_NO_SAMPLERS) { |
| 1853 bool cpu_profiling_enabled = |
| 1854 (state == SamplerRegistry::HAS_CPU_PROFILING_SAMPLERS); |
| 1855 bool runtime_profiler_enabled = RuntimeProfiler::IsEnabled(); |
| 1856 // When CPU profiling is enabled both JavaScript and C++ code is |
| 1857 // profiled. We must not suspend. |
| 1858 if (!cpu_profiling_enabled) { |
| 1859 if (rate_limiter_.SuspendIfNecessary()) continue; |
| 1860 } |
| 1861 if (cpu_profiling_enabled) { |
| 1862 if (!SamplerRegistry::IterateActiveSamplers(&DoCpuProfile, this)) { |
| 1863 return; |
| 1864 } |
| 1865 } |
| 1866 if (runtime_profiler_enabled) { |
| 1867 if (!SamplerRegistry::IterateActiveSamplers(&DoRuntimeProfile, NULL)) { |
| 1868 return; |
| 1869 } |
| 1870 } |
| 1871 OS::Sleep(interval_); |
| 1872 } |
| 1873 } |
| 1874 |
| 1875 static void DoCpuProfile(Sampler* sampler, void* raw_sampler_thread) { |
| 1876 if (!sampler->IsProfiling()) return; |
| 1877 SamplerThread* sampler_thread = |
| 1878 reinterpret_cast<SamplerThread*>(raw_sampler_thread); |
| 1879 sampler_thread->SampleContext(sampler); |
| 1880 } |
| 1881 |
| 1882 static void DoRuntimeProfile(Sampler* sampler, void* ignored) { |
| 1883 if (!sampler->isolate()->IsInitialized()) return; |
| 1884 sampler->isolate()->runtime_profiler()->NotifyTick(); |
| 1885 } |
| 1886 |
| 1887 void SampleContext(Sampler* sampler) { |
| 1888 HANDLE profiled_thread = sampler->platform_data()->profiled_thread(); |
| 1889 if (profiled_thread == NULL) return; |
| 1890 |
| 1863 // Context used for sampling the register state of the profiled thread. | 1891 // Context used for sampling the register state of the profiled thread. |
| 1864 CONTEXT context; | 1892 CONTEXT context; |
| 1865 memset(&context, 0, sizeof(context)); | 1893 memset(&context, 0, sizeof(context)); |
| 1866 // Loop until the sampler is disengaged, keeping the specified | |
| 1867 // sampling frequency. | |
| 1868 for ( ; sampler_->IsActive(); Sleep(sampler_->interval_)) { | |
| 1869 TickSample sample_obj; | |
| 1870 TickSample* sample = CpuProfiler::TickSampleEvent(); | |
| 1871 if (sample == NULL) sample = &sample_obj; | |
| 1872 | 1894 |
| 1873 // If the sampler runs in sync with the JS thread, we try to | 1895 TickSample sample_obj; |
| 1874 // suspend it. If we fail, we skip the current sample. | 1896 TickSample* sample = CpuProfiler::TickSampleEvent(sampler->isolate()); |
| 1875 if (sampler_->IsSynchronous()) { | 1897 if (sample == NULL) sample = &sample_obj; |
| 1876 static const DWORD kSuspendFailed = static_cast<DWORD>(-1); | |
| 1877 if (SuspendThread(profiled_thread_) == kSuspendFailed) continue; | |
| 1878 } | |
| 1879 | 1898 |
| 1880 // We always sample the VM state. | 1899 static const DWORD kSuspendFailed = static_cast<DWORD>(-1); |
| 1881 sample->state = VMState::current_state(); | 1900 if (SuspendThread(profiled_thread) == kSuspendFailed) return; |
| 1901 sample->state = sampler->isolate()->current_vm_state(); |
| 1882 | 1902 |
| 1883 // If profiling, we record the pc and sp of the profiled thread. | 1903 context.ContextFlags = CONTEXT_FULL; |
| 1884 if (sampler_->IsProfiling()) { | 1904 if (GetThreadContext(profiled_thread, &context) != 0) { |
| 1885 context.ContextFlags = CONTEXT_FULL; | |
| 1886 if (GetThreadContext(profiled_thread_, &context) != 0) { | |
| 1887 #if V8_HOST_ARCH_X64 | 1905 #if V8_HOST_ARCH_X64 |
| 1888 sample->pc = reinterpret_cast<Address>(context.Rip); | 1906 sample->pc = reinterpret_cast<Address>(context.Rip); |
| 1889 sample->sp = reinterpret_cast<Address>(context.Rsp); | 1907 sample->sp = reinterpret_cast<Address>(context.Rsp); |
| 1890 sample->fp = reinterpret_cast<Address>(context.Rbp); | 1908 sample->fp = reinterpret_cast<Address>(context.Rbp); |
| 1891 #else | 1909 #else |
| 1892 sample->pc = reinterpret_cast<Address>(context.Eip); | 1910 sample->pc = reinterpret_cast<Address>(context.Eip); |
| 1893 sample->sp = reinterpret_cast<Address>(context.Esp); | 1911 sample->sp = reinterpret_cast<Address>(context.Esp); |
| 1894 sample->fp = reinterpret_cast<Address>(context.Ebp); | 1912 sample->fp = reinterpret_cast<Address>(context.Ebp); |
| 1895 #endif | 1913 #endif |
| 1896 sampler_->SampleStack(sample); | 1914 sampler->SampleStack(sample); |
| 1897 } | 1915 sampler->Tick(sample); |
| 1898 } | 1916 } |
| 1917 ResumeThread(profiled_thread); |
| 1918 } |
| 1899 | 1919 |
| 1900 // Invoke tick handler with program counter and stack pointer. | 1920 const int interval_; |
| 1901 sampler_->Tick(sample); | 1921 RuntimeProfilerRateLimiter rate_limiter_; |
| 1902 | 1922 |
| 1903 // If the sampler runs in sync with the JS thread, we have to | 1923 // Protects the process wide state below. |
| 1904 // remember to resume it. | 1924 static Mutex* mutex_; |
| 1905 if (sampler_->IsSynchronous()) ResumeThread(profiled_thread_); | 1925 static SamplerThread* instance_; |
| 1906 } | 1926 |
| 1907 } | 1927 DISALLOW_COPY_AND_ASSIGN(SamplerThread); |
| 1908 }; | 1928 }; |
| 1909 | 1929 |
| 1910 | 1930 |
| 1911 // Entry point for sampler thread. | 1931 Mutex* SamplerThread::mutex_ = OS::CreateMutex(); |
| 1912 static unsigned int __stdcall SamplerEntry(void* arg) { | 1932 SamplerThread* SamplerThread::instance_ = NULL; |
| 1913 Sampler::PlatformData* data = | |
| 1914 reinterpret_cast<Sampler::PlatformData*>(arg); | |
| 1915 Thread::SetThreadLocal(Isolate::isolate_key(), data->sampler_->isolate()); | |
| 1916 data->Runner(); | |
| 1917 return 0; | |
| 1918 } | |
| 1919 | 1933 |
| 1920 | 1934 |
| 1921 // Initialize a profile sampler. | 1935 Sampler::Sampler(Isolate* isolate, int interval) |
| 1922 Sampler::Sampler(Isolate* isolate, int interval, bool profiling) | |
| 1923 : isolate_(isolate), | 1936 : isolate_(isolate), |
| 1924 interval_(interval), | 1937 interval_(interval), |
| 1925 profiling_(profiling), | 1938 profiling_(false), |
| 1926 synchronous_(profiling), | |
| 1927 active_(false), | 1939 active_(false), |
| 1928 samples_taken_(0) { | 1940 samples_taken_(0) { |
| 1929 data_ = new PlatformData(this); | 1941 data_ = new PlatformData; |
| 1930 } | 1942 } |
| 1931 | 1943 |
| 1932 | 1944 |
| 1933 Sampler::~Sampler() { | 1945 Sampler::~Sampler() { |
| 1946 ASSERT(!IsActive()); |
| 1934 delete data_; | 1947 delete data_; |
| 1935 } | 1948 } |
| 1936 | 1949 |
| 1937 | 1950 |
| 1938 // Start profiling. | |
| 1939 void Sampler::Start() { | 1951 void Sampler::Start() { |
| 1940 // If we are starting a synchronous sampler, we need to be able to | 1952 ASSERT(!IsActive()); |
| 1941 // access the calling thread. | 1953 SetActive(true); |
| 1942 if (IsSynchronous()) { | 1954 SamplerThread::AddActiveSampler(this); |
| 1943 // Get a handle to the calling thread. This is the thread that we are | |
| 1944 // going to profile. We need to make a copy of the handle because we are | |
| 1945 // going to use it in the sampler thread. Using GetThreadHandle() will | |
| 1946 // not work in this case. We're using OpenThread because DuplicateHandle | |
| 1947 // for some reason doesn't work in Chrome's sandbox. | |
| 1948 data_->profiled_thread_ = OpenThread(THREAD_GET_CONTEXT | | |
| 1949 THREAD_SUSPEND_RESUME | | |
| 1950 THREAD_QUERY_INFORMATION, | |
| 1951 FALSE, | |
| 1952 GetCurrentThreadId()); | |
| 1953 BOOL ok = data_->profiled_thread_ != NULL; | |
| 1954 if (!ok) return; | |
| 1955 } | |
| 1956 | |
| 1957 // Start sampler thread. | |
| 1958 unsigned int tid; | |
| 1959 active_ = true; | |
| 1960 data_->sampler_thread_ = reinterpret_cast<HANDLE>( | |
| 1961 _beginthreadex(NULL, 0, SamplerEntry, data_, 0, &tid)); | |
| 1962 // Set thread to high priority to increase sampling accuracy. | |
| 1963 SetThreadPriority(data_->sampler_thread_, THREAD_PRIORITY_TIME_CRITICAL); | |
| 1964 } | 1955 } |
| 1965 | 1956 |
| 1966 | 1957 |
| 1967 // Stop profiling. | |
| 1968 void Sampler::Stop() { | 1958 void Sampler::Stop() { |
| 1969 // Seting active to false triggers termination of the sampler | 1959 ASSERT(IsActive()); |
| 1970 // thread. | 1960 SamplerThread::RemoveActiveSampler(this); |
| 1971 active_ = false; | 1961 SetActive(false); |
| 1972 | |
| 1973 // Wait for sampler thread to terminate. | |
| 1974 WaitForSingleObject(data_->sampler_thread_, INFINITE); | |
| 1975 | |
| 1976 // Release the thread handles | |
| 1977 CloseHandle(data_->sampler_thread_); | |
| 1978 CloseHandle(data_->profiled_thread_); | |
| 1979 } | 1962 } |
| 1980 | 1963 |
| 1981 | |
| 1982 #endif // ENABLE_LOGGING_AND_PROFILING | 1964 #endif // ENABLE_LOGGING_AND_PROFILING |
| 1983 | 1965 |
| 1984 } } // namespace v8::internal | 1966 } } // namespace v8::internal |
| OLD | NEW |