1 // Copyright 2012 the V8 project authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 // Platform-specific code for Win32.
7 // Secure API functions are not available using MinGW with msvcrt.dll
8 // on Windows XP. Make sure MINGW_HAS_SECURE_API is not defined to
9 // disable definition of secure API functions in standard headers that
10 // would conflict with our own implementation.
13 #ifdef MINGW_HAS_SECURE_API
14 #undef MINGW_HAS_SECURE_API
15 #endif // MINGW_HAS_SECURE_API
22 #include "src/base/win32-headers.h"
24 #include "src/base/lazy-instance.h"
25 #include "src/base/macros.h"
26 #include "src/base/platform/platform.h"
27 #include "src/base/platform/time.h"
28 #include "src/base/utils/random-number-generator.h"
32 // Case-insensitive bounded string comparisons. Use stricmp() on Win32. Usually
33 // defined in strings.h.
34 int strncasecmp(const char* s1, const char* s2, int n) {
35 return _strnicmp(s1, s2, n);
41 // Extra functions for MinGW. Most of these are the _s functions which are in
42 // the Microsoft Visual Studio C++ CRT.
46 #ifndef __MINGW64_VERSION_MAJOR
51 inline void MemoryBarrier() {
53 __asm__ __volatile__("xchgl %%eax,%0 ":"=r" (barrier));
56 #endif // __MINGW64_VERSION_MAJOR
59 int localtime_s(tm* out_tm, const time_t* time) {
60 tm* posix_local_time_struct = localtime(time);
61 if (posix_local_time_struct == NULL) return 1;
62 *out_tm = *posix_local_time_struct;
67 int fopen_s(FILE** pFile, const char* filename, const char* mode) {
68 *pFile = fopen(filename, mode);
69 return *pFile != NULL ? 0 : 1;
72 int _vsnprintf_s(char* buffer, size_t sizeOfBuffer, size_t count,
73 const char* format, va_list argptr) {
74 DCHECK(count == _TRUNCATE);
75 return _vsnprintf(buffer, sizeOfBuffer, format, argptr);
79 int strncpy_s(char* dest, size_t dest_size, const char* source, size_t count) {
80 CHECK(source != NULL);
82 CHECK_GT(dest_size, 0);
84 if (count == _TRUNCATE) {
85 while (dest_size > 0 && *source != 0) {
86 *(dest++) = *(source++);
94 while (dest_size > 0 && count > 0 && *source != 0) {
95 *(dest++) = *(source++);
100 CHECK_GT(dest_size, 0);
105 #endif // __MINGW32__
112 bool g_hard_abort = false;
116 intptr_t OS::MaxVirtualMemory() {
121 class TimezoneCache {
123 TimezoneCache() : initialized_(false) { }
126 initialized_ = false;
129 // Initialize timezone information. The timezone information is obtained from
130 // windows. If we cannot get the timezone information we fall back to CET.
131 void InitializeIfNeeded() {
132 // Just return if timezone information has already been initialized.
133 if (initialized_) return;
135 // Initialize POSIX time zone data.
137 // Obtain timezone information from operating system.
138 memset(&tzinfo_, 0, sizeof(tzinfo_));
139 if (GetTimeZoneInformation(&tzinfo_) == TIME_ZONE_ID_INVALID) {
140 // If we cannot get timezone information we fall back to CET.
142 tzinfo_.StandardDate.wMonth = 10;
143 tzinfo_.StandardDate.wDay = 5;
144 tzinfo_.StandardDate.wHour = 3;
145 tzinfo_.StandardBias = 0;
146 tzinfo_.DaylightDate.wMonth = 3;
147 tzinfo_.DaylightDate.wDay = 5;
148 tzinfo_.DaylightDate.wHour = 2;
149 tzinfo_.DaylightBias = -60;
152 // Make standard and DST timezone names.
153 WideCharToMultiByte(CP_UTF8, 0, tzinfo_.StandardName, -1,
154 std_tz_name_, kTzNameSize, NULL, NULL);
155 std_tz_name_[kTzNameSize - 1] = '\0';
156 WideCharToMultiByte(CP_UTF8, 0, tzinfo_.DaylightName, -1,
157 dst_tz_name_, kTzNameSize, NULL, NULL);
158 dst_tz_name_[kTzNameSize - 1] = '\0';
160 // If OS returned empty string or resource id (like "@tzres.dll,-211")
161 // simply guess the name from the UTC bias of the timezone.
162 // To properly resolve the resource identifier requires a library load,
163 // which is not possible in a sandbox.
164 if (std_tz_name_[0] == '\0' || std_tz_name_[0] == '@') {
165 OS::SNPrintF(std_tz_name_, kTzNameSize - 1,
167 GuessTimezoneNameFromBias(tzinfo_.Bias));
169 if (dst_tz_name_[0] == '\0' || dst_tz_name_[0] == '@') {
170 OS::SNPrintF(dst_tz_name_, kTzNameSize - 1,
172 GuessTimezoneNameFromBias(tzinfo_.Bias));
174 // Timezone information initialized.
178 // Guess the name of the timezone from the bias.
179 // The guess is very biased towards the northern hemisphere.
180 const char* GuessTimezoneNameFromBias(int bias) {
181 static const int kHour = 60;
183 case -9*kHour: return "Alaska";
184 case -8*kHour: return "Pacific";
185 case -7*kHour: return "Mountain";
186 case -6*kHour: return "Central";
187 case -5*kHour: return "Eastern";
188 case -4*kHour: return "Atlantic";
189 case 0*kHour: return "GMT";
190 case +1*kHour: return "Central Europe";
191 case +2*kHour: return "Eastern Europe";
192 case +3*kHour: return "Russia";
193 case +5*kHour + 30: return "India";
194 case +8*kHour: return "China";
195 case +9*kHour: return "Japan";
196 case +12*kHour: return "New Zealand";
197 default: return "Local";
203 static const int kTzNameSize = 128;
205 char std_tz_name_[kTzNameSize];
206 char dst_tz_name_[kTzNameSize];
207 TIME_ZONE_INFORMATION tzinfo_;
208 friend class Win32Time;
212 // ----------------------------------------------------------------------------
213 // The Time class represents time on win32. A timestamp is represented as
214 // a 64-bit integer in 100 nanoseconds since January 1, 1601 (UTC). JavaScript
215 // timestamps are represented as a doubles in milliseconds since 00:00:00 UTC,
222 explicit Win32Time(double jstime);
223 Win32Time(int year, int mon, int day, int hour, int min, int sec);
225 // Convert timestamp to JavaScript representation.
228 // Set timestamp to current time.
229 void SetToCurrentTime();
231 // Returns the local timezone offset in milliseconds east of UTC. This is
232 // the number of milliseconds you must add to UTC to get local time, i.e.
233 // LocalOffset(CET) = 3600000 and LocalOffset(PST) = -28800000. This
234 // routine also takes into account whether daylight saving is effect
236 int64_t LocalOffset(TimezoneCache* cache);
238 // Returns the daylight savings time offset for the time in milliseconds.
239 int64_t DaylightSavingsOffset(TimezoneCache* cache);
241 // Returns a string identifying the current timezone for the
242 // timestamp taking into account daylight saving.
243 char* LocalTimezone(TimezoneCache* cache);
246 // Constants for time conversion.
247 static const int64_t kTimeEpoc = 116444736000000000LL;
248 static const int64_t kTimeScaler = 10000;
249 static const int64_t kMsPerMinute = 60000;
251 // Constants for timezone information.
252 static const bool kShortTzNames = false;
254 // Return whether or not daylight savings time is in effect at this time.
255 bool InDST(TimezoneCache* cache);
257 // Accessor for FILETIME representation.
258 FILETIME& ft() { return time_.ft_; }
260 // Accessor for integer representation.
261 int64_t& t() { return time_.t_; }
263 // Although win32 uses 64-bit integers for representing timestamps,
264 // these are packed into a FILETIME structure. The FILETIME structure
265 // is just a struct representing a 64-bit integer. The TimeStamp union
266 // allows access to both a FILETIME and an integer representation of
277 // Initialize timestamp to start of epoc.
278 Win32Time::Win32Time() {
283 // Initialize timestamp from a JavaScript timestamp.
284 Win32Time::Win32Time(double jstime) {
285 t() = static_cast<int64_t>(jstime) * kTimeScaler + kTimeEpoc;
289 // Initialize timestamp from date/time components.
290 Win32Time::Win32Time(int year, int mon, int day, int hour, int min, int sec) {
298 st.wMilliseconds = 0;
299 SystemTimeToFileTime(&st, &ft());
303 // Convert timestamp to JavaScript timestamp.
304 double Win32Time::ToJSTime() {
305 return static_cast<double>((t() - kTimeEpoc) / kTimeScaler);
309 // Set timestamp to current time.
310 void Win32Time::SetToCurrentTime() {
311 // The default GetSystemTimeAsFileTime has a ~15.5ms resolution.
312 // Because we're fast, we like fast timers which have at least a
315 // timeGetTime() provides 1ms granularity when combined with
316 // timeBeginPeriod(). If the host application for v8 wants fast
317 // timers, it can use timeBeginPeriod to increase the resolution.
319 // Using timeGetTime() has a drawback because it is a 32bit value
320 // and hence rolls-over every ~49days.
322 // To use the clock, we use GetSystemTimeAsFileTime as our base;
323 // and then use timeGetTime to extrapolate current time from the
324 // start time. To deal with rollovers, we resync the clock
325 // any time when more than kMaxClockElapsedTime has passed or
326 // whenever timeGetTime creates a rollover.
328 static bool initialized = false;
329 static TimeStamp init_time;
330 static DWORD init_ticks;
331 static const int64_t kHundredNanosecondsPerSecond = 10000000;
332 static const int64_t kMaxClockElapsedTime =
333 60*kHundredNanosecondsPerSecond; // 1 minute
335 // If we are uninitialized, we need to resync the clock.
336 bool needs_resync = !initialized;
338 // Get the current time.
340 GetSystemTimeAsFileTime(&time_now.ft_);
341 DWORD ticks_now = timeGetTime();
343 // Check if we need to resync due to clock rollover.
344 needs_resync |= ticks_now < init_ticks;
346 // Check if we need to resync due to elapsed time.
347 needs_resync |= (time_now.t_ - init_time.t_) > kMaxClockElapsedTime;
349 // Check if we need to resync due to backwards time change.
350 needs_resync |= time_now.t_ < init_time.t_;
352 // Resync the clock if necessary.
354 GetSystemTimeAsFileTime(&init_time.ft_);
355 init_ticks = ticks_now = timeGetTime();
359 // Finally, compute the actual time. Why is this so hard.
360 DWORD elapsed = ticks_now - init_ticks;
361 this->time_.t_ = init_time.t_ + (static_cast<int64_t>(elapsed) * 10000);
365 // Return the local timezone offset in milliseconds east of UTC. This
366 // takes into account whether daylight saving is in effect at the time.
367 // Only times in the 32-bit Unix range may be passed to this function.
368 // Also, adding the time-zone offset to the input must not overflow.
369 // The function EquivalentTime() in date.js guarantees this.
370 int64_t Win32Time::LocalOffset(TimezoneCache* cache) {
371 cache->InitializeIfNeeded();
373 Win32Time rounded_to_second(*this);
374 rounded_to_second.t() = rounded_to_second.t() / 1000 / kTimeScaler *
376 // Convert to local time using POSIX localtime function.
377 // Windows XP Service Pack 3 made SystemTimeToTzSpecificLocalTime()
378 // very slow. Other browsers use localtime().
380 // Convert from JavaScript milliseconds past 1/1/1970 0:00:00 to
381 // POSIX seconds past 1/1/1970 0:00:00.
382 double unchecked_posix_time = rounded_to_second.ToJSTime() / 1000;
383 if (unchecked_posix_time > INT_MAX || unchecked_posix_time < 0) {
386 // Because _USE_32BIT_TIME_T is defined, time_t is a 32-bit int.
387 time_t posix_time = static_cast<time_t>(unchecked_posix_time);
389 // Convert to local time, as struct with fields for day, hour, year, etc.
390 tm posix_local_time_struct;
391 if (localtime_s(&posix_local_time_struct, &posix_time)) return 0;
393 if (posix_local_time_struct.tm_isdst > 0) {
394 return (cache->tzinfo_.Bias + cache->tzinfo_.DaylightBias) * -kMsPerMinute;
395 } else if (posix_local_time_struct.tm_isdst == 0) {
396 return (cache->tzinfo_.Bias + cache->tzinfo_.StandardBias) * -kMsPerMinute;
398 return cache->tzinfo_.Bias * -kMsPerMinute;
403 // Return whether or not daylight savings time is in effect at this time.
404 bool Win32Time::InDST(TimezoneCache* cache) {
405 cache->InitializeIfNeeded();
407 // Determine if DST is in effect at the specified time.
409 if (cache->tzinfo_.StandardDate.wMonth != 0 ||
410 cache->tzinfo_.DaylightDate.wMonth != 0) {
411 // Get the local timezone offset for the timestamp in milliseconds.
412 int64_t offset = LocalOffset(cache);
414 // Compute the offset for DST. The bias parameters in the timezone info
415 // are specified in minutes. These must be converted to milliseconds.
417 -(cache->tzinfo_.Bias + cache->tzinfo_.DaylightBias) * kMsPerMinute;
419 // If the local time offset equals the timezone bias plus the daylight
420 // bias then DST is in effect.
421 in_dst = offset == dstofs;
428 // Return the daylight savings time offset for this time.
429 int64_t Win32Time::DaylightSavingsOffset(TimezoneCache* cache) {
430 return InDST(cache) ? 60 * kMsPerMinute : 0;
434 // Returns a string identifying the current timezone for the
435 // timestamp taking into account daylight saving.
436 char* Win32Time::LocalTimezone(TimezoneCache* cache) {
437 // Return the standard or DST time zone name based on whether daylight
438 // saving is in effect at the given time.
439 return InDST(cache) ? cache->dst_tz_name_ : cache->std_tz_name_;
443 // Returns the accumulated user time for thread.
444 int OS::GetUserTime(uint32_t* secs, uint32_t* usecs) {
448 // Get the amount of time that the thread has executed in user mode.
449 if (!GetThreadTimes(GetCurrentThread(), &dummy, &dummy, &dummy,
450 reinterpret_cast<FILETIME*>(&usertime))) return -1;
452 // Adjust the resolution to micro-seconds.
455 // Convert to seconds and microseconds
456 *secs = static_cast<uint32_t>(usertime / 1000000);
457 *usecs = static_cast<uint32_t>(usertime % 1000000);
462 // Returns current time as the number of milliseconds since
463 // 00:00:00 UTC, January 1, 1970.
464 double OS::TimeCurrentMillis() {
465 return Time::Now().ToJsTime();
469 TimezoneCache* OS::CreateTimezoneCache() {
470 return new TimezoneCache();
474 void OS::DisposeTimezoneCache(TimezoneCache* cache) {
479 void OS::ClearTimezoneCache(TimezoneCache* cache) {
484 // Returns a string identifying the current timezone taking into
485 // account daylight saving.
486 const char* OS::LocalTimezone(double time, TimezoneCache* cache) {
487 return Win32Time(time).LocalTimezone(cache);
491 // Returns the local time offset in milliseconds east of UTC without
492 // taking daylight savings time into account.
493 double OS::LocalTimeOffset(TimezoneCache* cache) {
494 // Use current time, rounded to the millisecond.
495 Win32Time t(TimeCurrentMillis());
496 // Time::LocalOffset inlcudes any daylight savings offset, so subtract it.
497 return static_cast<double>(t.LocalOffset(cache) -
498 t.DaylightSavingsOffset(cache));
502 // Returns the daylight savings offset in milliseconds for the given
504 double OS::DaylightSavingsOffset(double time, TimezoneCache* cache) {
505 int64_t offset = Win32Time(time).DaylightSavingsOffset(cache);
506 return static_cast<double>(offset);
510 int OS::GetLastError() {
511 return ::GetLastError();
515 int OS::GetCurrentProcessId() {
516 return static_cast<int>(::GetCurrentProcessId());
520 int OS::GetCurrentThreadId() {
521 return static_cast<int>(::GetCurrentThreadId());
525 // ----------------------------------------------------------------------------
526 // Win32 console output.
528 // If a Win32 application is linked as a console application it has a normal
529 // standard output and standard error. In this case normal printf works fine
530 // for output. However, if the application is linked as a GUI application,
531 // the process doesn't have a console, and therefore (debugging) output is lost.
532 // This is the case if we are embedded in a windows program (like a browser).
533 // In order to be able to get debug output in this case the the debugging
534 // facility using OutputDebugString. This output goes to the active debugger
535 // for the process (if any). Else the output can be monitored using DBMON.EXE.
538 UNKNOWN, // Output method has not yet been determined.
539 CONSOLE, // Output is written to stdout.
540 ODS // Output is written to debug facility.
543 static OutputMode output_mode = UNKNOWN; // Current output mode.
546 // Determine if the process has a console for output.
547 static bool HasConsole() {
548 // Only check the first time. Eventual race conditions are not a problem,
549 // because all threads will eventually determine the same mode.
550 if (output_mode == UNKNOWN) {
551 // We cannot just check that the standard output is attached to a console
552 // because this would fail if output is redirected to a file. Therefore we
553 // say that a process does not have an output console if either the
554 // standard output handle is invalid or its file type is unknown.
555 if (GetStdHandle(STD_OUTPUT_HANDLE) != INVALID_HANDLE_VALUE &&
556 GetFileType(GetStdHandle(STD_OUTPUT_HANDLE)) != FILE_TYPE_UNKNOWN)
557 output_mode = CONSOLE;
561 return output_mode == CONSOLE;
565 static void VPrintHelper(FILE* stream, const char* format, va_list args) {
566 if ((stream == stdout || stream == stderr) && !HasConsole()) {
567 // It is important to use safe print here in order to avoid
568 // overflowing the buffer. We might truncate the output, but this
571 OS::VSNPrintF(buffer, sizeof(buffer), format, args);
572 OutputDebugStringA(buffer);
574 vfprintf(stream, format, args);
579 FILE* OS::FOpen(const char* path, const char* mode) {
581 if (fopen_s(&result, path, mode) == 0) {
589 bool OS::Remove(const char* path) {
590 return (DeleteFileA(path) != 0);
594 FILE* OS::OpenTemporaryFile() {
595 // tmpfile_s tries to use the root dir, don't use it.
596 char tempPathBuffer[MAX_PATH];
597 DWORD path_result = 0;
598 path_result = GetTempPathA(MAX_PATH, tempPathBuffer);
599 if (path_result > MAX_PATH || path_result == 0) return NULL;
600 UINT name_result = 0;
601 char tempNameBuffer[MAX_PATH];
602 name_result = GetTempFileNameA(tempPathBuffer, "", 0, tempNameBuffer);
603 if (name_result == 0) return NULL;
604 FILE* result = FOpen(tempNameBuffer, "w+"); // Same mode as tmpfile uses.
605 if (result != NULL) {
606 Remove(tempNameBuffer); // Delete on close.
612 // Open log file in binary mode to avoid /n -> /r/n conversion.
613 const char* const OS::LogFileOpenMode = "wb";
616 // Print (debug) message to console.
617 void OS::Print(const char* format, ...) {
619 va_start(args, format);
620 VPrint(format, args);
625 void OS::VPrint(const char* format, va_list args) {
626 VPrintHelper(stdout, format, args);
630 void OS::FPrint(FILE* out, const char* format, ...) {
632 va_start(args, format);
633 VFPrint(out, format, args);
638 void OS::VFPrint(FILE* out, const char* format, va_list args) {
639 VPrintHelper(out, format, args);
643 // Print error message to console.
644 void OS::PrintError(const char* format, ...) {
646 va_start(args, format);
647 VPrintError(format, args);
652 void OS::VPrintError(const char* format, va_list args) {
653 VPrintHelper(stderr, format, args);
657 int OS::SNPrintF(char* str, int length, const char* format, ...) {
659 va_start(args, format);
660 int result = VSNPrintF(str, length, format, args);
666 int OS::VSNPrintF(char* str, int length, const char* format, va_list args) {
667 int n = _vsnprintf_s(str, length, _TRUNCATE, format, args);
668 // Make sure to zero-terminate the string if the output was
669 // truncated or if there was an error.
670 if (n < 0 || n >= length) {
672 str[length - 1] = '\0';
680 char* OS::StrChr(char* str, int c) {
681 return const_cast<char*>(strchr(str, c));
685 void OS::StrNCpy(char* dest, int length, const char* src, size_t n) {
686 // Use _TRUNCATE or strncpy_s crashes (by design) if buffer is too small.
687 size_t buffer_size = static_cast<size_t>(length);
688 if (n + 1 > buffer_size) // count for trailing '\0'
690 int result = strncpy_s(dest, length, src, n);
692 DCHECK(result == 0 || (n == _TRUNCATE && result == STRUNCATE));
700 // Get the system's page size used by VirtualAlloc() or the next power
701 // of two. The reason for always returning a power of two is that the
702 // rounding up in OS::Allocate expects that.
703 static size_t GetPageSize() {
704 static size_t page_size = 0;
705 if (page_size == 0) {
707 GetSystemInfo(&info);
708 page_size = RoundUpToPowerOf2(info.dwPageSize);
714 // The allocation alignment is the guaranteed alignment for
715 // VirtualAlloc'ed blocks of memory.
716 size_t OS::AllocateAlignment() {
717 static size_t allocate_alignment = 0;
718 if (allocate_alignment == 0) {
720 GetSystemInfo(&info);
721 allocate_alignment = info.dwAllocationGranularity;
723 return allocate_alignment;
727 static LazyInstance<RandomNumberGenerator>::type
728 platform_random_number_generator = LAZY_INSTANCE_INITIALIZER;
731 void OS::Initialize(int64_t random_seed, bool hard_abort,
732 const char* const gc_fake_mmap) {
734 platform_random_number_generator.Pointer()->SetSeed(random_seed);
736 g_hard_abort = hard_abort;
740 void* OS::GetRandomMmapAddr() {
741 // The address range used to randomize RWX allocations in OS::Allocate
742 // Try not to map pages into the default range that windows loads DLLs
743 // Use a multiple of 64k to prevent committing unused memory.
744 // Note: This does not guarantee RWX regions will be within the
745 // range kAllocationRandomAddressMin to kAllocationRandomAddressMax
746 #ifdef V8_HOST_ARCH_64_BIT
747 static const intptr_t kAllocationRandomAddressMin = 0x0000000080000000;
748 static const intptr_t kAllocationRandomAddressMax = 0x000003FFFFFF0000;
750 static const intptr_t kAllocationRandomAddressMin = 0x04000000;
751 static const intptr_t kAllocationRandomAddressMax = 0x3FFF0000;
754 (platform_random_number_generator.Pointer()->NextInt() << kPageSizeBits) |
755 kAllocationRandomAddressMin;
756 address &= kAllocationRandomAddressMax;
757 return reinterpret_cast<void *>(address);
761 static void* RandomizedVirtualAlloc(size_t size, int action, int protection) {
764 if (protection == PAGE_EXECUTE_READWRITE || protection == PAGE_NOACCESS) {
765 // For exectutable pages try and randomize the allocation address
766 for (size_t attempts = 0; base == NULL && attempts < 3; ++attempts) {
767 base = VirtualAlloc(OS::GetRandomMmapAddr(), size, action, protection);
771 // After three attempts give up and let the OS find an address to use.
772 if (base == NULL) base = VirtualAlloc(NULL, size, action, protection);
778 void* OS::Allocate(const size_t requested,
780 bool is_executable) {
781 // VirtualAlloc rounds allocated size to page size automatically.
782 size_t msize = RoundUp(requested, static_cast<int>(GetPageSize()));
784 // Windows XP SP2 allows Data Excution Prevention (DEP).
785 int prot = is_executable ? PAGE_EXECUTE_READWRITE : PAGE_READWRITE;
787 LPVOID mbase = RandomizedVirtualAlloc(msize,
788 MEM_COMMIT | MEM_RESERVE,
791 if (mbase == NULL) return NULL;
793 DCHECK(IsAligned(reinterpret_cast<size_t>(mbase), OS::AllocateAlignment()));
800 void OS::Free(void* address, const size_t size) {
801 // TODO(1240712): VirtualFree has a return value which is ignored here.
802 VirtualFree(address, 0, MEM_RELEASE);
807 intptr_t OS::CommitPageSize() {
812 void OS::ProtectCode(void* address, const size_t size) {
814 VirtualProtect(address, size, PAGE_EXECUTE_READ, &old_protect);
818 void OS::Guard(void* address, const size_t size) {
820 VirtualProtect(address, size, PAGE_NOACCESS, &oldprotect);
824 void OS::Sleep(int milliseconds) {
825 ::Sleep(milliseconds);
831 V8_IMMEDIATE_CRASH();
833 // Make the MSVCRT do a silent abort.
838 void OS::DebugBreak() {
840 // To avoid Visual Studio runtime support the following code can be used
850 class Win32MemoryMappedFile : public OS::MemoryMappedFile {
852 Win32MemoryMappedFile(HANDLE file,
857 file_mapping_(file_mapping),
860 virtual ~Win32MemoryMappedFile();
861 virtual void* memory() { return memory_; }
862 virtual int size() { return size_; }
865 HANDLE file_mapping_;
871 OS::MemoryMappedFile* OS::MemoryMappedFile::open(const char* name) {
872 // Open a physical file
873 HANDLE file = CreateFileA(name, GENERIC_READ | GENERIC_WRITE,
874 FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL);
875 if (file == INVALID_HANDLE_VALUE) return NULL;
877 int size = static_cast<int>(GetFileSize(file, NULL));
879 // Create a file mapping for the physical file
880 HANDLE file_mapping = CreateFileMapping(file, NULL,
881 PAGE_READWRITE, 0, static_cast<DWORD>(size), NULL);
882 if (file_mapping == NULL) return NULL;
884 // Map a view of the file into memory
885 void* memory = MapViewOfFile(file_mapping, FILE_MAP_ALL_ACCESS, 0, 0, size);
886 return new Win32MemoryMappedFile(file, file_mapping, memory, size);
890 OS::MemoryMappedFile* OS::MemoryMappedFile::create(const char* name, int size,
892 // Open a physical file
893 HANDLE file = CreateFileA(name, GENERIC_READ | GENERIC_WRITE,
894 FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_ALWAYS, 0, NULL);
895 if (file == NULL) return NULL;
896 // Create a file mapping for the physical file
897 HANDLE file_mapping = CreateFileMapping(file, NULL,
898 PAGE_READWRITE, 0, static_cast<DWORD>(size), NULL);
899 if (file_mapping == NULL) return NULL;
900 // Map a view of the file into memory
901 void* memory = MapViewOfFile(file_mapping, FILE_MAP_ALL_ACCESS, 0, 0, size);
902 if (memory) memmove(memory, initial, size);
903 return new Win32MemoryMappedFile(file, file_mapping, memory, size);
907 Win32MemoryMappedFile::~Win32MemoryMappedFile() {
909 UnmapViewOfFile(memory_);
910 CloseHandle(file_mapping_);
915 // The following code loads functions defined in DbhHelp.h and TlHelp32.h
916 // dynamically. This is to avoid being depending on dbghelp.dll and
917 // tlhelp32.dll when running (the functions in tlhelp32.dll have been moved to
918 // kernel32.dll at some point so loading functions defines in TlHelp32.h
919 // dynamically might not be necessary any more - for some versions of Windows?).
921 // Function pointers to functions dynamically loaded from dbghelp.dll.
922 #define DBGHELP_FUNCTION_LIST(V) \
926 V(SymGetSearchPath) \
929 V(SymGetSymFromAddr64) \
930 V(SymGetLineFromAddr64) \
931 V(SymFunctionTableAccess64) \
932 V(SymGetModuleBase64)
934 // Function pointers to functions dynamically loaded from dbghelp.dll.
935 #define TLHELP32_FUNCTION_LIST(V) \
936 V(CreateToolhelp32Snapshot) \
940 // Define the decoration to use for the type and variable name used for
941 // dynamically loaded DLL function..
942 #define DLL_FUNC_TYPE(name) _##name##_
943 #define DLL_FUNC_VAR(name) _##name
945 // Define the type for each dynamically loaded DLL function. The function
946 // definitions are copied from DbgHelp.h and TlHelp32.h. The IN and VOID macros
947 // from the Windows include files are redefined here to have the function
948 // definitions to be as close to the ones in the original .h files as possible.
956 // DbgHelp isn't supported on MinGW yet
958 // DbgHelp.h functions.
959 typedef BOOL (__stdcall *DLL_FUNC_TYPE(SymInitialize))(IN HANDLE hProcess,
960 IN PSTR UserSearchPath,
961 IN BOOL fInvadeProcess);
962 typedef DWORD (__stdcall *DLL_FUNC_TYPE(SymGetOptions))(VOID);
963 typedef DWORD (__stdcall *DLL_FUNC_TYPE(SymSetOptions))(IN DWORD SymOptions);
964 typedef BOOL (__stdcall *DLL_FUNC_TYPE(SymGetSearchPath))(
967 IN DWORD SearchPathLength);
968 typedef DWORD64 (__stdcall *DLL_FUNC_TYPE(SymLoadModule64))(
973 IN DWORD64 BaseOfDll,
975 typedef BOOL (__stdcall *DLL_FUNC_TYPE(StackWalk64))(
979 LPSTACKFRAME64 StackFrame,
981 PREAD_PROCESS_MEMORY_ROUTINE64 ReadMemoryRoutine,
982 PFUNCTION_TABLE_ACCESS_ROUTINE64 FunctionTableAccessRoutine,
983 PGET_MODULE_BASE_ROUTINE64 GetModuleBaseRoutine,
984 PTRANSLATE_ADDRESS_ROUTINE64 TranslateAddress);
985 typedef BOOL (__stdcall *DLL_FUNC_TYPE(SymGetSymFromAddr64))(
988 OUT PDWORD64 pdwDisplacement,
989 OUT PIMAGEHLP_SYMBOL64 Symbol);
990 typedef BOOL (__stdcall *DLL_FUNC_TYPE(SymGetLineFromAddr64))(
993 OUT PDWORD pdwDisplacement,
994 OUT PIMAGEHLP_LINE64 Line64);
995 // DbgHelp.h typedefs. Implementation found in dbghelp.dll.
996 typedef PVOID (__stdcall *DLL_FUNC_TYPE(SymFunctionTableAccess64))(
998 DWORD64 AddrBase); // DbgHelp.h typedef PFUNCTION_TABLE_ACCESS_ROUTINE64
999 typedef DWORD64 (__stdcall *DLL_FUNC_TYPE(SymGetModuleBase64))(
1001 DWORD64 AddrBase); // DbgHelp.h typedef PGET_MODULE_BASE_ROUTINE64
1003 // TlHelp32.h functions.
1004 typedef HANDLE (__stdcall *DLL_FUNC_TYPE(CreateToolhelp32Snapshot))(
1006 DWORD th32ProcessID);
1007 typedef BOOL (__stdcall *DLL_FUNC_TYPE(Module32FirstW))(HANDLE hSnapshot,
1008 LPMODULEENTRY32W lpme);
1009 typedef BOOL (__stdcall *DLL_FUNC_TYPE(Module32NextW))(HANDLE hSnapshot,
1010 LPMODULEENTRY32W lpme);
1015 // Declare a variable for each dynamically loaded DLL function.
1016 #define DEF_DLL_FUNCTION(name) DLL_FUNC_TYPE(name) DLL_FUNC_VAR(name) = NULL;
1017 DBGHELP_FUNCTION_LIST(DEF_DLL_FUNCTION)
1018 TLHELP32_FUNCTION_LIST(DEF_DLL_FUNCTION)
1019 #undef DEF_DLL_FUNCTION
1021 // Load the functions. This function has a lot of "ugly" macros in order to
1022 // keep down code duplication.
1024 static bool LoadDbgHelpAndTlHelp32() {
1025 static bool dbghelp_loaded = false;
1027 if (dbghelp_loaded) return true;
1031 // Load functions from the dbghelp.dll module.
1032 module = LoadLibrary(TEXT("dbghelp.dll"));
1033 if (module == NULL) {
1037 #define LOAD_DLL_FUNC(name) \
1038 DLL_FUNC_VAR(name) = \
1039 reinterpret_cast<DLL_FUNC_TYPE(name)>(GetProcAddress(module, #name));
1041 DBGHELP_FUNCTION_LIST(LOAD_DLL_FUNC)
1043 #undef LOAD_DLL_FUNC
1045 // Load functions from the kernel32.dll module (the TlHelp32.h function used
1046 // to be in tlhelp32.dll but are now moved to kernel32.dll).
1047 module = LoadLibrary(TEXT("kernel32.dll"));
1048 if (module == NULL) {
1052 #define LOAD_DLL_FUNC(name) \
1053 DLL_FUNC_VAR(name) = \
1054 reinterpret_cast<DLL_FUNC_TYPE(name)>(GetProcAddress(module, #name));
1056 TLHELP32_FUNCTION_LIST(LOAD_DLL_FUNC)
1058 #undef LOAD_DLL_FUNC
1060 // Check that all functions where loaded.
1062 #define DLL_FUNC_LOADED(name) (DLL_FUNC_VAR(name) != NULL) &&
1064 DBGHELP_FUNCTION_LIST(DLL_FUNC_LOADED)
1065 TLHELP32_FUNCTION_LIST(DLL_FUNC_LOADED)
1067 #undef DLL_FUNC_LOADED
1070 dbghelp_loaded = result;
1072 // NOTE: The modules are never unloaded and will stay around until the
1073 // application is closed.
1076 #undef DBGHELP_FUNCTION_LIST
1077 #undef TLHELP32_FUNCTION_LIST
1079 #undef DLL_FUNC_TYPE
1082 // Load the symbols for generating stack traces.
1083 static std::vector<OS::SharedLibraryAddress> LoadSymbols(
1084 HANDLE process_handle) {
1085 static std::vector<OS::SharedLibraryAddress> result;
1087 static bool symbols_loaded = false;
1089 if (symbols_loaded) return result;
1093 // Initialize the symbol engine.
1094 ok = _SymInitialize(process_handle, // hProcess
1095 NULL, // UserSearchPath
1096 false); // fInvadeProcess
1097 if (!ok) return result;
1099 DWORD options = _SymGetOptions();
1100 options |= SYMOPT_LOAD_LINES;
1101 options |= SYMOPT_FAIL_CRITICAL_ERRORS;
1102 options = _SymSetOptions(options);
1104 char buf[OS::kStackWalkMaxNameLen] = {0};
1105 ok = _SymGetSearchPath(process_handle, buf, OS::kStackWalkMaxNameLen);
1107 int err = GetLastError();
1108 OS::Print("%d\n", err);
1112 HANDLE snapshot = _CreateToolhelp32Snapshot(
1113 TH32CS_SNAPMODULE, // dwFlags
1114 GetCurrentProcessId()); // th32ProcessId
1115 if (snapshot == INVALID_HANDLE_VALUE) return result;
1116 MODULEENTRY32W module_entry;
1117 module_entry.dwSize = sizeof(module_entry); // Set the size of the structure.
1118 BOOL cont = _Module32FirstW(snapshot, &module_entry);
1121 // NOTE the SymLoadModule64 function has the peculiarity of accepting a
1122 // both unicode and ASCII strings even though the parameter is PSTR.
1123 base = _SymLoadModule64(
1124 process_handle, // hProcess
1126 reinterpret_cast<PSTR>(module_entry.szExePath), // ImageName
1127 reinterpret_cast<PSTR>(module_entry.szModule), // ModuleName
1128 reinterpret_cast<DWORD64>(module_entry.modBaseAddr), // BaseOfDll
1129 module_entry.modBaseSize); // SizeOfDll
1131 int err = GetLastError();
1132 if (err != ERROR_MOD_NOT_FOUND &&
1133 err != ERROR_INVALID_HANDLE) {
1138 int lib_name_length = WideCharToMultiByte(
1139 CP_UTF8, 0, module_entry.szExePath, -1, NULL, 0, NULL, NULL);
1140 std::string lib_name(lib_name_length, 0);
1141 WideCharToMultiByte(CP_UTF8, 0, module_entry.szExePath, -1, &lib_name[0],
1142 lib_name_length, NULL, NULL);
1143 result.push_back(OS::SharedLibraryAddress(
1144 lib_name, reinterpret_cast<unsigned int>(module_entry.modBaseAddr),
1145 reinterpret_cast<unsigned int>(module_entry.modBaseAddr +
1146 module_entry.modBaseSize)));
1147 cont = _Module32NextW(snapshot, &module_entry);
1149 CloseHandle(snapshot);
1151 symbols_loaded = true;
1156 std::vector<OS::SharedLibraryAddress> OS::GetSharedLibraryAddresses() {
1157 // SharedLibraryEvents are logged when loading symbol information.
1158 // Only the shared libraries loaded at the time of the call to
1159 // GetSharedLibraryAddresses are logged. DLLs loaded after
1160 // initialization are not accounted for.
1161 if (!LoadDbgHelpAndTlHelp32()) return std::vector<OS::SharedLibraryAddress>();
1162 HANDLE process_handle = GetCurrentProcess();
1163 return LoadSymbols(process_handle);
1167 void OS::SignalCodeMovingGC() {
1171 uint64_t OS::TotalPhysicalMemory() {
1172 MEMORYSTATUSEX memory_info;
1173 memory_info.dwLength = sizeof(memory_info);
1174 if (!GlobalMemoryStatusEx(&memory_info)) {
1179 return static_cast<uint64_t>(memory_info.ullTotalPhys);
1183 #else // __MINGW32__
1184 std::vector<OS::SharedLibraryAddress> OS::GetSharedLibraryAddresses() {
1185 return std::vector<OS::SharedLibraryAddress>();
1189 void OS::SignalCodeMovingGC() { }
1190 #endif // __MINGW32__
1193 int OS::NumberOfProcessorsOnline() {
1195 GetSystemInfo(&info);
1196 return info.dwNumberOfProcessors;
1200 double OS::nan_value() {
1202 return std::numeric_limits<double>::quiet_NaN();
1209 int OS::ActivationFrameAlignment() {
1211 return 16; // Windows 64-bit ABI requires the stack to be 16-byte aligned.
1212 #elif defined(__MINGW32__)
1213 // With gcc 4.4 the tree vectorization optimizer can generate code
1214 // that requires 16 byte alignment such as movdqa on x86.
1217 return 8; // Floating-point math runs faster with 8-byte alignment.
1222 VirtualMemory::VirtualMemory() : address_(NULL), size_(0) { }
1225 VirtualMemory::VirtualMemory(size_t size)
1226 : address_(ReserveRegion(size)), size_(size) { }
1229 VirtualMemory::VirtualMemory(size_t size, size_t alignment)
1230 : address_(NULL), size_(0) {
1231 DCHECK(IsAligned(alignment, static_cast<intptr_t>(OS::AllocateAlignment())));
1232 size_t request_size = RoundUp(size + alignment,
1233 static_cast<intptr_t>(OS::AllocateAlignment()));
1234 void* address = ReserveRegion(request_size);
1235 if (address == NULL) return;
1236 uint8_t* base = RoundUp(static_cast<uint8_t*>(address), alignment);
1237 // Try reducing the size by freeing and then reallocating a specific area.
1238 bool result = ReleaseRegion(address, request_size);
1241 address = VirtualAlloc(base, size, MEM_RESERVE, PAGE_NOACCESS);
1242 if (address != NULL) {
1243 request_size = size;
1244 DCHECK(base == static_cast<uint8_t*>(address));
1246 // Resizing failed, just go with a bigger area.
1247 address = ReserveRegion(request_size);
1248 if (address == NULL) return;
1251 size_ = request_size;
1255 VirtualMemory::~VirtualMemory() {
1257 bool result = ReleaseRegion(address(), size());
1264 bool VirtualMemory::IsReserved() {
1265 return address_ != NULL;
1269 void VirtualMemory::Reset() {
1275 bool VirtualMemory::Commit(void* address, size_t size, bool is_executable) {
1276 return CommitRegion(address, size, is_executable);
1280 bool VirtualMemory::Uncommit(void* address, size_t size) {
1281 DCHECK(IsReserved());
1282 return UncommitRegion(address, size);
1286 bool VirtualMemory::Guard(void* address) {
1287 if (NULL == VirtualAlloc(address,
1288 OS::CommitPageSize(),
1297 void* VirtualMemory::ReserveRegion(size_t size) {
1298 return RandomizedVirtualAlloc(size, MEM_RESERVE, PAGE_NOACCESS);
1302 bool VirtualMemory::CommitRegion(void* base, size_t size, bool is_executable) {
1303 int prot = is_executable ? PAGE_EXECUTE_READWRITE : PAGE_READWRITE;
1304 if (NULL == VirtualAlloc(base, size, MEM_COMMIT, prot)) {
1311 bool VirtualMemory::UncommitRegion(void* base, size_t size) {
1312 return VirtualFree(base, size, MEM_DECOMMIT) != 0;
1316 bool VirtualMemory::ReleaseRegion(void* base, size_t size) {
1317 return VirtualFree(base, 0, MEM_RELEASE) != 0;
1321 bool VirtualMemory::HasLazyCommits() {
1322 // TODO(alph): implement for the platform.
1327 // ----------------------------------------------------------------------------
1328 // Win32 thread support.
1330 // Definition of invalid thread handle and id.
1331 static const HANDLE kNoThread = INVALID_HANDLE_VALUE;
1333 // Entry point for threads. The supplied argument is a pointer to the thread
1334 // object. The entry function dispatches to the run method in the thread
1335 // object. It is important that this function has __stdcall calling
1337 static unsigned int __stdcall ThreadEntry(void* arg) {
1338 Thread* thread = reinterpret_cast<Thread*>(arg);
1339 thread->NotifyStartedAndRun();
1344 class Thread::PlatformData {
1346 explicit PlatformData(HANDLE thread) : thread_(thread) {}
1348 unsigned thread_id_;
1352 // Initialize a Win32 thread object. The thread has an invalid thread
1353 // handle until it is started.
1355 Thread::Thread(const Options& options)
1356 : stack_size_(options.stack_size()),
1357 start_semaphore_(NULL) {
1358 data_ = new PlatformData(kNoThread);
1359 set_name(options.name());
1363 void Thread::set_name(const char* name) {
1364 OS::StrNCpy(name_, sizeof(name_), name, strlen(name));
1365 name_[sizeof(name_) - 1] = '\0';
1369 // Close our own handle for the thread.
1371 if (data_->thread_ != kNoThread) CloseHandle(data_->thread_);
1376 // Create a new thread. It is important to use _beginthreadex() instead of
1377 // the Win32 function CreateThread(), because the CreateThread() does not
1378 // initialize thread specific structures in the C runtime library.
1379 void Thread::Start() {
1380 data_->thread_ = reinterpret_cast<HANDLE>(
1381 _beginthreadex(NULL,
1382 static_cast<unsigned>(stack_size_),
1386 &data_->thread_id_));
1390 // Wait for thread to terminate.
1391 void Thread::Join() {
1392 if (data_->thread_id_ != GetCurrentThreadId()) {
1393 WaitForSingleObject(data_->thread_, INFINITE);
1398 Thread::LocalStorageKey Thread::CreateThreadLocalKey() {
1399 DWORD result = TlsAlloc();
1400 DCHECK(result != TLS_OUT_OF_INDEXES);
1401 return static_cast<LocalStorageKey>(result);
1405 void Thread::DeleteThreadLocalKey(LocalStorageKey key) {
1406 BOOL result = TlsFree(static_cast<DWORD>(key));
1412 void* Thread::GetThreadLocal(LocalStorageKey key) {
1413 return TlsGetValue(static_cast<DWORD>(key));
1417 void Thread::SetThreadLocal(LocalStorageKey key, void* value) {
1418 BOOL result = TlsSetValue(static_cast<DWORD>(key), value);
1425 void Thread::YieldCPU() {
1429 } } // namespace v8::base