platform-win32.cc 42.7 KB
Newer Older
1
// Copyright 2012 the V8 project authors. All rights reserved.
2 3
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
4

5
// Platform-specific code for Win32.
6

7 8 9 10 11 12 13 14 15 16 17
// Secure API functions are not available using MinGW with msvcrt.dll
// on Windows XP. Make sure MINGW_HAS_SECURE_API is not defined to
// disable definition of secure API functions in standard headers that
// would conflict with our own implementation.
#ifdef __MINGW32__
#include <_mingw.h>
#ifdef MINGW_HAS_SECURE_API
#undef MINGW_HAS_SECURE_API
#endif  // MINGW_HAS_SECURE_API
#endif  // __MINGW32__

18 19
#include <limits>

20
#include "src/base/win32-headers.h"
21

22
#include "src/base/bits.h"
23
#include "src/base/lazy-instance.h"
24 25 26
#include "src/base/macros.h"
#include "src/base/platform/platform.h"
#include "src/base/platform/time.h"
27
#include "src/base/timezone-cache.h"
28
#include "src/base/utils/random-number-generator.h"
29

30 31 32 33
// Extra functions for MinGW. Most of these are the _s functions which are in
// the Microsoft Visual Studio C++ CRT.
#ifdef __MINGW32__

34 35 36 37 38 39

#ifndef __MINGW64_VERSION_MAJOR

#define _TRUNCATE 0
#define STRUNCATE 80

40 41 42 43 44
inline void MemoryBarrier() {
  int barrier = 0;
  __asm__ __volatile__("xchgl %%eax,%0 ":"=r" (barrier));
}

45 46 47
#endif  // __MINGW64_VERSION_MAJOR


48
int localtime_s(tm* out_tm, const time_t* time) {
49
  tm* posix_local_time_struct = localtime_r(time, out_tm);
50 51 52 53 54 55 56 57 58 59 60 61
  if (posix_local_time_struct == NULL) return 1;
  return 0;
}


int fopen_s(FILE** pFile, const char* filename, const char* mode) {
  *pFile = fopen(filename, mode);
  return *pFile != NULL ? 0 : 1;
}

int _vsnprintf_s(char* buffer, size_t sizeOfBuffer, size_t count,
                 const char* format, va_list argptr) {
62
  DCHECK(count == _TRUNCATE);
63 64 65 66
  return _vsnprintf(buffer, sizeOfBuffer, format, argptr);
}


67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89
int strncpy_s(char* dest, size_t dest_size, const char* source, size_t count) {
  CHECK(source != NULL);
  CHECK(dest != NULL);
  CHECK_GT(dest_size, 0);

  if (count == _TRUNCATE) {
    while (dest_size > 0 && *source != 0) {
      *(dest++) = *(source++);
      --dest_size;
    }
    if (dest_size == 0) {
      *(dest - 1) = 0;
      return STRUNCATE;
    }
  } else {
    while (dest_size > 0 && count > 0 && *source != 0) {
      *(dest++) = *(source++);
      --dest_size;
      --count;
    }
  }
  CHECK_GT(dest_size, 0);
  *dest = 0;
90 91 92 93 94
  return 0;
}

#endif  // __MINGW32__

95
namespace v8 {
96
namespace base {
97

98 99 100 101 102 103
namespace {

bool g_hard_abort = false;

}  // namespace

104
class WindowsTimezoneCache : public TimezoneCache {
105
 public:
106
  WindowsTimezoneCache() : initialized_(false) {}
107

108 109 110 111 112 113 114 115 116
  ~WindowsTimezoneCache() override {}

  void Clear() override { initialized_ = false; }

  const char* LocalTimezone(double time) override;

  double LocalTimeOffset() override;

  double DaylightSavingsOffset(double time) override;
117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153

  // Initialize timezone information. The timezone information is obtained from
  // windows. If we cannot get the timezone information we fall back to CET.
  void InitializeIfNeeded() {
    // Just return if timezone information has already been initialized.
    if (initialized_) return;

    // Initialize POSIX time zone data.
    _tzset();
    // Obtain timezone information from operating system.
    memset(&tzinfo_, 0, sizeof(tzinfo_));
    if (GetTimeZoneInformation(&tzinfo_) == TIME_ZONE_ID_INVALID) {
      // If we cannot get timezone information we fall back to CET.
      tzinfo_.Bias = -60;
      tzinfo_.StandardDate.wMonth = 10;
      tzinfo_.StandardDate.wDay = 5;
      tzinfo_.StandardDate.wHour = 3;
      tzinfo_.StandardBias = 0;
      tzinfo_.DaylightDate.wMonth = 3;
      tzinfo_.DaylightDate.wDay = 5;
      tzinfo_.DaylightDate.wHour = 2;
      tzinfo_.DaylightBias = -60;
    }

    // Make standard and DST timezone names.
    WideCharToMultiByte(CP_UTF8, 0, tzinfo_.StandardName, -1,
                        std_tz_name_, kTzNameSize, NULL, NULL);
    std_tz_name_[kTzNameSize - 1] = '\0';
    WideCharToMultiByte(CP_UTF8, 0, tzinfo_.DaylightName, -1,
                        dst_tz_name_, kTzNameSize, NULL, NULL);
    dst_tz_name_[kTzNameSize - 1] = '\0';

    // If OS returned empty string or resource id (like "@tzres.dll,-211")
    // simply guess the name from the UTC bias of the timezone.
    // To properly resolve the resource identifier requires a library load,
    // which is not possible in a sandbox.
    if (std_tz_name_[0] == '\0' || std_tz_name_[0] == '@') {
154
      OS::SNPrintF(std_tz_name_, kTzNameSize - 1,
155 156 157 158
                   "%s Standard Time",
                   GuessTimezoneNameFromBias(tzinfo_.Bias));
    }
    if (dst_tz_name_[0] == '\0' || dst_tz_name_[0] == '@') {
159
      OS::SNPrintF(dst_tz_name_, kTzNameSize - 1,
160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200
                   "%s Daylight Time",
                   GuessTimezoneNameFromBias(tzinfo_.Bias));
    }
    // Timezone information initialized.
    initialized_ = true;
  }

  // Guess the name of the timezone from the bias.
  // The guess is very biased towards the northern hemisphere.
  const char* GuessTimezoneNameFromBias(int bias) {
    static const int kHour = 60;
    switch (-bias) {
      case -9*kHour: return "Alaska";
      case -8*kHour: return "Pacific";
      case -7*kHour: return "Mountain";
      case -6*kHour: return "Central";
      case -5*kHour: return "Eastern";
      case -4*kHour: return "Atlantic";
      case  0*kHour: return "GMT";
      case +1*kHour: return "Central Europe";
      case +2*kHour: return "Eastern Europe";
      case +3*kHour: return "Russia";
      case +5*kHour + 30: return "India";
      case +8*kHour: return "China";
      case +9*kHour: return "Japan";
      case +12*kHour: return "New Zealand";
      default: return "Local";
    }
  }


 private:
  static const int kTzNameSize = 128;
  bool initialized_;
  char std_tz_name_[kTzNameSize];
  char dst_tz_name_[kTzNameSize];
  TIME_ZONE_INFORMATION tzinfo_;
  friend class Win32Time;
};


201 202
// ----------------------------------------------------------------------------
// The Time class represents time on win32. A timestamp is represented as
203
// a 64-bit integer in 100 nanoseconds since January 1, 1601 (UTC). JavaScript
204 205 206
// timestamps are represented as a doubles in milliseconds since 00:00:00 UTC,
// January 1, 1970.

207
class Win32Time {
208 209
 public:
  // Constructors.
210
  Win32Time();
211 212
  explicit Win32Time(double jstime);
  Win32Time(int year, int mon, int day, int hour, int min, int sec);
213 214 215 216

  // Convert timestamp to JavaScript representation.
  double ToJSTime();

217 218 219
  // Set timestamp to current time.
  void SetToCurrentTime();

220 221 222 223 224
  // Returns the local timezone offset in milliseconds east of UTC. This is
  // the number of milliseconds you must add to UTC to get local time, i.e.
  // LocalOffset(CET) = 3600000 and LocalOffset(PST) = -28800000. This
  // routine also takes into account whether daylight saving is effect
  // at the time.
225
  int64_t LocalOffset(WindowsTimezoneCache* cache);
226 227

  // Returns the daylight savings time offset for the time in milliseconds.
228
  int64_t DaylightSavingsOffset(WindowsTimezoneCache* cache);
229 230 231

  // Returns a string identifying the current timezone for the
  // timestamp taking into account daylight saving.
232
  char* LocalTimezone(WindowsTimezoneCache* cache);
233

234 235
 private:
  // Constants for time conversion.
236
  static const int64_t kTimeEpoc = 116444736000000000LL;
237 238 239 240 241 242 243
  static const int64_t kTimeScaler = 10000;
  static const int64_t kMsPerMinute = 60000;

  // Constants for timezone information.
  static const bool kShortTzNames = false;

  // Return whether or not daylight savings time is in effect at this time.
244
  bool InDST(WindowsTimezoneCache* cache);
245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264

  // Accessor for FILETIME representation.
  FILETIME& ft() { return time_.ft_; }

  // Accessor for integer representation.
  int64_t& t() { return time_.t_; }

  // Although win32 uses 64-bit integers for representing timestamps,
  // these are packed into a FILETIME structure. The FILETIME structure
  // is just a struct representing a 64-bit integer. The TimeStamp union
  // allows access to both a FILETIME and an integer representation of
  // the timestamp.
  union TimeStamp {
    FILETIME ft_;
    int64_t t_;
  };

  TimeStamp time_;
};

265

266 267 268 269 270 271
// Initialize timestamp to start of epoc.
Win32Time::Win32Time() {
  t() = 0;
}


272
// Initialize timestamp from a JavaScript timestamp.
273
Win32Time::Win32Time(double jstime) {
274
  t() = static_cast<int64_t>(jstime) * kTimeScaler + kTimeEpoc;
275 276 277 278
}


// Initialize timestamp from date/time components.
279
Win32Time::Win32Time(int year, int mon, int day, int hour, int min, int sec) {
280 281 282 283 284 285 286 287 288 289 290 291 292
  SYSTEMTIME st;
  st.wYear = year;
  st.wMonth = mon;
  st.wDay = day;
  st.wHour = hour;
  st.wMinute = min;
  st.wSecond = sec;
  st.wMilliseconds = 0;
  SystemTimeToFileTime(&st, &ft());
}


// Convert timestamp to JavaScript timestamp.
293
double Win32Time::ToJSTime() {
294 295 296 297
  return static_cast<double>((t() - kTimeEpoc) / kTimeScaler);
}


298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353
// Set timestamp to current time.
void Win32Time::SetToCurrentTime() {
  // The default GetSystemTimeAsFileTime has a ~15.5ms resolution.
  // Because we're fast, we like fast timers which have at least a
  // 1ms resolution.
  //
  // timeGetTime() provides 1ms granularity when combined with
  // timeBeginPeriod().  If the host application for v8 wants fast
  // timers, it can use timeBeginPeriod to increase the resolution.
  //
  // Using timeGetTime() has a drawback because it is a 32bit value
  // and hence rolls-over every ~49days.
  //
  // To use the clock, we use GetSystemTimeAsFileTime as our base;
  // and then use timeGetTime to extrapolate current time from the
  // start time.  To deal with rollovers, we resync the clock
  // any time when more than kMaxClockElapsedTime has passed or
  // whenever timeGetTime creates a rollover.

  static bool initialized = false;
  static TimeStamp init_time;
  static DWORD init_ticks;
  static const int64_t kHundredNanosecondsPerSecond = 10000000;
  static const int64_t kMaxClockElapsedTime =
      60*kHundredNanosecondsPerSecond;  // 1 minute

  // If we are uninitialized, we need to resync the clock.
  bool needs_resync = !initialized;

  // Get the current time.
  TimeStamp time_now;
  GetSystemTimeAsFileTime(&time_now.ft_);
  DWORD ticks_now = timeGetTime();

  // Check if we need to resync due to clock rollover.
  needs_resync |= ticks_now < init_ticks;

  // Check if we need to resync due to elapsed time.
  needs_resync |= (time_now.t_ - init_time.t_) > kMaxClockElapsedTime;

  // Check if we need to resync due to backwards time change.
  needs_resync |= time_now.t_ < init_time.t_;

  // Resync the clock if necessary.
  if (needs_resync) {
    GetSystemTimeAsFileTime(&init_time.ft_);
    init_ticks = ticks_now = timeGetTime();
    initialized = true;
  }

  // Finally, compute the actual time.  Why is this so hard.
  DWORD elapsed = ticks_now - init_ticks;
  this->time_.t_ = init_time.t_ + (static_cast<int64_t>(elapsed) * 10000);
}


354 355
// Return the local timezone offset in milliseconds east of UTC. This
// takes into account whether daylight saving is in effect at the time.
356 357
// Only times in the 32-bit Unix range may be passed to this function.
// Also, adding the time-zone offset to the input must not overflow.
358
// The function EquivalentTime() in date.js guarantees this.
359
int64_t Win32Time::LocalOffset(WindowsTimezoneCache* cache) {
360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388
  cache->InitializeIfNeeded();

  Win32Time rounded_to_second(*this);
  rounded_to_second.t() =
      rounded_to_second.t() / 1000 / kTimeScaler * 1000 * kTimeScaler;
  // Convert to local time using POSIX localtime function.
  // Windows XP Service Pack 3 made SystemTimeToTzSpecificLocalTime()
  // very slow.  Other browsers use localtime().

  // Convert from JavaScript milliseconds past 1/1/1970 0:00:00 to
  // POSIX seconds past 1/1/1970 0:00:00.
  double unchecked_posix_time = rounded_to_second.ToJSTime() / 1000;
  if (unchecked_posix_time > INT_MAX || unchecked_posix_time < 0) {
    return 0;
  }
  // Because _USE_32BIT_TIME_T is defined, time_t is a 32-bit int.
  time_t posix_time = static_cast<time_t>(unchecked_posix_time);

  // Convert to local time, as struct with fields for day, hour, year, etc.
  tm posix_local_time_struct;
  if (localtime_s(&posix_local_time_struct, &posix_time)) return 0;

  if (posix_local_time_struct.tm_isdst > 0) {
    return (cache->tzinfo_.Bias + cache->tzinfo_.DaylightBias) * -kMsPerMinute;
  } else if (posix_local_time_struct.tm_isdst == 0) {
    return (cache->tzinfo_.Bias + cache->tzinfo_.StandardBias) * -kMsPerMinute;
  } else {
    return cache->tzinfo_.Bias * -kMsPerMinute;
  }
389 390 391 392
}


// Return whether or not daylight savings time is in effect at this time.
393
bool Win32Time::InDST(WindowsTimezoneCache* cache) {
394
  cache->InitializeIfNeeded();
395 396 397

  // Determine if DST is in effect at the specified time.
  bool in_dst = false;
398 399
  if (cache->tzinfo_.StandardDate.wMonth != 0 ||
      cache->tzinfo_.DaylightDate.wMonth != 0) {
400
    // Get the local timezone offset for the timestamp in milliseconds.
401
    int64_t offset = LocalOffset(cache);
402 403 404

    // Compute the offset for DST. The bias parameters in the timezone info
    // are specified in minutes. These must be converted to milliseconds.
405 406
    int64_t dstofs =
        -(cache->tzinfo_.Bias + cache->tzinfo_.DaylightBias) * kMsPerMinute;
407 408 409 410 411 412 413 414 415 416

    // If the local time offset equals the timezone bias plus the daylight
    // bias then DST is in effect.
    in_dst = offset == dstofs;
  }

  return in_dst;
}


417
// Return the daylight savings time offset for this time.
418
int64_t Win32Time::DaylightSavingsOffset(WindowsTimezoneCache* cache) {
419
  return InDST(cache) ? 60 * kMsPerMinute : 0;
420 421 422 423 424
}


// Returns a string identifying the current timezone for the
// timestamp taking into account daylight saving.
425
char* Win32Time::LocalTimezone(WindowsTimezoneCache* cache) {
426 427
  // Return the standard or DST time zone name based on whether daylight
  // saving is in effect at the given time.
428
  return InDST(cache) ? cache->dst_tz_name_ : cache->std_tz_name_;
429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453
}


// Returns the accumulated user time for thread.
int OS::GetUserTime(uint32_t* secs,  uint32_t* usecs) {
  FILETIME dummy;
  uint64_t usertime;

  // Get the amount of time that the thread has executed in user mode.
  if (!GetThreadTimes(GetCurrentThread(), &dummy, &dummy, &dummy,
                      reinterpret_cast<FILETIME*>(&usertime))) return -1;

  // Adjust the resolution to micro-seconds.
  usertime /= 10;

  // Convert to seconds and microseconds
  *secs = static_cast<uint32_t>(usertime / 1000000);
  *usecs = static_cast<uint32_t>(usertime % 1000000);
  return 0;
}


// Returns current time as the number of milliseconds since
// 00:00:00 UTC, January 1, 1970.
double OS::TimeCurrentMillis() {
454
  return Time::Now().ToJsTime();
455 456 457 458
}

// Returns a string identifying the current timezone taking into
// account daylight saving.
459 460
const char* WindowsTimezoneCache::LocalTimezone(double time) {
  return Win32Time(time).LocalTimezone(this);
461 462
}

463 464
// Returns the local time offset in milliseconds east of UTC without
// taking daylight savings time into account.
465
double WindowsTimezoneCache::LocalTimeOffset() {
466
  // Use current time, rounded to the millisecond.
467
  Win32Time t(OS::TimeCurrentMillis());
468
  // Time::LocalOffset inlcudes any daylight savings offset, so subtract it.
469 470
  return static_cast<double>(t.LocalOffset(this) -
                             t.DaylightSavingsOffset(this));
471 472 473 474
}

// Returns the daylight savings offset in milliseconds for the given
// time.
475 476
double WindowsTimezoneCache::DaylightSavingsOffset(double time) {
  int64_t offset = Win32Time(time).DaylightSavingsOffset(this);
477 478 479
  return static_cast<double>(offset);
}

480
TimezoneCache* OS::CreateTimezoneCache() { return new WindowsTimezoneCache(); }
481

482 483 484 485 486
int OS::GetLastError() {
  return ::GetLastError();
}


487 488 489 490 491
int OS::GetCurrentProcessId() {
  return static_cast<int>(::GetCurrentProcessId());
}


492 493 494 495 496
int OS::GetCurrentThreadId() {
  return static_cast<int>(::GetCurrentThreadId());
}


497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537
// ----------------------------------------------------------------------------
// Win32 console output.
//
// If a Win32 application is linked as a console application it has a normal
// standard output and standard error. In this case normal printf works fine
// for output. However, if the application is linked as a GUI application,
// the process doesn't have a console, and therefore (debugging) output is lost.
// This is the case if we are embedded in a windows program (like a browser).
// In order to be able to get debug output in this case the the debugging
// facility using OutputDebugString. This output goes to the active debugger
// for the process (if any). Else the output can be monitored using DBMON.EXE.

enum OutputMode {
  UNKNOWN,  // Output method has not yet been determined.
  CONSOLE,  // Output is written to stdout.
  ODS       // Output is written to debug facility.
};

static OutputMode output_mode = UNKNOWN;  // Current output mode.


// Determine if the process has a console for output.
static bool HasConsole() {
  // Only check the first time. Eventual race conditions are not a problem,
  // because all threads will eventually determine the same mode.
  if (output_mode == UNKNOWN) {
    // We cannot just check that the standard output is attached to a console
    // because this would fail if output is redirected to a file. Therefore we
    // say that a process does not have an output console if either the
    // standard output handle is invalid or its file type is unknown.
    if (GetStdHandle(STD_OUTPUT_HANDLE) != INVALID_HANDLE_VALUE &&
        GetFileType(GetStdHandle(STD_OUTPUT_HANDLE)) != FILE_TYPE_UNKNOWN)
      output_mode = CONSOLE;
    else
      output_mode = ODS;
  }
  return output_mode == CONSOLE;
}


static void VPrintHelper(FILE* stream, const char* format, va_list args) {
538
  if ((stream == stdout || stream == stderr) && !HasConsole()) {
539 540 541
    // It is important to use safe print here in order to avoid
    // overflowing the buffer. We might truncate the output, but this
    // does not crash.
542 543 544
    char buffer[4096];
    OS::VSNPrintF(buffer, sizeof(buffer), format, args);
    OutputDebugStringA(buffer);
545 546
  } else {
    vfprintf(stream, format, args);
547 548 549 550 551 552 553 554 555 556
  }
}


FILE* OS::FOpen(const char* path, const char* mode) {
  FILE* result;
  if (fopen_s(&result, path, mode) == 0) {
    return result;
  } else {
    return NULL;
557 558 559 560
  }
}


561
bool OS::Remove(const char* path) {
562
  return (DeleteFileA(path) != 0);
563 564
}

jfb's avatar
jfb committed
565
char OS::DirectorySeparator() { return '\\'; }
566

sejunho's avatar
sejunho committed
567 568 569 570 571
bool OS::isDirectorySeparator(const char ch) {
  return ch == '/' || ch == '\\';
}


572 573 574 575
FILE* OS::OpenTemporaryFile() {
  // tmpfile_s tries to use the root dir, don't use it.
  char tempPathBuffer[MAX_PATH];
  DWORD path_result = 0;
576
  path_result = GetTempPathA(MAX_PATH, tempPathBuffer);
577 578 579
  if (path_result > MAX_PATH || path_result == 0) return NULL;
  UINT name_result = 0;
  char tempNameBuffer[MAX_PATH];
580
  name_result = GetTempFileNameA(tempPathBuffer, "", 0, tempNameBuffer);
581 582 583 584 585 586 587 588 589
  if (name_result == 0) return NULL;
  FILE* result = FOpen(tempNameBuffer, "w+");  // Same mode as tmpfile uses.
  if (result != NULL) {
    Remove(tempNameBuffer);  // Delete on close.
  }
  return result;
}


590
// Open log file in binary mode to avoid /n -> /r/n conversion.
591
const char* const OS::LogFileOpenMode = "wb";
592 593


594 595 596 597 598 599 600 601 602 603 604 605 606 607
// Print (debug) message to console.
void OS::Print(const char* format, ...) {
  va_list args;
  va_start(args, format);
  VPrint(format, args);
  va_end(args);
}


void OS::VPrint(const char* format, va_list args) {
  VPrintHelper(stdout, format, args);
}


608 609 610 611 612 613 614 615 616 617 618 619 620
void OS::FPrint(FILE* out, const char* format, ...) {
  va_list args;
  va_start(args, format);
  VFPrint(out, format, args);
  va_end(args);
}


void OS::VFPrint(FILE* out, const char* format, va_list args) {
  VPrintHelper(out, format, args);
}


621 622 623 624 625 626 627 628 629 630 631 632 633 634
// Print error message to console.
void OS::PrintError(const char* format, ...) {
  va_list args;
  va_start(args, format);
  VPrintError(format, args);
  va_end(args);
}


void OS::VPrintError(const char* format, va_list args) {
  VPrintHelper(stderr, format, args);
}


635
int OS::SNPrintF(char* str, int length, const char* format, ...) {
636 637
  va_list args;
  va_start(args, format);
638
  int result = VSNPrintF(str, length, format, args);
639 640 641 642 643
  va_end(args);
  return result;
}


644 645
int OS::VSNPrintF(char* str, int length, const char* format, va_list args) {
  int n = _vsnprintf_s(str, length, _TRUNCATE, format, args);
646 647
  // Make sure to zero-terminate the string if the output was
  // truncated or if there was an error.
648 649 650
  if (n < 0 || n >= length) {
    if (length > 0)
      str[length - 1] = '\0';
651 652 653 654
    return -1;
  } else {
    return n;
  }
655 656 657
}


658 659 660 661 662
char* OS::StrChr(char* str, int c) {
  return const_cast<char*>(strchr(str, c));
}


663
void OS::StrNCpy(char* dest, int length, const char* src, size_t n) {
664
  // Use _TRUNCATE or strncpy_s crashes (by design) if buffer is too small.
665
  size_t buffer_size = static_cast<size_t>(length);
dimich@chromium.org's avatar
dimich@chromium.org committed
666
  if (n + 1 > buffer_size)  // count for trailing '\0'
667
    n = _TRUNCATE;
668
  int result = strncpy_s(dest, length, src, n);
669
  USE(result);
670
  DCHECK(result == 0 || (n == _TRUNCATE && result == STRUNCATE));
671 672 673
}


674 675 676
#undef _TRUNCATE
#undef STRUNCATE

677

678 679 680 681 682 683 684 685
// Get the system's page size used by VirtualAlloc() or the next power
// of two. The reason for always returning a power of two is that the
// rounding up in OS::Allocate expects that.
static size_t GetPageSize() {
  static size_t page_size = 0;
  if (page_size == 0) {
    SYSTEM_INFO info;
    GetSystemInfo(&info);
686
    page_size = base::bits::RoundUpToPowerOfTwo32(info.dwPageSize);
687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704
  }
  return page_size;
}


// The allocation alignment is the guaranteed alignment for
// VirtualAlloc'ed blocks of memory.
size_t OS::AllocateAlignment() {
  static size_t allocate_alignment = 0;
  if (allocate_alignment == 0) {
    SYSTEM_INFO info;
    GetSystemInfo(&info);
    allocate_alignment = info.dwAllocationGranularity;
  }
  return allocate_alignment;
}


705
static LazyInstance<RandomNumberGenerator>::type
706 707 708
    platform_random_number_generator = LAZY_INSTANCE_INITIALIZER;


709 710 711 712 713 714
void OS::Initialize(int64_t random_seed, bool hard_abort,
                    const char* const gc_fake_mmap) {
  if (random_seed) {
    platform_random_number_generator.Pointer()->SetSeed(random_seed);
  }
  g_hard_abort = hard_abort;
715 716 717
}


718
void* OS::GetRandomMmapAddr() {
719 720 721 722 723
  // The address range used to randomize RWX allocations in OS::Allocate
  // Try not to map pages into the default range that windows loads DLLs
  // Use a multiple of 64k to prevent committing unused memory.
  // Note: This does not guarantee RWX regions will be within the
  // range kAllocationRandomAddressMin to kAllocationRandomAddressMax
724
#ifdef V8_HOST_ARCH_64_BIT
725 726
  static const uintptr_t kAllocationRandomAddressMin = 0x0000000080000000;
  static const uintptr_t kAllocationRandomAddressMax = 0x000003FFFFFF0000;
727
#else
728 729
  static const uintptr_t kAllocationRandomAddressMin = 0x04000000;
  static const uintptr_t kAllocationRandomAddressMax = 0x3FFF0000;
730
#endif
731 732 733 734 735
  uintptr_t address;
  platform_random_number_generator.Pointer()->NextBytes(&address,
                                                        sizeof(address));
  address <<= kPageSizeBits;
  address += kAllocationRandomAddressMin;
736 737
  address &= kAllocationRandomAddressMax;
  return reinterpret_cast<void *>(address);
738 739 740 741 742
}


static void* RandomizedVirtualAlloc(size_t size, int action, int protection) {
  LPVOID base = NULL;
743 744 745 746 747 748 749 750 751
  static BOOL use_aslr = -1;
#ifdef V8_HOST_ARCH_32_BIT
  // Don't bother randomizing on 32-bit hosts, because they lack the room and
  // don't have viable ASLR anyway.
  if (use_aslr == -1 && !IsWow64Process(GetCurrentProcess(), &use_aslr))
    use_aslr = FALSE;
#else
  use_aslr = TRUE;
#endif
752

753 754 755
  if (use_aslr &&
      (protection == PAGE_EXECUTE_READWRITE || protection == PAGE_NOACCESS)) {
    // For executable pages try and randomize the allocation address
756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780
    for (size_t attempts = 0; base == NULL && attempts < 3; ++attempts) {
      base = VirtualAlloc(OS::GetRandomMmapAddr(), size, action, protection);
    }
  }

  // After three attempts give up and let the OS find an address to use.
  if (base == NULL) base = VirtualAlloc(NULL, size, action, protection);

  return base;
}


void* OS::Allocate(const size_t requested,
                   size_t* allocated,
                   bool is_executable) {
  // VirtualAlloc rounds allocated size to page size automatically.
  size_t msize = RoundUp(requested, static_cast<int>(GetPageSize()));

  // Windows XP SP2 allows Data Excution Prevention (DEP).
  int prot = is_executable ? PAGE_EXECUTE_READWRITE : PAGE_READWRITE;

  LPVOID mbase = RandomizedVirtualAlloc(msize,
                                        MEM_COMMIT | MEM_RESERVE,
                                        prot);

781
  if (mbase == NULL) return NULL;
782

783
  DCHECK((reinterpret_cast<uintptr_t>(mbase) % OS::AllocateAlignment()) == 0);
784 785 786 787 788

  *allocated = msize;
  return mbase;
}

789 790 791
void* OS::AllocateGuarded(const size_t requested) {
  return VirtualAlloc(nullptr, requested, MEM_RESERVE, PAGE_NOACCESS);
}
792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815

void OS::Free(void* address, const size_t size) {
  // TODO(1240712): VirtualFree has a return value which is ignored here.
  VirtualFree(address, 0, MEM_RELEASE);
  USE(size);
}


intptr_t OS::CommitPageSize() {
  return 4096;
}


void OS::ProtectCode(void* address, const size_t size) {
  DWORD old_protect;
  VirtualProtect(address, size, PAGE_EXECUTE_READ, &old_protect);
}


void OS::Guard(void* address, const size_t size) {
  DWORD oldprotect;
  VirtualProtect(address, size, PAGE_NOACCESS, &oldprotect);
}

816 817 818
void OS::Unprotect(void* address, const size_t size) {
  LPVOID result = VirtualAlloc(address, size, MEM_COMMIT, PAGE_READWRITE);
  DCHECK_IMPLIES(result != nullptr, GetLastError() == 0);
819
  USE(result);
820
}
821

822 823
void OS::Sleep(TimeDelta interval) {
  ::Sleep(static_cast<DWORD>(interval.InMilliseconds()));
824 825 826 827
}


void OS::Abort() {
828
  if (g_hard_abort) {
829
    V8_IMMEDIATE_CRASH();
830
  }
831 832
  // Make the MSVCRT do a silent abort.
  raise(SIGABRT);
833 834 835

  // Make sure function doesn't return.
  abort();
836 837 838
}


839
void OS::DebugBreak() {
840
#if V8_CC_MSVC
841 842 843
  // To avoid Visual Studio runtime support the following code can be used
  // instead
  // __asm { int 3 }
844
  __debugbreak();
845 846
#else
  ::DebugBreak();
847
#endif
848 849 850
}


851
class Win32MemoryMappedFile final : public OS::MemoryMappedFile {
852
 public:
853 854
  Win32MemoryMappedFile(HANDLE file, HANDLE file_mapping, void* memory,
                        size_t size)
855 856 857
      : file_(file),
        file_mapping_(file_mapping),
        memory_(memory),
858 859 860 861 862
        size_(size) {}
  ~Win32MemoryMappedFile() final;
  void* memory() const final { return memory_; }
  size_t size() const final { return size_; }

863
 private:
864 865 866 867
  HANDLE const file_;
  HANDLE const file_mapping_;
  void* const memory_;
  size_t const size_;
868 869 870
};


871
// static
872 873 874 875
OS::MemoryMappedFile* OS::MemoryMappedFile::open(const char* name) {
  // Open a physical file
  HANDLE file = CreateFileA(name, GENERIC_READ | GENERIC_WRITE,
      FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL);
876
  if (file == INVALID_HANDLE_VALUE) return NULL;
877

878
  DWORD size = GetFileSize(file, NULL);
879 880

  // Create a file mapping for the physical file
881 882
  HANDLE file_mapping =
      CreateFileMapping(file, NULL, PAGE_READWRITE, 0, size, NULL);
883 884 885 886 887 888 889 890
  if (file_mapping == NULL) return NULL;

  // Map a view of the file into memory
  void* memory = MapViewOfFile(file_mapping, FILE_MAP_ALL_ACCESS, 0, 0, size);
  return new Win32MemoryMappedFile(file, file_mapping, memory, size);
}


891 892 893
// static
OS::MemoryMappedFile* OS::MemoryMappedFile::create(const char* name,
                                                   size_t size, void* initial) {
894 895
  // Open a physical file
  HANDLE file = CreateFileA(name, GENERIC_READ | GENERIC_WRITE,
896 897
                            FILE_SHARE_READ | FILE_SHARE_WRITE, NULL,
                            OPEN_ALWAYS, 0, NULL);
898 899
  if (file == NULL) return NULL;
  // Create a file mapping for the physical file
900 901
  HANDLE file_mapping = CreateFileMapping(file, NULL, PAGE_READWRITE, 0,
                                          static_cast<DWORD>(size), NULL);
902 903 904
  if (file_mapping == NULL) return NULL;
  // Map a view of the file into memory
  void* memory = MapViewOfFile(file_mapping, FILE_MAP_ALL_ACCESS, 0, 0, size);
905
  if (memory) memmove(memory, initial, size);
906
  return new Win32MemoryMappedFile(file, file_mapping, memory, size);
907 908 909 910
}


Win32MemoryMappedFile::~Win32MemoryMappedFile() {
911
  if (memory_) UnmapViewOfFile(memory_);
912 913 914 915 916 917
  CloseHandle(file_mapping_);
  CloseHandle(file_);
}


// The following code loads functions defined in DbhHelp.h and TlHelp32.h
918
// dynamically. This is to avoid being depending on dbghelp.dll and
919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957
// tlhelp32.dll when running (the functions in tlhelp32.dll have been moved to
// kernel32.dll at some point so loading functions defines in TlHelp32.h
// dynamically might not be necessary any more - for some versions of Windows?).

// Function pointers to functions dynamically loaded from dbghelp.dll.
#define DBGHELP_FUNCTION_LIST(V)  \
  V(SymInitialize)                \
  V(SymGetOptions)                \
  V(SymSetOptions)                \
  V(SymGetSearchPath)             \
  V(SymLoadModule64)              \
  V(StackWalk64)                  \
  V(SymGetSymFromAddr64)          \
  V(SymGetLineFromAddr64)         \
  V(SymFunctionTableAccess64)     \
  V(SymGetModuleBase64)

// Function pointers to functions dynamically loaded from dbghelp.dll.
#define TLHELP32_FUNCTION_LIST(V)  \
  V(CreateToolhelp32Snapshot)      \
  V(Module32FirstW)                \
  V(Module32NextW)

// Define the decoration to use for the type and variable name used for
// dynamically loaded DLL function..
#define DLL_FUNC_TYPE(name) _##name##_
#define DLL_FUNC_VAR(name) _##name

// Define the type for each dynamically loaded DLL function. The function
// definitions are copied from DbgHelp.h and TlHelp32.h. The IN and VOID macros
// from the Windows include files are redefined here to have the function
// definitions to be as close to the ones in the original .h files as possible.
#ifndef IN
#define IN
#endif
#ifndef VOID
#define VOID void
#endif

958 959
// DbgHelp isn't supported on MinGW yet
#ifndef __MINGW32__
960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073
// DbgHelp.h functions.
typedef BOOL (__stdcall *DLL_FUNC_TYPE(SymInitialize))(IN HANDLE hProcess,
                                                       IN PSTR UserSearchPath,
                                                       IN BOOL fInvadeProcess);
typedef DWORD (__stdcall *DLL_FUNC_TYPE(SymGetOptions))(VOID);
typedef DWORD (__stdcall *DLL_FUNC_TYPE(SymSetOptions))(IN DWORD SymOptions);
typedef BOOL (__stdcall *DLL_FUNC_TYPE(SymGetSearchPath))(
    IN HANDLE hProcess,
    OUT PSTR SearchPath,
    IN DWORD SearchPathLength);
typedef DWORD64 (__stdcall *DLL_FUNC_TYPE(SymLoadModule64))(
    IN HANDLE hProcess,
    IN HANDLE hFile,
    IN PSTR ImageName,
    IN PSTR ModuleName,
    IN DWORD64 BaseOfDll,
    IN DWORD SizeOfDll);
typedef BOOL (__stdcall *DLL_FUNC_TYPE(StackWalk64))(
    DWORD MachineType,
    HANDLE hProcess,
    HANDLE hThread,
    LPSTACKFRAME64 StackFrame,
    PVOID ContextRecord,
    PREAD_PROCESS_MEMORY_ROUTINE64 ReadMemoryRoutine,
    PFUNCTION_TABLE_ACCESS_ROUTINE64 FunctionTableAccessRoutine,
    PGET_MODULE_BASE_ROUTINE64 GetModuleBaseRoutine,
    PTRANSLATE_ADDRESS_ROUTINE64 TranslateAddress);
typedef BOOL (__stdcall *DLL_FUNC_TYPE(SymGetSymFromAddr64))(
    IN HANDLE hProcess,
    IN DWORD64 qwAddr,
    OUT PDWORD64 pdwDisplacement,
    OUT PIMAGEHLP_SYMBOL64 Symbol);
typedef BOOL (__stdcall *DLL_FUNC_TYPE(SymGetLineFromAddr64))(
    IN HANDLE hProcess,
    IN DWORD64 qwAddr,
    OUT PDWORD pdwDisplacement,
    OUT PIMAGEHLP_LINE64 Line64);
// DbgHelp.h typedefs. Implementation found in dbghelp.dll.
typedef PVOID (__stdcall *DLL_FUNC_TYPE(SymFunctionTableAccess64))(
    HANDLE hProcess,
    DWORD64 AddrBase);  // DbgHelp.h typedef PFUNCTION_TABLE_ACCESS_ROUTINE64
typedef DWORD64 (__stdcall *DLL_FUNC_TYPE(SymGetModuleBase64))(
    HANDLE hProcess,
    DWORD64 AddrBase);  // DbgHelp.h typedef PGET_MODULE_BASE_ROUTINE64

// TlHelp32.h functions.
typedef HANDLE (__stdcall *DLL_FUNC_TYPE(CreateToolhelp32Snapshot))(
    DWORD dwFlags,
    DWORD th32ProcessID);
typedef BOOL (__stdcall *DLL_FUNC_TYPE(Module32FirstW))(HANDLE hSnapshot,
                                                        LPMODULEENTRY32W lpme);
typedef BOOL (__stdcall *DLL_FUNC_TYPE(Module32NextW))(HANDLE hSnapshot,
                                                       LPMODULEENTRY32W lpme);

#undef IN
#undef VOID

// Declare a variable for each dynamically loaded DLL function.
#define DEF_DLL_FUNCTION(name) DLL_FUNC_TYPE(name) DLL_FUNC_VAR(name) = NULL;
DBGHELP_FUNCTION_LIST(DEF_DLL_FUNCTION)
TLHELP32_FUNCTION_LIST(DEF_DLL_FUNCTION)
#undef DEF_DLL_FUNCTION

// Load the functions. This function has a lot of "ugly" macros in order to
// keep down code duplication.

static bool LoadDbgHelpAndTlHelp32() {
  static bool dbghelp_loaded = false;

  if (dbghelp_loaded) return true;

  HMODULE module;

  // Load functions from the dbghelp.dll module.
  module = LoadLibrary(TEXT("dbghelp.dll"));
  if (module == NULL) {
    return false;
  }

#define LOAD_DLL_FUNC(name)                                                 \
  DLL_FUNC_VAR(name) =                                                      \
      reinterpret_cast<DLL_FUNC_TYPE(name)>(GetProcAddress(module, #name));

DBGHELP_FUNCTION_LIST(LOAD_DLL_FUNC)

#undef LOAD_DLL_FUNC

  // Load functions from the kernel32.dll module (the TlHelp32.h function used
  // to be in tlhelp32.dll but are now moved to kernel32.dll).
  module = LoadLibrary(TEXT("kernel32.dll"));
  if (module == NULL) {
    return false;
  }

#define LOAD_DLL_FUNC(name)                                                 \
  DLL_FUNC_VAR(name) =                                                      \
      reinterpret_cast<DLL_FUNC_TYPE(name)>(GetProcAddress(module, #name));

TLHELP32_FUNCTION_LIST(LOAD_DLL_FUNC)

#undef LOAD_DLL_FUNC

  // Check that all functions where loaded.
  bool result =
#define DLL_FUNC_LOADED(name) (DLL_FUNC_VAR(name) != NULL) &&

DBGHELP_FUNCTION_LIST(DLL_FUNC_LOADED)
TLHELP32_FUNCTION_LIST(DLL_FUNC_LOADED)

#undef DLL_FUNC_LOADED
  true;

  dbghelp_loaded = result;
  return result;
1074
  // NOTE: The modules are never unloaded and will stay around until the
1075 1076 1077
  // application is closed.
}

1078 1079 1080 1081 1082
#undef DBGHELP_FUNCTION_LIST
#undef TLHELP32_FUNCTION_LIST
#undef DLL_FUNC_VAR
#undef DLL_FUNC_TYPE

1083 1084

// Load the symbols for generating stack traces.
1085 1086 1087 1088
static std::vector<OS::SharedLibraryAddress> LoadSymbols(
    HANDLE process_handle) {
  static std::vector<OS::SharedLibraryAddress> result;

1089 1090
  static bool symbols_loaded = false;

1091
  if (symbols_loaded) return result;
1092 1093 1094 1095 1096 1097

  BOOL ok;

  // Initialize the symbol engine.
  ok = _SymInitialize(process_handle,  // hProcess
                      NULL,            // UserSearchPath
1098
                      false);          // fInvadeProcess
1099
  if (!ok) return result;
1100 1101 1102 1103 1104 1105 1106 1107 1108 1109

  DWORD options = _SymGetOptions();
  options |= SYMOPT_LOAD_LINES;
  options |= SYMOPT_FAIL_CRITICAL_ERRORS;
  options = _SymSetOptions(options);

  char buf[OS::kStackWalkMaxNameLen] = {0};
  ok = _SymGetSearchPath(process_handle, buf, OS::kStackWalkMaxNameLen);
  if (!ok) {
    int err = GetLastError();
1110
    OS::Print("%d\n", err);
1111
    return result;
1112 1113 1114 1115 1116
  }

  HANDLE snapshot = _CreateToolhelp32Snapshot(
      TH32CS_SNAPMODULE,       // dwFlags
      GetCurrentProcessId());  // th32ProcessId
1117
  if (snapshot == INVALID_HANDLE_VALUE) return result;
1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131 1132 1133 1134
  MODULEENTRY32W module_entry;
  module_entry.dwSize = sizeof(module_entry);  // Set the size of the structure.
  BOOL cont = _Module32FirstW(snapshot, &module_entry);
  while (cont) {
    DWORD64 base;
    // NOTE the SymLoadModule64 function has the peculiarity of accepting a
    // both unicode and ASCII strings even though the parameter is PSTR.
    base = _SymLoadModule64(
        process_handle,                                       // hProcess
        0,                                                    // hFile
        reinterpret_cast<PSTR>(module_entry.szExePath),       // ImageName
        reinterpret_cast<PSTR>(module_entry.szModule),        // ModuleName
        reinterpret_cast<DWORD64>(module_entry.modBaseAddr),  // BaseOfDll
        module_entry.modBaseSize);                            // SizeOfDll
    if (base == 0) {
      int err = GetLastError();
      if (err != ERROR_MOD_NOT_FOUND &&
1135 1136 1137 1138
          err != ERROR_INVALID_HANDLE) {
        result.clear();
        return result;
      }
1139
    }
1140 1141 1142 1143 1144 1145
    int lib_name_length = WideCharToMultiByte(
        CP_UTF8, 0, module_entry.szExePath, -1, NULL, 0, NULL, NULL);
    std::string lib_name(lib_name_length, 0);
    WideCharToMultiByte(CP_UTF8, 0, module_entry.szExePath, -1, &lib_name[0],
                        lib_name_length, NULL, NULL);
    result.push_back(OS::SharedLibraryAddress(
1146 1147 1148
        lib_name, reinterpret_cast<uintptr_t>(module_entry.modBaseAddr),
        reinterpret_cast<uintptr_t>(module_entry.modBaseAddr +
                                    module_entry.modBaseSize)));
1149 1150 1151 1152 1153
    cont = _Module32NextW(snapshot, &module_entry);
  }
  CloseHandle(snapshot);

  symbols_loaded = true;
1154
  return result;
1155 1156 1157
}


1158
std::vector<OS::SharedLibraryAddress> OS::GetSharedLibraryAddresses() {
1159 1160
  // SharedLibraryEvents are logged when loading symbol information.
  // Only the shared libraries loaded at the time of the call to
1161
  // GetSharedLibraryAddresses are logged.  DLLs loaded after
1162
  // initialization are not accounted for.
1163
  if (!LoadDbgHelpAndTlHelp32()) return std::vector<OS::SharedLibraryAddress>();
1164
  HANDLE process_handle = GetCurrentProcess();
1165
  return LoadSymbols(process_handle);
1166 1167 1168
}


1169 1170 1171 1172
void OS::SignalCodeMovingGC() {
}


1173
#else  // __MINGW32__
1174 1175 1176 1177 1178
std::vector<OS::SharedLibraryAddress> OS::GetSharedLibraryAddresses() {
  return std::vector<OS::SharedLibraryAddress>();
}


sgjesse@chromium.org's avatar
sgjesse@chromium.org committed
1179
void OS::SignalCodeMovingGC() { }
1180 1181
#endif  // __MINGW32__

1182

1183
int OS::ActivationFrameAlignment() {
1184
#ifdef _WIN64
whesse@chromium.org's avatar
whesse@chromium.org committed
1185
  return 16;  // Windows 64-bit ABI requires the stack to be 16-byte aligned.
1186
#elif defined(__MINGW32__)
1187 1188 1189
  // With gcc 4.4 the tree vectorization optimizer can generate code
  // that requires 16 byte alignment such as movdqa on x86.
  return 16;
1190
#else
whesse@chromium.org's avatar
whesse@chromium.org committed
1191
  return 8;  // Floating-point math runs faster with 8-byte alignment.
1192
#endif
1193 1194 1195
}


1196 1197 1198 1199 1200 1201 1202 1203 1204
VirtualMemory::VirtualMemory() : address_(NULL), size_(0) { }


VirtualMemory::VirtualMemory(size_t size)
    : address_(ReserveRegion(size)), size_(size) { }


VirtualMemory::VirtualMemory(size_t size, size_t alignment)
    : address_(NULL), size_(0) {
1205
  DCHECK((alignment % OS::AllocateAlignment()) == 0);
1206 1207 1208 1209
  size_t request_size = RoundUp(size + alignment,
                                static_cast<intptr_t>(OS::AllocateAlignment()));
  void* address = ReserveRegion(request_size);
  if (address == NULL) return;
1210
  uint8_t* base = RoundUp(static_cast<uint8_t*>(address), alignment);
1211 1212 1213
  // Try reducing the size by freeing and then reallocating a specific area.
  bool result = ReleaseRegion(address, request_size);
  USE(result);
1214
  DCHECK(result);
1215 1216 1217
  address = VirtualAlloc(base, size, MEM_RESERVE, PAGE_NOACCESS);
  if (address != NULL) {
    request_size = size;
1218
    DCHECK(base == static_cast<uint8_t*>(address));
1219 1220 1221 1222 1223 1224 1225 1226 1227 1228 1229 1230 1231
  } else {
    // Resizing failed, just go with a bigger area.
    address = ReserveRegion(request_size);
    if (address == NULL) return;
  }
  address_ = address;
  size_ = request_size;
}


VirtualMemory::~VirtualMemory() {
  if (IsReserved()) {
    bool result = ReleaseRegion(address(), size());
1232
    DCHECK(result);
1233 1234 1235 1236 1237 1238 1239 1240 1241 1242 1243 1244 1245 1246 1247 1248 1249 1250 1251 1252 1253 1254
    USE(result);
  }
}


bool VirtualMemory::IsReserved() {
  return address_ != NULL;
}


void VirtualMemory::Reset() {
  address_ = NULL;
  size_ = 0;
}


bool VirtualMemory::Commit(void* address, size_t size, bool is_executable) {
  return CommitRegion(address, size, is_executable);
}


bool VirtualMemory::Uncommit(void* address, size_t size) {
1255
  DCHECK(IsReserved());
1256 1257 1258 1259 1260 1261 1262 1263 1264 1265 1266 1267 1268 1269 1270 1271 1272 1273 1274 1275 1276 1277 1278 1279 1280 1281 1282 1283 1284 1285 1286 1287 1288
  return UncommitRegion(address, size);
}


bool VirtualMemory::Guard(void* address) {
  if (NULL == VirtualAlloc(address,
                           OS::CommitPageSize(),
                           MEM_COMMIT,
                           PAGE_NOACCESS)) {
    return false;
  }
  return true;
}


void* VirtualMemory::ReserveRegion(size_t size) {
  return RandomizedVirtualAlloc(size, MEM_RESERVE, PAGE_NOACCESS);
}


bool VirtualMemory::CommitRegion(void* base, size_t size, bool is_executable) {
  int prot = is_executable ? PAGE_EXECUTE_READWRITE : PAGE_READWRITE;
  if (NULL == VirtualAlloc(base, size, MEM_COMMIT, prot)) {
    return false;
  }
  return true;
}


bool VirtualMemory::UncommitRegion(void* base, size_t size) {
  return VirtualFree(base, size, MEM_DECOMMIT) != 0;
}

1289 1290 1291 1292
bool VirtualMemory::ReleasePartialRegion(void* base, size_t size,
                                         void* free_start, size_t free_size) {
  return VirtualFree(free_start, free_size, MEM_DECOMMIT) != 0;
}
1293 1294 1295 1296 1297 1298 1299 1300 1301 1302 1303 1304

bool VirtualMemory::ReleaseRegion(void* base, size_t size) {
  return VirtualFree(base, 0, MEM_RELEASE) != 0;
}


bool VirtualMemory::HasLazyCommits() {
  // TODO(alph): implement for the platform.
  return false;
}


1305 1306 1307 1308 1309 1310 1311 1312 1313 1314 1315 1316
// ----------------------------------------------------------------------------
// Win32 thread support.

// Definition of invalid thread handle and id.
static const HANDLE kNoThread = INVALID_HANDLE_VALUE;

// Entry point for threads. The supplied argument is a pointer to the thread
// object. The entry function dispatches to the run method in the thread
// object. It is important that this function has __stdcall calling
// convention.
static unsigned int __stdcall ThreadEntry(void* arg) {
  Thread* thread = reinterpret_cast<Thread*>(arg);
1317
  thread->NotifyStartedAndRun();
1318 1319 1320 1321
  return 0;
}


1322
class Thread::PlatformData {
1323 1324 1325
 public:
  explicit PlatformData(HANDLE thread) : thread_(thread) {}
  HANDLE thread_;
1326
  unsigned thread_id_;
1327 1328 1329 1330 1331 1332
};


// Initialize a Win32 thread object. The thread has an invalid thread
// handle until it is started.

1333
Thread::Thread(const Options& options)
1334 1335
    : stack_size_(options.stack_size()),
      start_semaphore_(NULL) {
1336
  data_ = new PlatformData(kNoThread);
1337
  set_name(options.name());
1338 1339 1340 1341
}


void Thread::set_name(const char* name) {
1342
  OS::StrNCpy(name_, sizeof(name_), name, strlen(name));
1343
  name_[sizeof(name_) - 1] = '\0';
1344 1345 1346 1347 1348 1349 1350 1351 1352 1353 1354 1355 1356 1357 1358 1359
}


// Close our own handle for the thread.
Thread::~Thread() {
  if (data_->thread_ != kNoThread) CloseHandle(data_->thread_);
  delete data_;
}


// Create a new thread. It is important to use _beginthreadex() instead of
// the Win32 function CreateThread(), because the CreateThread() does not
// initialize thread specific structures in the C runtime library.
void Thread::Start() {
  data_->thread_ = reinterpret_cast<HANDLE>(
      _beginthreadex(NULL,
1360
                     static_cast<unsigned>(stack_size_),
1361 1362 1363
                     ThreadEntry,
                     this,
                     0,
1364
                     &data_->thread_id_));
1365 1366 1367 1368 1369
}


// Wait for thread to terminate.
void Thread::Join() {
1370 1371 1372
  if (data_->thread_id_ != GetCurrentThreadId()) {
    WaitForSingleObject(data_->thread_, INFINITE);
  }
1373 1374 1375 1376 1377
}


Thread::LocalStorageKey Thread::CreateThreadLocalKey() {
  DWORD result = TlsAlloc();
1378
  DCHECK(result != TLS_OUT_OF_INDEXES);
1379 1380 1381 1382 1383 1384 1385
  return static_cast<LocalStorageKey>(result);
}


void Thread::DeleteThreadLocalKey(LocalStorageKey key) {
  BOOL result = TlsFree(static_cast<DWORD>(key));
  USE(result);
1386
  DCHECK(result);
1387 1388 1389 1390 1391 1392 1393 1394 1395 1396 1397
}


void* Thread::GetThreadLocal(LocalStorageKey key) {
  return TlsGetValue(static_cast<DWORD>(key));
}


void Thread::SetThreadLocal(LocalStorageKey key, void* value) {
  BOOL result = TlsSetValue(static_cast<DWORD>(key), value);
  USE(result);
1398
  DCHECK(result);
1399 1400
}

1401 1402
}  // namespace base
}  // namespace v8