~evarlast/ubuntu/utopic/mongodb/upstart-workaround-debian-bug-718702

« back to all changes in this revision

Viewing changes to src/third_party/v8/src/platform-win32.cc

  • Committer: Package Import Robot
  • Author(s): James Page, James Page, Robie Basak
  • Date: 2013-05-29 17:44:42 UTC
  • mfrom: (44.1.7 sid)
  • Revision ID: package-import@ubuntu.com-20130529174442-z0a4qmoww4y0t458
Tags: 1:2.4.3-1ubuntu1
[ James Page ]
* Merge from Debian unstable, remaining changes:
  - Enable SSL support:
    + d/control: Add libssl-dev to BD's.
    + d/rules: Enabled --ssl option.
    + d/mongodb.conf: Add example SSL configuration options.
  - d/mongodb-server.mongodb.upstart: Add upstart configuration.
  - d/rules: Don't strip binaries during scons build for Ubuntu.
  - d/control: Add armhf to target archs.
  - d/p/SConscript.client.patch: fixup install of client libraries.
  - d/p/0010-install-libs-to-usr-lib-not-usr-lib64-Closes-588557.patch:
    Install libraries to lib not lib64.
* Dropped changes:
  - d/p/arm-support.patch: Included in Debian.
  - d/p/double-alignment.patch: Included in Debian.
  - d/rules,control: Debian also builds with avaliable system libraries
    now.
* Fix FTBFS due to gcc and boost upgrades in saucy:
  - d/p/0008-ignore-unused-local-typedefs.patch: Add -Wno-unused-typedefs
    to unbreak building with g++-4.8.
  - d/p/0009-boost-1.53.patch: Fixup signed/unsigned casting issue.

[ Robie Basak ]
* d/p/0011-Use-a-signed-char-to-store-BSONType-enumerations.patch: Fixup
  build failure on ARM due to missing signed'ness of char cast.

Show diffs side-by-side

added added

removed removed

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