blob: 679584476083cbc84404b7b6501c627b523340be [file] [log] [blame]
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00001// Copyright 2012 the V8 project authors. All rights reserved.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002// 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.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000029
mmassi@chromium.org2f0efde2013-02-06 14:12:58 +000030// 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
kasperl@chromium.orga5551262010-12-07 12:49:48 +000041#define V8_WIN32_HEADERS_FULL
42#include "win32-headers.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000043
44#include "v8.h"
45
ulan@chromium.org9a21ec42012-03-06 08:42:24 +000046#include "codegen.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000047#include "platform.h"
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +000048#include "simulator.h"
kasperl@chromium.orga5551262010-12-07 12:49:48 +000049#include "vm-state-inl.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000050
iposva@chromium.org245aa852009-02-10 00:49:54 +000051#ifdef _MSC_VER
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000052
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000053// Case-insensitive bounded string comparisons. Use stricmp() on Win32. Usually
54// defined in strings.h.
55int strncasecmp(const char* s1, const char* s2, int n) {
kasperl@chromium.orgb9123622008-09-17 14:05:56 +000056 return _strnicmp(s1, s2, n);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000057}
58
iposva@chromium.org245aa852009-02-10 00:49:54 +000059#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
svenpanne@chromium.orgfb046332012-04-19 12:02:44 +000066
67#ifndef __MINGW64_VERSION_MAJOR
68
69#define _TRUNCATE 0
70#define STRUNCATE 80
71
72inline void MemoryBarrier() {
73 int barrier = 0;
74 __asm__ __volatile__("xchgl %%eax,%0 ":"=r" (barrier));
75}
76
77#endif // __MINGW64_VERSION_MAJOR
78
79
iposva@chromium.org245aa852009-02-10 00:49:54 +000080int 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
iposva@chromium.org245aa852009-02-10 00:49:54 +000088int fopen_s(FILE** pFile, const char* filename, const char* mode) {
89 *pFile = fopen(filename, mode);
90 return *pFile != NULL ? 0 : 1;
91}
92
iposva@chromium.org245aa852009-02-10 00:49:54 +000093int _vsnprintf_s(char* buffer, size_t sizeOfBuffer, size_t count,
94 const char* format, va_list argptr) {
sgjesse@chromium.org6db88712011-07-11 11:41:22 +000095 ASSERT(count == _TRUNCATE);
iposva@chromium.org245aa852009-02-10 00:49:54 +000096 return _vsnprintf(buffer, sizeOfBuffer, format, argptr);
97}
iposva@chromium.org245aa852009-02-10 00:49:54 +000098
99
sgjesse@chromium.org6db88712011-07-11 11:41:22 +0000100int 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;
iposva@chromium.org245aa852009-02-10 00:49:54 +0000123 return 0;
124}
125
126#endif // __MINGW32__
127
128// Generate a pseudo-random number in the range 0-2^31-1. Usually
129// defined in stdlib.h. Missing in both Microsoft Visual Studio C++ and MinGW.
130int random() {
131 return rand();
132}
133
134
kasperl@chromium.org71affb52009-05-26 05:44:31 +0000135namespace v8 {
136namespace internal {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000137
sgjesse@chromium.org6db88712011-07-11 11:41:22 +0000138intptr_t OS::MaxVirtualMemory() {
139 return 0;
140}
141
142
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000143double ceiling(double x) {
144 return ceil(x);
145}
146
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000147
148static Mutex* limit_mutex = NULL;
149
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000150#if defined(V8_TARGET_ARCH_IA32)
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000151static void MemMoveWrapper(void* dest, const void* src, size_t size) {
152 memmove(dest, src, size);
153}
154
155// Initialize to library version so we can call this at any time during startup.
156static OS::MemMoveFunction memmove_function = &MemMoveWrapper;
157
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000158// Defined in codegen-ia32.cc.
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000159OS::MemMoveFunction CreateMemMoveFunction();
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000160
161// Copy memory area to disjoint memory area.
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000162void OS::MemMove(void* dest, const void* src, size_t size) {
ulan@chromium.org77ca49a2013-04-22 09:43:56 +0000163 if (size == 0) return;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000164 // Note: here we rely on dependent reads being ordered. This is true
165 // on all architectures we currently support.
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000166 (*memmove_function)(dest, src, size);
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000167}
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000168
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000169#endif // V8_TARGET_ARCH_IA32
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000170
ager@chromium.org3811b432009-10-28 14:53:37 +0000171#ifdef _WIN64
172typedef double (*ModuloFunction)(double, double);
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000173static ModuloFunction modulo_function = NULL;
ager@chromium.org3811b432009-10-28 14:53:37 +0000174// Defined in codegen-x64.cc.
175ModuloFunction CreateModuloFunction();
176
jkummerow@chromium.org1456e702012-03-30 08:38:13 +0000177void init_modulo_function() {
178 modulo_function = CreateModuloFunction();
179}
180
ager@chromium.org3811b432009-10-28 14:53:37 +0000181double modulo(double x, double y) {
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000182 // Note: here we rely on dependent reads being ordered. This is true
183 // on all architectures we currently support.
184 return (*modulo_function)(x, y);
ager@chromium.org3811b432009-10-28 14:53:37 +0000185}
186#else // Win32
187
188double modulo(double x, double y) {
189 // Workaround MS fmod bugs. ECMA-262 says:
190 // dividend is finite and divisor is an infinity => result equals dividend
191 // dividend is a zero and divisor is nonzero finite => result equals dividend
ulan@chromium.org77ca49a2013-04-22 09:43:56 +0000192 if (!(std::isfinite(x) && (!std::isfinite(y) && !std::isnan(y))) &&
193 !(x == 0 && (y != 0 && std::isfinite(y)))) {
ager@chromium.org3811b432009-10-28 14:53:37 +0000194 x = fmod(x, y);
195 }
196 return x;
197}
198
199#endif // _WIN64
200
ulan@chromium.org9a21ec42012-03-06 08:42:24 +0000201
yangguo@chromium.org154ff992012-03-13 08:09:54 +0000202#define UNARY_MATH_FUNCTION(name, generator) \
203static UnaryMathFunction fast_##name##_function = NULL; \
jkummerow@chromium.org1456e702012-03-30 08:38:13 +0000204void init_fast_##name##_function() { \
205 fast_##name##_function = generator; \
206} \
yangguo@chromium.org154ff992012-03-13 08:09:54 +0000207double fast_##name(double x) { \
yangguo@chromium.org154ff992012-03-13 08:09:54 +0000208 return (*fast_##name##_function)(x); \
ulan@chromium.org9a21ec42012-03-06 08:42:24 +0000209}
210
yangguo@chromium.org154ff992012-03-13 08:09:54 +0000211UNARY_MATH_FUNCTION(sin, CreateTranscendentalFunction(TranscendentalCache::SIN))
212UNARY_MATH_FUNCTION(cos, CreateTranscendentalFunction(TranscendentalCache::COS))
213UNARY_MATH_FUNCTION(tan, CreateTranscendentalFunction(TranscendentalCache::TAN))
214UNARY_MATH_FUNCTION(log, CreateTranscendentalFunction(TranscendentalCache::LOG))
danno@chromium.org1f34ad32012-11-26 14:53:56 +0000215UNARY_MATH_FUNCTION(exp, CreateExpFunction())
yangguo@chromium.org154ff992012-03-13 08:09:54 +0000216UNARY_MATH_FUNCTION(sqrt, CreateSqrtFunction())
ulan@chromium.org9a21ec42012-03-06 08:42:24 +0000217
mmassi@chromium.org2f0efde2013-02-06 14:12:58 +0000218#undef UNARY_MATH_FUNCTION
ulan@chromium.org9a21ec42012-03-06 08:42:24 +0000219
220
danno@chromium.org1f34ad32012-11-26 14:53:56 +0000221void lazily_initialize_fast_exp() {
222 if (fast_exp_function == NULL) {
223 init_fast_exp_function();
224 }
225}
226
227
danno@chromium.org8c0a43f2012-04-03 08:37:53 +0000228void MathSetup() {
229#ifdef _WIN64
230 init_modulo_function();
231#endif
232 init_fast_sin_function();
233 init_fast_cos_function();
234 init_fast_tan_function();
235 init_fast_log_function();
danno@chromium.org1f34ad32012-11-26 14:53:56 +0000236 // fast_exp is initialized lazily.
danno@chromium.org8c0a43f2012-04-03 08:37:53 +0000237 init_fast_sqrt_function();
238}
239
240
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000241// ----------------------------------------------------------------------------
242// The Time class represents time on win32. A timestamp is represented as
ulan@chromium.org2efb9002012-01-19 15:36:35 +0000243// a 64-bit integer in 100 nanoseconds since January 1, 1601 (UTC). JavaScript
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000244// timestamps are represented as a doubles in milliseconds since 00:00:00 UTC,
245// January 1, 1970.
246
247class Time {
248 public:
249 // Constructors.
250 Time();
251 explicit Time(double jstime);
252 Time(int year, int mon, int day, int hour, int min, int sec);
253
254 // Convert timestamp to JavaScript representation.
255 double ToJSTime();
256
257 // Set timestamp to current time.
258 void SetToCurrentTime();
259
260 // Returns the local timezone offset in milliseconds east of UTC. This is
261 // the number of milliseconds you must add to UTC to get local time, i.e.
262 // LocalOffset(CET) = 3600000 and LocalOffset(PST) = -28800000. This
263 // routine also takes into account whether daylight saving is effect
264 // at the time.
265 int64_t LocalOffset();
266
267 // Returns the daylight savings time offset for the time in milliseconds.
268 int64_t DaylightSavingsOffset();
269
270 // Returns a string identifying the current timezone for the
271 // timestamp taking into account daylight saving.
272 char* LocalTimezone();
273
274 private:
275 // Constants for time conversion.
iposva@chromium.org245aa852009-02-10 00:49:54 +0000276 static const int64_t kTimeEpoc = 116444736000000000LL;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000277 static const int64_t kTimeScaler = 10000;
278 static const int64_t kMsPerMinute = 60000;
279
280 // Constants for timezone information.
281 static const int kTzNameSize = 128;
282 static const bool kShortTzNames = false;
283
284 // Timezone information. We need to have static buffers for the
285 // timezone names because we return pointers to these in
286 // LocalTimezone().
287 static bool tz_initialized_;
288 static TIME_ZONE_INFORMATION tzinfo_;
289 static char std_tz_name_[kTzNameSize];
290 static char dst_tz_name_[kTzNameSize];
291
292 // Initialize the timezone information (if not already done).
293 static void TzSet();
294
295 // Guess the name of the timezone from the bias.
296 static const char* GuessTimezoneNameFromBias(int bias);
297
298 // Return whether or not daylight savings time is in effect at this time.
299 bool InDST();
300
301 // Return the difference (in milliseconds) between this timestamp and
302 // another timestamp.
303 int64_t Diff(Time* other);
304
305 // Accessor for FILETIME representation.
306 FILETIME& ft() { return time_.ft_; }
307
308 // Accessor for integer representation.
309 int64_t& t() { return time_.t_; }
310
311 // Although win32 uses 64-bit integers for representing timestamps,
312 // these are packed into a FILETIME structure. The FILETIME structure
313 // is just a struct representing a 64-bit integer. The TimeStamp union
314 // allows access to both a FILETIME and an integer representation of
315 // the timestamp.
316 union TimeStamp {
317 FILETIME ft_;
318 int64_t t_;
319 };
320
321 TimeStamp time_;
322};
323
324// Static variables.
325bool Time::tz_initialized_ = false;
326TIME_ZONE_INFORMATION Time::tzinfo_;
327char Time::std_tz_name_[kTzNameSize];
328char Time::dst_tz_name_[kTzNameSize];
329
330
331// Initialize timestamp to start of epoc.
332Time::Time() {
333 t() = 0;
334}
335
336
337// Initialize timestamp from a JavaScript timestamp.
338Time::Time(double jstime) {
ager@chromium.org41826e72009-03-30 13:30:57 +0000339 t() = static_cast<int64_t>(jstime) * kTimeScaler + kTimeEpoc;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000340}
341
342
343// Initialize timestamp from date/time components.
344Time::Time(int year, int mon, int day, int hour, int min, int sec) {
345 SYSTEMTIME st;
346 st.wYear = year;
347 st.wMonth = mon;
348 st.wDay = day;
349 st.wHour = hour;
350 st.wMinute = min;
351 st.wSecond = sec;
352 st.wMilliseconds = 0;
353 SystemTimeToFileTime(&st, &ft());
354}
355
356
357// Convert timestamp to JavaScript timestamp.
358double Time::ToJSTime() {
359 return static_cast<double>((t() - kTimeEpoc) / kTimeScaler);
360}
361
362
363// Guess the name of the timezone from the bias.
364// The guess is very biased towards the northern hemisphere.
365const char* Time::GuessTimezoneNameFromBias(int bias) {
366 static const int kHour = 60;
367 switch (-bias) {
368 case -9*kHour: return "Alaska";
369 case -8*kHour: return "Pacific";
370 case -7*kHour: return "Mountain";
371 case -6*kHour: return "Central";
372 case -5*kHour: return "Eastern";
373 case -4*kHour: return "Atlantic";
374 case 0*kHour: return "GMT";
375 case +1*kHour: return "Central Europe";
376 case +2*kHour: return "Eastern Europe";
377 case +3*kHour: return "Russia";
378 case +5*kHour + 30: return "India";
379 case +8*kHour: return "China";
380 case +9*kHour: return "Japan";
381 case +12*kHour: return "New Zealand";
382 default: return "Local";
383 }
384}
385
386
387// Initialize timezone information. The timezone information is obtained from
388// windows. If we cannot get the timezone information we fall back to CET.
389// Please notice that this code is not thread-safe.
390void Time::TzSet() {
391 // Just return if timezone information has already been initialized.
392 if (tz_initialized_) return;
393
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000394 // Initialize POSIX time zone data.
395 _tzset();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000396 // Obtain timezone information from operating system.
397 memset(&tzinfo_, 0, sizeof(tzinfo_));
398 if (GetTimeZoneInformation(&tzinfo_) == TIME_ZONE_ID_INVALID) {
399 // If we cannot get timezone information we fall back to CET.
400 tzinfo_.Bias = -60;
401 tzinfo_.StandardDate.wMonth = 10;
402 tzinfo_.StandardDate.wDay = 5;
403 tzinfo_.StandardDate.wHour = 3;
404 tzinfo_.StandardBias = 0;
405 tzinfo_.DaylightDate.wMonth = 3;
406 tzinfo_.DaylightDate.wDay = 5;
407 tzinfo_.DaylightDate.wHour = 2;
408 tzinfo_.DaylightBias = -60;
409 }
410
411 // Make standard and DST timezone names.
jkummerow@chromium.orge297f592011-06-08 10:05:15 +0000412 WideCharToMultiByte(CP_UTF8, 0, tzinfo_.StandardName, -1,
413 std_tz_name_, kTzNameSize, NULL, NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000414 std_tz_name_[kTzNameSize - 1] = '\0';
jkummerow@chromium.orge297f592011-06-08 10:05:15 +0000415 WideCharToMultiByte(CP_UTF8, 0, tzinfo_.DaylightName, -1,
416 dst_tz_name_, kTzNameSize, NULL, NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000417 dst_tz_name_[kTzNameSize - 1] = '\0';
418
419 // If OS returned empty string or resource id (like "@tzres.dll,-211")
420 // simply guess the name from the UTC bias of the timezone.
421 // To properly resolve the resource identifier requires a library load,
422 // which is not possible in a sandbox.
423 if (std_tz_name_[0] == '\0' || std_tz_name_[0] == '@') {
kasperl@chromium.orgb9123622008-09-17 14:05:56 +0000424 OS::SNPrintF(Vector<char>(std_tz_name_, kTzNameSize - 1),
425 "%s Standard Time",
426 GuessTimezoneNameFromBias(tzinfo_.Bias));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000427 }
428 if (dst_tz_name_[0] == '\0' || dst_tz_name_[0] == '@') {
kasperl@chromium.orgb9123622008-09-17 14:05:56 +0000429 OS::SNPrintF(Vector<char>(dst_tz_name_, kTzNameSize - 1),
430 "%s Daylight Time",
431 GuessTimezoneNameFromBias(tzinfo_.Bias));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000432 }
433
434 // Timezone information initialized.
435 tz_initialized_ = true;
436}
437
438
439// Return the difference in milliseconds between this and another timestamp.
440int64_t Time::Diff(Time* other) {
441 return (t() - other->t()) / kTimeScaler;
442}
443
444
445// Set timestamp to current time.
446void Time::SetToCurrentTime() {
447 // The default GetSystemTimeAsFileTime has a ~15.5ms resolution.
448 // Because we're fast, we like fast timers which have at least a
449 // 1ms resolution.
450 //
451 // timeGetTime() provides 1ms granularity when combined with
452 // timeBeginPeriod(). If the host application for v8 wants fast
453 // timers, it can use timeBeginPeriod to increase the resolution.
454 //
455 // Using timeGetTime() has a drawback because it is a 32bit value
456 // and hence rolls-over every ~49days.
457 //
458 // To use the clock, we use GetSystemTimeAsFileTime as our base;
459 // and then use timeGetTime to extrapolate current time from the
460 // start time. To deal with rollovers, we resync the clock
461 // any time when more than kMaxClockElapsedTime has passed or
462 // whenever timeGetTime creates a rollover.
463
464 static bool initialized = false;
465 static TimeStamp init_time;
466 static DWORD init_ticks;
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000467 static const int64_t kHundredNanosecondsPerSecond = 10000000;
468 static const int64_t kMaxClockElapsedTime =
469 60*kHundredNanosecondsPerSecond; // 1 minute
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000470
471 // If we are uninitialized, we need to resync the clock.
472 bool needs_resync = !initialized;
473
474 // Get the current time.
475 TimeStamp time_now;
476 GetSystemTimeAsFileTime(&time_now.ft_);
477 DWORD ticks_now = timeGetTime();
478
479 // Check if we need to resync due to clock rollover.
480 needs_resync |= ticks_now < init_ticks;
481
482 // Check if we need to resync due to elapsed time.
483 needs_resync |= (time_now.t_ - init_time.t_) > kMaxClockElapsedTime;
484
jkummerow@chromium.org1456e702012-03-30 08:38:13 +0000485 // Check if we need to resync due to backwards time change.
486 needs_resync |= time_now.t_ < init_time.t_;
487
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000488 // Resync the clock if necessary.
489 if (needs_resync) {
490 GetSystemTimeAsFileTime(&init_time.ft_);
491 init_ticks = ticks_now = timeGetTime();
492 initialized = true;
493 }
494
495 // Finally, compute the actual time. Why is this so hard.
496 DWORD elapsed = ticks_now - init_ticks;
497 this->time_.t_ = init_time.t_ + (static_cast<int64_t>(elapsed) * 10000);
498}
499
500
501// Return the local timezone offset in milliseconds east of UTC. This
502// takes into account whether daylight saving is in effect at the time.
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000503// Only times in the 32-bit Unix range may be passed to this function.
504// Also, adding the time-zone offset to the input must not overflow.
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +0000505// The function EquivalentTime() in date.js guarantees this.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000506int64_t Time::LocalOffset() {
507 // Initialize timezone information, if needed.
508 TzSet();
509
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000510 Time rounded_to_second(*this);
511 rounded_to_second.t() = rounded_to_second.t() / 1000 / kTimeScaler *
512 1000 * kTimeScaler;
513 // Convert to local time using POSIX localtime function.
514 // Windows XP Service Pack 3 made SystemTimeToTzSpecificLocalTime()
515 // very slow. Other browsers use localtime().
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000516
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000517 // Convert from JavaScript milliseconds past 1/1/1970 0:00:00 to
518 // POSIX seconds past 1/1/1970 0:00:00.
519 double unchecked_posix_time = rounded_to_second.ToJSTime() / 1000;
520 if (unchecked_posix_time > INT_MAX || unchecked_posix_time < 0) {
521 return 0;
522 }
523 // Because _USE_32BIT_TIME_T is defined, time_t is a 32-bit int.
524 time_t posix_time = static_cast<time_t>(unchecked_posix_time);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000525
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000526 // Convert to local time, as struct with fields for day, hour, year, etc.
527 tm posix_local_time_struct;
528 if (localtime_s(&posix_local_time_struct, &posix_time)) return 0;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000529
jkummerow@chromium.org1456e702012-03-30 08:38:13 +0000530 if (posix_local_time_struct.tm_isdst > 0) {
531 return (tzinfo_.Bias + tzinfo_.DaylightBias) * -kMsPerMinute;
532 } else if (posix_local_time_struct.tm_isdst == 0) {
533 return (tzinfo_.Bias + tzinfo_.StandardBias) * -kMsPerMinute;
534 } else {
535 return tzinfo_.Bias * -kMsPerMinute;
536 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000537}
538
539
540// Return whether or not daylight savings time is in effect at this time.
541bool Time::InDST() {
542 // Initialize timezone information, if needed.
543 TzSet();
544
545 // Determine if DST is in effect at the specified time.
546 bool in_dst = false;
547 if (tzinfo_.StandardDate.wMonth != 0 || tzinfo_.DaylightDate.wMonth != 0) {
548 // Get the local timezone offset for the timestamp in milliseconds.
549 int64_t offset = LocalOffset();
550
551 // Compute the offset for DST. The bias parameters in the timezone info
552 // are specified in minutes. These must be converted to milliseconds.
553 int64_t dstofs = -(tzinfo_.Bias + tzinfo_.DaylightBias) * kMsPerMinute;
554
555 // If the local time offset equals the timezone bias plus the daylight
556 // bias then DST is in effect.
557 in_dst = offset == dstofs;
558 }
559
560 return in_dst;
561}
562
563
ager@chromium.org32912102009-01-16 10:38:43 +0000564// Return the daylight savings time offset for this time.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000565int64_t Time::DaylightSavingsOffset() {
566 return InDST() ? 60 * kMsPerMinute : 0;
567}
568
569
570// Returns a string identifying the current timezone for the
571// timestamp taking into account daylight saving.
572char* Time::LocalTimezone() {
573 // Return the standard or DST time zone name based on whether daylight
574 // saving is in effect at the given time.
575 return InDST() ? dst_tz_name_ : std_tz_name_;
576}
577
578
danno@chromium.org8c0a43f2012-04-03 08:37:53 +0000579void OS::PostSetUp() {
580 // Math functions depend on CPU features therefore they are initialized after
581 // CPU.
582 MathSetup();
fschneider@chromium.org7d10be52012-04-10 12:30:14 +0000583#if defined(V8_TARGET_ARCH_IA32)
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000584 OS::MemMoveFunction generated_memmove = CreateMemMoveFunction();
585 if (generated_memmove != NULL) {
586 memmove_function = generated_memmove;
587 }
fschneider@chromium.org7d10be52012-04-10 12:30:14 +0000588#endif
danno@chromium.org8c0a43f2012-04-03 08:37:53 +0000589}
590
591
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000592// Returns the accumulated user time for thread.
593int OS::GetUserTime(uint32_t* secs, uint32_t* usecs) {
594 FILETIME dummy;
595 uint64_t usertime;
596
597 // Get the amount of time that the thread has executed in user mode.
598 if (!GetThreadTimes(GetCurrentThread(), &dummy, &dummy, &dummy,
599 reinterpret_cast<FILETIME*>(&usertime))) return -1;
600
601 // Adjust the resolution to micro-seconds.
602 usertime /= 10;
603
604 // Convert to seconds and microseconds
605 *secs = static_cast<uint32_t>(usertime / 1000000);
606 *usecs = static_cast<uint32_t>(usertime % 1000000);
607 return 0;
608}
609
610
611// Returns current time as the number of milliseconds since
612// 00:00:00 UTC, January 1, 1970.
613double OS::TimeCurrentMillis() {
614 Time t;
615 t.SetToCurrentTime();
616 return t.ToJSTime();
617}
618
619// Returns the tickcounter based on timeGetTime.
620int64_t OS::Ticks() {
621 return timeGetTime() * 1000; // Convert to microseconds.
622}
623
624
625// Returns a string identifying the current timezone taking into
626// account daylight saving.
sgjesse@chromium.orgb9d7da12009-08-05 08:38:10 +0000627const char* OS::LocalTimezone(double time) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000628 return Time(time).LocalTimezone();
629}
630
631
kasper.lund7276f142008-07-30 08:49:36 +0000632// Returns the local time offset in milliseconds east of UTC without
633// taking daylight savings time into account.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000634double OS::LocalTimeOffset() {
kasper.lund7276f142008-07-30 08:49:36 +0000635 // Use current time, rounded to the millisecond.
636 Time t(TimeCurrentMillis());
637 // Time::LocalOffset inlcudes any daylight savings offset, so subtract it.
638 return static_cast<double>(t.LocalOffset() - t.DaylightSavingsOffset());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000639}
640
641
642// Returns the daylight savings offset in milliseconds for the given
643// time.
644double OS::DaylightSavingsOffset(double time) {
645 int64_t offset = Time(time).DaylightSavingsOffset();
646 return static_cast<double>(offset);
647}
648
649
ager@chromium.orgea4f62e2010-08-16 16:28:43 +0000650int OS::GetLastError() {
651 return ::GetLastError();
652}
653
654
rossberg@chromium.org657d53b2012-07-12 11:06:03 +0000655int OS::GetCurrentProcessId() {
656 return static_cast<int>(::GetCurrentProcessId());
657}
658
659
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000660// ----------------------------------------------------------------------------
661// Win32 console output.
662//
663// If a Win32 application is linked as a console application it has a normal
664// standard output and standard error. In this case normal printf works fine
665// for output. However, if the application is linked as a GUI application,
666// the process doesn't have a console, and therefore (debugging) output is lost.
667// This is the case if we are embedded in a windows program (like a browser).
668// In order to be able to get debug output in this case the the debugging
669// facility using OutputDebugString. This output goes to the active debugger
670// for the process (if any). Else the output can be monitored using DBMON.EXE.
671
672enum OutputMode {
673 UNKNOWN, // Output method has not yet been determined.
674 CONSOLE, // Output is written to stdout.
675 ODS // Output is written to debug facility.
676};
677
678static OutputMode output_mode = UNKNOWN; // Current output mode.
679
680
681// Determine if the process has a console for output.
682static bool HasConsole() {
683 // Only check the first time. Eventual race conditions are not a problem,
684 // because all threads will eventually determine the same mode.
685 if (output_mode == UNKNOWN) {
686 // We cannot just check that the standard output is attached to a console
687 // because this would fail if output is redirected to a file. Therefore we
688 // say that a process does not have an output console if either the
689 // standard output handle is invalid or its file type is unknown.
690 if (GetStdHandle(STD_OUTPUT_HANDLE) != INVALID_HANDLE_VALUE &&
691 GetFileType(GetStdHandle(STD_OUTPUT_HANDLE)) != FILE_TYPE_UNKNOWN)
692 output_mode = CONSOLE;
693 else
694 output_mode = ODS;
695 }
696 return output_mode == CONSOLE;
697}
698
699
700static void VPrintHelper(FILE* stream, const char* format, va_list args) {
701 if (HasConsole()) {
702 vfprintf(stream, format, args);
703 } else {
704 // It is important to use safe print here in order to avoid
705 // overflowing the buffer. We might truncate the output, but this
706 // does not crash.
kasperl@chromium.orgb9123622008-09-17 14:05:56 +0000707 EmbeddedVector<char, 4096> buffer;
708 OS::VSNPrintF(buffer, format, args);
709 OutputDebugStringA(buffer.start());
710 }
711}
712
713
714FILE* OS::FOpen(const char* path, const char* mode) {
715 FILE* result;
716 if (fopen_s(&result, path, mode) == 0) {
717 return result;
718 } else {
719 return NULL;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000720 }
721}
722
723
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +0000724bool OS::Remove(const char* path) {
725 return (DeleteFileA(path) != 0);
726}
727
728
whesse@chromium.org030d38e2011-07-13 13:23:34 +0000729FILE* OS::OpenTemporaryFile() {
730 // tmpfile_s tries to use the root dir, don't use it.
731 char tempPathBuffer[MAX_PATH];
732 DWORD path_result = 0;
733 path_result = GetTempPathA(MAX_PATH, tempPathBuffer);
734 if (path_result > MAX_PATH || path_result == 0) return NULL;
735 UINT name_result = 0;
736 char tempNameBuffer[MAX_PATH];
737 name_result = GetTempFileNameA(tempPathBuffer, "", 0, tempNameBuffer);
738 if (name_result == 0) return NULL;
739 FILE* result = FOpen(tempNameBuffer, "w+"); // Same mode as tmpfile uses.
740 if (result != NULL) {
741 Remove(tempNameBuffer); // Delete on close.
742 }
743 return result;
744}
745
746
ager@chromium.org71daaf62009-04-01 07:22:49 +0000747// Open log file in binary mode to avoid /n -> /r/n conversion.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000748const char* const OS::LogFileOpenMode = "wb";
ager@chromium.org71daaf62009-04-01 07:22:49 +0000749
750
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000751// Print (debug) message to console.
752void OS::Print(const char* format, ...) {
753 va_list args;
754 va_start(args, format);
755 VPrint(format, args);
756 va_end(args);
757}
758
759
760void OS::VPrint(const char* format, va_list args) {
761 VPrintHelper(stdout, format, args);
762}
763
764
whesse@chromium.org023421e2010-12-21 12:19:12 +0000765void OS::FPrint(FILE* out, const char* format, ...) {
766 va_list args;
767 va_start(args, format);
768 VFPrint(out, format, args);
769 va_end(args);
770}
771
772
773void OS::VFPrint(FILE* out, const char* format, va_list args) {
774 VPrintHelper(out, format, args);
775}
776
777
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000778// Print error message to console.
779void OS::PrintError(const char* format, ...) {
780 va_list args;
781 va_start(args, format);
782 VPrintError(format, args);
783 va_end(args);
784}
785
786
787void OS::VPrintError(const char* format, va_list args) {
788 VPrintHelper(stderr, format, args);
789}
790
791
kasperl@chromium.orgb9123622008-09-17 14:05:56 +0000792int OS::SNPrintF(Vector<char> str, const char* format, ...) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000793 va_list args;
794 va_start(args, format);
kasperl@chromium.orgb9123622008-09-17 14:05:56 +0000795 int result = VSNPrintF(str, format, args);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000796 va_end(args);
797 return result;
798}
799
800
kasperl@chromium.orgb9123622008-09-17 14:05:56 +0000801int OS::VSNPrintF(Vector<char> str, const char* format, va_list args) {
802 int n = _vsnprintf_s(str.start(), str.length(), _TRUNCATE, format, args);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000803 // Make sure to zero-terminate the string if the output was
804 // truncated or if there was an error.
kasperl@chromium.orgb9123622008-09-17 14:05:56 +0000805 if (n < 0 || n >= str.length()) {
whesse@chromium.org023421e2010-12-21 12:19:12 +0000806 if (str.length() > 0)
807 str[str.length() - 1] = '\0';
kasper.lund7276f142008-07-30 08:49:36 +0000808 return -1;
809 } else {
810 return n;
811 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000812}
813
814
ager@chromium.org381abbb2009-02-25 13:23:22 +0000815char* OS::StrChr(char* str, int c) {
816 return const_cast<char*>(strchr(str, c));
817}
818
819
kasperl@chromium.orgb9123622008-09-17 14:05:56 +0000820void OS::StrNCpy(Vector<char> dest, const char* src, size_t n) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000821 // Use _TRUNCATE or strncpy_s crashes (by design) if buffer is too small.
822 size_t buffer_size = static_cast<size_t>(dest.length());
823 if (n + 1 > buffer_size) // count for trailing '\0'
824 n = _TRUNCATE;
kasperl@chromium.orgb9123622008-09-17 14:05:56 +0000825 int result = strncpy_s(dest.start(), dest.length(), src, n);
826 USE(result);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000827 ASSERT(result == 0 || (n == _TRUNCATE && result == STRUNCATE));
kasperl@chromium.orgb9123622008-09-17 14:05:56 +0000828}
829
830
mmassi@chromium.org2f0efde2013-02-06 14:12:58 +0000831#undef _TRUNCATE
832#undef STRUNCATE
833
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000834// We keep the lowest and highest addresses mapped as a quick way of
835// determining that pointers are outside the heap (used mostly in assertions
ulan@chromium.org2efb9002012-01-19 15:36:35 +0000836// and verification). The estimate is conservative, i.e., not all addresses in
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000837// 'allocated' space are actually allocated to our heap. The range is
838// [lowest, highest), inclusive on the low and and exclusive on the high end.
839static void* lowest_ever_allocated = reinterpret_cast<void*>(-1);
840static void* highest_ever_allocated = reinterpret_cast<void*>(0);
841
842
843static void UpdateAllocatedSpaceLimits(void* address, int size) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000844 ASSERT(limit_mutex != NULL);
845 ScopedLock lock(limit_mutex);
846
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000847 lowest_ever_allocated = Min(lowest_ever_allocated, address);
848 highest_ever_allocated =
849 Max(highest_ever_allocated,
850 reinterpret_cast<void*>(reinterpret_cast<char*>(address) + size));
851}
852
853
854bool OS::IsOutsideAllocatedSpace(void* pointer) {
855 if (pointer < lowest_ever_allocated || pointer >= highest_ever_allocated)
856 return true;
857 // Ask the Windows API
858 if (IsBadWritePtr(pointer, 1))
859 return true;
860 return false;
861}
862
863
mads.s.ager@gmail.com769cc962008-08-06 10:02:49 +0000864// Get the system's page size used by VirtualAlloc() or the next power
865// of two. The reason for always returning a power of two is that the
866// rounding up in OS::Allocate expects that.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000867static size_t GetPageSize() {
868 static size_t page_size = 0;
869 if (page_size == 0) {
870 SYSTEM_INFO info;
871 GetSystemInfo(&info);
mads.s.ager@gmail.com769cc962008-08-06 10:02:49 +0000872 page_size = RoundUpToPowerOf2(info.dwPageSize);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000873 }
874 return page_size;
875}
876
877
mads.s.ager@gmail.com769cc962008-08-06 10:02:49 +0000878// The allocation alignment is the guaranteed alignment for
879// VirtualAlloc'ed blocks of memory.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000880size_t OS::AllocateAlignment() {
mads.s.ager@gmail.com769cc962008-08-06 10:02:49 +0000881 static size_t allocate_alignment = 0;
882 if (allocate_alignment == 0) {
883 SYSTEM_INFO info;
884 GetSystemInfo(&info);
885 allocate_alignment = info.dwAllocationGranularity;
886 }
887 return allocate_alignment;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000888}
889
890
kmillikin@chromium.orgbe6bd102012-02-23 08:45:21 +0000891static void* GetRandomAddr() {
892 Isolate* isolate = Isolate::UncheckedCurrent();
893 // Note that the current isolate isn't set up in a call path via
894 // CpuFeatures::Probe. We don't care about randomization in this case because
895 // the code page is immediately freed.
896 if (isolate != NULL) {
897 // The address range used to randomize RWX allocations in OS::Allocate
898 // Try not to map pages into the default range that windows loads DLLs
899 // Use a multiple of 64k to prevent committing unused memory.
900 // Note: This does not guarantee RWX regions will be within the
901 // range kAllocationRandomAddressMin to kAllocationRandomAddressMax
902#ifdef V8_HOST_ARCH_64_BIT
903 static const intptr_t kAllocationRandomAddressMin = 0x0000000080000000;
904 static const intptr_t kAllocationRandomAddressMax = 0x000003FFFFFF0000;
905#else
906 static const intptr_t kAllocationRandomAddressMin = 0x04000000;
907 static const intptr_t kAllocationRandomAddressMax = 0x3FFF0000;
908#endif
909 uintptr_t address = (V8::RandomPrivate(isolate) << kPageSizeBits)
910 | kAllocationRandomAddressMin;
911 address &= kAllocationRandomAddressMax;
912 return reinterpret_cast<void *>(address);
913 }
914 return NULL;
915}
916
917
918static void* RandomizedVirtualAlloc(size_t size, int action, int protection) {
919 LPVOID base = NULL;
920
921 if (protection == PAGE_EXECUTE_READWRITE || protection == PAGE_NOACCESS) {
922 // For exectutable pages try and randomize the allocation address
923 for (size_t attempts = 0; base == NULL && attempts < 3; ++attempts) {
924 base = VirtualAlloc(GetRandomAddr(), size, action, protection);
925 }
926 }
927
928 // After three attempts give up and let the OS find an address to use.
929 if (base == NULL) base = VirtualAlloc(NULL, size, action, protection);
930
931 return base;
932}
933
934
kasper.lund7276f142008-07-30 08:49:36 +0000935void* OS::Allocate(const size_t requested,
936 size_t* allocated,
kasperl@chromium.orgf5aa8372009-03-24 14:47:14 +0000937 bool is_executable) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000938 // VirtualAlloc rounds allocated size to page size automatically.
ager@chromium.orgc4c92722009-11-18 14:12:51 +0000939 size_t msize = RoundUp(requested, static_cast<int>(GetPageSize()));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000940
941 // Windows XP SP2 allows Data Excution Prevention (DEP).
kasperl@chromium.orgf5aa8372009-03-24 14:47:14 +0000942 int prot = is_executable ? PAGE_EXECUTE_READWRITE : PAGE_READWRITE;
sgjesse@chromium.orgc3a01972010-08-04 09:46:24 +0000943
kmillikin@chromium.orgbe6bd102012-02-23 08:45:21 +0000944 LPVOID mbase = RandomizedVirtualAlloc(msize,
945 MEM_COMMIT | MEM_RESERVE,
946 prot);
sgjesse@chromium.orgc3a01972010-08-04 09:46:24 +0000947
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000948 if (mbase == NULL) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000949 LOG(ISOLATE, StringEvent("OS::Allocate", "VirtualAlloc failed"));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000950 return NULL;
951 }
952
953 ASSERT(IsAligned(reinterpret_cast<size_t>(mbase), OS::AllocateAlignment()));
954
955 *allocated = msize;
ager@chromium.orgc4c92722009-11-18 14:12:51 +0000956 UpdateAllocatedSpaceLimits(mbase, static_cast<int>(msize));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000957 return mbase;
958}
959
960
kasperl@chromium.orgf5aa8372009-03-24 14:47:14 +0000961void OS::Free(void* address, const size_t size) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000962 // TODO(1240712): VirtualFree has a return value which is ignored here.
kasperl@chromium.orgf5aa8372009-03-24 14:47:14 +0000963 VirtualFree(address, 0, MEM_RELEASE);
964 USE(size);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000965}
966
967
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +0000968intptr_t OS::CommitPageSize() {
969 return 4096;
970}
971
972
lrn@chromium.orgd4e9e222011-08-03 12:01:58 +0000973void OS::ProtectCode(void* address, const size_t size) {
974 DWORD old_protect;
975 VirtualProtect(address, size, PAGE_EXECUTE_READ, &old_protect);
976}
977
978
rossberg@chromium.org717967f2011-07-20 13:44:42 +0000979void OS::Guard(void* address, const size_t size) {
980 DWORD oldprotect;
981 VirtualProtect(address, size, PAGE_READONLY | PAGE_GUARD, &oldprotect);
982}
983
984
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000985void OS::Sleep(int milliseconds) {
986 ::Sleep(milliseconds);
987}
988
989
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +0000990int OS::NumberOfCores() {
991 SYSTEM_INFO info;
992 GetSystemInfo(&info);
993 return info.dwNumberOfProcessors;
994}
995
996
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000997void OS::Abort() {
rossberg@chromium.org2c067b12012-03-19 11:01:52 +0000998 if (IsDebuggerPresent() || FLAG_break_on_abort) {
999 DebugBreak();
1000 } else {
ager@chromium.orga74f0da2008-12-03 16:05:52 +00001001 // Make the MSVCRT do a silent abort.
ulan@chromium.org9a21ec42012-03-06 08:42:24 +00001002 raise(SIGABRT);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00001003 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001004}
1005
1006
kasper.lund7276f142008-07-30 08:49:36 +00001007void OS::DebugBreak() {
iposva@chromium.org245aa852009-02-10 00:49:54 +00001008#ifdef _MSC_VER
kasper.lund7276f142008-07-30 08:49:36 +00001009 __debugbreak();
iposva@chromium.org245aa852009-02-10 00:49:54 +00001010#else
1011 ::DebugBreak();
1012#endif
kasper.lund7276f142008-07-30 08:49:36 +00001013}
1014
1015
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00001016void OS::DumpBacktrace() {
1017 // Currently unsupported.
1018}
1019
1020
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001021class Win32MemoryMappedFile : public OS::MemoryMappedFile {
1022 public:
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00001023 Win32MemoryMappedFile(HANDLE file,
1024 HANDLE file_mapping,
1025 void* memory,
1026 int size)
1027 : file_(file),
1028 file_mapping_(file_mapping),
1029 memory_(memory),
1030 size_(size) { }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001031 virtual ~Win32MemoryMappedFile();
1032 virtual void* memory() { return memory_; }
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00001033 virtual int size() { return size_; }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001034 private:
1035 HANDLE file_;
1036 HANDLE file_mapping_;
1037 void* memory_;
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00001038 int size_;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001039};
1040
1041
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00001042OS::MemoryMappedFile* OS::MemoryMappedFile::open(const char* name) {
1043 // Open a physical file
1044 HANDLE file = CreateFileA(name, GENERIC_READ | GENERIC_WRITE,
1045 FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001046 if (file == INVALID_HANDLE_VALUE) return NULL;
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00001047
1048 int size = static_cast<int>(GetFileSize(file, NULL));
1049
1050 // Create a file mapping for the physical file
1051 HANDLE file_mapping = CreateFileMapping(file, NULL,
1052 PAGE_READWRITE, 0, static_cast<DWORD>(size), NULL);
1053 if (file_mapping == NULL) return NULL;
1054
1055 // Map a view of the file into memory
1056 void* memory = MapViewOfFile(file_mapping, FILE_MAP_ALL_ACCESS, 0, 0, size);
1057 return new Win32MemoryMappedFile(file, file_mapping, memory, size);
1058}
1059
1060
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001061OS::MemoryMappedFile* OS::MemoryMappedFile::create(const char* name, int size,
1062 void* initial) {
1063 // Open a physical file
1064 HANDLE file = CreateFileA(name, GENERIC_READ | GENERIC_WRITE,
1065 FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_ALWAYS, 0, NULL);
1066 if (file == NULL) return NULL;
1067 // Create a file mapping for the physical file
1068 HANDLE file_mapping = CreateFileMapping(file, NULL,
1069 PAGE_READWRITE, 0, static_cast<DWORD>(size), NULL);
1070 if (file_mapping == NULL) return NULL;
1071 // Map a view of the file into memory
1072 void* memory = MapViewOfFile(file_mapping, FILE_MAP_ALL_ACCESS, 0, 0, size);
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00001073 if (memory) OS::MemMove(memory, initial, size);
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00001074 return new Win32MemoryMappedFile(file, file_mapping, memory, size);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001075}
1076
1077
1078Win32MemoryMappedFile::~Win32MemoryMappedFile() {
1079 if (memory_ != NULL)
1080 UnmapViewOfFile(memory_);
1081 CloseHandle(file_mapping_);
1082 CloseHandle(file_);
1083}
1084
1085
1086// The following code loads functions defined in DbhHelp.h and TlHelp32.h
ager@chromium.org32912102009-01-16 10:38:43 +00001087// dynamically. This is to avoid being depending on dbghelp.dll and
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001088// tlhelp32.dll when running (the functions in tlhelp32.dll have been moved to
1089// kernel32.dll at some point so loading functions defines in TlHelp32.h
1090// dynamically might not be necessary any more - for some versions of Windows?).
1091
1092// Function pointers to functions dynamically loaded from dbghelp.dll.
1093#define DBGHELP_FUNCTION_LIST(V) \
1094 V(SymInitialize) \
1095 V(SymGetOptions) \
1096 V(SymSetOptions) \
1097 V(SymGetSearchPath) \
1098 V(SymLoadModule64) \
1099 V(StackWalk64) \
1100 V(SymGetSymFromAddr64) \
1101 V(SymGetLineFromAddr64) \
1102 V(SymFunctionTableAccess64) \
1103 V(SymGetModuleBase64)
1104
1105// Function pointers to functions dynamically loaded from dbghelp.dll.
1106#define TLHELP32_FUNCTION_LIST(V) \
1107 V(CreateToolhelp32Snapshot) \
1108 V(Module32FirstW) \
1109 V(Module32NextW)
1110
1111// Define the decoration to use for the type and variable name used for
1112// dynamically loaded DLL function..
1113#define DLL_FUNC_TYPE(name) _##name##_
1114#define DLL_FUNC_VAR(name) _##name
1115
1116// Define the type for each dynamically loaded DLL function. The function
1117// definitions are copied from DbgHelp.h and TlHelp32.h. The IN and VOID macros
1118// from the Windows include files are redefined here to have the function
1119// definitions to be as close to the ones in the original .h files as possible.
1120#ifndef IN
1121#define IN
1122#endif
1123#ifndef VOID
1124#define VOID void
1125#endif
1126
iposva@chromium.org245aa852009-02-10 00:49:54 +00001127// DbgHelp isn't supported on MinGW yet
1128#ifndef __MINGW32__
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001129// DbgHelp.h functions.
1130typedef BOOL (__stdcall *DLL_FUNC_TYPE(SymInitialize))(IN HANDLE hProcess,
1131 IN PSTR UserSearchPath,
1132 IN BOOL fInvadeProcess);
1133typedef DWORD (__stdcall *DLL_FUNC_TYPE(SymGetOptions))(VOID);
1134typedef DWORD (__stdcall *DLL_FUNC_TYPE(SymSetOptions))(IN DWORD SymOptions);
1135typedef BOOL (__stdcall *DLL_FUNC_TYPE(SymGetSearchPath))(
1136 IN HANDLE hProcess,
1137 OUT PSTR SearchPath,
1138 IN DWORD SearchPathLength);
1139typedef DWORD64 (__stdcall *DLL_FUNC_TYPE(SymLoadModule64))(
1140 IN HANDLE hProcess,
1141 IN HANDLE hFile,
1142 IN PSTR ImageName,
1143 IN PSTR ModuleName,
1144 IN DWORD64 BaseOfDll,
1145 IN DWORD SizeOfDll);
1146typedef BOOL (__stdcall *DLL_FUNC_TYPE(StackWalk64))(
1147 DWORD MachineType,
1148 HANDLE hProcess,
1149 HANDLE hThread,
1150 LPSTACKFRAME64 StackFrame,
1151 PVOID ContextRecord,
1152 PREAD_PROCESS_MEMORY_ROUTINE64 ReadMemoryRoutine,
1153 PFUNCTION_TABLE_ACCESS_ROUTINE64 FunctionTableAccessRoutine,
1154 PGET_MODULE_BASE_ROUTINE64 GetModuleBaseRoutine,
1155 PTRANSLATE_ADDRESS_ROUTINE64 TranslateAddress);
1156typedef BOOL (__stdcall *DLL_FUNC_TYPE(SymGetSymFromAddr64))(
1157 IN HANDLE hProcess,
1158 IN DWORD64 qwAddr,
1159 OUT PDWORD64 pdwDisplacement,
1160 OUT PIMAGEHLP_SYMBOL64 Symbol);
1161typedef BOOL (__stdcall *DLL_FUNC_TYPE(SymGetLineFromAddr64))(
1162 IN HANDLE hProcess,
1163 IN DWORD64 qwAddr,
1164 OUT PDWORD pdwDisplacement,
1165 OUT PIMAGEHLP_LINE64 Line64);
1166// DbgHelp.h typedefs. Implementation found in dbghelp.dll.
1167typedef PVOID (__stdcall *DLL_FUNC_TYPE(SymFunctionTableAccess64))(
1168 HANDLE hProcess,
1169 DWORD64 AddrBase); // DbgHelp.h typedef PFUNCTION_TABLE_ACCESS_ROUTINE64
1170typedef DWORD64 (__stdcall *DLL_FUNC_TYPE(SymGetModuleBase64))(
1171 HANDLE hProcess,
1172 DWORD64 AddrBase); // DbgHelp.h typedef PGET_MODULE_BASE_ROUTINE64
1173
1174// TlHelp32.h functions.
1175typedef HANDLE (__stdcall *DLL_FUNC_TYPE(CreateToolhelp32Snapshot))(
1176 DWORD dwFlags,
1177 DWORD th32ProcessID);
1178typedef BOOL (__stdcall *DLL_FUNC_TYPE(Module32FirstW))(HANDLE hSnapshot,
1179 LPMODULEENTRY32W lpme);
1180typedef BOOL (__stdcall *DLL_FUNC_TYPE(Module32NextW))(HANDLE hSnapshot,
1181 LPMODULEENTRY32W lpme);
1182
1183#undef IN
1184#undef VOID
1185
1186// Declare a variable for each dynamically loaded DLL function.
1187#define DEF_DLL_FUNCTION(name) DLL_FUNC_TYPE(name) DLL_FUNC_VAR(name) = NULL;
1188DBGHELP_FUNCTION_LIST(DEF_DLL_FUNCTION)
1189TLHELP32_FUNCTION_LIST(DEF_DLL_FUNCTION)
1190#undef DEF_DLL_FUNCTION
1191
1192// Load the functions. This function has a lot of "ugly" macros in order to
1193// keep down code duplication.
1194
1195static bool LoadDbgHelpAndTlHelp32() {
1196 static bool dbghelp_loaded = false;
1197
1198 if (dbghelp_loaded) return true;
1199
1200 HMODULE module;
1201
1202 // Load functions from the dbghelp.dll module.
1203 module = LoadLibrary(TEXT("dbghelp.dll"));
1204 if (module == NULL) {
1205 return false;
1206 }
1207
1208#define LOAD_DLL_FUNC(name) \
1209 DLL_FUNC_VAR(name) = \
1210 reinterpret_cast<DLL_FUNC_TYPE(name)>(GetProcAddress(module, #name));
1211
1212DBGHELP_FUNCTION_LIST(LOAD_DLL_FUNC)
1213
1214#undef LOAD_DLL_FUNC
1215
1216 // Load functions from the kernel32.dll module (the TlHelp32.h function used
1217 // to be in tlhelp32.dll but are now moved to kernel32.dll).
1218 module = LoadLibrary(TEXT("kernel32.dll"));
1219 if (module == NULL) {
1220 return false;
1221 }
1222
1223#define LOAD_DLL_FUNC(name) \
1224 DLL_FUNC_VAR(name) = \
1225 reinterpret_cast<DLL_FUNC_TYPE(name)>(GetProcAddress(module, #name));
1226
1227TLHELP32_FUNCTION_LIST(LOAD_DLL_FUNC)
1228
1229#undef LOAD_DLL_FUNC
1230
1231 // Check that all functions where loaded.
1232 bool result =
1233#define DLL_FUNC_LOADED(name) (DLL_FUNC_VAR(name) != NULL) &&
1234
1235DBGHELP_FUNCTION_LIST(DLL_FUNC_LOADED)
1236TLHELP32_FUNCTION_LIST(DLL_FUNC_LOADED)
1237
1238#undef DLL_FUNC_LOADED
1239 true;
1240
1241 dbghelp_loaded = result;
1242 return result;
ager@chromium.org32912102009-01-16 10:38:43 +00001243 // NOTE: The modules are never unloaded and will stay around until the
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001244 // application is closed.
1245}
1246
mmassi@chromium.org2f0efde2013-02-06 14:12:58 +00001247#undef DBGHELP_FUNCTION_LIST
1248#undef TLHELP32_FUNCTION_LIST
1249#undef DLL_FUNC_VAR
1250#undef DLL_FUNC_TYPE
1251
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001252
1253// Load the symbols for generating stack traces.
1254static bool LoadSymbols(HANDLE process_handle) {
1255 static bool symbols_loaded = false;
1256
1257 if (symbols_loaded) return true;
1258
1259 BOOL ok;
1260
1261 // Initialize the symbol engine.
1262 ok = _SymInitialize(process_handle, // hProcess
1263 NULL, // UserSearchPath
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001264 false); // fInvadeProcess
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001265 if (!ok) return false;
1266
1267 DWORD options = _SymGetOptions();
1268 options |= SYMOPT_LOAD_LINES;
1269 options |= SYMOPT_FAIL_CRITICAL_ERRORS;
1270 options = _SymSetOptions(options);
1271
1272 char buf[OS::kStackWalkMaxNameLen] = {0};
1273 ok = _SymGetSearchPath(process_handle, buf, OS::kStackWalkMaxNameLen);
1274 if (!ok) {
1275 int err = GetLastError();
1276 PrintF("%d\n", err);
1277 return false;
1278 }
1279
1280 HANDLE snapshot = _CreateToolhelp32Snapshot(
1281 TH32CS_SNAPMODULE, // dwFlags
1282 GetCurrentProcessId()); // th32ProcessId
1283 if (snapshot == INVALID_HANDLE_VALUE) return false;
1284 MODULEENTRY32W module_entry;
1285 module_entry.dwSize = sizeof(module_entry); // Set the size of the structure.
1286 BOOL cont = _Module32FirstW(snapshot, &module_entry);
1287 while (cont) {
1288 DWORD64 base;
1289 // NOTE the SymLoadModule64 function has the peculiarity of accepting a
1290 // both unicode and ASCII strings even though the parameter is PSTR.
1291 base = _SymLoadModule64(
1292 process_handle, // hProcess
1293 0, // hFile
1294 reinterpret_cast<PSTR>(module_entry.szExePath), // ImageName
1295 reinterpret_cast<PSTR>(module_entry.szModule), // ModuleName
1296 reinterpret_cast<DWORD64>(module_entry.modBaseAddr), // BaseOfDll
1297 module_entry.modBaseSize); // SizeOfDll
1298 if (base == 0) {
1299 int err = GetLastError();
1300 if (err != ERROR_MOD_NOT_FOUND &&
1301 err != ERROR_INVALID_HANDLE) return false;
1302 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001303 LOG(i::Isolate::Current(),
1304 SharedLibraryEvent(
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001305 module_entry.szExePath,
1306 reinterpret_cast<unsigned int>(module_entry.modBaseAddr),
1307 reinterpret_cast<unsigned int>(module_entry.modBaseAddr +
1308 module_entry.modBaseSize)));
1309 cont = _Module32NextW(snapshot, &module_entry);
1310 }
1311 CloseHandle(snapshot);
1312
1313 symbols_loaded = true;
1314 return true;
1315}
1316
1317
1318void OS::LogSharedLibraryAddresses() {
1319 // SharedLibraryEvents are logged when loading symbol information.
1320 // Only the shared libraries loaded at the time of the call to
1321 // LogSharedLibraryAddresses are logged. DLLs loaded after
1322 // initialization are not accounted for.
1323 if (!LoadDbgHelpAndTlHelp32()) return;
1324 HANDLE process_handle = GetCurrentProcess();
1325 LoadSymbols(process_handle);
1326}
1327
1328
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00001329void OS::SignalCodeMovingGC() {
1330}
1331
1332
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001333// Walk the stack using the facilities in dbghelp.dll and tlhelp32.dll
1334
1335// Switch off warning 4748 (/GS can not protect parameters and local variables
1336// from local buffer overrun because optimizations are disabled in function) as
1337// it is triggered by the use of inline assembler.
1338#pragma warning(push)
1339#pragma warning(disable : 4748)
ager@chromium.org65dad4b2009-04-23 08:48:43 +00001340int OS::StackWalk(Vector<OS::StackFrame> frames) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001341 BOOL ok;
1342
1343 // Load the required functions from DLL's.
1344 if (!LoadDbgHelpAndTlHelp32()) return kStackWalkError;
1345
1346 // Get the process and thread handles.
1347 HANDLE process_handle = GetCurrentProcess();
1348 HANDLE thread_handle = GetCurrentThread();
1349
1350 // Read the symbols.
1351 if (!LoadSymbols(process_handle)) return kStackWalkError;
1352
1353 // Capture current context.
1354 CONTEXT context;
ager@chromium.org3811b432009-10-28 14:53:37 +00001355 RtlCaptureContext(&context);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001356
1357 // Initialize the stack walking
1358 STACKFRAME64 stack_frame;
1359 memset(&stack_frame, 0, sizeof(stack_frame));
ager@chromium.orgab99eea2009-08-25 07:05:41 +00001360#ifdef _WIN64
1361 stack_frame.AddrPC.Offset = context.Rip;
1362 stack_frame.AddrFrame.Offset = context.Rbp;
1363 stack_frame.AddrStack.Offset = context.Rsp;
1364#else
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001365 stack_frame.AddrPC.Offset = context.Eip;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001366 stack_frame.AddrFrame.Offset = context.Ebp;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001367 stack_frame.AddrStack.Offset = context.Esp;
ager@chromium.orgab99eea2009-08-25 07:05:41 +00001368#endif
1369 stack_frame.AddrPC.Mode = AddrModeFlat;
1370 stack_frame.AddrFrame.Mode = AddrModeFlat;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001371 stack_frame.AddrStack.Mode = AddrModeFlat;
1372 int frames_count = 0;
1373
1374 // Collect stack frames.
ager@chromium.org65dad4b2009-04-23 08:48:43 +00001375 int frames_size = frames.length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001376 while (frames_count < frames_size) {
1377 ok = _StackWalk64(
1378 IMAGE_FILE_MACHINE_I386, // MachineType
1379 process_handle, // hProcess
1380 thread_handle, // hThread
1381 &stack_frame, // StackFrame
1382 &context, // ContextRecord
1383 NULL, // ReadMemoryRoutine
1384 _SymFunctionTableAccess64, // FunctionTableAccessRoutine
1385 _SymGetModuleBase64, // GetModuleBaseRoutine
1386 NULL); // TranslateAddress
1387 if (!ok) break;
1388
1389 // Store the address.
1390 ASSERT((stack_frame.AddrPC.Offset >> 32) == 0); // 32-bit address.
1391 frames[frames_count].address =
1392 reinterpret_cast<void*>(stack_frame.AddrPC.Offset);
1393
1394 // Try to locate a symbol for this frame.
1395 DWORD64 symbol_displacement;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00001396 SmartArrayPointer<IMAGEHLP_SYMBOL64> symbol(
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +00001397 NewArray<IMAGEHLP_SYMBOL64>(kStackWalkMaxNameLen));
1398 if (symbol.is_empty()) return kStackWalkError; // Out of memory.
1399 memset(*symbol, 0, sizeof(IMAGEHLP_SYMBOL64) + kStackWalkMaxNameLen);
1400 (*symbol)->SizeOfStruct = sizeof(IMAGEHLP_SYMBOL64);
1401 (*symbol)->MaxNameLength = kStackWalkMaxNameLen;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001402 ok = _SymGetSymFromAddr64(process_handle, // hProcess
1403 stack_frame.AddrPC.Offset, // Address
1404 &symbol_displacement, // Displacement
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +00001405 *symbol); // Symbol
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001406 if (ok) {
1407 // Try to locate more source information for the symbol.
1408 IMAGEHLP_LINE64 Line;
1409 memset(&Line, 0, sizeof(Line));
1410 Line.SizeOfStruct = sizeof(Line);
1411 DWORD line_displacement;
1412 ok = _SymGetLineFromAddr64(
1413 process_handle, // hProcess
1414 stack_frame.AddrPC.Offset, // dwAddr
1415 &line_displacement, // pdwDisplacement
1416 &Line); // Line
1417 // Format a text representation of the frame based on the information
1418 // available.
1419 if (ok) {
kasperl@chromium.orgb9123622008-09-17 14:05:56 +00001420 SNPrintF(MutableCStrVector(frames[frames_count].text,
1421 kStackWalkMaxTextLen),
1422 "%s %s:%d:%d",
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +00001423 (*symbol)->Name, Line.FileName, Line.LineNumber,
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001424 line_displacement);
1425 } else {
kasperl@chromium.orgb9123622008-09-17 14:05:56 +00001426 SNPrintF(MutableCStrVector(frames[frames_count].text,
1427 kStackWalkMaxTextLen),
1428 "%s",
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +00001429 (*symbol)->Name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001430 }
1431 // Make sure line termination is in place.
1432 frames[frames_count].text[kStackWalkMaxTextLen - 1] = '\0';
1433 } else {
1434 // No text representation of this frame
1435 frames[frames_count].text[0] = '\0';
1436
1437 // Continue if we are just missing a module (for non C/C++ frames a
1438 // module will never be found).
1439 int err = GetLastError();
1440 if (err != ERROR_MOD_NOT_FOUND) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001441 break;
1442 }
1443 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001444
1445 frames_count++;
1446 }
1447
1448 // Return the number of frames filled in.
1449 return frames_count;
1450}
1451
1452// Restore warnings to previous settings.
1453#pragma warning(pop)
1454
iposva@chromium.org245aa852009-02-10 00:49:54 +00001455#else // __MINGW32__
1456void OS::LogSharedLibraryAddresses() { }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001457void OS::SignalCodeMovingGC() { }
ager@chromium.org65dad4b2009-04-23 08:48:43 +00001458int OS::StackWalk(Vector<OS::StackFrame> frames) { return 0; }
iposva@chromium.org245aa852009-02-10 00:49:54 +00001459#endif // __MINGW32__
1460
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001461
ager@chromium.orgc4c92722009-11-18 14:12:51 +00001462uint64_t OS::CpuFeaturesImpliedByPlatform() {
1463 return 0; // Windows runs on anything.
1464}
1465
1466
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001467double OS::nan_value() {
iposva@chromium.org245aa852009-02-10 00:49:54 +00001468#ifdef _MSC_VER
ager@chromium.org3811b432009-10-28 14:53:37 +00001469 // Positive Quiet NaN with no payload (aka. Indeterminate) has all bits
1470 // in mask set, so value equals mask.
1471 static const __int64 nanval = kQuietNaNMask;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001472 return *reinterpret_cast<const double*>(&nanval);
iposva@chromium.org245aa852009-02-10 00:49:54 +00001473#else // _MSC_VER
1474 return NAN;
1475#endif // _MSC_VER
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001476}
1477
ager@chromium.org236ad962008-09-25 09:45:57 +00001478
1479int OS::ActivationFrameAlignment() {
ager@chromium.org18ad94b2009-09-02 08:22:29 +00001480#ifdef _WIN64
1481 return 16; // Windows 64-bit ABI requires the stack to be 16-byte aligned.
1482#else
1483 return 8; // Floating-point math runs faster with 8-byte alignment.
1484#endif
ager@chromium.org236ad962008-09-25 09:45:57 +00001485}
1486
1487
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00001488void OS::ReleaseStore(volatile AtomicWord* ptr, AtomicWord value) {
1489 MemoryBarrier();
1490 *ptr = value;
1491}
1492
1493
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001494VirtualMemory::VirtualMemory() : address_(NULL), size_(0) { }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001495
1496
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001497VirtualMemory::VirtualMemory(size_t size)
1498 : address_(ReserveRegion(size)), size_(size) { }
1499
1500
1501VirtualMemory::VirtualMemory(size_t size, size_t alignment)
1502 : address_(NULL), size_(0) {
1503 ASSERT(IsAligned(alignment, static_cast<intptr_t>(OS::AllocateAlignment())));
1504 size_t request_size = RoundUp(size + alignment,
1505 static_cast<intptr_t>(OS::AllocateAlignment()));
1506 void* address = ReserveRegion(request_size);
1507 if (address == NULL) return;
1508 Address base = RoundUp(static_cast<Address>(address), alignment);
1509 // Try reducing the size by freeing and then reallocating a specific area.
1510 bool result = ReleaseRegion(address, request_size);
1511 USE(result);
1512 ASSERT(result);
1513 address = VirtualAlloc(base, size, MEM_RESERVE, PAGE_NOACCESS);
1514 if (address != NULL) {
1515 request_size = size;
1516 ASSERT(base == static_cast<Address>(address));
1517 } else {
1518 // Resizing failed, just go with a bigger area.
1519 address = ReserveRegion(request_size);
1520 if (address == NULL) return;
1521 }
1522 address_ = address;
1523 size_ = request_size;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001524}
1525
1526
1527VirtualMemory::~VirtualMemory() {
1528 if (IsReserved()) {
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00001529 bool result = ReleaseRegion(address(), size());
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001530 ASSERT(result);
1531 USE(result);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001532 }
1533}
1534
1535
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001536bool VirtualMemory::IsReserved() {
1537 return address_ != NULL;
1538}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001539
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001540
1541void VirtualMemory::Reset() {
1542 address_ = NULL;
1543 size_ = 0;
1544}
1545
1546
1547bool VirtualMemory::Commit(void* address, size_t size, bool is_executable) {
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00001548 return CommitRegion(address, size, is_executable);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001549}
1550
1551
1552bool VirtualMemory::Uncommit(void* address, size_t size) {
1553 ASSERT(IsReserved());
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001554 return UncommitRegion(address, size);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001555}
1556
1557
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00001558bool VirtualMemory::Guard(void* address) {
1559 if (NULL == VirtualAlloc(address,
1560 OS::CommitPageSize(),
1561 MEM_COMMIT,
1562 PAGE_READONLY | PAGE_GUARD)) {
1563 return false;
1564 }
1565 return true;
1566}
1567
1568
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001569void* VirtualMemory::ReserveRegion(size_t size) {
kmillikin@chromium.orgbe6bd102012-02-23 08:45:21 +00001570 return RandomizedVirtualAlloc(size, MEM_RESERVE, PAGE_NOACCESS);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001571}
1572
1573
1574bool VirtualMemory::CommitRegion(void* base, size_t size, bool is_executable) {
1575 int prot = is_executable ? PAGE_EXECUTE_READWRITE : PAGE_READWRITE;
1576 if (NULL == VirtualAlloc(base, size, MEM_COMMIT, prot)) {
1577 return false;
1578 }
1579
1580 UpdateAllocatedSpaceLimits(base, static_cast<int>(size));
1581 return true;
1582}
1583
1584
1585bool VirtualMemory::UncommitRegion(void* base, size_t size) {
1586 return VirtualFree(base, size, MEM_DECOMMIT) != 0;
1587}
1588
1589
1590bool VirtualMemory::ReleaseRegion(void* base, size_t size) {
1591 return VirtualFree(base, 0, MEM_RELEASE) != 0;
1592}
1593
1594
danno@chromium.org72204d52012-10-31 10:02:10 +00001595bool VirtualMemory::HasLazyCommits() {
1596 // TODO(alph): implement for the platform.
1597 return false;
1598}
1599
1600
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001601// ----------------------------------------------------------------------------
1602// Win32 thread support.
1603
1604// Definition of invalid thread handle and id.
1605static const HANDLE kNoThread = INVALID_HANDLE_VALUE;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001606
1607// Entry point for threads. The supplied argument is a pointer to the thread
1608// object. The entry function dispatches to the run method in the thread
1609// object. It is important that this function has __stdcall calling
1610// convention.
1611static unsigned int __stdcall ThreadEntry(void* arg) {
1612 Thread* thread = reinterpret_cast<Thread*>(arg);
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00001613 thread->NotifyStartedAndRun();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001614 return 0;
1615}
1616
1617
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001618class Thread::PlatformData : public Malloced {
1619 public:
1620 explicit PlatformData(HANDLE thread) : thread_(thread) {}
1621 HANDLE thread_;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001622 unsigned thread_id_;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001623};
1624
1625
1626// Initialize a Win32 thread object. The thread has an invalid thread
1627// handle until it is started.
1628
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00001629Thread::Thread(const Options& options)
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00001630 : stack_size_(options.stack_size()),
1631 start_semaphore_(NULL) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001632 data_ = new PlatformData(kNoThread);
yangguo@chromium.org659ceec2012-01-26 07:37:54 +00001633 set_name(options.name());
lrn@chromium.org5d00b602011-01-05 09:51:43 +00001634}
1635
1636
1637void Thread::set_name(const char* name) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00001638 OS::StrNCpy(Vector<char>(name_, sizeof(name_)), name, strlen(name));
lrn@chromium.org5d00b602011-01-05 09:51:43 +00001639 name_[sizeof(name_) - 1] = '\0';
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001640}
1641
1642
1643// Close our own handle for the thread.
1644Thread::~Thread() {
1645 if (data_->thread_ != kNoThread) CloseHandle(data_->thread_);
1646 delete data_;
1647}
1648
1649
1650// Create a new thread. It is important to use _beginthreadex() instead of
1651// the Win32 function CreateThread(), because the CreateThread() does not
1652// initialize thread specific structures in the C runtime library.
1653void Thread::Start() {
1654 data_->thread_ = reinterpret_cast<HANDLE>(
1655 _beginthreadex(NULL,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001656 static_cast<unsigned>(stack_size_),
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001657 ThreadEntry,
1658 this,
1659 0,
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001660 &data_->thread_id_));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001661}
1662
1663
1664// Wait for thread to terminate.
1665void Thread::Join() {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001666 if (data_->thread_id_ != GetCurrentThreadId()) {
1667 WaitForSingleObject(data_->thread_, INFINITE);
1668 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001669}
1670
1671
1672Thread::LocalStorageKey Thread::CreateThreadLocalKey() {
1673 DWORD result = TlsAlloc();
1674 ASSERT(result != TLS_OUT_OF_INDEXES);
1675 return static_cast<LocalStorageKey>(result);
1676}
1677
1678
1679void Thread::DeleteThreadLocalKey(LocalStorageKey key) {
1680 BOOL result = TlsFree(static_cast<DWORD>(key));
1681 USE(result);
1682 ASSERT(result);
1683}
1684
1685
1686void* Thread::GetThreadLocal(LocalStorageKey key) {
1687 return TlsGetValue(static_cast<DWORD>(key));
1688}
1689
1690
1691void Thread::SetThreadLocal(LocalStorageKey key, void* value) {
1692 BOOL result = TlsSetValue(static_cast<DWORD>(key), value);
1693 USE(result);
1694 ASSERT(result);
1695}
1696
1697
1698
1699void Thread::YieldCPU() {
1700 Sleep(0);
1701}
1702
1703
1704// ----------------------------------------------------------------------------
1705// Win32 mutex support.
1706//
1707// On Win32 mutexes are implemented using CRITICAL_SECTION objects. These are
1708// faster than Win32 Mutex objects because they are implemented using user mode
1709// atomic instructions. Therefore we only do ring transitions if there is lock
1710// contention.
1711
1712class Win32Mutex : public Mutex {
1713 public:
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001714 Win32Mutex() { InitializeCriticalSection(&cs_); }
1715
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001716 virtual ~Win32Mutex() { DeleteCriticalSection(&cs_); }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001717
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001718 virtual int Lock() {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001719 EnterCriticalSection(&cs_);
1720 return 0;
1721 }
1722
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001723 virtual int Unlock() {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001724 LeaveCriticalSection(&cs_);
1725 return 0;
1726 }
1727
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001728
1729 virtual bool TryLock() {
1730 // Returns non-zero if critical section is entered successfully entered.
1731 return TryEnterCriticalSection(&cs_);
1732 }
1733
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001734 private:
1735 CRITICAL_SECTION cs_; // Critical section used for mutex
1736};
1737
1738
1739Mutex* OS::CreateMutex() {
1740 return new Win32Mutex();
1741}
1742
1743
1744// ----------------------------------------------------------------------------
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001745// Win32 semaphore support.
1746//
1747// On Win32 semaphores are implemented using Win32 Semaphore objects. The
1748// semaphores are anonymous. Also, the semaphores are initialized to have
1749// no upper limit on count.
1750
1751
1752class Win32Semaphore : public Semaphore {
1753 public:
1754 explicit Win32Semaphore(int count) {
1755 sem = ::CreateSemaphoreA(NULL, count, 0x7fffffff, NULL);
1756 }
1757
1758 ~Win32Semaphore() {
1759 CloseHandle(sem);
1760 }
1761
1762 void Wait() {
1763 WaitForSingleObject(sem, INFINITE);
1764 }
1765
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00001766 bool Wait(int timeout) {
1767 // Timeout in Windows API is in milliseconds.
1768 DWORD millis_timeout = timeout / 1000;
1769 return WaitForSingleObject(sem, millis_timeout) != WAIT_TIMEOUT;
1770 }
1771
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001772 void Signal() {
1773 LONG dummy;
1774 ReleaseSemaphore(sem, 1, &dummy);
1775 }
1776
1777 private:
1778 HANDLE sem;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001779};
1780
1781
1782Semaphore* OS::CreateSemaphore(int count) {
1783 return new Win32Semaphore(count);
1784}
1785
ager@chromium.org381abbb2009-02-25 13:23:22 +00001786
1787// ----------------------------------------------------------------------------
1788// Win32 socket support.
1789//
1790
1791class Win32Socket : public Socket {
1792 public:
1793 explicit Win32Socket() {
1794 // Create the socket.
1795 socket_ = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
1796 }
1797 explicit Win32Socket(SOCKET socket): socket_(socket) { }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00001798 virtual ~Win32Socket() { Shutdown(); }
ager@chromium.org381abbb2009-02-25 13:23:22 +00001799
1800 // Server initialization.
1801 bool Bind(const int port);
1802 bool Listen(int backlog) const;
1803 Socket* Accept() const;
1804
1805 // Client initialization.
1806 bool Connect(const char* host, const char* port);
1807
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00001808 // Shutdown socket for both read and write.
1809 bool Shutdown();
1810
ager@chromium.org381abbb2009-02-25 13:23:22 +00001811 // Data Transimission
1812 int Send(const char* data, int len) const;
ager@chromium.org381abbb2009-02-25 13:23:22 +00001813 int Receive(char* data, int len) const;
1814
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00001815 bool SetReuseAddress(bool reuse_address);
1816
ager@chromium.org381abbb2009-02-25 13:23:22 +00001817 bool IsValid() const { return socket_ != INVALID_SOCKET; }
1818
1819 private:
1820 SOCKET socket_;
1821};
1822
1823
1824bool Win32Socket::Bind(const int port) {
1825 if (!IsValid()) {
1826 return false;
1827 }
1828
1829 sockaddr_in addr;
1830 memset(&addr, 0, sizeof(addr));
1831 addr.sin_family = AF_INET;
1832 addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
1833 addr.sin_port = htons(port);
1834 int status = bind(socket_,
1835 reinterpret_cast<struct sockaddr *>(&addr),
1836 sizeof(addr));
1837 return status == 0;
1838}
1839
1840
1841bool Win32Socket::Listen(int backlog) const {
1842 if (!IsValid()) {
1843 return false;
1844 }
1845
1846 int status = listen(socket_, backlog);
1847 return status == 0;
1848}
1849
1850
1851Socket* Win32Socket::Accept() const {
1852 if (!IsValid()) {
1853 return NULL;
1854 }
1855
1856 SOCKET socket = accept(socket_, NULL, NULL);
1857 if (socket == INVALID_SOCKET) {
1858 return NULL;
1859 } else {
1860 return new Win32Socket(socket);
1861 }
1862}
1863
1864
1865bool Win32Socket::Connect(const char* host, const char* port) {
1866 if (!IsValid()) {
1867 return false;
1868 }
1869
1870 // Lookup host and port.
1871 struct addrinfo *result = NULL;
1872 struct addrinfo hints;
1873 memset(&hints, 0, sizeof(addrinfo));
1874 hints.ai_family = AF_INET;
1875 hints.ai_socktype = SOCK_STREAM;
1876 hints.ai_protocol = IPPROTO_TCP;
1877 int status = getaddrinfo(host, port, &hints, &result);
1878 if (status != 0) {
1879 return false;
1880 }
1881
1882 // Connect.
ager@chromium.orgc4c92722009-11-18 14:12:51 +00001883 status = connect(socket_,
1884 result->ai_addr,
1885 static_cast<int>(result->ai_addrlen));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00001886 freeaddrinfo(result);
ager@chromium.org381abbb2009-02-25 13:23:22 +00001887 return status == 0;
1888}
1889
1890
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00001891bool Win32Socket::Shutdown() {
1892 if (IsValid()) {
1893 // Shutdown socket for both read and write.
1894 int status = shutdown(socket_, SD_BOTH);
1895 closesocket(socket_);
1896 socket_ = INVALID_SOCKET;
1897 return status == SOCKET_ERROR;
1898 }
1899 return true;
1900}
1901
1902
ager@chromium.org381abbb2009-02-25 13:23:22 +00001903int Win32Socket::Send(const char* data, int len) const {
ulan@chromium.org0e3f88b2012-05-22 09:16:05 +00001904 if (len <= 0) return 0;
1905 int written = 0;
1906 while (written < len) {
1907 int status = send(socket_, data + written, len - written, 0);
1908 if (status == 0) {
1909 break;
1910 } else if (status > 0) {
1911 written += status;
1912 } else {
1913 return 0;
1914 }
1915 }
1916 return written;
ager@chromium.org381abbb2009-02-25 13:23:22 +00001917}
1918
1919
ager@chromium.org381abbb2009-02-25 13:23:22 +00001920int Win32Socket::Receive(char* data, int len) const {
ulan@chromium.org0e3f88b2012-05-22 09:16:05 +00001921 if (len <= 0) return 0;
ager@chromium.org381abbb2009-02-25 13:23:22 +00001922 int status = recv(socket_, data, len, 0);
ulan@chromium.org0e3f88b2012-05-22 09:16:05 +00001923 return (status == SOCKET_ERROR) ? 0 : status;
ager@chromium.org381abbb2009-02-25 13:23:22 +00001924}
1925
1926
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00001927bool Win32Socket::SetReuseAddress(bool reuse_address) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001928 BOOL on = reuse_address ? true : false;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00001929 int status = setsockopt(socket_, SOL_SOCKET, SO_REUSEADDR,
1930 reinterpret_cast<char*>(&on), sizeof(on));
1931 return status == SOCKET_ERROR;
1932}
1933
1934
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001935bool Socket::SetUp() {
ager@chromium.org381abbb2009-02-25 13:23:22 +00001936 // Initialize Winsock32
1937 int err;
1938 WSADATA winsock_data;
1939 WORD version_requested = MAKEWORD(1, 0);
1940 err = WSAStartup(version_requested, &winsock_data);
1941 if (err != 0) {
1942 PrintF("Unable to initialize Winsock, err = %d\n", Socket::LastError());
1943 }
1944
1945 return err == 0;
1946}
1947
1948
1949int Socket::LastError() {
1950 return WSAGetLastError();
1951}
1952
1953
1954uint16_t Socket::HToN(uint16_t value) {
1955 return htons(value);
1956}
1957
1958
1959uint16_t Socket::NToH(uint16_t value) {
1960 return ntohs(value);
1961}
1962
1963
1964uint32_t Socket::HToN(uint32_t value) {
1965 return htonl(value);
1966}
1967
1968
1969uint32_t Socket::NToH(uint32_t value) {
1970 return ntohl(value);
1971}
1972
1973
1974Socket* OS::CreateSocket() {
1975 return new Win32Socket();
1976}
1977
1978
fschneider@chromium.org7d10be52012-04-10 12:30:14 +00001979void OS::SetUp() {
1980 // Seed the random number generator.
1981 // Convert the current time to a 64-bit integer first, before converting it
1982 // to an unsigned. Going directly can cause an overflow and the seed to be
1983 // set to all ones. The seed will be identical for different instances that
1984 // call this setup code within the same millisecond.
1985 uint64_t seed = static_cast<uint64_t>(TimeCurrentMillis());
1986 srand(static_cast<unsigned int>(seed));
1987 limit_mutex = CreateMutex();
fschneider@chromium.org7d10be52012-04-10 12:30:14 +00001988}
1989
1990
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00001991void OS::TearDown() {
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00001992 delete limit_mutex;
1993}
1994
1995
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001996} } // namespace v8::internal