1 // Copyright 2012 the V8 project authors. All rights reserved. 2 // Redistribution and use in source and binary forms, with or without 3 // modification, are permitted provided that the following conditions are 4 // met: 5 // 6 // * Redistributions of source code must retain the above copyright 7 // notice, this list of conditions and the following disclaimer. 8 // * Redistributions in binary form must reproduce the above 9 // copyright notice, this list of conditions and the following 10 // disclaimer in the documentation and/or other materials provided 11 // with the distribution. 12 // * Neither the name of Google Inc. nor the names of its 13 // contributors may be used to endorse or promote products derived 14 // from this software without specific prior written permission. 15 // 16 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 17 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 18 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 19 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 20 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 21 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 22 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 23 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 24 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 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. 27 28 // Platform specific code for Win32. 29 30 // Secure API functions are not available using MinGW with msvcrt.dll 31 // on Windows XP. Make sure MINGW_HAS_SECURE_API is not defined to 32 // disable definition of secure API functions in standard headers that 33 // would conflict with our own implementation. 34 #ifdef __MINGW32__ 35 #include <_mingw.h> 36 #ifdef MINGW_HAS_SECURE_API 37 #undef MINGW_HAS_SECURE_API 38 #endif // MINGW_HAS_SECURE_API 39 #endif // __MINGW32__ 40 41 #define V8_WIN32_HEADERS_FULL 42 #include "win32-headers.h" 43 44 #include "v8.h" 45 46 #include "codegen.h" 47 #include "platform.h" 48 #include "simulator.h" 49 #include "vm-state-inl.h" 50 51 #ifdef _MSC_VER 52 53 // Case-insensitive bounded string comparisons. Use stricmp() on Win32. Usually 54 // defined in strings.h. 55 int strncasecmp(const char* s1, const char* s2, int n) { 56 return _strnicmp(s1, s2, n); 57 } 58 59 #endif // _MSC_VER 60 61 62 // Extra functions for MinGW. Most of these are the _s functions which are in 63 // the Microsoft Visual Studio C++ CRT. 64 #ifdef __MINGW32__ 65 66 67 #ifndef __MINGW64_VERSION_MAJOR 68 69 #define _TRUNCATE 0 70 #define STRUNCATE 80 71 72 inline void MemoryBarrier() { 73 int barrier = 0; 74 __asm__ __volatile__("xchgl %%eax,%0 ":"=r" (barrier)); 75 } 76 77 #endif // __MINGW64_VERSION_MAJOR 78 79 80 int localtime_s(tm* out_tm, const time_t* time) { 81 tm* posix_local_time_struct = localtime(time); 82 if (posix_local_time_struct == NULL) return 1; 83 *out_tm = *posix_local_time_struct; 84 return 0; 85 } 86 87 88 int fopen_s(FILE** pFile, const char* filename, const char* mode) { 89 *pFile = fopen(filename, mode); 90 return *pFile != NULL ? 0 : 1; 91 } 92 93 int _vsnprintf_s(char* buffer, size_t sizeOfBuffer, size_t count, 94 const char* format, va_list argptr) { 95 ASSERT(count == _TRUNCATE); 96 return _vsnprintf(buffer, sizeOfBuffer, format, argptr); 97 } 98 99 100 int strncpy_s(char* dest, size_t dest_size, const char* source, size_t count) { 101 CHECK(source != NULL); 102 CHECK(dest != NULL); 103 CHECK_GT(dest_size, 0); 104 105 if (count == _TRUNCATE) { 106 while (dest_size > 0 && *source != 0) { 107 *(dest++) = *(source++); 108 --dest_size; 109 } 110 if (dest_size == 0) { 111 *(dest - 1) = 0; 112 return STRUNCATE; 113 } 114 } else { 115 while (dest_size > 0 && count > 0 && *source != 0) { 116 *(dest++) = *(source++); 117 --dest_size; 118 --count; 119 } 120 } 121 CHECK_GT(dest_size, 0); 122 *dest = 0; 123 return 0; 124 } 125 126 #endif // __MINGW32__ 127 128 // Generate a pseudo-random number in the range 0-2^31-1. Usually 129 // defined in stdlib.h. Missing in both Microsoft Visual Studio C++ and MinGW. 130 int random() { 131 return rand(); 132 } 133 134 135 namespace v8 { 136 namespace internal { 137 138 intptr_t OS::MaxVirtualMemory() { 139 return 0; 140 } 141 142 143 double ceiling(double x) { 144 return ceil(x); 145 } 146 147 148 static Mutex* limit_mutex = NULL; 149 150 #if V8_TARGET_ARCH_IA32 151 static void MemMoveWrapper(void* dest, const void* src, size_t size) { 152 memmove(dest, src, size); 153 } 154 155 156 // Initialize to library version so we can call this at any time during startup. 157 static OS::MemMoveFunction memmove_function = &MemMoveWrapper; 158 159 // Defined in codegen-ia32.cc. 160 OS::MemMoveFunction CreateMemMoveFunction(); 161 162 // Copy memory area to disjoint memory area. 163 void OS::MemMove(void* dest, const void* src, size_t size) { 164 if (size == 0) return; 165 // Note: here we rely on dependent reads being ordered. This is true 166 // on all architectures we currently support. 167 (*memmove_function)(dest, src, size); 168 } 169 170 #endif // V8_TARGET_ARCH_IA32 171 172 #ifdef _WIN64 173 typedef double (*ModuloFunction)(double, double); 174 static ModuloFunction modulo_function = NULL; 175 // Defined in codegen-x64.cc. 176 ModuloFunction CreateModuloFunction(); 177 178 void init_modulo_function() { 179 modulo_function = CreateModuloFunction(); 180 } 181 182 183 double modulo(double x, double y) { 184 // Note: here we rely on dependent reads being ordered. This is true 185 // on all architectures we currently support. 186 return (*modulo_function)(x, y); 187 } 188 #else // Win32 189 190 double modulo(double x, double y) { 191 // Workaround MS fmod bugs. ECMA-262 says: 192 // dividend is finite and divisor is an infinity => result equals dividend 193 // dividend is a zero and divisor is nonzero finite => result equals dividend 194 if (!(std::isfinite(x) && (!std::isfinite(y) && !std::isnan(y))) && 195 !(x == 0 && (y != 0 && std::isfinite(y)))) { 196 x = fmod(x, y); 197 } 198 return x; 199 } 200 201 #endif // _WIN64 202 203 204 #define UNARY_MATH_FUNCTION(name, generator) \ 205 static UnaryMathFunction fast_##name##_function = NULL; \ 206 void init_fast_##name##_function() { \ 207 fast_##name##_function = generator; \ 208 } \ 209 double fast_##name(double x) { \ 210 return (*fast_##name##_function)(x); \ 211 } 212 213 UNARY_MATH_FUNCTION(sin, CreateTranscendentalFunction(TranscendentalCache::SIN)) 214 UNARY_MATH_FUNCTION(cos, CreateTranscendentalFunction(TranscendentalCache::COS)) 215 UNARY_MATH_FUNCTION(tan, CreateTranscendentalFunction(TranscendentalCache::TAN)) 216 UNARY_MATH_FUNCTION(log, CreateTranscendentalFunction(TranscendentalCache::LOG)) 217 UNARY_MATH_FUNCTION(exp, CreateExpFunction()) 218 UNARY_MATH_FUNCTION(sqrt, CreateSqrtFunction()) 219 220 #undef UNARY_MATH_FUNCTION 221 222 223 void lazily_initialize_fast_exp() { 224 if (fast_exp_function == NULL) { 225 init_fast_exp_function(); 226 } 227 } 228 229 230 void MathSetup() { 231 #ifdef _WIN64 232 init_modulo_function(); 233 #endif 234 init_fast_sin_function(); 235 init_fast_cos_function(); 236 init_fast_tan_function(); 237 init_fast_log_function(); 238 // fast_exp is initialized lazily. 239 init_fast_sqrt_function(); 240 } 241 242 243 // ---------------------------------------------------------------------------- 244 // The Time class represents time on win32. A timestamp is represented as 245 // a 64-bit integer in 100 nanoseconds since January 1, 1601 (UTC). JavaScript 246 // timestamps are represented as a doubles in milliseconds since 00:00:00 UTC, 247 // January 1, 1970. 248 249 class Time { 250 public: 251 // Constructors. 252 Time(); 253 explicit Time(double jstime); 254 Time(int year, int mon, int day, int hour, int min, int sec); 255 256 // Convert timestamp to JavaScript representation. 257 double ToJSTime(); 258 259 // Set timestamp to current time. 260 void SetToCurrentTime(); 261 262 // Returns the local timezone offset in milliseconds east of UTC. This is 263 // the number of milliseconds you must add to UTC to get local time, i.e. 264 // LocalOffset(CET) = 3600000 and LocalOffset(PST) = -28800000. This 265 // routine also takes into account whether daylight saving is effect 266 // at the time. 267 int64_t LocalOffset(); 268 269 // Returns the daylight savings time offset for the time in milliseconds. 270 int64_t DaylightSavingsOffset(); 271 272 // Returns a string identifying the current timezone for the 273 // timestamp taking into account daylight saving. 274 char* LocalTimezone(); 275 276 private: 277 // Constants for time conversion. 278 static const int64_t kTimeEpoc = 116444736000000000LL; 279 static const int64_t kTimeScaler = 10000; 280 static const int64_t kMsPerMinute = 60000; 281 282 // Constants for timezone information. 283 static const int kTzNameSize = 128; 284 static const bool kShortTzNames = false; 285 286 // Timezone information. We need to have static buffers for the 287 // timezone names because we return pointers to these in 288 // LocalTimezone(). 289 static bool tz_initialized_; 290 static TIME_ZONE_INFORMATION tzinfo_; 291 static char std_tz_name_[kTzNameSize]; 292 static char dst_tz_name_[kTzNameSize]; 293 294 // Initialize the timezone information (if not already done). 295 static void TzSet(); 296 297 // Guess the name of the timezone from the bias. 298 static const char* GuessTimezoneNameFromBias(int bias); 299 300 // Return whether or not daylight savings time is in effect at this time. 301 bool InDST(); 302 303 // Return the difference (in milliseconds) between this timestamp and 304 // another timestamp. 305 int64_t Diff(Time* other); 306 307 // Accessor for FILETIME representation. 308 FILETIME& ft() { return time_.ft_; } 309 310 // Accessor for integer representation. 311 int64_t& t() { return time_.t_; } 312 313 // Although win32 uses 64-bit integers for representing timestamps, 314 // these are packed into a FILETIME structure. The FILETIME structure 315 // is just a struct representing a 64-bit integer. The TimeStamp union 316 // allows access to both a FILETIME and an integer representation of 317 // the timestamp. 318 union TimeStamp { 319 FILETIME ft_; 320 int64_t t_; 321 }; 322 323 TimeStamp time_; 324 }; 325 326 327 // Static variables. 328 bool Time::tz_initialized_ = false; 329 TIME_ZONE_INFORMATION Time::tzinfo_; 330 char Time::std_tz_name_[kTzNameSize]; 331 char Time::dst_tz_name_[kTzNameSize]; 332 333 334 // Initialize timestamp to start of epoc. 335 Time::Time() { 336 t() = 0; 337 } 338 339 340 // Initialize timestamp from a JavaScript timestamp. 341 Time::Time(double jstime) { 342 t() = static_cast<int64_t>(jstime) * kTimeScaler + kTimeEpoc; 343 } 344 345 346 // Initialize timestamp from date/time components. 347 Time::Time(int year, int mon, int day, int hour, int min, int sec) { 348 SYSTEMTIME st; 349 st.wYear = year; 350 st.wMonth = mon; 351 st.wDay = day; 352 st.wHour = hour; 353 st.wMinute = min; 354 st.wSecond = sec; 355 st.wMilliseconds = 0; 356 SystemTimeToFileTime(&st, &ft()); 357 } 358 359 360 // Convert timestamp to JavaScript timestamp. 361 double Time::ToJSTime() { 362 return static_cast<double>((t() - kTimeEpoc) / kTimeScaler); 363 } 364 365 366 // Guess the name of the timezone from the bias. 367 // The guess is very biased towards the northern hemisphere. 368 const char* Time::GuessTimezoneNameFromBias(int bias) { 369 static const int kHour = 60; 370 switch (-bias) { 371 case -9*kHour: return "Alaska"; 372 case -8*kHour: return "Pacific"; 373 case -7*kHour: return "Mountain"; 374 case -6*kHour: return "Central"; 375 case -5*kHour: return "Eastern"; 376 case -4*kHour: return "Atlantic"; 377 case 0*kHour: return "GMT"; 378 case +1*kHour: return "Central Europe"; 379 case +2*kHour: return "Eastern Europe"; 380 case +3*kHour: return "Russia"; 381 case +5*kHour + 30: return "India"; 382 case +8*kHour: return "China"; 383 case +9*kHour: return "Japan"; 384 case +12*kHour: return "New Zealand"; 385 default: return "Local"; 386 } 387 } 388 389 390 // Initialize timezone information. The timezone information is obtained from 391 // windows. If we cannot get the timezone information we fall back to CET. 392 // Please notice that this code is not thread-safe. 393 void Time::TzSet() { 394 // Just return if timezone information has already been initialized. 395 if (tz_initialized_) return; 396 397 // Initialize POSIX time zone data. 398 _tzset(); 399 // Obtain timezone information from operating system. 400 memset(&tzinfo_, 0, sizeof(tzinfo_)); 401 if (GetTimeZoneInformation(&tzinfo_) == TIME_ZONE_ID_INVALID) { 402 // If we cannot get timezone information we fall back to CET. 403 tzinfo_.Bias = -60; 404 tzinfo_.StandardDate.wMonth = 10; 405 tzinfo_.StandardDate.wDay = 5; 406 tzinfo_.StandardDate.wHour = 3; 407 tzinfo_.StandardBias = 0; 408 tzinfo_.DaylightDate.wMonth = 3; 409 tzinfo_.DaylightDate.wDay = 5; 410 tzinfo_.DaylightDate.wHour = 2; 411 tzinfo_.DaylightBias = -60; 412 } 413 414 // Make standard and DST timezone names. 415 WideCharToMultiByte(CP_UTF8, 0, tzinfo_.StandardName, -1, 416 std_tz_name_, kTzNameSize, NULL, NULL); 417 std_tz_name_[kTzNameSize - 1] = '\0'; 418 WideCharToMultiByte(CP_UTF8, 0, tzinfo_.DaylightName, -1, 419 dst_tz_name_, kTzNameSize, NULL, NULL); 420 dst_tz_name_[kTzNameSize - 1] = '\0'; 421 422 // If OS returned empty string or resource id (like "@tzres.dll,-211") 423 // simply guess the name from the UTC bias of the timezone. 424 // To properly resolve the resource identifier requires a library load, 425 // which is not possible in a sandbox. 426 if (std_tz_name_[0] == '\0' || std_tz_name_[0] == '@') { 427 OS::SNPrintF(Vector<char>(std_tz_name_, kTzNameSize - 1), 428 "%s Standard Time", 429 GuessTimezoneNameFromBias(tzinfo_.Bias)); 430 } 431 if (dst_tz_name_[0] == '\0' || dst_tz_name_[0] == '@') { 432 OS::SNPrintF(Vector<char>(dst_tz_name_, kTzNameSize - 1), 433 "%s Daylight Time", 434 GuessTimezoneNameFromBias(tzinfo_.Bias)); 435 } 436 437 // Timezone information initialized. 438 tz_initialized_ = true; 439 } 440 441 442 // Return the difference in milliseconds between this and another timestamp. 443 int64_t Time::Diff(Time* other) { 444 return (t() - other->t()) / kTimeScaler; 445 } 446 447 448 // Set timestamp to current time. 449 void Time::SetToCurrentTime() { 450 // The default GetSystemTimeAsFileTime has a ~15.5ms resolution. 451 // Because we're fast, we like fast timers which have at least a 452 // 1ms resolution. 453 // 454 // timeGetTime() provides 1ms granularity when combined with 455 // timeBeginPeriod(). If the host application for v8 wants fast 456 // timers, it can use timeBeginPeriod to increase the resolution. 457 // 458 // Using timeGetTime() has a drawback because it is a 32bit value 459 // and hence rolls-over every ~49days. 460 // 461 // To use the clock, we use GetSystemTimeAsFileTime as our base; 462 // and then use timeGetTime to extrapolate current time from the 463 // start time. To deal with rollovers, we resync the clock 464 // any time when more than kMaxClockElapsedTime has passed or 465 // whenever timeGetTime creates a rollover. 466 467 static bool initialized = false; 468 static TimeStamp init_time; 469 static DWORD init_ticks; 470 static const int64_t kHundredNanosecondsPerSecond = 10000000; 471 static const int64_t kMaxClockElapsedTime = 472 60*kHundredNanosecondsPerSecond; // 1 minute 473 474 // If we are uninitialized, we need to resync the clock. 475 bool needs_resync = !initialized; 476 477 // Get the current time. 478 TimeStamp time_now; 479 GetSystemTimeAsFileTime(&time_now.ft_); 480 DWORD ticks_now = timeGetTime(); 481 482 // Check if we need to resync due to clock rollover. 483 needs_resync |= ticks_now < init_ticks; 484 485 // Check if we need to resync due to elapsed time. 486 needs_resync |= (time_now.t_ - init_time.t_) > kMaxClockElapsedTime; 487 488 // Check if we need to resync due to backwards time change. 489 needs_resync |= time_now.t_ < init_time.t_; 490 491 // Resync the clock if necessary. 492 if (needs_resync) { 493 GetSystemTimeAsFileTime(&init_time.ft_); 494 init_ticks = ticks_now = timeGetTime(); 495 initialized = true; 496 } 497 498 // Finally, compute the actual time. Why is this so hard. 499 DWORD elapsed = ticks_now - init_ticks; 500 this->time_.t_ = init_time.t_ + (static_cast<int64_t>(elapsed) * 10000); 501 } 502 503 504 // Return the local timezone offset in milliseconds east of UTC. This 505 // takes into account whether daylight saving is in effect at the time. 506 // Only times in the 32-bit Unix range may be passed to this function. 507 // Also, adding the time-zone offset to the input must not overflow. 508 // The function EquivalentTime() in date.js guarantees this. 509 int64_t Time::LocalOffset() { 510 // Initialize timezone information, if needed. 511 TzSet(); 512 513 Time rounded_to_second(*this); 514 rounded_to_second.t() = rounded_to_second.t() / 1000 / kTimeScaler * 515 1000 * kTimeScaler; 516 // Convert to local time using POSIX localtime function. 517 // Windows XP Service Pack 3 made SystemTimeToTzSpecificLocalTime() 518 // very slow. Other browsers use localtime(). 519 520 // Convert from JavaScript milliseconds past 1/1/1970 0:00:00 to 521 // POSIX seconds past 1/1/1970 0:00:00. 522 double unchecked_posix_time = rounded_to_second.ToJSTime() / 1000; 523 if (unchecked_posix_time > INT_MAX || unchecked_posix_time < 0) { 524 return 0; 525 } 526 // Because _USE_32BIT_TIME_T is defined, time_t is a 32-bit int. 527 time_t posix_time = static_cast<time_t>(unchecked_posix_time); 528 529 // Convert to local time, as struct with fields for day, hour, year, etc. 530 tm posix_local_time_struct; 531 if (localtime_s(&posix_local_time_struct, &posix_time)) return 0; 532 533 if (posix_local_time_struct.tm_isdst > 0) { 534 return (tzinfo_.Bias + tzinfo_.DaylightBias) * -kMsPerMinute; 535 } else if (posix_local_time_struct.tm_isdst == 0) { 536 return (tzinfo_.Bias + tzinfo_.StandardBias) * -kMsPerMinute; 537 } else { 538 return tzinfo_.Bias * -kMsPerMinute; 539 } 540 } 541 542 543 // Return whether or not daylight savings time is in effect at this time. 544 bool Time::InDST() { 545 // Initialize timezone information, if needed. 546 TzSet(); 547 548 // Determine if DST is in effect at the specified time. 549 bool in_dst = false; 550 if (tzinfo_.StandardDate.wMonth != 0 || tzinfo_.DaylightDate.wMonth != 0) { 551 // Get the local timezone offset for the timestamp in milliseconds. 552 int64_t offset = LocalOffset(); 553 554 // Compute the offset for DST. The bias parameters in the timezone info 555 // are specified in minutes. These must be converted to milliseconds. 556 int64_t dstofs = -(tzinfo_.Bias + tzinfo_.DaylightBias) * kMsPerMinute; 557 558 // If the local time offset equals the timezone bias plus the daylight 559 // bias then DST is in effect. 560 in_dst = offset == dstofs; 561 } 562 563 return in_dst; 564 } 565 566 567 // Return the daylight savings time offset for this time. 568 int64_t Time::DaylightSavingsOffset() { 569 return InDST() ? 60 * kMsPerMinute : 0; 570 } 571 572 573 // Returns a string identifying the current timezone for the 574 // timestamp taking into account daylight saving. 575 char* Time::LocalTimezone() { 576 // Return the standard or DST time zone name based on whether daylight 577 // saving is in effect at the given time. 578 return InDST() ? dst_tz_name_ : std_tz_name_; 579 } 580 581 582 void OS::PostSetUp() { 583 // Math functions depend on CPU features therefore they are initialized after 584 // CPU. 585 MathSetup(); 586 #if V8_TARGET_ARCH_IA32 587 OS::MemMoveFunction generated_memmove = CreateMemMoveFunction(); 588 if (generated_memmove != NULL) { 589 memmove_function = generated_memmove; 590 } 591 #endif 592 } 593 594 595 // Returns the accumulated user time for thread. 596 int OS::GetUserTime(uint32_t* secs, uint32_t* usecs) { 597 FILETIME dummy; 598 uint64_t usertime; 599 600 // Get the amount of time that the thread has executed in user mode. 601 if (!GetThreadTimes(GetCurrentThread(), &dummy, &dummy, &dummy, 602 reinterpret_cast<FILETIME*>(&usertime))) return -1; 603 604 // Adjust the resolution to micro-seconds. 605 usertime /= 10; 606 607 // Convert to seconds and microseconds 608 *secs = static_cast<uint32_t>(usertime / 1000000); 609 *usecs = static_cast<uint32_t>(usertime % 1000000); 610 return 0; 611 } 612 613 614 // Returns current time as the number of milliseconds since 615 // 00:00:00 UTC, January 1, 1970. 616 double OS::TimeCurrentMillis() { 617 Time t; 618 t.SetToCurrentTime(); 619 return t.ToJSTime(); 620 } 621 622 623 // Returns the tickcounter based on timeGetTime. 624 int64_t OS::Ticks() { 625 return timeGetTime() * 1000; // Convert to microseconds. 626 } 627 628 629 // Returns a string identifying the current timezone taking into 630 // account daylight saving. 631 const char* OS::LocalTimezone(double time) { 632 return Time(time).LocalTimezone(); 633 } 634 635 636 // Returns the local time offset in milliseconds east of UTC without 637 // taking daylight savings time into account. 638 double OS::LocalTimeOffset() { 639 // Use current time, rounded to the millisecond. 640 Time t(TimeCurrentMillis()); 641 // Time::LocalOffset inlcudes any daylight savings offset, so subtract it. 642 return static_cast<double>(t.LocalOffset() - t.DaylightSavingsOffset()); 643 } 644 645 646 // Returns the daylight savings offset in milliseconds for the given 647 // time. 648 double OS::DaylightSavingsOffset(double time) { 649 int64_t offset = Time(time).DaylightSavingsOffset(); 650 return static_cast<double>(offset); 651 } 652 653 654 int OS::GetLastError() { 655 return ::GetLastError(); 656 } 657 658 659 int OS::GetCurrentProcessId() { 660 return static_cast<int>(::GetCurrentProcessId()); 661 } 662 663 664 // ---------------------------------------------------------------------------- 665 // Win32 console output. 666 // 667 // If a Win32 application is linked as a console application it has a normal 668 // standard output and standard error. In this case normal printf works fine 669 // for output. However, if the application is linked as a GUI application, 670 // the process doesn't have a console, and therefore (debugging) output is lost. 671 // This is the case if we are embedded in a windows program (like a browser). 672 // In order to be able to get debug output in this case the the debugging 673 // facility using OutputDebugString. This output goes to the active debugger 674 // for the process (if any). Else the output can be monitored using DBMON.EXE. 675 676 enum OutputMode { 677 UNKNOWN, // Output method has not yet been determined. 678 CONSOLE, // Output is written to stdout. 679 ODS // Output is written to debug facility. 680 }; 681 682 static OutputMode output_mode = UNKNOWN; // Current output mode. 683 684 685 // Determine if the process has a console for output. 686 static bool HasConsole() { 687 // Only check the first time. Eventual race conditions are not a problem, 688 // because all threads will eventually determine the same mode. 689 if (output_mode == UNKNOWN) { 690 // We cannot just check that the standard output is attached to a console 691 // because this would fail if output is redirected to a file. Therefore we 692 // say that a process does not have an output console if either the 693 // standard output handle is invalid or its file type is unknown. 694 if (GetStdHandle(STD_OUTPUT_HANDLE) != INVALID_HANDLE_VALUE && 695 GetFileType(GetStdHandle(STD_OUTPUT_HANDLE)) != FILE_TYPE_UNKNOWN) 696 output_mode = CONSOLE; 697 else 698 output_mode = ODS; 699 } 700 return output_mode == CONSOLE; 701 } 702 703 704 static void VPrintHelper(FILE* stream, const char* format, va_list args) { 705 if (HasConsole()) { 706 vfprintf(stream, format, args); 707 } else { 708 // It is important to use safe print here in order to avoid 709 // overflowing the buffer. We might truncate the output, but this 710 // does not crash. 711 EmbeddedVector<char, 4096> buffer; 712 OS::VSNPrintF(buffer, format, args); 713 OutputDebugStringA(buffer.start()); 714 } 715 } 716 717 718 FILE* OS::FOpen(const char* path, const char* mode) { 719 FILE* result; 720 if (fopen_s(&result, path, mode) == 0) { 721 return result; 722 } else { 723 return NULL; 724 } 725 } 726 727 728 bool OS::Remove(const char* path) { 729 return (DeleteFileA(path) != 0); 730 } 731 732 733 FILE* OS::OpenTemporaryFile() { 734 // tmpfile_s tries to use the root dir, don't use it. 735 char tempPathBuffer[MAX_PATH]; 736 DWORD path_result = 0; 737 path_result = GetTempPathA(MAX_PATH, tempPathBuffer); 738 if (path_result > MAX_PATH || path_result == 0) return NULL; 739 UINT name_result = 0; 740 char tempNameBuffer[MAX_PATH]; 741 name_result = GetTempFileNameA(tempPathBuffer, "", 0, tempNameBuffer); 742 if (name_result == 0) return NULL; 743 FILE* result = FOpen(tempNameBuffer, "w+"); // Same mode as tmpfile uses. 744 if (result != NULL) { 745 Remove(tempNameBuffer); // Delete on close. 746 } 747 return result; 748 } 749 750 751 // Open log file in binary mode to avoid /n -> /r/n conversion. 752 const char* const OS::LogFileOpenMode = "wb"; 753 754 755 // Print (debug) message to console. 756 void OS::Print(const char* format, ...) { 757 va_list args; 758 va_start(args, format); 759 VPrint(format, args); 760 va_end(args); 761 } 762 763 764 void OS::VPrint(const char* format, va_list args) { 765 VPrintHelper(stdout, format, args); 766 } 767 768 769 void OS::FPrint(FILE* out, const char* format, ...) { 770 va_list args; 771 va_start(args, format); 772 VFPrint(out, format, args); 773 va_end(args); 774 } 775 776 777 void OS::VFPrint(FILE* out, const char* format, va_list args) { 778 VPrintHelper(out, format, args); 779 } 780 781 782 // Print error message to console. 783 void OS::PrintError(const char* format, ...) { 784 va_list args; 785 va_start(args, format); 786 VPrintError(format, args); 787 va_end(args); 788 } 789 790 791 void OS::VPrintError(const char* format, va_list args) { 792 VPrintHelper(stderr, format, args); 793 } 794 795 796 int OS::SNPrintF(Vector<char> str, const char* format, ...) { 797 va_list args; 798 va_start(args, format); 799 int result = VSNPrintF(str, format, args); 800 va_end(args); 801 return result; 802 } 803 804 805 int OS::VSNPrintF(Vector<char> str, const char* format, va_list args) { 806 int n = _vsnprintf_s(str.start(), str.length(), _TRUNCATE, format, args); 807 // Make sure to zero-terminate the string if the output was 808 // truncated or if there was an error. 809 if (n < 0 || n >= str.length()) { 810 if (str.length() > 0) 811 str[str.length() - 1] = '\0'; 812 return -1; 813 } else { 814 return n; 815 } 816 } 817 818 819 char* OS::StrChr(char* str, int c) { 820 return const_cast<char*>(strchr(str, c)); 821 } 822 823 824 void OS::StrNCpy(Vector<char> dest, const char* src, size_t n) { 825 // Use _TRUNCATE or strncpy_s crashes (by design) if buffer is too small. 826 size_t buffer_size = static_cast<size_t>(dest.length()); 827 if (n + 1 > buffer_size) // count for trailing '\0' 828 n = _TRUNCATE; 829 int result = strncpy_s(dest.start(), dest.length(), src, n); 830 USE(result); 831 ASSERT(result == 0 || (n == _TRUNCATE && result == STRUNCATE)); 832 } 833 834 835 #undef _TRUNCATE 836 #undef STRUNCATE 837 838 // We keep the lowest and highest addresses mapped as a quick way of 839 // determining that pointers are outside the heap (used mostly in assertions 840 // and verification). The estimate is conservative, i.e., not all addresses in 841 // 'allocated' space are actually allocated to our heap. The range is 842 // [lowest, highest), inclusive on the low and and exclusive on the high end. 843 static void* lowest_ever_allocated = reinterpret_cast<void*>(-1); 844 static void* highest_ever_allocated = reinterpret_cast<void*>(0); 845 846 847 static void UpdateAllocatedSpaceLimits(void* address, int size) { 848 ASSERT(limit_mutex != NULL); 849 ScopedLock lock(limit_mutex); 850 851 lowest_ever_allocated = Min(lowest_ever_allocated, address); 852 highest_ever_allocated = 853 Max(highest_ever_allocated, 854 reinterpret_cast<void*>(reinterpret_cast<char*>(address) + size)); 855 } 856 857 858 bool OS::IsOutsideAllocatedSpace(void* pointer) { 859 if (pointer < lowest_ever_allocated || pointer >= highest_ever_allocated) 860 return true; 861 // Ask the Windows API 862 if (IsBadWritePtr(pointer, 1)) 863 return true; 864 return false; 865 } 866 867 868 // Get the system's page size used by VirtualAlloc() or the next power 869 // of two. The reason for always returning a power of two is that the 870 // rounding up in OS::Allocate expects that. 871 static size_t GetPageSize() { 872 static size_t page_size = 0; 873 if (page_size == 0) { 874 SYSTEM_INFO info; 875 GetSystemInfo(&info); 876 page_size = RoundUpToPowerOf2(info.dwPageSize); 877 } 878 return page_size; 879 } 880 881 882 // The allocation alignment is the guaranteed alignment for 883 // VirtualAlloc'ed blocks of memory. 884 size_t OS::AllocateAlignment() { 885 static size_t allocate_alignment = 0; 886 if (allocate_alignment == 0) { 887 SYSTEM_INFO info; 888 GetSystemInfo(&info); 889 allocate_alignment = info.dwAllocationGranularity; 890 } 891 return allocate_alignment; 892 } 893 894 895 void* OS::GetRandomMmapAddr() { 896 Isolate* isolate = Isolate::UncheckedCurrent(); 897 // Note that the current isolate isn't set up in a call path via 898 // CpuFeatures::Probe. We don't care about randomization in this case because 899 // the code page is immediately freed. 900 if (isolate != NULL) { 901 // The address range used to randomize RWX allocations in OS::Allocate 902 // Try not to map pages into the default range that windows loads DLLs 903 // Use a multiple of 64k to prevent committing unused memory. 904 // Note: This does not guarantee RWX regions will be within the 905 // range kAllocationRandomAddressMin to kAllocationRandomAddressMax 906 #ifdef V8_HOST_ARCH_64_BIT 907 static const intptr_t kAllocationRandomAddressMin = 0x0000000080000000; 908 static const intptr_t kAllocationRandomAddressMax = 0x000003FFFFFF0000; 909 #else 910 static const intptr_t kAllocationRandomAddressMin = 0x04000000; 911 static const intptr_t kAllocationRandomAddressMax = 0x3FFF0000; 912 #endif 913 uintptr_t address = (V8::RandomPrivate(isolate) << kPageSizeBits) 914 | kAllocationRandomAddressMin; 915 address &= kAllocationRandomAddressMax; 916 return reinterpret_cast<void *>(address); 917 } 918 return NULL; 919 } 920 921 922 static void* RandomizedVirtualAlloc(size_t size, int action, int protection) { 923 LPVOID base = NULL; 924 925 if (protection == PAGE_EXECUTE_READWRITE || protection == PAGE_NOACCESS) { 926 // For exectutable pages try and randomize the allocation address 927 for (size_t attempts = 0; base == NULL && attempts < 3; ++attempts) { 928 base = VirtualAlloc(OS::GetRandomMmapAddr(), size, action, protection); 929 } 930 } 931 932 // After three attempts give up and let the OS find an address to use. 933 if (base == NULL) base = VirtualAlloc(NULL, size, action, protection); 934 935 return base; 936 } 937 938 939 void* OS::Allocate(const size_t requested, 940 size_t* allocated, 941 bool is_executable) { 942 // VirtualAlloc rounds allocated size to page size automatically. 943 size_t msize = RoundUp(requested, static_cast<int>(GetPageSize())); 944 945 // Windows XP SP2 allows Data Excution Prevention (DEP). 946 int prot = is_executable ? PAGE_EXECUTE_READWRITE : PAGE_READWRITE; 947 948 LPVOID mbase = RandomizedVirtualAlloc(msize, 949 MEM_COMMIT | MEM_RESERVE, 950 prot); 951 952 if (mbase == NULL) { 953 LOG(ISOLATE, StringEvent("OS::Allocate", "VirtualAlloc failed")); 954 return NULL; 955 } 956 957 ASSERT(IsAligned(reinterpret_cast<size_t>(mbase), OS::AllocateAlignment())); 958 959 *allocated = msize; 960 UpdateAllocatedSpaceLimits(mbase, static_cast<int>(msize)); 961 return mbase; 962 } 963 964 965 void OS::Free(void* address, const size_t size) { 966 // TODO(1240712): VirtualFree has a return value which is ignored here. 967 VirtualFree(address, 0, MEM_RELEASE); 968 USE(size); 969 } 970 971 972 intptr_t OS::CommitPageSize() { 973 return 4096; 974 } 975 976 977 void OS::ProtectCode(void* address, const size_t size) { 978 DWORD old_protect; 979 VirtualProtect(address, size, PAGE_EXECUTE_READ, &old_protect); 980 } 981 982 983 void OS::Guard(void* address, const size_t size) { 984 DWORD oldprotect; 985 VirtualProtect(address, size, PAGE_READONLY | PAGE_GUARD, &oldprotect); 986 } 987 988 989 void OS::Sleep(int milliseconds) { 990 ::Sleep(milliseconds); 991 } 992 993 994 int OS::NumberOfCores() { 995 SYSTEM_INFO info; 996 GetSystemInfo(&info); 997 return info.dwNumberOfProcessors; 998 } 999 1000 1001 void OS::Abort() { 1002 if (IsDebuggerPresent() || FLAG_break_on_abort) { 1003 DebugBreak(); 1004 } else { 1005 // Make the MSVCRT do a silent abort. 1006 raise(SIGABRT); 1007 } 1008 } 1009 1010 1011 void OS::DebugBreak() { 1012 #ifdef _MSC_VER 1013 __debugbreak(); 1014 #else 1015 ::DebugBreak(); 1016 #endif 1017 } 1018 1019 1020 void OS::DumpBacktrace() { 1021 // Currently unsupported. 1022 } 1023 1024 1025 class Win32MemoryMappedFile : public OS::MemoryMappedFile { 1026 public: 1027 Win32MemoryMappedFile(HANDLE file, 1028 HANDLE file_mapping, 1029 void* memory, 1030 int size) 1031 : file_(file), 1032 file_mapping_(file_mapping), 1033 memory_(memory), 1034 size_(size) { } 1035 virtual ~Win32MemoryMappedFile(); 1036 virtual void* memory() { return memory_; } 1037 virtual int size() { return size_; } 1038 private: 1039 HANDLE file_; 1040 HANDLE file_mapping_; 1041 void* memory_; 1042 int size_; 1043 }; 1044 1045 1046 OS::MemoryMappedFile* OS::MemoryMappedFile::open(const char* name) { 1047 // Open a physical file 1048 HANDLE file = CreateFileA(name, GENERIC_READ | GENERIC_WRITE, 1049 FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL); 1050 if (file == INVALID_HANDLE_VALUE) return NULL; 1051 1052 int size = static_cast<int>(GetFileSize(file, NULL)); 1053 1054 // Create a file mapping for the physical file 1055 HANDLE file_mapping = CreateFileMapping(file, NULL, 1056 PAGE_READWRITE, 0, static_cast<DWORD>(size), NULL); 1057 if (file_mapping == NULL) return NULL; 1058 1059 // Map a view of the file into memory 1060 void* memory = MapViewOfFile(file_mapping, FILE_MAP_ALL_ACCESS, 0, 0, size); 1061 return new Win32MemoryMappedFile(file, file_mapping, memory, size); 1062 } 1063 1064 1065 OS::MemoryMappedFile* OS::MemoryMappedFile::create(const char* name, int size, 1066 void* initial) { 1067 // Open a physical file 1068 HANDLE file = CreateFileA(name, GENERIC_READ | GENERIC_WRITE, 1069 FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_ALWAYS, 0, NULL); 1070 if (file == NULL) return NULL; 1071 // Create a file mapping for the physical file 1072 HANDLE file_mapping = CreateFileMapping(file, NULL, 1073 PAGE_READWRITE, 0, static_cast<DWORD>(size), NULL); 1074 if (file_mapping == NULL) return NULL; 1075 // Map a view of the file into memory 1076 void* memory = MapViewOfFile(file_mapping, FILE_MAP_ALL_ACCESS, 0, 0, size); 1077 if (memory) OS::MemMove(memory, initial, size); 1078 return new Win32MemoryMappedFile(file, file_mapping, memory, size); 1079 } 1080 1081 1082 Win32MemoryMappedFile::~Win32MemoryMappedFile() { 1083 if (memory_ != NULL) 1084 UnmapViewOfFile(memory_); 1085 CloseHandle(file_mapping_); 1086 CloseHandle(file_); 1087 } 1088 1089 1090 // The following code loads functions defined in DbhHelp.h and TlHelp32.h 1091 // dynamically. This is to avoid being depending on dbghelp.dll and 1092 // tlhelp32.dll when running (the functions in tlhelp32.dll have been moved to 1093 // kernel32.dll at some point so loading functions defines in TlHelp32.h 1094 // dynamically might not be necessary any more - for some versions of Windows?). 1095 1096 // Function pointers to functions dynamically loaded from dbghelp.dll. 1097 #define DBGHELP_FUNCTION_LIST(V) \ 1098 V(SymInitialize) \ 1099 V(SymGetOptions) \ 1100 V(SymSetOptions) \ 1101 V(SymGetSearchPath) \ 1102 V(SymLoadModule64) \ 1103 V(StackWalk64) \ 1104 V(SymGetSymFromAddr64) \ 1105 V(SymGetLineFromAddr64) \ 1106 V(SymFunctionTableAccess64) \ 1107 V(SymGetModuleBase64) 1108 1109 // Function pointers to functions dynamically loaded from dbghelp.dll. 1110 #define TLHELP32_FUNCTION_LIST(V) \ 1111 V(CreateToolhelp32Snapshot) \ 1112 V(Module32FirstW) \ 1113 V(Module32NextW) 1114 1115 // Define the decoration to use for the type and variable name used for 1116 // dynamically loaded DLL function.. 1117 #define DLL_FUNC_TYPE(name) _##name##_ 1118 #define DLL_FUNC_VAR(name) _##name 1119 1120 // Define the type for each dynamically loaded DLL function. The function 1121 // definitions are copied from DbgHelp.h and TlHelp32.h. The IN and VOID macros 1122 // from the Windows include files are redefined here to have the function 1123 // definitions to be as close to the ones in the original .h files as possible. 1124 #ifndef IN 1125 #define IN 1126 #endif 1127 #ifndef VOID 1128 #define VOID void 1129 #endif 1130 1131 // DbgHelp isn't supported on MinGW yet 1132 #ifndef __MINGW32__ 1133 // DbgHelp.h functions. 1134 typedef BOOL (__stdcall *DLL_FUNC_TYPE(SymInitialize))(IN HANDLE hProcess, 1135 IN PSTR UserSearchPath, 1136 IN BOOL fInvadeProcess); 1137 typedef DWORD (__stdcall *DLL_FUNC_TYPE(SymGetOptions))(VOID); 1138 typedef DWORD (__stdcall *DLL_FUNC_TYPE(SymSetOptions))(IN DWORD SymOptions); 1139 typedef BOOL (__stdcall *DLL_FUNC_TYPE(SymGetSearchPath))( 1140 IN HANDLE hProcess, 1141 OUT PSTR SearchPath, 1142 IN DWORD SearchPathLength); 1143 typedef DWORD64 (__stdcall *DLL_FUNC_TYPE(SymLoadModule64))( 1144 IN HANDLE hProcess, 1145 IN HANDLE hFile, 1146 IN PSTR ImageName, 1147 IN PSTR ModuleName, 1148 IN DWORD64 BaseOfDll, 1149 IN DWORD SizeOfDll); 1150 typedef BOOL (__stdcall *DLL_FUNC_TYPE(StackWalk64))( 1151 DWORD MachineType, 1152 HANDLE hProcess, 1153 HANDLE hThread, 1154 LPSTACKFRAME64 StackFrame, 1155 PVOID ContextRecord, 1156 PREAD_PROCESS_MEMORY_ROUTINE64 ReadMemoryRoutine, 1157 PFUNCTION_TABLE_ACCESS_ROUTINE64 FunctionTableAccessRoutine, 1158 PGET_MODULE_BASE_ROUTINE64 GetModuleBaseRoutine, 1159 PTRANSLATE_ADDRESS_ROUTINE64 TranslateAddress); 1160 typedef BOOL (__stdcall *DLL_FUNC_TYPE(SymGetSymFromAddr64))( 1161 IN HANDLE hProcess, 1162 IN DWORD64 qwAddr, 1163 OUT PDWORD64 pdwDisplacement, 1164 OUT PIMAGEHLP_SYMBOL64 Symbol); 1165 typedef BOOL (__stdcall *DLL_FUNC_TYPE(SymGetLineFromAddr64))( 1166 IN HANDLE hProcess, 1167 IN DWORD64 qwAddr, 1168 OUT PDWORD pdwDisplacement, 1169 OUT PIMAGEHLP_LINE64 Line64); 1170 // DbgHelp.h typedefs. Implementation found in dbghelp.dll. 1171 typedef PVOID (__stdcall *DLL_FUNC_TYPE(SymFunctionTableAccess64))( 1172 HANDLE hProcess, 1173 DWORD64 AddrBase); // DbgHelp.h typedef PFUNCTION_TABLE_ACCESS_ROUTINE64 1174 typedef DWORD64 (__stdcall *DLL_FUNC_TYPE(SymGetModuleBase64))( 1175 HANDLE hProcess, 1176 DWORD64 AddrBase); // DbgHelp.h typedef PGET_MODULE_BASE_ROUTINE64 1177 1178 // TlHelp32.h functions. 1179 typedef HANDLE (__stdcall *DLL_FUNC_TYPE(CreateToolhelp32Snapshot))( 1180 DWORD dwFlags, 1181 DWORD th32ProcessID); 1182 typedef BOOL (__stdcall *DLL_FUNC_TYPE(Module32FirstW))(HANDLE hSnapshot, 1183 LPMODULEENTRY32W lpme); 1184 typedef BOOL (__stdcall *DLL_FUNC_TYPE(Module32NextW))(HANDLE hSnapshot, 1185 LPMODULEENTRY32W lpme); 1186 1187 #undef IN 1188 #undef VOID 1189 1190 // Declare a variable for each dynamically loaded DLL function. 1191 #define DEF_DLL_FUNCTION(name) DLL_FUNC_TYPE(name) DLL_FUNC_VAR(name) = NULL; 1192 DBGHELP_FUNCTION_LIST(DEF_DLL_FUNCTION) 1193 TLHELP32_FUNCTION_LIST(DEF_DLL_FUNCTION) 1194 #undef DEF_DLL_FUNCTION 1195 1196 // Load the functions. This function has a lot of "ugly" macros in order to 1197 // keep down code duplication. 1198 1199 static bool LoadDbgHelpAndTlHelp32() { 1200 static bool dbghelp_loaded = false; 1201 1202 if (dbghelp_loaded) return true; 1203 1204 HMODULE module; 1205 1206 // Load functions from the dbghelp.dll module. 1207 module = LoadLibrary(TEXT("dbghelp.dll")); 1208 if (module == NULL) { 1209 return false; 1210 } 1211 1212 #define LOAD_DLL_FUNC(name) \ 1213 DLL_FUNC_VAR(name) = \ 1214 reinterpret_cast<DLL_FUNC_TYPE(name)>(GetProcAddress(module, #name)); 1215 1216 DBGHELP_FUNCTION_LIST(LOAD_DLL_FUNC) 1217 1218 #undef LOAD_DLL_FUNC 1219 1220 // Load functions from the kernel32.dll module (the TlHelp32.h function used 1221 // to be in tlhelp32.dll but are now moved to kernel32.dll). 1222 module = LoadLibrary(TEXT("kernel32.dll")); 1223 if (module == NULL) { 1224 return false; 1225 } 1226 1227 #define LOAD_DLL_FUNC(name) \ 1228 DLL_FUNC_VAR(name) = \ 1229 reinterpret_cast<DLL_FUNC_TYPE(name)>(GetProcAddress(module, #name)); 1230 1231 TLHELP32_FUNCTION_LIST(LOAD_DLL_FUNC) 1232 1233 #undef LOAD_DLL_FUNC 1234 1235 // Check that all functions where loaded. 1236 bool result = 1237 #define DLL_FUNC_LOADED(name) (DLL_FUNC_VAR(name) != NULL) && 1238 1239 DBGHELP_FUNCTION_LIST(DLL_FUNC_LOADED) 1240 TLHELP32_FUNCTION_LIST(DLL_FUNC_LOADED) 1241 1242 #undef DLL_FUNC_LOADED 1243 true; 1244 1245 dbghelp_loaded = result; 1246 return result; 1247 // NOTE: The modules are never unloaded and will stay around until the 1248 // application is closed. 1249 } 1250 1251 #undef DBGHELP_FUNCTION_LIST 1252 #undef TLHELP32_FUNCTION_LIST 1253 #undef DLL_FUNC_VAR 1254 #undef DLL_FUNC_TYPE 1255 1256 1257 // Load the symbols for generating stack traces. 1258 static bool LoadSymbols(HANDLE process_handle) { 1259 static bool symbols_loaded = false; 1260 1261 if (symbols_loaded) return true; 1262 1263 BOOL ok; 1264 1265 // Initialize the symbol engine. 1266 ok = _SymInitialize(process_handle, // hProcess 1267 NULL, // UserSearchPath 1268 false); // fInvadeProcess 1269 if (!ok) return false; 1270 1271 DWORD options = _SymGetOptions(); 1272 options |= SYMOPT_LOAD_LINES; 1273 options |= SYMOPT_FAIL_CRITICAL_ERRORS; 1274 options = _SymSetOptions(options); 1275 1276 char buf[OS::kStackWalkMaxNameLen] = {0}; 1277 ok = _SymGetSearchPath(process_handle, buf, OS::kStackWalkMaxNameLen); 1278 if (!ok) { 1279 int err = GetLastError(); 1280 PrintF("%d\n", err); 1281 return false; 1282 } 1283 1284 HANDLE snapshot = _CreateToolhelp32Snapshot( 1285 TH32CS_SNAPMODULE, // dwFlags 1286 GetCurrentProcessId()); // th32ProcessId 1287 if (snapshot == INVALID_HANDLE_VALUE) return false; 1288 MODULEENTRY32W module_entry; 1289 module_entry.dwSize = sizeof(module_entry); // Set the size of the structure. 1290 BOOL cont = _Module32FirstW(snapshot, &module_entry); 1291 while (cont) { 1292 DWORD64 base; 1293 // NOTE the SymLoadModule64 function has the peculiarity of accepting a 1294 // both unicode and ASCII strings even though the parameter is PSTR. 1295 base = _SymLoadModule64( 1296 process_handle, // hProcess 1297 0, // hFile 1298 reinterpret_cast<PSTR>(module_entry.szExePath), // ImageName 1299 reinterpret_cast<PSTR>(module_entry.szModule), // ModuleName 1300 reinterpret_cast<DWORD64>(module_entry.modBaseAddr), // BaseOfDll 1301 module_entry.modBaseSize); // SizeOfDll 1302 if (base == 0) { 1303 int err = GetLastError(); 1304 if (err != ERROR_MOD_NOT_FOUND && 1305 err != ERROR_INVALID_HANDLE) return false; 1306 } 1307 LOG(i::Isolate::Current(), 1308 SharedLibraryEvent( 1309 module_entry.szExePath, 1310 reinterpret_cast<unsigned int>(module_entry.modBaseAddr), 1311 reinterpret_cast<unsigned int>(module_entry.modBaseAddr + 1312 module_entry.modBaseSize))); 1313 cont = _Module32NextW(snapshot, &module_entry); 1314 } 1315 CloseHandle(snapshot); 1316 1317 symbols_loaded = true; 1318 return true; 1319 } 1320 1321 1322 void OS::LogSharedLibraryAddresses() { 1323 // SharedLibraryEvents are logged when loading symbol information. 1324 // Only the shared libraries loaded at the time of the call to 1325 // LogSharedLibraryAddresses are logged. DLLs loaded after 1326 // initialization are not accounted for. 1327 if (!LoadDbgHelpAndTlHelp32()) return; 1328 HANDLE process_handle = GetCurrentProcess(); 1329 LoadSymbols(process_handle); 1330 } 1331 1332 1333 void OS::SignalCodeMovingGC() { 1334 } 1335 1336 1337 // Walk the stack using the facilities in dbghelp.dll and tlhelp32.dll 1338 1339 // Switch off warning 4748 (/GS can not protect parameters and local variables 1340 // from local buffer overrun because optimizations are disabled in function) as 1341 // it is triggered by the use of inline assembler. 1342 #pragma warning(push) 1343 #pragma warning(disable : 4748) 1344 int OS::StackWalk(Vector<OS::StackFrame> frames) { 1345 BOOL ok; 1346 1347 // Load the required functions from DLL's. 1348 if (!LoadDbgHelpAndTlHelp32()) return kStackWalkError; 1349 1350 // Get the process and thread handles. 1351 HANDLE process_handle = GetCurrentProcess(); 1352 HANDLE thread_handle = GetCurrentThread(); 1353 1354 // Read the symbols. 1355 if (!LoadSymbols(process_handle)) return kStackWalkError; 1356 1357 // Capture current context. 1358 CONTEXT context; 1359 RtlCaptureContext(&context); 1360 1361 // Initialize the stack walking 1362 STACKFRAME64 stack_frame; 1363 memset(&stack_frame, 0, sizeof(stack_frame)); 1364 #ifdef _WIN64 1365 stack_frame.AddrPC.Offset = context.Rip; 1366 stack_frame.AddrFrame.Offset = context.Rbp; 1367 stack_frame.AddrStack.Offset = context.Rsp; 1368 #else 1369 stack_frame.AddrPC.Offset = context.Eip; 1370 stack_frame.AddrFrame.Offset = context.Ebp; 1371 stack_frame.AddrStack.Offset = context.Esp; 1372 #endif 1373 stack_frame.AddrPC.Mode = AddrModeFlat; 1374 stack_frame.AddrFrame.Mode = AddrModeFlat; 1375 stack_frame.AddrStack.Mode = AddrModeFlat; 1376 int frames_count = 0; 1377 1378 // Collect stack frames. 1379 int frames_size = frames.length(); 1380 while (frames_count < frames_size) { 1381 ok = _StackWalk64( 1382 IMAGE_FILE_MACHINE_I386, // MachineType 1383 process_handle, // hProcess 1384 thread_handle, // hThread 1385 &stack_frame, // StackFrame 1386 &context, // ContextRecord 1387 NULL, // ReadMemoryRoutine 1388 _SymFunctionTableAccess64, // FunctionTableAccessRoutine 1389 _SymGetModuleBase64, // GetModuleBaseRoutine 1390 NULL); // TranslateAddress 1391 if (!ok) break; 1392 1393 // Store the address. 1394 ASSERT((stack_frame.AddrPC.Offset >> 32) == 0); // 32-bit address. 1395 frames[frames_count].address = 1396 reinterpret_cast<void*>(stack_frame.AddrPC.Offset); 1397 1398 // Try to locate a symbol for this frame. 1399 DWORD64 symbol_displacement; 1400 SmartArrayPointer<IMAGEHLP_SYMBOL64> symbol( 1401 NewArray<IMAGEHLP_SYMBOL64>(kStackWalkMaxNameLen)); 1402 if (symbol.is_empty()) return kStackWalkError; // Out of memory. 1403 memset(*symbol, 0, sizeof(IMAGEHLP_SYMBOL64) + kStackWalkMaxNameLen); 1404 (*symbol)->SizeOfStruct = sizeof(IMAGEHLP_SYMBOL64); 1405 (*symbol)->MaxNameLength = kStackWalkMaxNameLen; 1406 ok = _SymGetSymFromAddr64(process_handle, // hProcess 1407 stack_frame.AddrPC.Offset, // Address 1408 &symbol_displacement, // Displacement 1409 *symbol); // Symbol 1410 if (ok) { 1411 // Try to locate more source information for the symbol. 1412 IMAGEHLP_LINE64 Line; 1413 memset(&Line, 0, sizeof(Line)); 1414 Line.SizeOfStruct = sizeof(Line); 1415 DWORD line_displacement; 1416 ok = _SymGetLineFromAddr64( 1417 process_handle, // hProcess 1418 stack_frame.AddrPC.Offset, // dwAddr 1419 &line_displacement, // pdwDisplacement 1420 &Line); // Line 1421 // Format a text representation of the frame based on the information 1422 // available. 1423 if (ok) { 1424 SNPrintF(MutableCStrVector(frames[frames_count].text, 1425 kStackWalkMaxTextLen), 1426 "%s %s:%d:%d", 1427 (*symbol)->Name, Line.FileName, Line.LineNumber, 1428 line_displacement); 1429 } else { 1430 SNPrintF(MutableCStrVector(frames[frames_count].text, 1431 kStackWalkMaxTextLen), 1432 "%s", 1433 (*symbol)->Name); 1434 } 1435 // Make sure line termination is in place. 1436 frames[frames_count].text[kStackWalkMaxTextLen - 1] = '\0'; 1437 } else { 1438 // No text representation of this frame 1439 frames[frames_count].text[0] = '\0'; 1440 1441 // Continue if we are just missing a module (for non C/C++ frames a 1442 // module will never be found). 1443 int err = GetLastError(); 1444 if (err != ERROR_MOD_NOT_FOUND) { 1445 break; 1446 } 1447 } 1448 1449 frames_count++; 1450 } 1451 1452 // Return the number of frames filled in. 1453 return frames_count; 1454 } 1455 1456 1457 // Restore warnings to previous settings. 1458 #pragma warning(pop) 1459 1460 #else // __MINGW32__ 1461 void OS::LogSharedLibraryAddresses() { } 1462 void OS::SignalCodeMovingGC() { } 1463 int OS::StackWalk(Vector<OS::StackFrame> frames) { return 0; } 1464 #endif // __MINGW32__ 1465 1466 1467 uint64_t OS::CpuFeaturesImpliedByPlatform() { 1468 return 0; // Windows runs on anything. 1469 } 1470 1471 1472 double OS::nan_value() { 1473 #ifdef _MSC_VER 1474 // Positive Quiet NaN with no payload (aka. Indeterminate) has all bits 1475 // in mask set, so value equals mask. 1476 static const __int64 nanval = kQuietNaNMask; 1477 return *reinterpret_cast<const double*>(&nanval); 1478 #else // _MSC_VER 1479 return NAN; 1480 #endif // _MSC_VER 1481 } 1482 1483 1484 int OS::ActivationFrameAlignment() { 1485 #ifdef _WIN64 1486 return 16; // Windows 64-bit ABI requires the stack to be 16-byte aligned. 1487 #elif defined(__MINGW32__) 1488 // With gcc 4.4 the tree vectorization optimizer can generate code 1489 // that requires 16 byte alignment such as movdqa on x86. 1490 return 16; 1491 #else 1492 return 8; // Floating-point math runs faster with 8-byte alignment. 1493 #endif 1494 } 1495 1496 1497 VirtualMemory::VirtualMemory() : address_(NULL), size_(0) { } 1498 1499 1500 VirtualMemory::VirtualMemory(size_t size) 1501 : address_(ReserveRegion(size)), size_(size) { } 1502 1503 1504 VirtualMemory::VirtualMemory(size_t size, size_t alignment) 1505 : address_(NULL), size_(0) { 1506 ASSERT(IsAligned(alignment, static_cast<intptr_t>(OS::AllocateAlignment()))); 1507 size_t request_size = RoundUp(size + alignment, 1508 static_cast<intptr_t>(OS::AllocateAlignment())); 1509 void* address = ReserveRegion(request_size); 1510 if (address == NULL) return; 1511 Address base = RoundUp(static_cast<Address>(address), alignment); 1512 // Try reducing the size by freeing and then reallocating a specific area. 1513 bool result = ReleaseRegion(address, request_size); 1514 USE(result); 1515 ASSERT(result); 1516 address = VirtualAlloc(base, size, MEM_RESERVE, PAGE_NOACCESS); 1517 if (address != NULL) { 1518 request_size = size; 1519 ASSERT(base == static_cast<Address>(address)); 1520 } else { 1521 // Resizing failed, just go with a bigger area. 1522 address = ReserveRegion(request_size); 1523 if (address == NULL) return; 1524 } 1525 address_ = address; 1526 size_ = request_size; 1527 } 1528 1529 1530 VirtualMemory::~VirtualMemory() { 1531 if (IsReserved()) { 1532 bool result = ReleaseRegion(address(), size()); 1533 ASSERT(result); 1534 USE(result); 1535 } 1536 } 1537 1538 1539 bool VirtualMemory::IsReserved() { 1540 return address_ != NULL; 1541 } 1542 1543 1544 void VirtualMemory::Reset() { 1545 address_ = NULL; 1546 size_ = 0; 1547 } 1548 1549 1550 bool VirtualMemory::Commit(void* address, size_t size, bool is_executable) { 1551 return CommitRegion(address, size, is_executable); 1552 } 1553 1554 1555 bool VirtualMemory::Uncommit(void* address, size_t size) { 1556 ASSERT(IsReserved()); 1557 return UncommitRegion(address, size); 1558 } 1559 1560 1561 bool VirtualMemory::Guard(void* address) { 1562 if (NULL == VirtualAlloc(address, 1563 OS::CommitPageSize(), 1564 MEM_COMMIT, 1565 PAGE_READONLY | PAGE_GUARD)) { 1566 return false; 1567 } 1568 return true; 1569 } 1570 1571 1572 void* VirtualMemory::ReserveRegion(size_t size) { 1573 return RandomizedVirtualAlloc(size, MEM_RESERVE, PAGE_NOACCESS); 1574 } 1575 1576 1577 bool VirtualMemory::CommitRegion(void* base, size_t size, bool is_executable) { 1578 int prot = is_executable ? PAGE_EXECUTE_READWRITE : PAGE_READWRITE; 1579 if (NULL == VirtualAlloc(base, size, MEM_COMMIT, prot)) { 1580 return false; 1581 } 1582 1583 UpdateAllocatedSpaceLimits(base, static_cast<int>(size)); 1584 return true; 1585 } 1586 1587 1588 bool VirtualMemory::UncommitRegion(void* base, size_t size) { 1589 return VirtualFree(base, size, MEM_DECOMMIT) != 0; 1590 } 1591 1592 1593 bool VirtualMemory::ReleaseRegion(void* base, size_t size) { 1594 return VirtualFree(base, 0, MEM_RELEASE) != 0; 1595 } 1596 1597 1598 bool VirtualMemory::HasLazyCommits() { 1599 // TODO(alph): implement for the platform. 1600 return false; 1601 } 1602 1603 1604 // ---------------------------------------------------------------------------- 1605 // Win32 thread support. 1606 1607 // Definition of invalid thread handle and id. 1608 static const HANDLE kNoThread = INVALID_HANDLE_VALUE; 1609 1610 // Entry point for threads. The supplied argument is a pointer to the thread 1611 // object. The entry function dispatches to the run method in the thread 1612 // object. It is important that this function has __stdcall calling 1613 // convention. 1614 static unsigned int __stdcall ThreadEntry(void* arg) { 1615 Thread* thread = reinterpret_cast<Thread*>(arg); 1616 thread->NotifyStartedAndRun(); 1617 return 0; 1618 } 1619 1620 1621 class Thread::PlatformData : public Malloced { 1622 public: 1623 explicit PlatformData(HANDLE thread) : thread_(thread) {} 1624 HANDLE thread_; 1625 unsigned thread_id_; 1626 }; 1627 1628 1629 // Initialize a Win32 thread object. The thread has an invalid thread 1630 // handle until it is started. 1631 1632 Thread::Thread(const Options& options) 1633 : stack_size_(options.stack_size()), 1634 start_semaphore_(NULL) { 1635 data_ = new PlatformData(kNoThread); 1636 set_name(options.name()); 1637 } 1638 1639 1640 void Thread::set_name(const char* name) { 1641 OS::StrNCpy(Vector<char>(name_, sizeof(name_)), name, strlen(name)); 1642 name_[sizeof(name_) - 1] = '\0'; 1643 } 1644 1645 1646 // Close our own handle for the thread. 1647 Thread::~Thread() { 1648 if (data_->thread_ != kNoThread) CloseHandle(data_->thread_); 1649 delete data_; 1650 } 1651 1652 1653 // Create a new thread. It is important to use _beginthreadex() instead of 1654 // the Win32 function CreateThread(), because the CreateThread() does not 1655 // initialize thread specific structures in the C runtime library. 1656 void Thread::Start() { 1657 data_->thread_ = reinterpret_cast<HANDLE>( 1658 _beginthreadex(NULL, 1659 static_cast<unsigned>(stack_size_), 1660 ThreadEntry, 1661 this, 1662 0, 1663 &data_->thread_id_)); 1664 } 1665 1666 1667 // Wait for thread to terminate. 1668 void Thread::Join() { 1669 if (data_->thread_id_ != GetCurrentThreadId()) { 1670 WaitForSingleObject(data_->thread_, INFINITE); 1671 } 1672 } 1673 1674 1675 Thread::LocalStorageKey Thread::CreateThreadLocalKey() { 1676 DWORD result = TlsAlloc(); 1677 ASSERT(result != TLS_OUT_OF_INDEXES); 1678 return static_cast<LocalStorageKey>(result); 1679 } 1680 1681 1682 void Thread::DeleteThreadLocalKey(LocalStorageKey key) { 1683 BOOL result = TlsFree(static_cast<DWORD>(key)); 1684 USE(result); 1685 ASSERT(result); 1686 } 1687 1688 1689 void* Thread::GetThreadLocal(LocalStorageKey key) { 1690 return TlsGetValue(static_cast<DWORD>(key)); 1691 } 1692 1693 1694 void Thread::SetThreadLocal(LocalStorageKey key, void* value) { 1695 BOOL result = TlsSetValue(static_cast<DWORD>(key), value); 1696 USE(result); 1697 ASSERT(result); 1698 } 1699 1700 1701 1702 void Thread::YieldCPU() { 1703 Sleep(0); 1704 } 1705 1706 1707 // ---------------------------------------------------------------------------- 1708 // Win32 mutex support. 1709 // 1710 // On Win32 mutexes are implemented using CRITICAL_SECTION objects. These are 1711 // faster than Win32 Mutex objects because they are implemented using user mode 1712 // atomic instructions. Therefore we only do ring transitions if there is lock 1713 // contention. 1714 1715 class Win32Mutex : public Mutex { 1716 public: 1717 Win32Mutex() { InitializeCriticalSection(&cs_); } 1718 1719 virtual ~Win32Mutex() { DeleteCriticalSection(&cs_); } 1720 1721 virtual int Lock() { 1722 EnterCriticalSection(&cs_); 1723 return 0; 1724 } 1725 1726 virtual int Unlock() { 1727 LeaveCriticalSection(&cs_); 1728 return 0; 1729 } 1730 1731 1732 virtual bool TryLock() { 1733 // Returns non-zero if critical section is entered successfully entered. 1734 return TryEnterCriticalSection(&cs_); 1735 } 1736 1737 private: 1738 CRITICAL_SECTION cs_; // Critical section used for mutex 1739 }; 1740 1741 1742 Mutex* OS::CreateMutex() { 1743 return new Win32Mutex(); 1744 } 1745 1746 1747 // ---------------------------------------------------------------------------- 1748 // Win32 semaphore support. 1749 // 1750 // On Win32 semaphores are implemented using Win32 Semaphore objects. The 1751 // semaphores are anonymous. Also, the semaphores are initialized to have 1752 // no upper limit on count. 1753 1754 1755 class Win32Semaphore : public Semaphore { 1756 public: 1757 explicit Win32Semaphore(int count) { 1758 sem = ::CreateSemaphoreA(NULL, count, 0x7fffffff, NULL); 1759 } 1760 1761 ~Win32Semaphore() { 1762 CloseHandle(sem); 1763 } 1764 1765 void Wait() { 1766 WaitForSingleObject(sem, INFINITE); 1767 } 1768 1769 bool Wait(int timeout) { 1770 // Timeout in Windows API is in milliseconds. 1771 DWORD millis_timeout = timeout / 1000; 1772 return WaitForSingleObject(sem, millis_timeout) != WAIT_TIMEOUT; 1773 } 1774 1775 void Signal() { 1776 LONG dummy; 1777 ReleaseSemaphore(sem, 1, &dummy); 1778 } 1779 1780 private: 1781 HANDLE sem; 1782 }; 1783 1784 1785 Semaphore* OS::CreateSemaphore(int count) { 1786 return new Win32Semaphore(count); 1787 } 1788 1789 1790 // ---------------------------------------------------------------------------- 1791 // Win32 socket support. 1792 // 1793 1794 class Win32Socket : public Socket { 1795 public: 1796 explicit Win32Socket() { 1797 // Create the socket. 1798 socket_ = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); 1799 } 1800 explicit Win32Socket(SOCKET socket): socket_(socket) { } 1801 virtual ~Win32Socket() { Shutdown(); } 1802 1803 // Server initialization. 1804 bool Bind(const int port); 1805 bool Listen(int backlog) const; 1806 Socket* Accept() const; 1807 1808 // Client initialization. 1809 bool Connect(const char* host, const char* port); 1810 1811 // Shutdown socket for both read and write. 1812 bool Shutdown(); 1813 1814 // Data Transimission 1815 int Send(const char* data, int len) const; 1816 int Receive(char* data, int len) const; 1817 1818 bool SetReuseAddress(bool reuse_address); 1819 1820 bool IsValid() const { return socket_ != INVALID_SOCKET; } 1821 1822 private: 1823 SOCKET socket_; 1824 }; 1825 1826 1827 bool Win32Socket::Bind(const int port) { 1828 if (!IsValid()) { 1829 return false; 1830 } 1831 1832 sockaddr_in addr; 1833 memset(&addr, 0, sizeof(addr)); 1834 addr.sin_family = AF_INET; 1835 addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK); 1836 addr.sin_port = htons(port); 1837 int status = bind(socket_, 1838 reinterpret_cast<struct sockaddr *>(&addr), 1839 sizeof(addr)); 1840 return status == 0; 1841 } 1842 1843 1844 bool Win32Socket::Listen(int backlog) const { 1845 if (!IsValid()) { 1846 return false; 1847 } 1848 1849 int status = listen(socket_, backlog); 1850 return status == 0; 1851 } 1852 1853 1854 Socket* Win32Socket::Accept() const { 1855 if (!IsValid()) { 1856 return NULL; 1857 } 1858 1859 SOCKET socket = accept(socket_, NULL, NULL); 1860 if (socket == INVALID_SOCKET) { 1861 return NULL; 1862 } else { 1863 return new Win32Socket(socket); 1864 } 1865 } 1866 1867 1868 bool Win32Socket::Connect(const char* host, const char* port) { 1869 if (!IsValid()) { 1870 return false; 1871 } 1872 1873 // Lookup host and port. 1874 struct addrinfo *result = NULL; 1875 struct addrinfo hints; 1876 memset(&hints, 0, sizeof(addrinfo)); 1877 hints.ai_family = AF_INET; 1878 hints.ai_socktype = SOCK_STREAM; 1879 hints.ai_protocol = IPPROTO_TCP; 1880 int status = getaddrinfo(host, port, &hints, &result); 1881 if (status != 0) { 1882 return false; 1883 } 1884 1885 // Connect. 1886 status = connect(socket_, 1887 result->ai_addr, 1888 static_cast<int>(result->ai_addrlen)); 1889 freeaddrinfo(result); 1890 return status == 0; 1891 } 1892 1893 1894 bool Win32Socket::Shutdown() { 1895 if (IsValid()) { 1896 // Shutdown socket for both read and write. 1897 int status = shutdown(socket_, SD_BOTH); 1898 closesocket(socket_); 1899 socket_ = INVALID_SOCKET; 1900 return status == SOCKET_ERROR; 1901 } 1902 return true; 1903 } 1904 1905 1906 int Win32Socket::Send(const char* data, int len) const { 1907 if (len <= 0) return 0; 1908 int written = 0; 1909 while (written < len) { 1910 int status = send(socket_, data + written, len - written, 0); 1911 if (status == 0) { 1912 break; 1913 } else if (status > 0) { 1914 written += status; 1915 } else { 1916 return 0; 1917 } 1918 } 1919 return written; 1920 } 1921 1922 1923 int Win32Socket::Receive(char* data, int len) const { 1924 if (len <= 0) return 0; 1925 int status = recv(socket_, data, len, 0); 1926 return (status == SOCKET_ERROR) ? 0 : status; 1927 } 1928 1929 1930 bool Win32Socket::SetReuseAddress(bool reuse_address) { 1931 BOOL on = reuse_address ? true : false; 1932 int status = setsockopt(socket_, SOL_SOCKET, SO_REUSEADDR, 1933 reinterpret_cast<char*>(&on), sizeof(on)); 1934 return status == SOCKET_ERROR; 1935 } 1936 1937 1938 bool Socket::SetUp() { 1939 // Initialize Winsock32 1940 int err; 1941 WSADATA winsock_data; 1942 WORD version_requested = MAKEWORD(1, 0); 1943 err = WSAStartup(version_requested, &winsock_data); 1944 if (err != 0) { 1945 PrintF("Unable to initialize Winsock, err = %d\n", Socket::LastError()); 1946 } 1947 1948 return err == 0; 1949 } 1950 1951 1952 int Socket::LastError() { 1953 return WSAGetLastError(); 1954 } 1955 1956 1957 uint16_t Socket::HToN(uint16_t value) { 1958 return htons(value); 1959 } 1960 1961 1962 uint16_t Socket::NToH(uint16_t value) { 1963 return ntohs(value); 1964 } 1965 1966 1967 uint32_t Socket::HToN(uint32_t value) { 1968 return htonl(value); 1969 } 1970 1971 1972 uint32_t Socket::NToH(uint32_t value) { 1973 return ntohl(value); 1974 } 1975 1976 1977 Socket* OS::CreateSocket() { 1978 return new Win32Socket(); 1979 } 1980 1981 1982 void OS::SetUp() { 1983 // Seed the random number generator. 1984 // Convert the current time to a 64-bit integer first, before converting it 1985 // to an unsigned. Going directly can cause an overflow and the seed to be 1986 // set to all ones. The seed will be identical for different instances that 1987 // call this setup code within the same millisecond. 1988 uint64_t seed = static_cast<uint64_t>(TimeCurrentMillis()); 1989 srand(static_cast<unsigned int>(seed)); 1990 limit_mutex = CreateMutex(); 1991 } 1992 1993 1994 void OS::TearDown() { 1995 delete limit_mutex; 1996 } 1997 1998 1999 } } // namespace v8::internal 2000