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. 4 5 // Platform-specific code for Win32. 6 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. 11 #ifdef __MINGW32__ 12 #include <_mingw.h> 13 #ifdef MINGW_HAS_SECURE_API 14 #undef MINGW_HAS_SECURE_API 15 #endif // MINGW_HAS_SECURE_API 16 #endif // __MINGW32__ 17 18 #include <limits> 19 20 #include "src/base/win32-headers.h" 21 22 #include "src/base/bits.h" 23 #include "src/base/lazy-instance.h" 24 #include "src/base/macros.h" 25 #include "src/base/platform/platform.h" 26 #include "src/base/platform/time.h" 27 #include "src/base/timezone-cache.h" 28 #include "src/base/utils/random-number-generator.h" 29 30 #include <VersionHelpers.h> 31 32 #if defined(_MSC_VER) 33 #include <crtdbg.h> // NOLINT 34 #endif // defined(_MSC_VER) 35 36 // Extra functions for MinGW. Most of these are the _s functions which are in 37 // the Microsoft Visual Studio C++ CRT. 38 #ifdef __MINGW32__ 39 40 41 #ifndef __MINGW64_VERSION_MAJOR 42 43 #define _TRUNCATE 0 44 #define STRUNCATE 80 45 46 inline void MemoryFence() { 47 int barrier = 0; 48 __asm__ __volatile__("xchgl %%eax,%0 ":"=r" (barrier)); 49 } 50 51 #endif // __MINGW64_VERSION_MAJOR 52 53 54 int localtime_s(tm* out_tm, const time_t* time) { 55 tm* posix_local_time_struct = localtime_r(time, out_tm); 56 if (posix_local_time_struct == nullptr) return 1; 57 return 0; 58 } 59 60 61 int fopen_s(FILE** pFile, const char* filename, const char* mode) { 62 *pFile = fopen(filename, mode); 63 return *pFile != nullptr ? 0 : 1; 64 } 65 66 int _vsnprintf_s(char* buffer, size_t sizeOfBuffer, size_t count, 67 const char* format, va_list argptr) { 68 DCHECK(count == _TRUNCATE); 69 return _vsnprintf(buffer, sizeOfBuffer, format, argptr); 70 } 71 72 73 int strncpy_s(char* dest, size_t dest_size, const char* source, size_t count) { 74 CHECK(source != nullptr); 75 CHECK(dest != nullptr); 76 CHECK_GT(dest_size, 0); 77 78 if (count == _TRUNCATE) { 79 while (dest_size > 0 && *source != 0) { 80 *(dest++) = *(source++); 81 --dest_size; 82 } 83 if (dest_size == 0) { 84 *(dest - 1) = 0; 85 return STRUNCATE; 86 } 87 } else { 88 while (dest_size > 0 && count > 0 && *source != 0) { 89 *(dest++) = *(source++); 90 --dest_size; 91 --count; 92 } 93 } 94 CHECK_GT(dest_size, 0); 95 *dest = 0; 96 return 0; 97 } 98 99 #endif // __MINGW32__ 100 101 namespace v8 { 102 namespace base { 103 104 namespace { 105 106 bool g_hard_abort = false; 107 108 } // namespace 109 110 class WindowsTimezoneCache : public TimezoneCache { 111 public: 112 WindowsTimezoneCache() : initialized_(false) {} 113 114 ~WindowsTimezoneCache() override {} 115 116 void Clear() override { initialized_ = false; } 117 118 const char* LocalTimezone(double time) override; 119 120 double LocalTimeOffset(double time, bool is_utc) override; 121 122 double DaylightSavingsOffset(double time) override; 123 124 // Initialize timezone information. The timezone information is obtained from 125 // windows. If we cannot get the timezone information we fall back to CET. 126 void InitializeIfNeeded() { 127 // Just return if timezone information has already been initialized. 128 if (initialized_) return; 129 130 // Initialize POSIX time zone data. 131 _tzset(); 132 // Obtain timezone information from operating system. 133 memset(&tzinfo_, 0, sizeof(tzinfo_)); 134 if (GetTimeZoneInformation(&tzinfo_) == TIME_ZONE_ID_INVALID) { 135 // If we cannot get timezone information we fall back to CET. 136 tzinfo_.Bias = -60; 137 tzinfo_.StandardDate.wMonth = 10; 138 tzinfo_.StandardDate.wDay = 5; 139 tzinfo_.StandardDate.wHour = 3; 140 tzinfo_.StandardBias = 0; 141 tzinfo_.DaylightDate.wMonth = 3; 142 tzinfo_.DaylightDate.wDay = 5; 143 tzinfo_.DaylightDate.wHour = 2; 144 tzinfo_.DaylightBias = -60; 145 } 146 147 // Make standard and DST timezone names. 148 WideCharToMultiByte(CP_UTF8, 0, tzinfo_.StandardName, -1, std_tz_name_, 149 kTzNameSize, nullptr, nullptr); 150 std_tz_name_[kTzNameSize - 1] = '\0'; 151 WideCharToMultiByte(CP_UTF8, 0, tzinfo_.DaylightName, -1, dst_tz_name_, 152 kTzNameSize, nullptr, nullptr); 153 dst_tz_name_[kTzNameSize - 1] = '\0'; 154 155 // If OS returned empty string or resource id (like "@tzres.dll,-211") 156 // simply guess the name from the UTC bias of the timezone. 157 // To properly resolve the resource identifier requires a library load, 158 // which is not possible in a sandbox. 159 if (std_tz_name_[0] == '\0' || std_tz_name_[0] == '@') { 160 OS::SNPrintF(std_tz_name_, kTzNameSize - 1, 161 "%s Standard Time", 162 GuessTimezoneNameFromBias(tzinfo_.Bias)); 163 } 164 if (dst_tz_name_[0] == '\0' || dst_tz_name_[0] == '@') { 165 OS::SNPrintF(dst_tz_name_, kTzNameSize - 1, 166 "%s Daylight Time", 167 GuessTimezoneNameFromBias(tzinfo_.Bias)); 168 } 169 // Timezone information initialized. 170 initialized_ = true; 171 } 172 173 // Guess the name of the timezone from the bias. 174 // The guess is very biased towards the northern hemisphere. 175 const char* GuessTimezoneNameFromBias(int bias) { 176 static const int kHour = 60; 177 switch (-bias) { 178 case -9*kHour: return "Alaska"; 179 case -8*kHour: return "Pacific"; 180 case -7*kHour: return "Mountain"; 181 case -6*kHour: return "Central"; 182 case -5*kHour: return "Eastern"; 183 case -4*kHour: return "Atlantic"; 184 case 0*kHour: return "GMT"; 185 case +1*kHour: return "Central Europe"; 186 case +2*kHour: return "Eastern Europe"; 187 case +3*kHour: return "Russia"; 188 case +5*kHour + 30: return "India"; 189 case +8*kHour: return "China"; 190 case +9*kHour: return "Japan"; 191 case +12*kHour: return "New Zealand"; 192 default: return "Local"; 193 } 194 } 195 196 197 private: 198 static const int kTzNameSize = 128; 199 bool initialized_; 200 char std_tz_name_[kTzNameSize]; 201 char dst_tz_name_[kTzNameSize]; 202 TIME_ZONE_INFORMATION tzinfo_; 203 friend class Win32Time; 204 }; 205 206 207 // ---------------------------------------------------------------------------- 208 // The Time class represents time on win32. A timestamp is represented as 209 // a 64-bit integer in 100 nanoseconds since January 1, 1601 (UTC). JavaScript 210 // timestamps are represented as a doubles in milliseconds since 00:00:00 UTC, 211 // January 1, 1970. 212 213 class Win32Time { 214 public: 215 // Constructors. 216 Win32Time(); 217 explicit Win32Time(double jstime); 218 Win32Time(int year, int mon, int day, int hour, int min, int sec); 219 220 // Convert timestamp to JavaScript representation. 221 double ToJSTime(); 222 223 // Set timestamp to current time. 224 void SetToCurrentTime(); 225 226 // Returns the local timezone offset in milliseconds east of UTC. This is 227 // the number of milliseconds you must add to UTC to get local time, i.e. 228 // LocalOffset(CET) = 3600000 and LocalOffset(PST) = -28800000. This 229 // routine also takes into account whether daylight saving is effect 230 // at the time. 231 int64_t LocalOffset(WindowsTimezoneCache* cache); 232 233 // Returns the daylight savings time offset for the time in milliseconds. 234 int64_t DaylightSavingsOffset(WindowsTimezoneCache* cache); 235 236 // Returns a string identifying the current timezone for the 237 // timestamp taking into account daylight saving. 238 char* LocalTimezone(WindowsTimezoneCache* cache); 239 240 private: 241 // Constants for time conversion. 242 static const int64_t kTimeEpoc = 116444736000000000LL; 243 static const int64_t kTimeScaler = 10000; 244 static const int64_t kMsPerMinute = 60000; 245 246 // Constants for timezone information. 247 static const bool kShortTzNames = false; 248 249 // Return whether or not daylight savings time is in effect at this time. 250 bool InDST(WindowsTimezoneCache* cache); 251 252 // Accessor for FILETIME representation. 253 FILETIME& ft() { return time_.ft_; } 254 255 // Accessor for integer representation. 256 int64_t& t() { return time_.t_; } 257 258 // Although win32 uses 64-bit integers for representing timestamps, 259 // these are packed into a FILETIME structure. The FILETIME structure 260 // is just a struct representing a 64-bit integer. The TimeStamp union 261 // allows access to both a FILETIME and an integer representation of 262 // the timestamp. 263 union TimeStamp { 264 FILETIME ft_; 265 int64_t t_; 266 }; 267 268 TimeStamp time_; 269 }; 270 271 272 // Initialize timestamp to start of epoc. 273 Win32Time::Win32Time() { 274 t() = 0; 275 } 276 277 278 // Initialize timestamp from a JavaScript timestamp. 279 Win32Time::Win32Time(double jstime) { 280 t() = static_cast<int64_t>(jstime) * kTimeScaler + kTimeEpoc; 281 } 282 283 284 // Initialize timestamp from date/time components. 285 Win32Time::Win32Time(int year, int mon, int day, int hour, int min, int sec) { 286 SYSTEMTIME st; 287 st.wYear = year; 288 st.wMonth = mon; 289 st.wDay = day; 290 st.wHour = hour; 291 st.wMinute = min; 292 st.wSecond = sec; 293 st.wMilliseconds = 0; 294 SystemTimeToFileTime(&st, &ft()); 295 } 296 297 298 // Convert timestamp to JavaScript timestamp. 299 double Win32Time::ToJSTime() { 300 return static_cast<double>((t() - kTimeEpoc) / kTimeScaler); 301 } 302 303 304 // Set timestamp to current time. 305 void Win32Time::SetToCurrentTime() { 306 // The default GetSystemTimeAsFileTime has a ~15.5ms resolution. 307 // Because we're fast, we like fast timers which have at least a 308 // 1ms resolution. 309 // 310 // timeGetTime() provides 1ms granularity when combined with 311 // timeBeginPeriod(). If the host application for v8 wants fast 312 // timers, it can use timeBeginPeriod to increase the resolution. 313 // 314 // Using timeGetTime() has a drawback because it is a 32bit value 315 // and hence rolls-over every ~49days. 316 // 317 // To use the clock, we use GetSystemTimeAsFileTime as our base; 318 // and then use timeGetTime to extrapolate current time from the 319 // start time. To deal with rollovers, we resync the clock 320 // any time when more than kMaxClockElapsedTime has passed or 321 // whenever timeGetTime creates a rollover. 322 323 static bool initialized = false; 324 static TimeStamp init_time; 325 static DWORD init_ticks; 326 static const int64_t kHundredNanosecondsPerSecond = 10000000; 327 static const int64_t kMaxClockElapsedTime = 328 60*kHundredNanosecondsPerSecond; // 1 minute 329 330 // If we are uninitialized, we need to resync the clock. 331 bool needs_resync = !initialized; 332 333 // Get the current time. 334 TimeStamp time_now; 335 GetSystemTimeAsFileTime(&time_now.ft_); 336 DWORD ticks_now = timeGetTime(); 337 338 // Check if we need to resync due to clock rollover. 339 needs_resync |= ticks_now < init_ticks; 340 341 // Check if we need to resync due to elapsed time. 342 needs_resync |= (time_now.t_ - init_time.t_) > kMaxClockElapsedTime; 343 344 // Check if we need to resync due to backwards time change. 345 needs_resync |= time_now.t_ < init_time.t_; 346 347 // Resync the clock if necessary. 348 if (needs_resync) { 349 GetSystemTimeAsFileTime(&init_time.ft_); 350 init_ticks = ticks_now = timeGetTime(); 351 initialized = true; 352 } 353 354 // Finally, compute the actual time. Why is this so hard. 355 DWORD elapsed = ticks_now - init_ticks; 356 this->time_.t_ = init_time.t_ + (static_cast<int64_t>(elapsed) * 10000); 357 } 358 359 360 // Return the local timezone offset in milliseconds east of UTC. This 361 // takes into account whether daylight saving is in effect at the time. 362 // Only times in the 32-bit Unix range may be passed to this function. 363 // Also, adding the time-zone offset to the input must not overflow. 364 // The function EquivalentTime() in date.js guarantees this. 365 int64_t Win32Time::LocalOffset(WindowsTimezoneCache* cache) { 366 cache->InitializeIfNeeded(); 367 368 Win32Time rounded_to_second(*this); 369 rounded_to_second.t() = 370 rounded_to_second.t() / 1000 / kTimeScaler * 1000 * kTimeScaler; 371 // Convert to local time using POSIX localtime function. 372 // Windows XP Service Pack 3 made SystemTimeToTzSpecificLocalTime() 373 // very slow. Other browsers use localtime(). 374 375 // Convert from JavaScript milliseconds past 1/1/1970 0:00:00 to 376 // POSIX seconds past 1/1/1970 0:00:00. 377 double unchecked_posix_time = rounded_to_second.ToJSTime() / 1000; 378 if (unchecked_posix_time > INT_MAX || unchecked_posix_time < 0) { 379 return 0; 380 } 381 // Because _USE_32BIT_TIME_T is defined, time_t is a 32-bit int. 382 time_t posix_time = static_cast<time_t>(unchecked_posix_time); 383 384 // Convert to local time, as struct with fields for day, hour, year, etc. 385 tm posix_local_time_struct; 386 if (localtime_s(&posix_local_time_struct, &posix_time)) return 0; 387 388 if (posix_local_time_struct.tm_isdst > 0) { 389 return (cache->tzinfo_.Bias + cache->tzinfo_.DaylightBias) * -kMsPerMinute; 390 } else if (posix_local_time_struct.tm_isdst == 0) { 391 return (cache->tzinfo_.Bias + cache->tzinfo_.StandardBias) * -kMsPerMinute; 392 } else { 393 return cache->tzinfo_.Bias * -kMsPerMinute; 394 } 395 } 396 397 398 // Return whether or not daylight savings time is in effect at this time. 399 bool Win32Time::InDST(WindowsTimezoneCache* cache) { 400 cache->InitializeIfNeeded(); 401 402 // Determine if DST is in effect at the specified time. 403 bool in_dst = false; 404 if (cache->tzinfo_.StandardDate.wMonth != 0 || 405 cache->tzinfo_.DaylightDate.wMonth != 0) { 406 // Get the local timezone offset for the timestamp in milliseconds. 407 int64_t offset = LocalOffset(cache); 408 409 // Compute the offset for DST. The bias parameters in the timezone info 410 // are specified in minutes. These must be converted to milliseconds. 411 int64_t dstofs = 412 -(cache->tzinfo_.Bias + cache->tzinfo_.DaylightBias) * kMsPerMinute; 413 414 // If the local time offset equals the timezone bias plus the daylight 415 // bias then DST is in effect. 416 in_dst = offset == dstofs; 417 } 418 419 return in_dst; 420 } 421 422 423 // Return the daylight savings time offset for this time. 424 int64_t Win32Time::DaylightSavingsOffset(WindowsTimezoneCache* cache) { 425 return InDST(cache) ? 60 * kMsPerMinute : 0; 426 } 427 428 429 // Returns a string identifying the current timezone for the 430 // timestamp taking into account daylight saving. 431 char* Win32Time::LocalTimezone(WindowsTimezoneCache* cache) { 432 // Return the standard or DST time zone name based on whether daylight 433 // saving is in effect at the given time. 434 return InDST(cache) ? cache->dst_tz_name_ : cache->std_tz_name_; 435 } 436 437 438 // Returns the accumulated user time for thread. 439 int OS::GetUserTime(uint32_t* secs, uint32_t* usecs) { 440 FILETIME dummy; 441 uint64_t usertime; 442 443 // Get the amount of time that the thread has executed in user mode. 444 if (!GetThreadTimes(GetCurrentThread(), &dummy, &dummy, &dummy, 445 reinterpret_cast<FILETIME*>(&usertime))) return -1; 446 447 // Adjust the resolution to micro-seconds. 448 usertime /= 10; 449 450 // Convert to seconds and microseconds 451 *secs = static_cast<uint32_t>(usertime / 1000000); 452 *usecs = static_cast<uint32_t>(usertime % 1000000); 453 return 0; 454 } 455 456 457 // Returns current time as the number of milliseconds since 458 // 00:00:00 UTC, January 1, 1970. 459 double OS::TimeCurrentMillis() { 460 return Time::Now().ToJsTime(); 461 } 462 463 // Returns a string identifying the current timezone taking into 464 // account daylight saving. 465 const char* WindowsTimezoneCache::LocalTimezone(double time) { 466 return Win32Time(time).LocalTimezone(this); 467 } 468 469 // Returns the local time offset in milliseconds east of UTC without 470 // taking daylight savings time into account. 471 double WindowsTimezoneCache::LocalTimeOffset(double time_ms, bool is_utc) { 472 // Ignore is_utc and time_ms for now. That way, the behavior wouldn't 473 // change with icu_timezone_data disabled. 474 // Use current time, rounded to the millisecond. 475 Win32Time t(OS::TimeCurrentMillis()); 476 // Time::LocalOffset inlcudes any daylight savings offset, so subtract it. 477 return static_cast<double>(t.LocalOffset(this) - 478 t.DaylightSavingsOffset(this)); 479 } 480 481 // Returns the daylight savings offset in milliseconds for the given 482 // time. 483 double WindowsTimezoneCache::DaylightSavingsOffset(double time) { 484 int64_t offset = Win32Time(time).DaylightSavingsOffset(this); 485 return static_cast<double>(offset); 486 } 487 488 TimezoneCache* OS::CreateTimezoneCache() { return new WindowsTimezoneCache(); } 489 490 int OS::GetLastError() { 491 return ::GetLastError(); 492 } 493 494 495 int OS::GetCurrentProcessId() { 496 return static_cast<int>(::GetCurrentProcessId()); 497 } 498 499 500 int OS::GetCurrentThreadId() { 501 return static_cast<int>(::GetCurrentThreadId()); 502 } 503 504 void OS::ExitProcess(int exit_code) { 505 // Use TerminateProcess avoid races between isolate threads and 506 // static destructors. 507 fflush(stdout); 508 fflush(stderr); 509 TerminateProcess(GetCurrentProcess(), exit_code); 510 } 511 512 // ---------------------------------------------------------------------------- 513 // Win32 console output. 514 // 515 // If a Win32 application is linked as a console application it has a normal 516 // standard output and standard error. In this case normal printf works fine 517 // for output. However, if the application is linked as a GUI application, 518 // the process doesn't have a console, and therefore (debugging) output is lost. 519 // This is the case if we are embedded in a windows program (like a browser). 520 // In order to be able to get debug output in this case the the debugging 521 // facility using OutputDebugString. This output goes to the active debugger 522 // for the process (if any). Else the output can be monitored using DBMON.EXE. 523 524 enum OutputMode { 525 UNKNOWN, // Output method has not yet been determined. 526 CONSOLE, // Output is written to stdout. 527 ODS // Output is written to debug facility. 528 }; 529 530 static OutputMode output_mode = UNKNOWN; // Current output mode. 531 532 533 // Determine if the process has a console for output. 534 static bool HasConsole() { 535 // Only check the first time. Eventual race conditions are not a problem, 536 // because all threads will eventually determine the same mode. 537 if (output_mode == UNKNOWN) { 538 // We cannot just check that the standard output is attached to a console 539 // because this would fail if output is redirected to a file. Therefore we 540 // say that a process does not have an output console if either the 541 // standard output handle is invalid or its file type is unknown. 542 if (GetStdHandle(STD_OUTPUT_HANDLE) != INVALID_HANDLE_VALUE && 543 GetFileType(GetStdHandle(STD_OUTPUT_HANDLE)) != FILE_TYPE_UNKNOWN) 544 output_mode = CONSOLE; 545 else 546 output_mode = ODS; 547 } 548 return output_mode == CONSOLE; 549 } 550 551 552 static void VPrintHelper(FILE* stream, const char* format, va_list args) { 553 if ((stream == stdout || stream == stderr) && !HasConsole()) { 554 // It is important to use safe print here in order to avoid 555 // overflowing the buffer. We might truncate the output, but this 556 // does not crash. 557 char buffer[4096]; 558 OS::VSNPrintF(buffer, sizeof(buffer), format, args); 559 OutputDebugStringA(buffer); 560 } else { 561 vfprintf(stream, format, args); 562 } 563 } 564 565 566 FILE* OS::FOpen(const char* path, const char* mode) { 567 FILE* result; 568 if (fopen_s(&result, path, mode) == 0) { 569 return result; 570 } else { 571 return nullptr; 572 } 573 } 574 575 576 bool OS::Remove(const char* path) { 577 return (DeleteFileA(path) != 0); 578 } 579 580 char OS::DirectorySeparator() { return '\\'; } 581 582 bool OS::isDirectorySeparator(const char ch) { 583 return ch == '/' || ch == '\\'; 584 } 585 586 587 FILE* OS::OpenTemporaryFile() { 588 // tmpfile_s tries to use the root dir, don't use it. 589 char tempPathBuffer[MAX_PATH]; 590 DWORD path_result = 0; 591 path_result = GetTempPathA(MAX_PATH, tempPathBuffer); 592 if (path_result > MAX_PATH || path_result == 0) return nullptr; 593 UINT name_result = 0; 594 char tempNameBuffer[MAX_PATH]; 595 name_result = GetTempFileNameA(tempPathBuffer, "", 0, tempNameBuffer); 596 if (name_result == 0) return nullptr; 597 FILE* result = FOpen(tempNameBuffer, "w+"); // Same mode as tmpfile uses. 598 if (result != nullptr) { 599 Remove(tempNameBuffer); // Delete on close. 600 } 601 return result; 602 } 603 604 605 // Open log file in binary mode to avoid /n -> /r/n conversion. 606 const char* const OS::LogFileOpenMode = "wb"; 607 608 609 // Print (debug) message to console. 610 void OS::Print(const char* format, ...) { 611 va_list args; 612 va_start(args, format); 613 VPrint(format, args); 614 va_end(args); 615 } 616 617 618 void OS::VPrint(const char* format, va_list args) { 619 VPrintHelper(stdout, format, args); 620 } 621 622 623 void OS::FPrint(FILE* out, const char* format, ...) { 624 va_list args; 625 va_start(args, format); 626 VFPrint(out, format, args); 627 va_end(args); 628 } 629 630 631 void OS::VFPrint(FILE* out, const char* format, va_list args) { 632 VPrintHelper(out, format, args); 633 } 634 635 636 // Print error message to console. 637 void OS::PrintError(const char* format, ...) { 638 va_list args; 639 va_start(args, format); 640 VPrintError(format, args); 641 va_end(args); 642 } 643 644 645 void OS::VPrintError(const char* format, va_list args) { 646 VPrintHelper(stderr, format, args); 647 } 648 649 650 int OS::SNPrintF(char* str, int length, const char* format, ...) { 651 va_list args; 652 va_start(args, format); 653 int result = VSNPrintF(str, length, format, args); 654 va_end(args); 655 return result; 656 } 657 658 659 int OS::VSNPrintF(char* str, int length, const char* format, va_list args) { 660 int n = _vsnprintf_s(str, length, _TRUNCATE, format, args); 661 // Make sure to zero-terminate the string if the output was 662 // truncated or if there was an error. 663 if (n < 0 || n >= length) { 664 if (length > 0) 665 str[length - 1] = '\0'; 666 return -1; 667 } else { 668 return n; 669 } 670 } 671 672 673 char* OS::StrChr(char* str, int c) { 674 return const_cast<char*>(strchr(str, c)); 675 } 676 677 678 void OS::StrNCpy(char* dest, int length, const char* src, size_t n) { 679 // Use _TRUNCATE or strncpy_s crashes (by design) if buffer is too small. 680 size_t buffer_size = static_cast<size_t>(length); 681 if (n + 1 > buffer_size) // count for trailing '\0' 682 n = _TRUNCATE; 683 int result = strncpy_s(dest, length, src, n); 684 USE(result); 685 DCHECK(result == 0 || (n == _TRUNCATE && result == STRUNCATE)); 686 } 687 688 689 #undef _TRUNCATE 690 #undef STRUNCATE 691 692 static LazyInstance<RandomNumberGenerator>::type 693 platform_random_number_generator = LAZY_INSTANCE_INITIALIZER; 694 static LazyMutex rng_mutex = LAZY_MUTEX_INITIALIZER; 695 696 void OS::Initialize(bool hard_abort, const char* const gc_fake_mmap) { 697 g_hard_abort = hard_abort; 698 } 699 700 // static 701 size_t OS::AllocatePageSize() { 702 static size_t allocate_alignment = 0; 703 if (allocate_alignment == 0) { 704 SYSTEM_INFO info; 705 GetSystemInfo(&info); 706 allocate_alignment = info.dwAllocationGranularity; 707 } 708 return allocate_alignment; 709 } 710 711 // static 712 size_t OS::CommitPageSize() { 713 static size_t page_size = 0; 714 if (page_size == 0) { 715 SYSTEM_INFO info; 716 GetSystemInfo(&info); 717 page_size = info.dwPageSize; 718 DCHECK_EQ(4096, page_size); 719 } 720 return page_size; 721 } 722 723 // static 724 void OS::SetRandomMmapSeed(int64_t seed) { 725 if (seed) { 726 LockGuard<Mutex> guard(rng_mutex.Pointer()); 727 platform_random_number_generator.Pointer()->SetSeed(seed); 728 } 729 } 730 731 // static 732 void* OS::GetRandomMmapAddr() { 733 // The address range used to randomize RWX allocations in OS::Allocate 734 // Try not to map pages into the default range that windows loads DLLs 735 // Use a multiple of 64k to prevent committing unused memory. 736 // Note: This does not guarantee RWX regions will be within the 737 // range kAllocationRandomAddressMin to kAllocationRandomAddressMax 738 #ifdef V8_HOST_ARCH_64_BIT 739 static const uintptr_t kAllocationRandomAddressMin = 0x0000000080000000; 740 static const uintptr_t kAllocationRandomAddressMax = 0x000003FFFFFF0000; 741 #else 742 static const uintptr_t kAllocationRandomAddressMin = 0x04000000; 743 static const uintptr_t kAllocationRandomAddressMax = 0x3FFF0000; 744 #endif 745 uintptr_t address; 746 { 747 LockGuard<Mutex> guard(rng_mutex.Pointer()); 748 platform_random_number_generator.Pointer()->NextBytes(&address, 749 sizeof(address)); 750 } 751 address <<= kPageSizeBits; 752 address += kAllocationRandomAddressMin; 753 address &= kAllocationRandomAddressMax; 754 return reinterpret_cast<void*>(address); 755 } 756 757 namespace { 758 759 DWORD GetProtectionFromMemoryPermission(OS::MemoryPermission access) { 760 switch (access) { 761 case OS::MemoryPermission::kNoAccess: 762 return PAGE_NOACCESS; 763 case OS::MemoryPermission::kRead: 764 return PAGE_READONLY; 765 case OS::MemoryPermission::kReadWrite: 766 return PAGE_READWRITE; 767 case OS::MemoryPermission::kReadWriteExecute: 768 if (IsWindows10OrGreater()) 769 return PAGE_EXECUTE_READWRITE | PAGE_TARGETS_INVALID; 770 return PAGE_EXECUTE_READWRITE; 771 case OS::MemoryPermission::kReadExecute: 772 if (IsWindows10OrGreater()) 773 return PAGE_EXECUTE_READ | PAGE_TARGETS_INVALID; 774 return PAGE_EXECUTE_READ; 775 } 776 UNREACHABLE(); 777 } 778 779 uint8_t* RandomizedVirtualAlloc(size_t size, DWORD flags, DWORD protect, 780 void* hint) { 781 LPVOID base = nullptr; 782 static BOOL use_aslr = -1; 783 #ifdef V8_HOST_ARCH_32_BIT 784 // Don't bother randomizing on 32-bit hosts, because they lack the room and 785 // don't have viable ASLR anyway. 786 if (use_aslr == -1 && !IsWow64Process(GetCurrentProcess(), &use_aslr)) 787 use_aslr = FALSE; 788 #else 789 use_aslr = TRUE; 790 #endif 791 792 if (use_aslr && protect != PAGE_READWRITE) { 793 // For executable or reserved pages try to randomize the allocation address. 794 base = VirtualAlloc(hint, size, flags, protect); 795 } 796 797 // On failure, let the OS find an address to use. 798 if (base == nullptr) { 799 base = VirtualAlloc(nullptr, size, flags, protect); 800 } 801 return reinterpret_cast<uint8_t*>(base); 802 } 803 804 } // namespace 805 806 // static 807 void* OS::Allocate(void* address, size_t size, size_t alignment, 808 MemoryPermission access) { 809 size_t page_size = AllocatePageSize(); 810 DCHECK_EQ(0, size % page_size); 811 DCHECK_EQ(0, alignment % page_size); 812 DCHECK_LE(page_size, alignment); 813 address = AlignedAddress(address, alignment); 814 815 DWORD flags = (access == OS::MemoryPermission::kNoAccess) 816 ? MEM_RESERVE 817 : MEM_RESERVE | MEM_COMMIT; 818 DWORD protect = GetProtectionFromMemoryPermission(access); 819 820 // First, try an exact size aligned allocation. 821 uint8_t* base = RandomizedVirtualAlloc(size, flags, protect, address); 822 if (base == nullptr) return nullptr; // Can't allocate, we're OOM. 823 824 // If address is suitably aligned, we're done. 825 uint8_t* aligned_base = RoundUp(base, alignment); 826 if (base == aligned_base) return reinterpret_cast<void*>(base); 827 828 // Otherwise, free it and try a larger allocation. 829 CHECK(Free(base, size)); 830 831 // Clear the hint. It's unlikely we can allocate at this address. 832 address = nullptr; 833 834 // Add the maximum misalignment so we are guaranteed an aligned base address 835 // in the allocated region. 836 size_t padded_size = size + (alignment - page_size); 837 const int kMaxAttempts = 3; 838 aligned_base = nullptr; 839 for (int i = 0; i < kMaxAttempts; ++i) { 840 base = RandomizedVirtualAlloc(padded_size, flags, protect, address); 841 if (base == nullptr) return nullptr; // Can't allocate, we're OOM. 842 843 // Try to trim the allocation by freeing the padded allocation and then 844 // calling VirtualAlloc at the aligned base. 845 CHECK(Free(base, padded_size)); 846 aligned_base = RoundUp(base, alignment); 847 base = reinterpret_cast<uint8_t*>( 848 VirtualAlloc(aligned_base, size, flags, protect)); 849 // We might not get the reduced allocation due to a race. In that case, 850 // base will be nullptr. 851 if (base != nullptr) break; 852 } 853 DCHECK_IMPLIES(base, base == aligned_base); 854 return reinterpret_cast<void*>(base); 855 } 856 857 // static 858 bool OS::Free(void* address, const size_t size) { 859 DCHECK_EQ(0, reinterpret_cast<uintptr_t>(address) % AllocatePageSize()); 860 DCHECK_EQ(0, size % AllocatePageSize()); 861 USE(size); 862 return VirtualFree(address, 0, MEM_RELEASE) != 0; 863 } 864 865 // static 866 bool OS::Release(void* address, size_t size) { 867 DCHECK_EQ(0, reinterpret_cast<uintptr_t>(address) % CommitPageSize()); 868 DCHECK_EQ(0, size % CommitPageSize()); 869 return VirtualFree(address, size, MEM_DECOMMIT) != 0; 870 } 871 872 // static 873 bool OS::SetPermissions(void* address, size_t size, MemoryPermission access) { 874 DCHECK_EQ(0, reinterpret_cast<uintptr_t>(address) % CommitPageSize()); 875 DCHECK_EQ(0, size % CommitPageSize()); 876 if (access == MemoryPermission::kNoAccess) { 877 return VirtualFree(address, size, MEM_DECOMMIT) != 0; 878 } 879 DWORD protect = GetProtectionFromMemoryPermission(access); 880 return VirtualAlloc(address, size, MEM_COMMIT, protect) != nullptr; 881 } 882 883 // static 884 bool OS::HasLazyCommits() { 885 // TODO(alph): implement for the platform. 886 return false; 887 } 888 889 void OS::Sleep(TimeDelta interval) { 890 ::Sleep(static_cast<DWORD>(interval.InMilliseconds())); 891 } 892 893 894 void OS::Abort() { 895 // Before aborting, make sure to flush output buffers. 896 fflush(stdout); 897 fflush(stderr); 898 899 if (g_hard_abort) { 900 V8_IMMEDIATE_CRASH(); 901 } 902 // Make the MSVCRT do a silent abort. 903 raise(SIGABRT); 904 905 // Make sure function doesn't return. 906 abort(); 907 } 908 909 910 void OS::DebugBreak() { 911 #if V8_CC_MSVC 912 // To avoid Visual Studio runtime support the following code can be used 913 // instead 914 // __asm { int 3 } 915 __debugbreak(); 916 #else 917 ::DebugBreak(); 918 #endif 919 } 920 921 922 class Win32MemoryMappedFile final : public OS::MemoryMappedFile { 923 public: 924 Win32MemoryMappedFile(HANDLE file, HANDLE file_mapping, void* memory, 925 size_t size) 926 : file_(file), 927 file_mapping_(file_mapping), 928 memory_(memory), 929 size_(size) {} 930 ~Win32MemoryMappedFile() final; 931 void* memory() const final { return memory_; } 932 size_t size() const final { return size_; } 933 934 private: 935 HANDLE const file_; 936 HANDLE const file_mapping_; 937 void* const memory_; 938 size_t const size_; 939 }; 940 941 942 // static 943 OS::MemoryMappedFile* OS::MemoryMappedFile::open(const char* name) { 944 // Open a physical file 945 HANDLE file = CreateFileA(name, GENERIC_READ | GENERIC_WRITE, 946 FILE_SHARE_READ | FILE_SHARE_WRITE, nullptr, 947 OPEN_EXISTING, 0, nullptr); 948 if (file == INVALID_HANDLE_VALUE) return nullptr; 949 950 DWORD size = GetFileSize(file, nullptr); 951 952 // Create a file mapping for the physical file 953 HANDLE file_mapping = 954 CreateFileMapping(file, nullptr, PAGE_READWRITE, 0, size, nullptr); 955 if (file_mapping == nullptr) return nullptr; 956 957 // Map a view of the file into memory 958 void* memory = MapViewOfFile(file_mapping, FILE_MAP_ALL_ACCESS, 0, 0, size); 959 return new Win32MemoryMappedFile(file, file_mapping, memory, size); 960 } 961 962 963 // static 964 OS::MemoryMappedFile* OS::MemoryMappedFile::create(const char* name, 965 size_t size, void* initial) { 966 // Open a physical file 967 HANDLE file = CreateFileA(name, GENERIC_READ | GENERIC_WRITE, 968 FILE_SHARE_READ | FILE_SHARE_WRITE, nullptr, 969 OPEN_ALWAYS, 0, nullptr); 970 if (file == nullptr) return nullptr; 971 // Create a file mapping for the physical file 972 HANDLE file_mapping = CreateFileMapping(file, nullptr, PAGE_READWRITE, 0, 973 static_cast<DWORD>(size), nullptr); 974 if (file_mapping == nullptr) return nullptr; 975 // Map a view of the file into memory 976 void* memory = MapViewOfFile(file_mapping, FILE_MAP_ALL_ACCESS, 0, 0, size); 977 if (memory) memmove(memory, initial, size); 978 return new Win32MemoryMappedFile(file, file_mapping, memory, size); 979 } 980 981 982 Win32MemoryMappedFile::~Win32MemoryMappedFile() { 983 if (memory_) UnmapViewOfFile(memory_); 984 CloseHandle(file_mapping_); 985 CloseHandle(file_); 986 } 987 988 989 // The following code loads functions defined in DbhHelp.h and TlHelp32.h 990 // dynamically. This is to avoid being depending on dbghelp.dll and 991 // tlhelp32.dll when running (the functions in tlhelp32.dll have been moved to 992 // kernel32.dll at some point so loading functions defines in TlHelp32.h 993 // dynamically might not be necessary any more - for some versions of Windows?). 994 995 // Function pointers to functions dynamically loaded from dbghelp.dll. 996 #define DBGHELP_FUNCTION_LIST(V) \ 997 V(SymInitialize) \ 998 V(SymGetOptions) \ 999 V(SymSetOptions) \ 1000 V(SymGetSearchPath) \ 1001 V(SymLoadModule64) \ 1002 V(StackWalk64) \ 1003 V(SymGetSymFromAddr64) \ 1004 V(SymGetLineFromAddr64) \ 1005 V(SymFunctionTableAccess64) \ 1006 V(SymGetModuleBase64) 1007 1008 // Function pointers to functions dynamically loaded from dbghelp.dll. 1009 #define TLHELP32_FUNCTION_LIST(V) \ 1010 V(CreateToolhelp32Snapshot) \ 1011 V(Module32FirstW) \ 1012 V(Module32NextW) 1013 1014 // Define the decoration to use for the type and variable name used for 1015 // dynamically loaded DLL function.. 1016 #define DLL_FUNC_TYPE(name) _##name##_ 1017 #define DLL_FUNC_VAR(name) _##name 1018 1019 // Define the type for each dynamically loaded DLL function. The function 1020 // definitions are copied from DbgHelp.h and TlHelp32.h. The IN and VOID macros 1021 // from the Windows include files are redefined here to have the function 1022 // definitions to be as close to the ones in the original .h files as possible. 1023 #ifndef IN 1024 #define IN 1025 #endif 1026 #ifndef VOID 1027 #define VOID void 1028 #endif 1029 1030 // DbgHelp isn't supported on MinGW yet 1031 #ifndef __MINGW32__ 1032 // DbgHelp.h functions. 1033 typedef BOOL (__stdcall *DLL_FUNC_TYPE(SymInitialize))(IN HANDLE hProcess, 1034 IN PSTR UserSearchPath, 1035 IN BOOL fInvadeProcess); 1036 typedef DWORD (__stdcall *DLL_FUNC_TYPE(SymGetOptions))(VOID); 1037 typedef DWORD (__stdcall *DLL_FUNC_TYPE(SymSetOptions))(IN DWORD SymOptions); 1038 typedef BOOL (__stdcall *DLL_FUNC_TYPE(SymGetSearchPath))( 1039 IN HANDLE hProcess, 1040 OUT PSTR SearchPath, 1041 IN DWORD SearchPathLength); 1042 typedef DWORD64 (__stdcall *DLL_FUNC_TYPE(SymLoadModule64))( 1043 IN HANDLE hProcess, 1044 IN HANDLE hFile, 1045 IN PSTR ImageName, 1046 IN PSTR ModuleName, 1047 IN DWORD64 BaseOfDll, 1048 IN DWORD SizeOfDll); 1049 typedef BOOL (__stdcall *DLL_FUNC_TYPE(StackWalk64))( 1050 DWORD MachineType, 1051 HANDLE hProcess, 1052 HANDLE hThread, 1053 LPSTACKFRAME64 StackFrame, 1054 PVOID ContextRecord, 1055 PREAD_PROCESS_MEMORY_ROUTINE64 ReadMemoryRoutine, 1056 PFUNCTION_TABLE_ACCESS_ROUTINE64 FunctionTableAccessRoutine, 1057 PGET_MODULE_BASE_ROUTINE64 GetModuleBaseRoutine, 1058 PTRANSLATE_ADDRESS_ROUTINE64 TranslateAddress); 1059 typedef BOOL (__stdcall *DLL_FUNC_TYPE(SymGetSymFromAddr64))( 1060 IN HANDLE hProcess, 1061 IN DWORD64 qwAddr, 1062 OUT PDWORD64 pdwDisplacement, 1063 OUT PIMAGEHLP_SYMBOL64 Symbol); 1064 typedef BOOL (__stdcall *DLL_FUNC_TYPE(SymGetLineFromAddr64))( 1065 IN HANDLE hProcess, 1066 IN DWORD64 qwAddr, 1067 OUT PDWORD pdwDisplacement, 1068 OUT PIMAGEHLP_LINE64 Line64); 1069 // DbgHelp.h typedefs. Implementation found in dbghelp.dll. 1070 typedef PVOID (__stdcall *DLL_FUNC_TYPE(SymFunctionTableAccess64))( 1071 HANDLE hProcess, 1072 DWORD64 AddrBase); // DbgHelp.h typedef PFUNCTION_TABLE_ACCESS_ROUTINE64 1073 typedef DWORD64 (__stdcall *DLL_FUNC_TYPE(SymGetModuleBase64))( 1074 HANDLE hProcess, 1075 DWORD64 AddrBase); // DbgHelp.h typedef PGET_MODULE_BASE_ROUTINE64 1076 1077 // TlHelp32.h functions. 1078 typedef HANDLE (__stdcall *DLL_FUNC_TYPE(CreateToolhelp32Snapshot))( 1079 DWORD dwFlags, 1080 DWORD th32ProcessID); 1081 typedef BOOL (__stdcall *DLL_FUNC_TYPE(Module32FirstW))(HANDLE hSnapshot, 1082 LPMODULEENTRY32W lpme); 1083 typedef BOOL (__stdcall *DLL_FUNC_TYPE(Module32NextW))(HANDLE hSnapshot, 1084 LPMODULEENTRY32W lpme); 1085 1086 #undef IN 1087 #undef VOID 1088 1089 // Declare a variable for each dynamically loaded DLL function. 1090 #define DEF_DLL_FUNCTION(name) DLL_FUNC_TYPE(name) DLL_FUNC_VAR(name) = nullptr; 1091 DBGHELP_FUNCTION_LIST(DEF_DLL_FUNCTION) 1092 TLHELP32_FUNCTION_LIST(DEF_DLL_FUNCTION) 1093 #undef DEF_DLL_FUNCTION 1094 1095 // Load the functions. This function has a lot of "ugly" macros in order to 1096 // keep down code duplication. 1097 1098 static bool LoadDbgHelpAndTlHelp32() { 1099 static bool dbghelp_loaded = false; 1100 1101 if (dbghelp_loaded) return true; 1102 1103 HMODULE module; 1104 1105 // Load functions from the dbghelp.dll module. 1106 module = LoadLibrary(TEXT("dbghelp.dll")); 1107 if (module == nullptr) { 1108 return false; 1109 } 1110 1111 #define LOAD_DLL_FUNC(name) \ 1112 DLL_FUNC_VAR(name) = \ 1113 reinterpret_cast<DLL_FUNC_TYPE(name)>(GetProcAddress(module, #name)); 1114 1115 DBGHELP_FUNCTION_LIST(LOAD_DLL_FUNC) 1116 1117 #undef LOAD_DLL_FUNC 1118 1119 // Load functions from the kernel32.dll module (the TlHelp32.h function used 1120 // to be in tlhelp32.dll but are now moved to kernel32.dll). 1121 module = LoadLibrary(TEXT("kernel32.dll")); 1122 if (module == nullptr) { 1123 return false; 1124 } 1125 1126 #define LOAD_DLL_FUNC(name) \ 1127 DLL_FUNC_VAR(name) = \ 1128 reinterpret_cast<DLL_FUNC_TYPE(name)>(GetProcAddress(module, #name)); 1129 1130 TLHELP32_FUNCTION_LIST(LOAD_DLL_FUNC) 1131 1132 #undef LOAD_DLL_FUNC 1133 1134 // Check that all functions where loaded. 1135 bool result = 1136 #define DLL_FUNC_LOADED(name) (DLL_FUNC_VAR(name) != nullptr)&& 1137 1138 DBGHELP_FUNCTION_LIST(DLL_FUNC_LOADED) 1139 TLHELP32_FUNCTION_LIST(DLL_FUNC_LOADED) 1140 1141 #undef DLL_FUNC_LOADED 1142 true; 1143 1144 dbghelp_loaded = result; 1145 return result; 1146 // NOTE: The modules are never unloaded and will stay around until the 1147 // application is closed. 1148 } 1149 1150 #undef DBGHELP_FUNCTION_LIST 1151 #undef TLHELP32_FUNCTION_LIST 1152 #undef DLL_FUNC_VAR 1153 #undef DLL_FUNC_TYPE 1154 1155 1156 // Load the symbols for generating stack traces. 1157 static std::vector<OS::SharedLibraryAddress> LoadSymbols( 1158 HANDLE process_handle) { 1159 static std::vector<OS::SharedLibraryAddress> result; 1160 1161 static bool symbols_loaded = false; 1162 1163 if (symbols_loaded) return result; 1164 1165 BOOL ok; 1166 1167 // Initialize the symbol engine. 1168 ok = _SymInitialize(process_handle, // hProcess 1169 nullptr, // UserSearchPath 1170 false); // fInvadeProcess 1171 if (!ok) return result; 1172 1173 DWORD options = _SymGetOptions(); 1174 options |= SYMOPT_LOAD_LINES; 1175 options |= SYMOPT_FAIL_CRITICAL_ERRORS; 1176 options = _SymSetOptions(options); 1177 1178 char buf[OS::kStackWalkMaxNameLen] = {0}; 1179 ok = _SymGetSearchPath(process_handle, buf, OS::kStackWalkMaxNameLen); 1180 if (!ok) { 1181 int err = GetLastError(); 1182 OS::Print("%d\n", err); 1183 return result; 1184 } 1185 1186 HANDLE snapshot = _CreateToolhelp32Snapshot( 1187 TH32CS_SNAPMODULE, // dwFlags 1188 GetCurrentProcessId()); // th32ProcessId 1189 if (snapshot == INVALID_HANDLE_VALUE) return result; 1190 MODULEENTRY32W module_entry; 1191 module_entry.dwSize = sizeof(module_entry); // Set the size of the structure. 1192 BOOL cont = _Module32FirstW(snapshot, &module_entry); 1193 while (cont) { 1194 DWORD64 base; 1195 // NOTE the SymLoadModule64 function has the peculiarity of accepting a 1196 // both unicode and ASCII strings even though the parameter is PSTR. 1197 base = _SymLoadModule64( 1198 process_handle, // hProcess 1199 0, // hFile 1200 reinterpret_cast<PSTR>(module_entry.szExePath), // ImageName 1201 reinterpret_cast<PSTR>(module_entry.szModule), // ModuleName 1202 reinterpret_cast<DWORD64>(module_entry.modBaseAddr), // BaseOfDll 1203 module_entry.modBaseSize); // SizeOfDll 1204 if (base == 0) { 1205 int err = GetLastError(); 1206 if (err != ERROR_MOD_NOT_FOUND && 1207 err != ERROR_INVALID_HANDLE) { 1208 result.clear(); 1209 return result; 1210 } 1211 } 1212 int lib_name_length = WideCharToMultiByte( 1213 CP_UTF8, 0, module_entry.szExePath, -1, nullptr, 0, nullptr, nullptr); 1214 std::string lib_name(lib_name_length, 0); 1215 WideCharToMultiByte(CP_UTF8, 0, module_entry.szExePath, -1, &lib_name[0], 1216 lib_name_length, nullptr, nullptr); 1217 result.push_back(OS::SharedLibraryAddress( 1218 lib_name, reinterpret_cast<uintptr_t>(module_entry.modBaseAddr), 1219 reinterpret_cast<uintptr_t>(module_entry.modBaseAddr + 1220 module_entry.modBaseSize))); 1221 cont = _Module32NextW(snapshot, &module_entry); 1222 } 1223 CloseHandle(snapshot); 1224 1225 symbols_loaded = true; 1226 return result; 1227 } 1228 1229 1230 std::vector<OS::SharedLibraryAddress> OS::GetSharedLibraryAddresses() { 1231 // SharedLibraryEvents are logged when loading symbol information. 1232 // Only the shared libraries loaded at the time of the call to 1233 // GetSharedLibraryAddresses are logged. DLLs loaded after 1234 // initialization are not accounted for. 1235 if (!LoadDbgHelpAndTlHelp32()) return std::vector<OS::SharedLibraryAddress>(); 1236 HANDLE process_handle = GetCurrentProcess(); 1237 return LoadSymbols(process_handle); 1238 } 1239 1240 void OS::SignalCodeMovingGC() {} 1241 1242 #else // __MINGW32__ 1243 std::vector<OS::SharedLibraryAddress> OS::GetSharedLibraryAddresses() { 1244 return std::vector<OS::SharedLibraryAddress>(); 1245 } 1246 1247 void OS::SignalCodeMovingGC() {} 1248 #endif // __MINGW32__ 1249 1250 1251 int OS::ActivationFrameAlignment() { 1252 #ifdef _WIN64 1253 return 16; // Windows 64-bit ABI requires the stack to be 16-byte aligned. 1254 #elif defined(__MINGW32__) 1255 // With gcc 4.4 the tree vectorization optimizer can generate code 1256 // that requires 16 byte alignment such as movdqa on x86. 1257 return 16; 1258 #else 1259 return 8; // Floating-point math runs faster with 8-byte alignment. 1260 #endif 1261 } 1262 1263 #if (defined(_WIN32) || defined(_WIN64)) 1264 void EnsureConsoleOutputWin32() { 1265 UINT new_flags = 1266 SEM_FAILCRITICALERRORS | SEM_NOGPFAULTERRORBOX | SEM_NOOPENFILEERRORBOX; 1267 UINT existing_flags = SetErrorMode(new_flags); 1268 SetErrorMode(existing_flags | new_flags); 1269 #if defined(_MSC_VER) 1270 _CrtSetReportMode(_CRT_WARN, _CRTDBG_MODE_DEBUG | _CRTDBG_MODE_FILE); 1271 _CrtSetReportFile(_CRT_WARN, _CRTDBG_FILE_STDERR); 1272 _CrtSetReportMode(_CRT_ASSERT, _CRTDBG_MODE_DEBUG | _CRTDBG_MODE_FILE); 1273 _CrtSetReportFile(_CRT_ASSERT, _CRTDBG_FILE_STDERR); 1274 _CrtSetReportMode(_CRT_ERROR, _CRTDBG_MODE_DEBUG | _CRTDBG_MODE_FILE); 1275 _CrtSetReportFile(_CRT_ERROR, _CRTDBG_FILE_STDERR); 1276 _set_error_mode(_OUT_TO_STDERR); 1277 #endif // defined(_MSC_VER) 1278 } 1279 #endif // (defined(_WIN32) || defined(_WIN64)) 1280 1281 // ---------------------------------------------------------------------------- 1282 // Win32 thread support. 1283 1284 // Definition of invalid thread handle and id. 1285 static const HANDLE kNoThread = INVALID_HANDLE_VALUE; 1286 1287 // Entry point for threads. The supplied argument is a pointer to the thread 1288 // object. The entry function dispatches to the run method in the thread 1289 // object. It is important that this function has __stdcall calling 1290 // convention. 1291 static unsigned int __stdcall ThreadEntry(void* arg) { 1292 Thread* thread = reinterpret_cast<Thread*>(arg); 1293 thread->NotifyStartedAndRun(); 1294 return 0; 1295 } 1296 1297 1298 class Thread::PlatformData { 1299 public: 1300 explicit PlatformData(HANDLE thread) : thread_(thread) {} 1301 HANDLE thread_; 1302 unsigned thread_id_; 1303 }; 1304 1305 1306 // Initialize a Win32 thread object. The thread has an invalid thread 1307 // handle until it is started. 1308 1309 Thread::Thread(const Options& options) 1310 : stack_size_(options.stack_size()), start_semaphore_(nullptr) { 1311 data_ = new PlatformData(kNoThread); 1312 set_name(options.name()); 1313 } 1314 1315 1316 void Thread::set_name(const char* name) { 1317 OS::StrNCpy(name_, sizeof(name_), name, strlen(name)); 1318 name_[sizeof(name_) - 1] = '\0'; 1319 } 1320 1321 1322 // Close our own handle for the thread. 1323 Thread::~Thread() { 1324 if (data_->thread_ != kNoThread) CloseHandle(data_->thread_); 1325 delete data_; 1326 } 1327 1328 1329 // Create a new thread. It is important to use _beginthreadex() instead of 1330 // the Win32 function CreateThread(), because the CreateThread() does not 1331 // initialize thread specific structures in the C runtime library. 1332 void Thread::Start() { 1333 data_->thread_ = reinterpret_cast<HANDLE>( 1334 _beginthreadex(nullptr, static_cast<unsigned>(stack_size_), ThreadEntry, 1335 this, 0, &data_->thread_id_)); 1336 } 1337 1338 1339 // Wait for thread to terminate. 1340 void Thread::Join() { 1341 if (data_->thread_id_ != GetCurrentThreadId()) { 1342 WaitForSingleObject(data_->thread_, INFINITE); 1343 } 1344 } 1345 1346 1347 Thread::LocalStorageKey Thread::CreateThreadLocalKey() { 1348 DWORD result = TlsAlloc(); 1349 DCHECK(result != TLS_OUT_OF_INDEXES); 1350 return static_cast<LocalStorageKey>(result); 1351 } 1352 1353 1354 void Thread::DeleteThreadLocalKey(LocalStorageKey key) { 1355 BOOL result = TlsFree(static_cast<DWORD>(key)); 1356 USE(result); 1357 DCHECK(result); 1358 } 1359 1360 1361 void* Thread::GetThreadLocal(LocalStorageKey key) { 1362 return TlsGetValue(static_cast<DWORD>(key)); 1363 } 1364 1365 1366 void Thread::SetThreadLocal(LocalStorageKey key, void* value) { 1367 BOOL result = TlsSetValue(static_cast<DWORD>(key), value); 1368 USE(result); 1369 DCHECK(result); 1370 } 1371 1372 } // namespace base 1373 } // namespace v8 1374