The data contained in this repository can be downloaded to your computer using one of several clients.
Please see the documentation of your version control software client for more information.

Please select the desired protocol below to get the URL.

This URL has Read-Only access.

Statistics
| Branch: | Revision:

main_repo / deps / v8 / src / platform-win32.cc @ f230a1cf

History | View | Annotate | Download (45.9 KB)

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
#include "win32-headers.h"
42

    
43
#include "v8.h"
44

    
45
#include "codegen.h"
46
#include "isolate-inl.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
namespace v8 {
129
namespace internal {
130

    
131
intptr_t OS::MaxVirtualMemory() {
132
  return 0;
133
}
134

    
135

    
136
double ceiling(double x) {
137
  return ceil(x);
138
}
139

    
140

    
141
#if V8_TARGET_ARCH_IA32
142
static void MemMoveWrapper(void* dest, const void* src, size_t size) {
143
  memmove(dest, src, size);
144
}
145

    
146

    
147
// Initialize to library version so we can call this at any time during startup.
148
static OS::MemMoveFunction memmove_function = &MemMoveWrapper;
149

    
150
// Defined in codegen-ia32.cc.
151
OS::MemMoveFunction CreateMemMoveFunction();
152

    
153
// Copy memory area to disjoint memory area.
154
void OS::MemMove(void* dest, const void* src, size_t size) {
155
  if (size == 0) return;
156
  // Note: here we rely on dependent reads being ordered. This is true
157
  // on all architectures we currently support.
158
  (*memmove_function)(dest, src, size);
159
}
160

    
161
#endif  // V8_TARGET_ARCH_IA32
162

    
163
#ifdef _WIN64
164
typedef double (*ModuloFunction)(double, double);
165
static ModuloFunction modulo_function = NULL;
166
// Defined in codegen-x64.cc.
167
ModuloFunction CreateModuloFunction();
168

    
169
void init_modulo_function() {
170
  modulo_function = CreateModuloFunction();
171
}
172

    
173

    
174
double modulo(double x, double y) {
175
  // Note: here we rely on dependent reads being ordered. This is true
176
  // on all architectures we currently support.
177
  return (*modulo_function)(x, y);
178
}
179
#else  // Win32
180

    
181
double modulo(double x, double y) {
182
  // Workaround MS fmod bugs. ECMA-262 says:
183
  // dividend is finite and divisor is an infinity => result equals dividend
184
  // dividend is a zero and divisor is nonzero finite => result equals dividend
185
  if (!(std::isfinite(x) && (!std::isfinite(y) && !std::isnan(y))) &&
186
      !(x == 0 && (y != 0 && std::isfinite(y)))) {
187
    x = fmod(x, y);
188
  }
189
  return x;
190
}
191

    
192
#endif  // _WIN64
193

    
194

    
195
#define UNARY_MATH_FUNCTION(name, generator)             \
196
static UnaryMathFunction fast_##name##_function = NULL;  \
197
void init_fast_##name##_function() {                     \
198
  fast_##name##_function = generator;                    \
199
}                                                        \
200
double fast_##name(double x) {                           \
201
  return (*fast_##name##_function)(x);                   \
202
}
203

    
204
UNARY_MATH_FUNCTION(sin, CreateTranscendentalFunction(TranscendentalCache::SIN))
205
UNARY_MATH_FUNCTION(cos, CreateTranscendentalFunction(TranscendentalCache::COS))
206
UNARY_MATH_FUNCTION(tan, CreateTranscendentalFunction(TranscendentalCache::TAN))
207
UNARY_MATH_FUNCTION(log, CreateTranscendentalFunction(TranscendentalCache::LOG))
208
UNARY_MATH_FUNCTION(exp, CreateExpFunction())
209
UNARY_MATH_FUNCTION(sqrt, CreateSqrtFunction())
210

    
211
#undef UNARY_MATH_FUNCTION
212

    
213

    
214
void lazily_initialize_fast_exp() {
215
  if (fast_exp_function == NULL) {
216
    init_fast_exp_function();
217
  }
218
}
219

    
220

    
221
void MathSetup() {
222
#ifdef _WIN64
223
  init_modulo_function();
224
#endif
225
  init_fast_sin_function();
226
  init_fast_cos_function();
227
  init_fast_tan_function();
228
  init_fast_log_function();
229
  // fast_exp is initialized lazily.
230
  init_fast_sqrt_function();
231
}
232

    
233

    
234
// ----------------------------------------------------------------------------
235
// The Time class represents time on win32. A timestamp is represented as
236
// a 64-bit integer in 100 nanoseconds since January 1, 1601 (UTC). JavaScript
237
// timestamps are represented as a doubles in milliseconds since 00:00:00 UTC,
238
// January 1, 1970.
239

    
240
class Win32Time {
241
 public:
242
  // Constructors.
243
  Win32Time();
244
  explicit Win32Time(double jstime);
245
  Win32Time(int year, int mon, int day, int hour, int min, int sec);
246

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

    
250
  // Set timestamp to current time.
251
  void SetToCurrentTime();
252

    
253
  // Returns the local timezone offset in milliseconds east of UTC. This is
254
  // the number of milliseconds you must add to UTC to get local time, i.e.
255
  // LocalOffset(CET) = 3600000 and LocalOffset(PST) = -28800000. This
256
  // routine also takes into account whether daylight saving is effect
257
  // at the time.
258
  int64_t LocalOffset();
259

    
260
  // Returns the daylight savings time offset for the time in milliseconds.
261
  int64_t DaylightSavingsOffset();
262

    
263
  // Returns a string identifying the current timezone for the
264
  // timestamp taking into account daylight saving.
265
  char* LocalTimezone();
266

    
267
 private:
268
  // Constants for time conversion.
269
  static const int64_t kTimeEpoc = 116444736000000000LL;
270
  static const int64_t kTimeScaler = 10000;
271
  static const int64_t kMsPerMinute = 60000;
272

    
273
  // Constants for timezone information.
274
  static const int kTzNameSize = 128;
275
  static const bool kShortTzNames = false;
276

    
277
  // Timezone information. We need to have static buffers for the
278
  // timezone names because we return pointers to these in
279
  // LocalTimezone().
280
  static bool tz_initialized_;
281
  static TIME_ZONE_INFORMATION tzinfo_;
282
  static char std_tz_name_[kTzNameSize];
283
  static char dst_tz_name_[kTzNameSize];
284

    
285
  // Initialize the timezone information (if not already done).
286
  static void TzSet();
287

    
288
  // Guess the name of the timezone from the bias.
289
  static const char* GuessTimezoneNameFromBias(int bias);
290

    
291
  // Return whether or not daylight savings time is in effect at this time.
292
  bool InDST();
293

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

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

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

    
310
  TimeStamp time_;
311
};
312

    
313

    
314
// Static variables.
315
bool Win32Time::tz_initialized_ = false;
316
TIME_ZONE_INFORMATION Win32Time::tzinfo_;
317
char Win32Time::std_tz_name_[kTzNameSize];
318
char Win32Time::dst_tz_name_[kTzNameSize];
319

    
320

    
321
// Initialize timestamp to start of epoc.
322
Win32Time::Win32Time() {
323
  t() = 0;
324
}
325

    
326

    
327
// Initialize timestamp from a JavaScript timestamp.
328
Win32Time::Win32Time(double jstime) {
329
  t() = static_cast<int64_t>(jstime) * kTimeScaler + kTimeEpoc;
330
}
331

    
332

    
333
// Initialize timestamp from date/time components.
334
Win32Time::Win32Time(int year, int mon, int day, int hour, int min, int sec) {
335
  SYSTEMTIME st;
336
  st.wYear = year;
337
  st.wMonth = mon;
338
  st.wDay = day;
339
  st.wHour = hour;
340
  st.wMinute = min;
341
  st.wSecond = sec;
342
  st.wMilliseconds = 0;
343
  SystemTimeToFileTime(&st, &ft());
344
}
345

    
346

    
347
// Convert timestamp to JavaScript timestamp.
348
double Win32Time::ToJSTime() {
349
  return static_cast<double>((t() - kTimeEpoc) / kTimeScaler);
350
}
351

    
352

    
353
// Set timestamp to current time.
354
void Win32Time::SetToCurrentTime() {
355
  // The default GetSystemTimeAsFileTime has a ~15.5ms resolution.
356
  // Because we're fast, we like fast timers which have at least a
357
  // 1ms resolution.
358
  //
359
  // timeGetTime() provides 1ms granularity when combined with
360
  // timeBeginPeriod().  If the host application for v8 wants fast
361
  // timers, it can use timeBeginPeriod to increase the resolution.
362
  //
363
  // Using timeGetTime() has a drawback because it is a 32bit value
364
  // and hence rolls-over every ~49days.
365
  //
366
  // To use the clock, we use GetSystemTimeAsFileTime as our base;
367
  // and then use timeGetTime to extrapolate current time from the
368
  // start time.  To deal with rollovers, we resync the clock
369
  // any time when more than kMaxClockElapsedTime has passed or
370
  // whenever timeGetTime creates a rollover.
371

    
372
  static bool initialized = false;
373
  static TimeStamp init_time;
374
  static DWORD init_ticks;
375
  static const int64_t kHundredNanosecondsPerSecond = 10000000;
376
  static const int64_t kMaxClockElapsedTime =
377
      60*kHundredNanosecondsPerSecond;  // 1 minute
378

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

    
382
  // Get the current time.
383
  TimeStamp time_now;
384
  GetSystemTimeAsFileTime(&time_now.ft_);
385
  DWORD ticks_now = timeGetTime();
386

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

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

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

    
396
  // Resync the clock if necessary.
397
  if (needs_resync) {
398
    GetSystemTimeAsFileTime(&init_time.ft_);
399
    init_ticks = ticks_now = timeGetTime();
400
    initialized = true;
401
  }
402

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

    
408

    
409
// Guess the name of the timezone from the bias.
410
// The guess is very biased towards the northern hemisphere.
411
const char* Win32Time::GuessTimezoneNameFromBias(int bias) {
412
  static const int kHour = 60;
413
  switch (-bias) {
414
    case -9*kHour: return "Alaska";
415
    case -8*kHour: return "Pacific";
416
    case -7*kHour: return "Mountain";
417
    case -6*kHour: return "Central";
418
    case -5*kHour: return "Eastern";
419
    case -4*kHour: return "Atlantic";
420
    case  0*kHour: return "GMT";
421
    case +1*kHour: return "Central Europe";
422
    case +2*kHour: return "Eastern Europe";
423
    case +3*kHour: return "Russia";
424
    case +5*kHour + 30: return "India";
425
    case +8*kHour: return "China";
426
    case +9*kHour: return "Japan";
427
    case +12*kHour: return "New Zealand";
428
    default: return "Local";
429
  }
430
}
431

    
432

    
433
// Initialize timezone information. The timezone information is obtained from
434
// windows. If we cannot get the timezone information we fall back to CET.
435
// Please notice that this code is not thread-safe.
436
void Win32Time::TzSet() {
437
  // Just return if timezone information has already been initialized.
438
  if (tz_initialized_) return;
439

    
440
  // Initialize POSIX time zone data.
441
  _tzset();
442
  // Obtain timezone information from operating system.
443
  memset(&tzinfo_, 0, sizeof(tzinfo_));
444
  if (GetTimeZoneInformation(&tzinfo_) == TIME_ZONE_ID_INVALID) {
445
    // If we cannot get timezone information we fall back to CET.
446
    tzinfo_.Bias = -60;
447
    tzinfo_.StandardDate.wMonth = 10;
448
    tzinfo_.StandardDate.wDay = 5;
449
    tzinfo_.StandardDate.wHour = 3;
450
    tzinfo_.StandardBias = 0;
451
    tzinfo_.DaylightDate.wMonth = 3;
452
    tzinfo_.DaylightDate.wDay = 5;
453
    tzinfo_.DaylightDate.wHour = 2;
454
    tzinfo_.DaylightBias = -60;
455
  }
456

    
457
  // Make standard and DST timezone names.
458
  WideCharToMultiByte(CP_UTF8, 0, tzinfo_.StandardName, -1,
459
                      std_tz_name_, kTzNameSize, NULL, NULL);
460
  std_tz_name_[kTzNameSize - 1] = '\0';
461
  WideCharToMultiByte(CP_UTF8, 0, tzinfo_.DaylightName, -1,
462
                      dst_tz_name_, kTzNameSize, NULL, NULL);
463
  dst_tz_name_[kTzNameSize - 1] = '\0';
464

    
465
  // If OS returned empty string or resource id (like "@tzres.dll,-211")
466
  // simply guess the name from the UTC bias of the timezone.
467
  // To properly resolve the resource identifier requires a library load,
468
  // which is not possible in a sandbox.
469
  if (std_tz_name_[0] == '\0' || std_tz_name_[0] == '@') {
470
    OS::SNPrintF(Vector<char>(std_tz_name_, kTzNameSize - 1),
471
                 "%s Standard Time",
472
                 GuessTimezoneNameFromBias(tzinfo_.Bias));
473
  }
474
  if (dst_tz_name_[0] == '\0' || dst_tz_name_[0] == '@') {
475
    OS::SNPrintF(Vector<char>(dst_tz_name_, kTzNameSize - 1),
476
                 "%s Daylight Time",
477
                 GuessTimezoneNameFromBias(tzinfo_.Bias));
478
  }
479

    
480
  // Timezone information initialized.
481
  tz_initialized_ = true;
482
}
483

    
484

    
485
// Return the local timezone offset in milliseconds east of UTC. This
486
// takes into account whether daylight saving is in effect at the time.
487
// Only times in the 32-bit Unix range may be passed to this function.
488
// Also, adding the time-zone offset to the input must not overflow.
489
// The function EquivalentTime() in date.js guarantees this.
490
int64_t Win32Time::LocalOffset() {
491
  // Initialize timezone information, if needed.
492
  TzSet();
493

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

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

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

    
514
  if (posix_local_time_struct.tm_isdst > 0) {
515
    return (tzinfo_.Bias + tzinfo_.DaylightBias) * -kMsPerMinute;
516
  } else if (posix_local_time_struct.tm_isdst == 0) {
517
    return (tzinfo_.Bias + tzinfo_.StandardBias) * -kMsPerMinute;
518
  } else {
519
    return tzinfo_.Bias * -kMsPerMinute;
520
  }
521
}
522

    
523

    
524
// Return whether or not daylight savings time is in effect at this time.
525
bool Win32Time::InDST() {
526
  // Initialize timezone information, if needed.
527
  TzSet();
528

    
529
  // Determine if DST is in effect at the specified time.
530
  bool in_dst = false;
531
  if (tzinfo_.StandardDate.wMonth != 0 || tzinfo_.DaylightDate.wMonth != 0) {
532
    // Get the local timezone offset for the timestamp in milliseconds.
533
    int64_t offset = LocalOffset();
534

    
535
    // Compute the offset for DST. The bias parameters in the timezone info
536
    // are specified in minutes. These must be converted to milliseconds.
537
    int64_t dstofs = -(tzinfo_.Bias + tzinfo_.DaylightBias) * kMsPerMinute;
538

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

    
544
  return in_dst;
545
}
546

    
547

    
548
// Return the daylight savings time offset for this time.
549
int64_t Win32Time::DaylightSavingsOffset() {
550
  return InDST() ? 60 * kMsPerMinute : 0;
551
}
552

    
553

    
554
// Returns a string identifying the current timezone for the
555
// timestamp taking into account daylight saving.
556
char* Win32Time::LocalTimezone() {
557
  // Return the standard or DST time zone name based on whether daylight
558
  // saving is in effect at the given time.
559
  return InDST() ? dst_tz_name_ : std_tz_name_;
560
}
561

    
562

    
563
void OS::PostSetUp() {
564
  // Math functions depend on CPU features therefore they are initialized after
565
  // CPU.
566
  MathSetup();
567
#if V8_TARGET_ARCH_IA32
568
  OS::MemMoveFunction generated_memmove = CreateMemMoveFunction();
569
  if (generated_memmove != NULL) {
570
    memmove_function = generated_memmove;
571
  }
572
#endif
573
}
574

    
575

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

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

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

    
588
  // Convert to seconds and microseconds
589
  *secs = static_cast<uint32_t>(usertime / 1000000);
590
  *usecs = static_cast<uint32_t>(usertime % 1000000);
591
  return 0;
592
}
593

    
594

    
595
// Returns current time as the number of milliseconds since
596
// 00:00:00 UTC, January 1, 1970.
597
double OS::TimeCurrentMillis() {
598
  return Time::Now().ToJsTime();
599
}
600

    
601

    
602
// Returns a string identifying the current timezone taking into
603
// account daylight saving.
604
const char* OS::LocalTimezone(double time) {
605
  return Win32Time(time).LocalTimezone();
606
}
607

    
608

    
609
// Returns the local time offset in milliseconds east of UTC without
610
// taking daylight savings time into account.
611
double OS::LocalTimeOffset() {
612
  // Use current time, rounded to the millisecond.
613
  Win32Time t(TimeCurrentMillis());
614
  // Time::LocalOffset inlcudes any daylight savings offset, so subtract it.
615
  return static_cast<double>(t.LocalOffset() - t.DaylightSavingsOffset());
616
}
617

    
618

    
619
// Returns the daylight savings offset in milliseconds for the given
620
// time.
621
double OS::DaylightSavingsOffset(double time) {
622
  int64_t offset = Win32Time(time).DaylightSavingsOffset();
623
  return static_cast<double>(offset);
624
}
625

    
626

    
627
int OS::GetLastError() {
628
  return ::GetLastError();
629
}
630

    
631

    
632
int OS::GetCurrentProcessId() {
633
  return static_cast<int>(::GetCurrentProcessId());
634
}
635

    
636

    
637
// ----------------------------------------------------------------------------
638
// Win32 console output.
639
//
640
// If a Win32 application is linked as a console application it has a normal
641
// standard output and standard error. In this case normal printf works fine
642
// for output. However, if the application is linked as a GUI application,
643
// the process doesn't have a console, and therefore (debugging) output is lost.
644
// This is the case if we are embedded in a windows program (like a browser).
645
// In order to be able to get debug output in this case the the debugging
646
// facility using OutputDebugString. This output goes to the active debugger
647
// for the process (if any). Else the output can be monitored using DBMON.EXE.
648

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

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

    
657

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

    
676

    
677
static void VPrintHelper(FILE* stream, const char* format, va_list args) {
678
  if (HasConsole()) {
679
    vfprintf(stream, format, args);
680
  } else {
681
    // It is important to use safe print here in order to avoid
682
    // overflowing the buffer. We might truncate the output, but this
683
    // does not crash.
684
    EmbeddedVector<char, 4096> buffer;
685
    OS::VSNPrintF(buffer, format, args);
686
    OutputDebugStringA(buffer.start());
687
  }
688
}
689

    
690

    
691
FILE* OS::FOpen(const char* path, const char* mode) {
692
  FILE* result;
693
  if (fopen_s(&result, path, mode) == 0) {
694
    return result;
695
  } else {
696
    return NULL;
697
  }
698
}
699

    
700

    
701
bool OS::Remove(const char* path) {
702
  return (DeleteFileA(path) != 0);
703
}
704

    
705

    
706
FILE* OS::OpenTemporaryFile() {
707
  // tmpfile_s tries to use the root dir, don't use it.
708
  char tempPathBuffer[MAX_PATH];
709
  DWORD path_result = 0;
710
  path_result = GetTempPathA(MAX_PATH, tempPathBuffer);
711
  if (path_result > MAX_PATH || path_result == 0) return NULL;
712
  UINT name_result = 0;
713
  char tempNameBuffer[MAX_PATH];
714
  name_result = GetTempFileNameA(tempPathBuffer, "", 0, tempNameBuffer);
715
  if (name_result == 0) return NULL;
716
  FILE* result = FOpen(tempNameBuffer, "w+");  // Same mode as tmpfile uses.
717
  if (result != NULL) {
718
    Remove(tempNameBuffer);  // Delete on close.
719
  }
720
  return result;
721
}
722

    
723

    
724
// Open log file in binary mode to avoid /n -> /r/n conversion.
725
const char* const OS::LogFileOpenMode = "wb";
726

    
727

    
728
// Print (debug) message to console.
729
void OS::Print(const char* format, ...) {
730
  va_list args;
731
  va_start(args, format);
732
  VPrint(format, args);
733
  va_end(args);
734
}
735

    
736

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

    
741

    
742
void OS::FPrint(FILE* out, const char* format, ...) {
743
  va_list args;
744
  va_start(args, format);
745
  VFPrint(out, format, args);
746
  va_end(args);
747
}
748

    
749

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

    
754

    
755
// Print error message to console.
756
void OS::PrintError(const char* format, ...) {
757
  va_list args;
758
  va_start(args, format);
759
  VPrintError(format, args);
760
  va_end(args);
761
}
762

    
763

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

    
768

    
769
int OS::SNPrintF(Vector<char> str, const char* format, ...) {
770
  va_list args;
771
  va_start(args, format);
772
  int result = VSNPrintF(str, format, args);
773
  va_end(args);
774
  return result;
775
}
776

    
777

    
778
int OS::VSNPrintF(Vector<char> str, const char* format, va_list args) {
779
  int n = _vsnprintf_s(str.start(), str.length(), _TRUNCATE, format, args);
780
  // Make sure to zero-terminate the string if the output was
781
  // truncated or if there was an error.
782
  if (n < 0 || n >= str.length()) {
783
    if (str.length() > 0)
784
      str[str.length() - 1] = '\0';
785
    return -1;
786
  } else {
787
    return n;
788
  }
789
}
790

    
791

    
792
char* OS::StrChr(char* str, int c) {
793
  return const_cast<char*>(strchr(str, c));
794
}
795

    
796

    
797
void OS::StrNCpy(Vector<char> dest, const char* src, size_t n) {
798
  // Use _TRUNCATE or strncpy_s crashes (by design) if buffer is too small.
799
  size_t buffer_size = static_cast<size_t>(dest.length());
800
  if (n + 1 > buffer_size)  // count for trailing '\0'
801
    n = _TRUNCATE;
802
  int result = strncpy_s(dest.start(), dest.length(), src, n);
803
  USE(result);
804
  ASSERT(result == 0 || (n == _TRUNCATE && result == STRUNCATE));
805
}
806

    
807

    
808
#undef _TRUNCATE
809
#undef STRUNCATE
810

    
811

    
812
// Get the system's page size used by VirtualAlloc() or the next power
813
// of two. The reason for always returning a power of two is that the
814
// rounding up in OS::Allocate expects that.
815
static size_t GetPageSize() {
816
  static size_t page_size = 0;
817
  if (page_size == 0) {
818
    SYSTEM_INFO info;
819
    GetSystemInfo(&info);
820
    page_size = RoundUpToPowerOf2(info.dwPageSize);
821
  }
822
  return page_size;
823
}
824

    
825

    
826
// The allocation alignment is the guaranteed alignment for
827
// VirtualAlloc'ed blocks of memory.
828
size_t OS::AllocateAlignment() {
829
  static size_t allocate_alignment = 0;
830
  if (allocate_alignment == 0) {
831
    SYSTEM_INFO info;
832
    GetSystemInfo(&info);
833
    allocate_alignment = info.dwAllocationGranularity;
834
  }
835
  return allocate_alignment;
836
}
837

    
838

    
839
void* OS::GetRandomMmapAddr() {
840
  Isolate* isolate = Isolate::UncheckedCurrent();
841
  // Note that the current isolate isn't set up in a call path via
842
  // CpuFeatures::Probe. We don't care about randomization in this case because
843
  // the code page is immediately freed.
844
  if (isolate != NULL) {
845
    // The address range used to randomize RWX allocations in OS::Allocate
846
    // Try not to map pages into the default range that windows loads DLLs
847
    // Use a multiple of 64k to prevent committing unused memory.
848
    // Note: This does not guarantee RWX regions will be within the
849
    // range kAllocationRandomAddressMin to kAllocationRandomAddressMax
850
#ifdef V8_HOST_ARCH_64_BIT
851
    static const intptr_t kAllocationRandomAddressMin = 0x0000000080000000;
852
    static const intptr_t kAllocationRandomAddressMax = 0x000003FFFFFF0000;
853
#else
854
    static const intptr_t kAllocationRandomAddressMin = 0x04000000;
855
    static const intptr_t kAllocationRandomAddressMax = 0x3FFF0000;
856
#endif
857
    uintptr_t address =
858
        (isolate->random_number_generator()->NextInt() << kPageSizeBits) |
859
        kAllocationRandomAddressMin;
860
    address &= kAllocationRandomAddressMax;
861
    return reinterpret_cast<void *>(address);
862
  }
863
  return NULL;
864
}
865

    
866

    
867
static void* RandomizedVirtualAlloc(size_t size, int action, int protection) {
868
  LPVOID base = NULL;
869

    
870
  if (protection == PAGE_EXECUTE_READWRITE || protection == PAGE_NOACCESS) {
871
    // For exectutable pages try and randomize the allocation address
872
    for (size_t attempts = 0; base == NULL && attempts < 3; ++attempts) {
873
      base = VirtualAlloc(OS::GetRandomMmapAddr(), size, action, protection);
874
    }
875
  }
876

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

    
880
  return base;
881
}
882

    
883

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

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

    
893
  LPVOID mbase = RandomizedVirtualAlloc(msize,
894
                                        MEM_COMMIT | MEM_RESERVE,
895
                                        prot);
896

    
897
  if (mbase == NULL) {
898
    LOG(Isolate::Current(), StringEvent("OS::Allocate", "VirtualAlloc failed"));
899
    return NULL;
900
  }
901

    
902
  ASSERT(IsAligned(reinterpret_cast<size_t>(mbase), OS::AllocateAlignment()));
903

    
904
  *allocated = msize;
905
  return mbase;
906
}
907

    
908

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

    
915

    
916
intptr_t OS::CommitPageSize() {
917
  return 4096;
918
}
919

    
920

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

    
926

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

    
932

    
933
void OS::Sleep(int milliseconds) {
934
  ::Sleep(milliseconds);
935
}
936

    
937

    
938
void OS::Abort() {
939
  if (IsDebuggerPresent() || FLAG_break_on_abort) {
940
    DebugBreak();
941
  } else {
942
    // Make the MSVCRT do a silent abort.
943
    raise(SIGABRT);
944
  }
945
}
946

    
947

    
948
void OS::DebugBreak() {
949
#ifdef _MSC_VER
950
  // To avoid Visual Studio runtime support the following code can be used
951
  // instead
952
  // __asm { int 3 }
953
  __debugbreak();
954
#else
955
  ::DebugBreak();
956
#endif
957
}
958

    
959

    
960
class Win32MemoryMappedFile : public OS::MemoryMappedFile {
961
 public:
962
  Win32MemoryMappedFile(HANDLE file,
963
                        HANDLE file_mapping,
964
                        void* memory,
965
                        int size)
966
      : file_(file),
967
        file_mapping_(file_mapping),
968
        memory_(memory),
969
        size_(size) { }
970
  virtual ~Win32MemoryMappedFile();
971
  virtual void* memory() { return memory_; }
972
  virtual int size() { return size_; }
973
 private:
974
  HANDLE file_;
975
  HANDLE file_mapping_;
976
  void* memory_;
977
  int size_;
978
};
979

    
980

    
981
OS::MemoryMappedFile* OS::MemoryMappedFile::open(const char* name) {
982
  // Open a physical file
983
  HANDLE file = CreateFileA(name, GENERIC_READ | GENERIC_WRITE,
984
      FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL);
985
  if (file == INVALID_HANDLE_VALUE) return NULL;
986

    
987
  int size = static_cast<int>(GetFileSize(file, NULL));
988

    
989
  // Create a file mapping for the physical file
990
  HANDLE file_mapping = CreateFileMapping(file, NULL,
991
      PAGE_READWRITE, 0, static_cast<DWORD>(size), NULL);
992
  if (file_mapping == NULL) return NULL;
993

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

    
999

    
1000
OS::MemoryMappedFile* OS::MemoryMappedFile::create(const char* name, int size,
1001
    void* initial) {
1002
  // Open a physical file
1003
  HANDLE file = CreateFileA(name, GENERIC_READ | GENERIC_WRITE,
1004
      FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_ALWAYS, 0, NULL);
1005
  if (file == NULL) return NULL;
1006
  // Create a file mapping for the physical file
1007
  HANDLE file_mapping = CreateFileMapping(file, NULL,
1008
      PAGE_READWRITE, 0, static_cast<DWORD>(size), NULL);
1009
  if (file_mapping == NULL) return NULL;
1010
  // Map a view of the file into memory
1011
  void* memory = MapViewOfFile(file_mapping, FILE_MAP_ALL_ACCESS, 0, 0, size);
1012
  if (memory) OS::MemMove(memory, initial, size);
1013
  return new Win32MemoryMappedFile(file, file_mapping, memory, size);
1014
}
1015

    
1016

    
1017
Win32MemoryMappedFile::~Win32MemoryMappedFile() {
1018
  if (memory_ != NULL)
1019
    UnmapViewOfFile(memory_);
1020
  CloseHandle(file_mapping_);
1021
  CloseHandle(file_);
1022
}
1023

    
1024

    
1025
// The following code loads functions defined in DbhHelp.h and TlHelp32.h
1026
// dynamically. This is to avoid being depending on dbghelp.dll and
1027
// tlhelp32.dll when running (the functions in tlhelp32.dll have been moved to
1028
// kernel32.dll at some point so loading functions defines in TlHelp32.h
1029
// dynamically might not be necessary any more - for some versions of Windows?).
1030

    
1031
// Function pointers to functions dynamically loaded from dbghelp.dll.
1032
#define DBGHELP_FUNCTION_LIST(V)  \
1033
  V(SymInitialize)                \
1034
  V(SymGetOptions)                \
1035
  V(SymSetOptions)                \
1036
  V(SymGetSearchPath)             \
1037
  V(SymLoadModule64)              \
1038
  V(StackWalk64)                  \
1039
  V(SymGetSymFromAddr64)          \
1040
  V(SymGetLineFromAddr64)         \
1041
  V(SymFunctionTableAccess64)     \
1042
  V(SymGetModuleBase64)
1043

    
1044
// Function pointers to functions dynamically loaded from dbghelp.dll.
1045
#define TLHELP32_FUNCTION_LIST(V)  \
1046
  V(CreateToolhelp32Snapshot)      \
1047
  V(Module32FirstW)                \
1048
  V(Module32NextW)
1049

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

    
1055
// Define the type for each dynamically loaded DLL function. The function
1056
// definitions are copied from DbgHelp.h and TlHelp32.h. The IN and VOID macros
1057
// from the Windows include files are redefined here to have the function
1058
// definitions to be as close to the ones in the original .h files as possible.
1059
#ifndef IN
1060
#define IN
1061
#endif
1062
#ifndef VOID
1063
#define VOID void
1064
#endif
1065

    
1066
// DbgHelp isn't supported on MinGW yet
1067
#ifndef __MINGW32__
1068
// DbgHelp.h functions.
1069
typedef BOOL (__stdcall *DLL_FUNC_TYPE(SymInitialize))(IN HANDLE hProcess,
1070
                                                       IN PSTR UserSearchPath,
1071
                                                       IN BOOL fInvadeProcess);
1072
typedef DWORD (__stdcall *DLL_FUNC_TYPE(SymGetOptions))(VOID);
1073
typedef DWORD (__stdcall *DLL_FUNC_TYPE(SymSetOptions))(IN DWORD SymOptions);
1074
typedef BOOL (__stdcall *DLL_FUNC_TYPE(SymGetSearchPath))(
1075
    IN HANDLE hProcess,
1076
    OUT PSTR SearchPath,
1077
    IN DWORD SearchPathLength);
1078
typedef DWORD64 (__stdcall *DLL_FUNC_TYPE(SymLoadModule64))(
1079
    IN HANDLE hProcess,
1080
    IN HANDLE hFile,
1081
    IN PSTR ImageName,
1082
    IN PSTR ModuleName,
1083
    IN DWORD64 BaseOfDll,
1084
    IN DWORD SizeOfDll);
1085
typedef BOOL (__stdcall *DLL_FUNC_TYPE(StackWalk64))(
1086
    DWORD MachineType,
1087
    HANDLE hProcess,
1088
    HANDLE hThread,
1089
    LPSTACKFRAME64 StackFrame,
1090
    PVOID ContextRecord,
1091
    PREAD_PROCESS_MEMORY_ROUTINE64 ReadMemoryRoutine,
1092
    PFUNCTION_TABLE_ACCESS_ROUTINE64 FunctionTableAccessRoutine,
1093
    PGET_MODULE_BASE_ROUTINE64 GetModuleBaseRoutine,
1094
    PTRANSLATE_ADDRESS_ROUTINE64 TranslateAddress);
1095
typedef BOOL (__stdcall *DLL_FUNC_TYPE(SymGetSymFromAddr64))(
1096
    IN HANDLE hProcess,
1097
    IN DWORD64 qwAddr,
1098
    OUT PDWORD64 pdwDisplacement,
1099
    OUT PIMAGEHLP_SYMBOL64 Symbol);
1100
typedef BOOL (__stdcall *DLL_FUNC_TYPE(SymGetLineFromAddr64))(
1101
    IN HANDLE hProcess,
1102
    IN DWORD64 qwAddr,
1103
    OUT PDWORD pdwDisplacement,
1104
    OUT PIMAGEHLP_LINE64 Line64);
1105
// DbgHelp.h typedefs. Implementation found in dbghelp.dll.
1106
typedef PVOID (__stdcall *DLL_FUNC_TYPE(SymFunctionTableAccess64))(
1107
    HANDLE hProcess,
1108
    DWORD64 AddrBase);  // DbgHelp.h typedef PFUNCTION_TABLE_ACCESS_ROUTINE64
1109
typedef DWORD64 (__stdcall *DLL_FUNC_TYPE(SymGetModuleBase64))(
1110
    HANDLE hProcess,
1111
    DWORD64 AddrBase);  // DbgHelp.h typedef PGET_MODULE_BASE_ROUTINE64
1112

    
1113
// TlHelp32.h functions.
1114
typedef HANDLE (__stdcall *DLL_FUNC_TYPE(CreateToolhelp32Snapshot))(
1115
    DWORD dwFlags,
1116
    DWORD th32ProcessID);
1117
typedef BOOL (__stdcall *DLL_FUNC_TYPE(Module32FirstW))(HANDLE hSnapshot,
1118
                                                        LPMODULEENTRY32W lpme);
1119
typedef BOOL (__stdcall *DLL_FUNC_TYPE(Module32NextW))(HANDLE hSnapshot,
1120
                                                       LPMODULEENTRY32W lpme);
1121

    
1122
#undef IN
1123
#undef VOID
1124

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

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

    
1134
static bool LoadDbgHelpAndTlHelp32() {
1135
  static bool dbghelp_loaded = false;
1136

    
1137
  if (dbghelp_loaded) return true;
1138

    
1139
  HMODULE module;
1140

    
1141
  // Load functions from the dbghelp.dll module.
1142
  module = LoadLibrary(TEXT("dbghelp.dll"));
1143
  if (module == NULL) {
1144
    return false;
1145
  }
1146

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

    
1151
DBGHELP_FUNCTION_LIST(LOAD_DLL_FUNC)
1152

    
1153
#undef LOAD_DLL_FUNC
1154

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

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

    
1166
TLHELP32_FUNCTION_LIST(LOAD_DLL_FUNC)
1167

    
1168
#undef LOAD_DLL_FUNC
1169

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

    
1174
DBGHELP_FUNCTION_LIST(DLL_FUNC_LOADED)
1175
TLHELP32_FUNCTION_LIST(DLL_FUNC_LOADED)
1176

    
1177
#undef DLL_FUNC_LOADED
1178
  true;
1179

    
1180
  dbghelp_loaded = result;
1181
  return result;
1182
  // NOTE: The modules are never unloaded and will stay around until the
1183
  // application is closed.
1184
}
1185

    
1186
#undef DBGHELP_FUNCTION_LIST
1187
#undef TLHELP32_FUNCTION_LIST
1188
#undef DLL_FUNC_VAR
1189
#undef DLL_FUNC_TYPE
1190

    
1191

    
1192
// Load the symbols for generating stack traces.
1193
static bool LoadSymbols(Isolate* isolate, HANDLE process_handle) {
1194
  static bool symbols_loaded = false;
1195

    
1196
  if (symbols_loaded) return true;
1197

    
1198
  BOOL ok;
1199

    
1200
  // Initialize the symbol engine.
1201
  ok = _SymInitialize(process_handle,  // hProcess
1202
                      NULL,            // UserSearchPath
1203
                      false);          // fInvadeProcess
1204
  if (!ok) return false;
1205

    
1206
  DWORD options = _SymGetOptions();
1207
  options |= SYMOPT_LOAD_LINES;
1208
  options |= SYMOPT_FAIL_CRITICAL_ERRORS;
1209
  options = _SymSetOptions(options);
1210

    
1211
  char buf[OS::kStackWalkMaxNameLen] = {0};
1212
  ok = _SymGetSearchPath(process_handle, buf, OS::kStackWalkMaxNameLen);
1213
  if (!ok) {
1214
    int err = GetLastError();
1215
    PrintF("%d\n", err);
1216
    return false;
1217
  }
1218

    
1219
  HANDLE snapshot = _CreateToolhelp32Snapshot(
1220
      TH32CS_SNAPMODULE,       // dwFlags
1221
      GetCurrentProcessId());  // th32ProcessId
1222
  if (snapshot == INVALID_HANDLE_VALUE) return false;
1223
  MODULEENTRY32W module_entry;
1224
  module_entry.dwSize = sizeof(module_entry);  // Set the size of the structure.
1225
  BOOL cont = _Module32FirstW(snapshot, &module_entry);
1226
  while (cont) {
1227
    DWORD64 base;
1228
    // NOTE the SymLoadModule64 function has the peculiarity of accepting a
1229
    // both unicode and ASCII strings even though the parameter is PSTR.
1230
    base = _SymLoadModule64(
1231
        process_handle,                                       // hProcess
1232
        0,                                                    // hFile
1233
        reinterpret_cast<PSTR>(module_entry.szExePath),       // ImageName
1234
        reinterpret_cast<PSTR>(module_entry.szModule),        // ModuleName
1235
        reinterpret_cast<DWORD64>(module_entry.modBaseAddr),  // BaseOfDll
1236
        module_entry.modBaseSize);                            // SizeOfDll
1237
    if (base == 0) {
1238
      int err = GetLastError();
1239
      if (err != ERROR_MOD_NOT_FOUND &&
1240
          err != ERROR_INVALID_HANDLE) return false;
1241
    }
1242
    LOG(isolate,
1243
        SharedLibraryEvent(
1244
            module_entry.szExePath,
1245
            reinterpret_cast<unsigned int>(module_entry.modBaseAddr),
1246
            reinterpret_cast<unsigned int>(module_entry.modBaseAddr +
1247
                                           module_entry.modBaseSize)));
1248
    cont = _Module32NextW(snapshot, &module_entry);
1249
  }
1250
  CloseHandle(snapshot);
1251

    
1252
  symbols_loaded = true;
1253
  return true;
1254
}
1255

    
1256

    
1257
void OS::LogSharedLibraryAddresses(Isolate* isolate) {
1258
  // SharedLibraryEvents are logged when loading symbol information.
1259
  // Only the shared libraries loaded at the time of the call to
1260
  // LogSharedLibraryAddresses are logged.  DLLs loaded after
1261
  // initialization are not accounted for.
1262
  if (!LoadDbgHelpAndTlHelp32()) return;
1263
  HANDLE process_handle = GetCurrentProcess();
1264
  LoadSymbols(isolate, process_handle);
1265
}
1266

    
1267

    
1268
void OS::SignalCodeMovingGC() {
1269
}
1270

    
1271

    
1272
uint64_t OS::TotalPhysicalMemory() {
1273
  MEMORYSTATUSEX memory_info;
1274
  memory_info.dwLength = sizeof(memory_info);
1275
  if (!GlobalMemoryStatusEx(&memory_info)) {
1276
    UNREACHABLE();
1277
    return 0;
1278
  }
1279

    
1280
  return static_cast<uint64_t>(memory_info.ullTotalPhys);
1281
}
1282

    
1283

    
1284
#else  // __MINGW32__
1285
void OS::LogSharedLibraryAddresses(Isolate* isolate) { }
1286
void OS::SignalCodeMovingGC() { }
1287
#endif  // __MINGW32__
1288

    
1289

    
1290
uint64_t OS::CpuFeaturesImpliedByPlatform() {
1291
  return 0;  // Windows runs on anything.
1292
}
1293

    
1294

    
1295
double OS::nan_value() {
1296
#ifdef _MSC_VER
1297
  // Positive Quiet NaN with no payload (aka. Indeterminate) has all bits
1298
  // in mask set, so value equals mask.
1299
  static const __int64 nanval = kQuietNaNMask;
1300
  return *reinterpret_cast<const double*>(&nanval);
1301
#else  // _MSC_VER
1302
  return NAN;
1303
#endif  // _MSC_VER
1304
}
1305

    
1306

    
1307
int OS::ActivationFrameAlignment() {
1308
#ifdef _WIN64
1309
  return 16;  // Windows 64-bit ABI requires the stack to be 16-byte aligned.
1310
#elif defined(__MINGW32__)
1311
  // With gcc 4.4 the tree vectorization optimizer can generate code
1312
  // that requires 16 byte alignment such as movdqa on x86.
1313
  return 16;
1314
#else
1315
  return 8;  // Floating-point math runs faster with 8-byte alignment.
1316
#endif
1317
}
1318

    
1319

    
1320
VirtualMemory::VirtualMemory() : address_(NULL), size_(0) { }
1321

    
1322

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

    
1326

    
1327
VirtualMemory::VirtualMemory(size_t size, size_t alignment)
1328
    : address_(NULL), size_(0) {
1329
  ASSERT(IsAligned(alignment, static_cast<intptr_t>(OS::AllocateAlignment())));
1330
  size_t request_size = RoundUp(size + alignment,
1331
                                static_cast<intptr_t>(OS::AllocateAlignment()));
1332
  void* address = ReserveRegion(request_size);
1333
  if (address == NULL) return;
1334
  Address base = RoundUp(static_cast<Address>(address), alignment);
1335
  // Try reducing the size by freeing and then reallocating a specific area.
1336
  bool result = ReleaseRegion(address, request_size);
1337
  USE(result);
1338
  ASSERT(result);
1339
  address = VirtualAlloc(base, size, MEM_RESERVE, PAGE_NOACCESS);
1340
  if (address != NULL) {
1341
    request_size = size;
1342
    ASSERT(base == static_cast<Address>(address));
1343
  } else {
1344
    // Resizing failed, just go with a bigger area.
1345
    address = ReserveRegion(request_size);
1346
    if (address == NULL) return;
1347
  }
1348
  address_ = address;
1349
  size_ = request_size;
1350
}
1351

    
1352

    
1353
VirtualMemory::~VirtualMemory() {
1354
  if (IsReserved()) {
1355
    bool result = ReleaseRegion(address(), size());
1356
    ASSERT(result);
1357
    USE(result);
1358
  }
1359
}
1360

    
1361

    
1362
bool VirtualMemory::IsReserved() {
1363
  return address_ != NULL;
1364
}
1365

    
1366

    
1367
void VirtualMemory::Reset() {
1368
  address_ = NULL;
1369
  size_ = 0;
1370
}
1371

    
1372

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

    
1377

    
1378
bool VirtualMemory::Uncommit(void* address, size_t size) {
1379
  ASSERT(IsReserved());
1380
  return UncommitRegion(address, size);
1381
}
1382

    
1383

    
1384
bool VirtualMemory::Guard(void* address) {
1385
  if (NULL == VirtualAlloc(address,
1386
                           OS::CommitPageSize(),
1387
                           MEM_COMMIT,
1388
                           PAGE_NOACCESS)) {
1389
    return false;
1390
  }
1391
  return true;
1392
}
1393

    
1394

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

    
1399

    
1400
bool VirtualMemory::CommitRegion(void* base, size_t size, bool is_executable) {
1401
  int prot = is_executable ? PAGE_EXECUTE_READWRITE : PAGE_READWRITE;
1402
  if (NULL == VirtualAlloc(base, size, MEM_COMMIT, prot)) {
1403
    return false;
1404
  }
1405
  return true;
1406
}
1407

    
1408

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

    
1413

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

    
1418

    
1419
bool VirtualMemory::HasLazyCommits() {
1420
  // TODO(alph): implement for the platform.
1421
  return false;
1422
}
1423

    
1424

    
1425
// ----------------------------------------------------------------------------
1426
// Win32 thread support.
1427

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

    
1431
// Entry point for threads. The supplied argument is a pointer to the thread
1432
// object. The entry function dispatches to the run method in the thread
1433
// object. It is important that this function has __stdcall calling
1434
// convention.
1435
static unsigned int __stdcall ThreadEntry(void* arg) {
1436
  Thread* thread = reinterpret_cast<Thread*>(arg);
1437
  thread->NotifyStartedAndRun();
1438
  return 0;
1439
}
1440

    
1441

    
1442
class Thread::PlatformData : public Malloced {
1443
 public:
1444
  explicit PlatformData(HANDLE thread) : thread_(thread) {}
1445
  HANDLE thread_;
1446
  unsigned thread_id_;
1447
};
1448

    
1449

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

    
1453
Thread::Thread(const Options& options)
1454
    : stack_size_(options.stack_size()),
1455
      start_semaphore_(NULL) {
1456
  data_ = new PlatformData(kNoThread);
1457
  set_name(options.name());
1458
}
1459

    
1460

    
1461
void Thread::set_name(const char* name) {
1462
  OS::StrNCpy(Vector<char>(name_, sizeof(name_)), name, strlen(name));
1463
  name_[sizeof(name_) - 1] = '\0';
1464
}
1465

    
1466

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

    
1473

    
1474
// Create a new thread. It is important to use _beginthreadex() instead of
1475
// the Win32 function CreateThread(), because the CreateThread() does not
1476
// initialize thread specific structures in the C runtime library.
1477
void Thread::Start() {
1478
  data_->thread_ = reinterpret_cast<HANDLE>(
1479
      _beginthreadex(NULL,
1480
                     static_cast<unsigned>(stack_size_),
1481
                     ThreadEntry,
1482
                     this,
1483
                     0,
1484
                     &data_->thread_id_));
1485
}
1486

    
1487

    
1488
// Wait for thread to terminate.
1489
void Thread::Join() {
1490
  if (data_->thread_id_ != GetCurrentThreadId()) {
1491
    WaitForSingleObject(data_->thread_, INFINITE);
1492
  }
1493
}
1494

    
1495

    
1496
Thread::LocalStorageKey Thread::CreateThreadLocalKey() {
1497
  DWORD result = TlsAlloc();
1498
  ASSERT(result != TLS_OUT_OF_INDEXES);
1499
  return static_cast<LocalStorageKey>(result);
1500
}
1501

    
1502

    
1503
void Thread::DeleteThreadLocalKey(LocalStorageKey key) {
1504
  BOOL result = TlsFree(static_cast<DWORD>(key));
1505
  USE(result);
1506
  ASSERT(result);
1507
}
1508

    
1509

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

    
1514

    
1515
void Thread::SetThreadLocal(LocalStorageKey key, void* value) {
1516
  BOOL result = TlsSetValue(static_cast<DWORD>(key), value);
1517
  USE(result);
1518
  ASSERT(result);
1519
}
1520

    
1521

    
1522

    
1523
void Thread::YieldCPU() {
1524
  Sleep(0);
1525
}
1526

    
1527
} }  // namespace v8::internal