v8
V8 is Google’s open source high-performance JavaScript and WebAssembly engine, written in C++.
Loading...
Searching...
No Matches
platform-win32.cc
Go to the documentation of this file.
1// Copyright 2012 the V8 project authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5// Platform-specific code for Win32.
6
8
9// Secure API functions are not available using MinGW with msvcrt.dll
10// on Windows XP. Make sure MINGW_HAS_SECURE_API is not defined to
11// disable definition of secure API functions in standard headers that
12// would conflict with our own implementation.
13#ifdef __MINGW32__
14#include <_mingw.h>
15#ifdef MINGW_HAS_SECURE_API
16#undef MINGW_HAS_SECURE_API
17#endif // MINGW_HAS_SECURE_API
18#endif // __MINGW32__
19
20#include <windows.h>
21
22// This has to come after windows.h.
23#include <VersionHelpers.h>
24#include <dbghelp.h> // For SymLoadModule64 and al.
25#include <malloc.h> // For _msize()
26#include <mmsystem.h> // For timeGetTime().
27#include <processthreadsapi.h> // For GetProcessMitigationPolicy().
28#include <psapi.h> // For GetProcessMemoryInfo().
29#include <tlhelp32.h> // For Module32First and al.
30
31#include <limits>
32#include <optional>
33
34#include "src/base/bits.h"
36#include "src/base/macros.h"
42
43#if defined(_MSC_VER)
44#include <crtdbg.h>
45#endif // defined(_MSC_VER)
46
47// Check that type sizes and alignments match.
48static_assert(sizeof(V8_CONDITION_VARIABLE) == sizeof(CONDITION_VARIABLE));
49static_assert(alignof(V8_CONDITION_VARIABLE) == alignof(CONDITION_VARIABLE));
50static_assert(sizeof(V8_SRWLOCK) == sizeof(SRWLOCK));
51static_assert(alignof(V8_SRWLOCK) == alignof(SRWLOCK));
52static_assert(sizeof(V8_CRITICAL_SECTION) == sizeof(CRITICAL_SECTION));
53static_assert(alignof(V8_CRITICAL_SECTION) == alignof(CRITICAL_SECTION));
54
55// Check that CRITICAL_SECTION offsets match.
56static_assert(offsetof(V8_CRITICAL_SECTION, DebugInfo) ==
57 offsetof(CRITICAL_SECTION, DebugInfo));
58static_assert(offsetof(V8_CRITICAL_SECTION, LockCount) ==
59 offsetof(CRITICAL_SECTION, LockCount));
60static_assert(offsetof(V8_CRITICAL_SECTION, RecursionCount) ==
61 offsetof(CRITICAL_SECTION, RecursionCount));
62static_assert(offsetof(V8_CRITICAL_SECTION, OwningThread) ==
63 offsetof(CRITICAL_SECTION, OwningThread));
64static_assert(offsetof(V8_CRITICAL_SECTION, LockSemaphore) ==
65 offsetof(CRITICAL_SECTION, LockSemaphore));
66static_assert(offsetof(V8_CRITICAL_SECTION, SpinCount) ==
67 offsetof(CRITICAL_SECTION, SpinCount));
68
69// Extra functions for MinGW. Most of these are the _s functions which are in
70// the Microsoft Visual Studio C++ CRT.
71#ifdef __MINGW32__
72
73
74#ifndef __MINGW64_VERSION_MAJOR
75
76#define _TRUNCATE 0
77#define STRUNCATE 80
78
79inline void MemoryFence() {
80 int barrier = 0;
81 __asm__ __volatile__("xchgl %%eax,%0 ":"=r" (barrier));
82}
83
84#endif // __MINGW64_VERSION_MAJOR
85
86
87int localtime_s(tm* out_tm, const time_t* time) {
88 tm* posix_local_time_struct = localtime_r(time, out_tm);
89 if (posix_local_time_struct == nullptr) return 1;
90 return 0;
91}
92
93
94int fopen_s(FILE** pFile, const char* filename, const char* mode) {
95 *pFile = fopen(filename, mode);
96 return *pFile != nullptr ? 0 : 1;
97}
98
99int _wfopen_s(FILE** pFile, const wchar_t* filename, const wchar_t* mode) {
100 *pFile = _wfopen(filename, mode);
101 return *pFile != nullptr ? 0 : 1;
102}
103
104int _vsnprintf_s(char* buffer, size_t sizeOfBuffer, size_t count,
105 const char* format, va_list argptr) {
106 DCHECK(count == _TRUNCATE);
107 return _vsnprintf(buffer, sizeOfBuffer, format, argptr);
108}
109
110
111int strncpy_s(char* dest, size_t dest_size, const char* source, size_t count) {
112 CHECK(source != nullptr);
113 CHECK(dest != nullptr);
114 CHECK_GT(dest_size, 0);
115
116 if (count == _TRUNCATE) {
117 while (dest_size > 0 && *source != 0) {
118 *(dest++) = *(source++);
119 --dest_size;
120 }
121 if (dest_size == 0) {
122 *(dest - 1) = 0;
123 return STRUNCATE;
124 }
125 } else {
126 while (dest_size > 0 && count > 0 && *source != 0) {
127 *(dest++) = *(source++);
128 --dest_size;
129 --count;
130 }
131 }
132 CHECK_GT(dest_size, 0);
133 *dest = 0;
134 return 0;
135}
136
137#endif // __MINGW32__
138
139namespace v8 {
140namespace base {
141
143 public:
145
147
148 void Clear(TimeZoneDetection) override { initialized_ = false; }
149
150 const char* LocalTimezone(double time) override;
151
152 double LocalTimeOffset(double time, bool is_utc) override;
153
154 double DaylightSavingsOffset(double time) override;
155
156 // Initialize timezone information. The timezone information is obtained from
157 // windows. If we cannot get the timezone information we fall back to CET.
159 // Just return if timezone information has already been initialized.
160 if (initialized_) return;
161
162 // Initialize POSIX time zone data.
163 _tzset();
164 // Obtain timezone information from operating system.
165 memset(&tzinfo_, 0, sizeof(tzinfo_));
166 if (GetTimeZoneInformation(&tzinfo_) == TIME_ZONE_ID_INVALID) {
167 // If we cannot get timezone information we fall back to CET.
168 tzinfo_.Bias = -60;
169 tzinfo_.StandardDate.wMonth = 10;
170 tzinfo_.StandardDate.wDay = 5;
171 tzinfo_.StandardDate.wHour = 3;
172 tzinfo_.StandardBias = 0;
173 tzinfo_.DaylightDate.wMonth = 3;
174 tzinfo_.DaylightDate.wDay = 5;
175 tzinfo_.DaylightDate.wHour = 2;
176 tzinfo_.DaylightBias = -60;
177 }
178
179 // Make standard and DST timezone names.
180 WideCharToMultiByte(CP_UTF8, 0, tzinfo_.StandardName, -1, std_tz_name_,
181 kTzNameSize, nullptr, nullptr);
182 std_tz_name_[kTzNameSize - 1] = '\0';
183 WideCharToMultiByte(CP_UTF8, 0, tzinfo_.DaylightName, -1, dst_tz_name_,
184 kTzNameSize, nullptr, nullptr);
185 dst_tz_name_[kTzNameSize - 1] = '\0';
186
187 // If OS returned empty string or resource id (like "@tzres.dll,-211")
188 // simply guess the name from the UTC bias of the timezone.
189 // To properly resolve the resource identifier requires a library load,
190 // which is not possible in a sandbox.
191 if (std_tz_name_[0] == '\0' || std_tz_name_[0] == '@') {
192 OS::SNPrintF(std_tz_name_, kTzNameSize - 1,
193 "%s Standard Time",
195 }
196 if (dst_tz_name_[0] == '\0' || dst_tz_name_[0] == '@') {
197 OS::SNPrintF(dst_tz_name_, kTzNameSize - 1,
198 "%s Daylight Time",
200 }
201 // Timezone information initialized.
202 initialized_ = true;
203 }
204
205 // Guess the name of the timezone from the bias.
206 // The guess is very biased towards the northern hemisphere.
207 const char* GuessTimezoneNameFromBias(int bias) {
208 static const int kHour = 60;
209 switch (-bias) {
210 case -9*kHour: return "Alaska";
211 case -8*kHour: return "Pacific";
212 case -7*kHour: return "Mountain";
213 case -6*kHour: return "Central";
214 case -5*kHour: return "Eastern";
215 case -4*kHour: return "Atlantic";
216 case 0*kHour: return "GMT";
217 case +1*kHour: return "Central Europe";
218 case +2*kHour: return "Eastern Europe";
219 case +3*kHour: return "Russia";
220 case +5*kHour + 30: return "India";
221 case +8*kHour: return "China";
222 case +9*kHour: return "Japan";
223 case +12*kHour: return "New Zealand";
224 default: return "Local";
225 }
226 }
227
228
229 private:
230 static const int kTzNameSize = 128;
234 TIME_ZONE_INFORMATION tzinfo_;
235 friend class Win32Time;
236};
237
238
239// ----------------------------------------------------------------------------
240// The Time class represents time on win32. A timestamp is represented as
241// a 64-bit integer in 100 nanoseconds since January 1, 1601 (UTC). JavaScript
242// timestamps are represented as a doubles in milliseconds since 00:00:00 UTC,
243// January 1, 1970.
244
246 public:
247 // Constructors.
248 Win32Time();
249 explicit Win32Time(double jstime);
250 Win32Time(int year, int mon, int day, int hour, int min, int sec);
251
252 // Convert timestamp to JavaScript representation.
253 double ToJSTime();
254
255 // Set timestamp to current time.
256 void SetToCurrentTime();
257
258 // Returns the local timezone offset in milliseconds east of UTC. This is
259 // the number of milliseconds you must add to UTC to get local time, i.e.
260 // LocalOffset(CET) = 3600000 and LocalOffset(PST) = -28800000. This
261 // routine also takes into account whether daylight saving is effect
262 // at the time.
263 int64_t LocalOffset(WindowsTimezoneCache* cache);
264
265 // Returns the daylight savings time offset for the time in milliseconds.
267
268 // Returns a string identifying the current timezone for the
269 // timestamp taking into account daylight saving.
271
272 private:
273 // Constants for time conversion.
274 static const int64_t kTimeEpoc = 116444736000000000LL;
275 static const int64_t kTimeScaler = 10000;
276 static const int64_t kMsPerMinute = 60000;
277
278 // Constants for timezone information.
279 static const bool kShortTzNames = false;
280
281 // Return whether or not daylight savings time is in effect at this time.
282 bool InDST(WindowsTimezoneCache* cache);
283
284 // Accessor for FILETIME representation.
285 FILETIME& ft() { return time_.ft_; }
286
287 // Accessor for integer representation.
288 int64_t& t() { return time_.t_; }
289
290 // Although win32 uses 64-bit integers for representing timestamps,
291 // these are packed into a FILETIME structure. The FILETIME structure
292 // is just a struct representing a 64-bit integer. The TimeStamp union
293 // allows access to both a FILETIME and an integer representation of
294 // the timestamp.
295 union TimeStamp {
296 FILETIME ft_;
297 int64_t t_;
298 };
299
301};
302
303
304// Initialize timestamp to start of epoc.
306 t() = 0;
307}
308
309
310// Initialize timestamp from a JavaScript timestamp.
311Win32Time::Win32Time(double jstime) {
312 t() = static_cast<int64_t>(jstime) * kTimeScaler + kTimeEpoc;
313}
314
315
316// Initialize timestamp from date/time components.
317Win32Time::Win32Time(int year, int mon, int day, int hour, int min, int sec) {
318 SYSTEMTIME st;
319 st.wYear = year;
320 st.wMonth = mon;
321 st.wDay = day;
322 st.wHour = hour;
323 st.wMinute = min;
324 st.wSecond = sec;
325 st.wMilliseconds = 0;
326 SystemTimeToFileTime(&st, &ft());
327}
328
329
330// Convert timestamp to JavaScript timestamp.
332 return static_cast<double>((t() - kTimeEpoc) / kTimeScaler);
333}
334
335
336// Set timestamp to current time.
338 // The default GetSystemTimeAsFileTime has a ~15.5ms resolution.
339 // Because we're fast, we like fast timers which have at least a
340 // 1ms resolution.
341 //
342 // timeGetTime() provides 1ms granularity when combined with
343 // timeBeginPeriod(). If the host application for v8 wants fast
344 // timers, it can use timeBeginPeriod to increase the resolution.
345 //
346 // Using timeGetTime() has a drawback because it is a 32bit value
347 // and hence rolls-over every ~49days.
348 //
349 // To use the clock, we use GetSystemTimeAsFileTime as our base;
350 // and then use timeGetTime to extrapolate current time from the
351 // start time. To deal with rollovers, we resync the clock
352 // any time when more than kMaxClockElapsedTime has passed or
353 // whenever timeGetTime creates a rollover.
354
355 static bool initialized = false;
356 static TimeStamp init_time;
357 static DWORD init_ticks;
358 static const int64_t kHundredNanosecondsPerSecond = 10000000;
359 static const int64_t kMaxClockElapsedTime =
360 60*kHundredNanosecondsPerSecond; // 1 minute
361
362 // If we are uninitialized, we need to resync the clock.
363 bool needs_resync = !initialized;
364
365 // Get the current time.
366 TimeStamp time_now;
367 GetSystemTimeAsFileTime(&time_now.ft_);
368 DWORD ticks_now = timeGetTime();
369
370 // Check if we need to resync due to clock rollover.
371 needs_resync |= ticks_now < init_ticks;
372
373 // Check if we need to resync due to elapsed time.
374 needs_resync |= (time_now.t_ - init_time.t_) > kMaxClockElapsedTime;
375
376 // Check if we need to resync due to backwards time change.
377 needs_resync |= time_now.t_ < init_time.t_;
378
379 // Resync the clock if necessary.
380 if (needs_resync) {
381 GetSystemTimeAsFileTime(&init_time.ft_);
382 init_ticks = ticks_now = timeGetTime();
383 initialized = true;
384 }
385
386 // Finally, compute the actual time. Why is this so hard.
387 DWORD elapsed = ticks_now - init_ticks;
388 this->time_.t_ = init_time.t_ + (static_cast<int64_t>(elapsed) * 10000);
389}
390
391
392// Return the local timezone offset in milliseconds east of UTC. This
393// takes into account whether daylight saving is in effect at the time.
394// Only times in the 32-bit Unix range may be passed to this function.
395// Also, adding the time-zone offset to the input must not overflow.
396// The function EquivalentTime() in date.js guarantees this.
398 cache->InitializeIfNeeded();
399
400 Win32Time rounded_to_second(*this);
401 rounded_to_second.t() =
402 rounded_to_second.t() / 1000 / kTimeScaler * 1000 * kTimeScaler;
403 // Convert to local time using POSIX localtime function.
404 // Windows XP Service Pack 3 made SystemTimeToTzSpecificLocalTime()
405 // very slow. Other browsers use localtime().
406
407 // Convert from JavaScript milliseconds past 1/1/1970 0:00:00 to
408 // POSIX seconds past 1/1/1970 0:00:00.
409 double unchecked_posix_time = rounded_to_second.ToJSTime() / 1000;
410 if (unchecked_posix_time > INT_MAX || unchecked_posix_time < 0) {
411 return 0;
412 }
413 // Because _USE_32BIT_TIME_T is defined, time_t is a 32-bit int.
414 time_t posix_time = static_cast<time_t>(unchecked_posix_time);
415
416 // Convert to local time, as struct with fields for day, hour, year, etc.
417 tm posix_local_time_struct;
418 if (localtime_s(&posix_local_time_struct, &posix_time)) return 0;
419
420 if (posix_local_time_struct.tm_isdst > 0) {
421 return (cache->tzinfo_.Bias + cache->tzinfo_.DaylightBias) * -kMsPerMinute;
422 } else if (posix_local_time_struct.tm_isdst == 0) {
423 return (cache->tzinfo_.Bias + cache->tzinfo_.StandardBias) * -kMsPerMinute;
424 } else {
425 return cache->tzinfo_.Bias * -kMsPerMinute;
426 }
427}
428
429
430// Return whether or not daylight savings time is in effect at this time.
432 cache->InitializeIfNeeded();
433
434 // Determine if DST is in effect at the specified time.
435 bool in_dst = false;
436 if (cache->tzinfo_.StandardDate.wMonth != 0 ||
437 cache->tzinfo_.DaylightDate.wMonth != 0) {
438 // Get the local timezone offset for the timestamp in milliseconds.
439 int64_t offset = LocalOffset(cache);
440
441 // Compute the offset for DST. The bias parameters in the timezone info
442 // are specified in minutes. These must be converted to milliseconds.
443 int64_t dstofs =
444 -(cache->tzinfo_.Bias + cache->tzinfo_.DaylightBias) * kMsPerMinute;
445
446 // If the local time offset equals the timezone bias plus the daylight
447 // bias then DST is in effect.
448 in_dst = offset == dstofs;
449 }
450
451 return in_dst;
452}
453
454
455// Return the daylight savings time offset for this time.
457 return InDST(cache) ? 60 * kMsPerMinute : 0;
458}
459
460
461// Returns a string identifying the current timezone for the
462// timestamp taking into account daylight saving.
464 // Return the standard or DST time zone name based on whether daylight
465 // saving is in effect at the given time.
466 return InDST(cache) ? cache->dst_tz_name_ : cache->std_tz_name_;
467}
468
469
470// Returns the accumulated user time for thread.
471int OS::GetUserTime(uint32_t* secs, uint32_t* usecs) {
472 FILETIME dummy;
473 uint64_t usertime;
474
475 // Get the amount of time that the thread has executed in user mode.
476 if (!GetThreadTimes(GetCurrentThread(), &dummy, &dummy, &dummy,
477 reinterpret_cast<FILETIME*>(&usertime))) return -1;
478
479 // Adjust the resolution to micro-seconds.
480 usertime /= 10;
481
482 // Convert to seconds and microseconds
483 *secs = static_cast<uint32_t>(usertime / 1000000);
484 *usecs = static_cast<uint32_t>(usertime % 1000000);
485 return 0;
486}
487
489 constexpr int KB = 1024;
490
491 PROCESS_MEMORY_COUNTERS mem_counters;
492 int ret;
493
494 ret = GetProcessMemoryInfo(GetCurrentProcess(), &mem_counters,
495 sizeof(mem_counters));
496 if (ret == 0) return -1;
497
498 return static_cast<int>(mem_counters.PeakWorkingSetSize / KB);
499}
500
501// Returns current time as the number of milliseconds since
502// 00:00:00 UTC, January 1, 1970.
503double OS::TimeCurrentMillis() {
504 return Time::Now().ToJsTime();
505}
506
507// Returns a string identifying the current timezone taking into
508// account daylight saving.
509const char* WindowsTimezoneCache::LocalTimezone(double time) {
510 return Win32Time(time).LocalTimezone(this);
511}
512
513// Returns the local time offset in milliseconds east of UTC without
514// taking daylight savings time into account.
515double WindowsTimezoneCache::LocalTimeOffset(double time_ms, bool is_utc) {
516 // Ignore is_utc and time_ms for now. That way, the behavior wouldn't
517 // change with icu_timezone_data disabled.
518 // Use current time, rounded to the millisecond.
520 // Time::LocalOffset inlcudes any daylight savings offset, so subtract it.
521 return static_cast<double>(t.LocalOffset(this) -
522 t.DaylightSavingsOffset(this));
523}
524
525// Returns the daylight savings offset in milliseconds for the given
526// time.
528 int64_t offset = Win32Time(time).DaylightSavingsOffset(this);
529 return static_cast<double>(offset);
530}
531
533
534int OS::GetLastError() {
535 return ::GetLastError();
536}
537
538
540 return static_cast<int>(::GetCurrentProcessId());
541}
542
544 return static_cast<int>(::GetCurrentThreadId());
545}
546
547void OS::ExitProcess(int exit_code) {
548 // Use TerminateProcess to avoid races between isolate threads and
549 // static destructors.
550 fflush(stdout);
551 fflush(stderr);
552 TerminateProcess(GetCurrentProcess(), exit_code);
553 // Termination the current process does not return. {TerminateProcess} is not
554 // marked [[noreturn]] though, since it can also be used to terminate another
555 // process.
556 UNREACHABLE();
557}
558
559// ----------------------------------------------------------------------------
560// Win32 console output.
561//
562// If a Win32 application is linked as a console application it has a normal
563// standard output and standard error. In this case normal printf works fine
564// for output. However, if the application is linked as a GUI application,
565// the process doesn't have a console, and therefore (debugging) output is lost.
566// This is the case if we are embedded in a windows program (like a browser).
567// In order to be able to get debug output in this case the the debugging
568// facility using OutputDebugString. This output goes to the active debugger
569// for the process (if any). Else the output can be monitored using DBMON.EXE.
570
572 UNKNOWN, // Output method has not yet been determined.
573 CONSOLE, // Output is written to stdout.
574 ODS // Output is written to debug facility.
576
577static OutputMode output_mode = UNKNOWN; // Current output mode.
578
579
580// Determine if the process has a console for output.
581static bool HasConsole() {
582 // Only check the first time. Eventual race conditions are not a problem,
583 // because all threads will eventually determine the same mode.
584 if (output_mode == UNKNOWN) {
585 // We cannot just check that the standard output is attached to a console
586 // because this would fail if output is redirected to a file. Therefore we
587 // say that a process does not have an output console if either the
588 // standard output handle is invalid or its file type is unknown.
589 if (GetStdHandle(STD_OUTPUT_HANDLE) != INVALID_HANDLE_VALUE &&
590 GetFileType(GetStdHandle(STD_OUTPUT_HANDLE)) != FILE_TYPE_UNKNOWN)
592 else
594 }
595 return output_mode == CONSOLE;
596}
597
598
599static void VPrintHelper(FILE* stream, const char* format, va_list args) {
600 if ((stream == stdout || stream == stderr) && !HasConsole()) {
601 // It is important to use safe print here in order to avoid
602 // overflowing the buffer. We might truncate the output, but this
603 // does not crash.
604 char buffer[4096];
605 OS::VSNPrintF(buffer, sizeof(buffer), format, args);
606 OutputDebugStringA(buffer);
607 } else {
608 vfprintf(stream, format, args);
609 }
610}
611
612// Convert utf-8 encoded string to utf-16 encoded.
613static std::wstring ConvertUtf8StringToUtf16(const char* str) {
614 // On Windows wchar_t must be a 16-bit value.
615 static_assert(sizeof(wchar_t) == 2, "wrong wchar_t size");
616 std::wstring utf16_str;
617 int name_length = static_cast<int>(strlen(str));
618 int len = MultiByteToWideChar(CP_UTF8, 0, str, name_length, nullptr, 0);
619 if (len > 0) {
620 utf16_str.resize(len);
621 MultiByteToWideChar(CP_UTF8, 0, str, name_length, &utf16_str[0], len);
622 }
623 return utf16_str;
624}
625
626FILE* OS::FOpen(const char* path, const char* mode) {
627 FILE* result;
628 std::wstring utf16_path = ConvertUtf8StringToUtf16(path);
629 std::wstring utf16_mode = ConvertUtf8StringToUtf16(mode);
630 if (_wfopen_s(&result, utf16_path.c_str(), utf16_mode.c_str()) == 0) {
631 return result;
632 } else {
633 return nullptr;
634 }
635}
636
637
638bool OS::Remove(const char* path) {
639 return (DeleteFileA(path) != 0);
640}
641
642char OS::DirectorySeparator() { return '\\'; }
643
644bool OS::isDirectorySeparator(const char ch) {
645 return ch == '/' || ch == '\\';
646}
647
648
649FILE* OS::OpenTemporaryFile() {
650 // tmpfile_s tries to use the root dir, don't use it.
651 char tempPathBuffer[MAX_PATH];
652 DWORD path_result = 0;
653 path_result = GetTempPathA(MAX_PATH, tempPathBuffer);
654 if (path_result > MAX_PATH || path_result == 0) return nullptr;
655 UINT name_result = 0;
656 char tempNameBuffer[MAX_PATH];
657 name_result = GetTempFileNameA(tempPathBuffer, "", 0, tempNameBuffer);
658 if (name_result == 0) return nullptr;
659 FILE* result = FOpen(tempNameBuffer, "w+"); // Same mode as tmpfile uses.
660 if (result != nullptr) {
661 Remove(tempNameBuffer); // Delete on close.
662 }
663 return result;
664}
665
666
667// Open log file in binary mode to avoid /n -> /r/n conversion.
668const char* const OS::LogFileOpenMode = "wb+";
669
670// Print (debug) message to console.
671void OS::Print(const char* format, ...) {
672 va_list args;
673 va_start(args, format);
674 VPrint(format, args);
675 va_end(args);
676}
677
678
679void OS::VPrint(const char* format, va_list args) {
680 VPrintHelper(stdout, format, args);
681}
682
683
684void OS::FPrint(FILE* out, const char* format, ...) {
685 va_list args;
686 va_start(args, format);
687 VFPrint(out, format, args);
688 va_end(args);
689}
690
691
692void OS::VFPrint(FILE* out, const char* format, va_list args) {
693 VPrintHelper(out, format, args);
694}
695
696
697// Print error message to console.
698void OS::PrintError(const char* format, ...) {
699 va_list args;
700 va_start(args, format);
701 VPrintError(format, args);
702 va_end(args);
703 fflush(stderr);
704}
705
706
707void OS::VPrintError(const char* format, va_list args) {
708 VPrintHelper(stderr, format, args);
709}
710
711
712int OS::SNPrintF(char* str, int length, const char* format, ...) {
713 va_list args;
714 va_start(args, format);
715 int result = VSNPrintF(str, length, format, args);
716 va_end(args);
717 return result;
718}
719
720
721int OS::VSNPrintF(char* str, int length, const char* format, va_list args) {
722 int n = _vsnprintf_s(str, length, _TRUNCATE, format, args);
723 // Make sure to zero-terminate the string if the output was
724 // truncated or if there was an error.
725 if (n < 0 || n >= length) {
726 if (length > 0)
727 str[length - 1] = '\0';
728 return -1;
729 } else {
730 return n;
731 }
732}
733
734
735void OS::StrNCpy(char* dest, int length, const char* src, size_t n) {
736 // Use _TRUNCATE or strncpy_s crashes (by design) if buffer is too small.
737 size_t buffer_size = static_cast<size_t>(length);
738 if (n + 1 > buffer_size) // count for trailing '\0'
739 n = _TRUNCATE;
740 int result = strncpy_s(dest, length, src, n);
741 USE(result);
742 DCHECK(result == 0 || (n == _TRUNCATE && result == STRUNCATE));
743}
744
745
746#undef _TRUNCATE
747#undef STRUNCATE
748
750 GetPlatformRandomNumberGenerator)
751static LazyMutex rng_mutex = LAZY_MUTEX_INITIALIZER;
752
753namespace {
754
755bool UserShadowStackEnabled() {
756 auto is_user_cet_available_in_environment =
757 reinterpret_cast<decltype(&IsUserCetAvailableInEnvironment)>(
758 ::GetProcAddress(::GetModuleHandleW(L"kernel32.dll"),
759 "IsUserCetAvailableInEnvironment"));
760 auto get_process_mitigation_policy =
761 reinterpret_cast<decltype(&GetProcessMitigationPolicy)>(::GetProcAddress(
762 ::GetModuleHandle(L"Kernel32.dll"), "GetProcessMitigationPolicy"));
763
764 if (!is_user_cet_available_in_environment || !get_process_mitigation_policy) {
765 return false;
766 }
767
768 if (!is_user_cet_available_in_environment(
769 USER_CET_ENVIRONMENT_WIN32_PROCESS)) {
770 return false;
771 }
772
773 PROCESS_MITIGATION_USER_SHADOW_STACK_POLICY uss_policy;
774 if (!get_process_mitigation_policy(GetCurrentProcess(),
775 ProcessUserShadowStackPolicy, &uss_policy,
776 sizeof(uss_policy))) {
777 return false;
778 }
779
780 return uss_policy.EnableUserShadowStack;
781}
782
783} // namespace
784
785void OS::Initialize(AbortMode abort_mode, const char* const gc_fake_mmap) {
786 g_abort_mode = abort_mode;
787}
788
789typedef PVOID(__stdcall* VirtualAlloc2_t)(HANDLE, PVOID, SIZE_T, ULONG, ULONG,
790 MEM_EXTENDED_PARAMETER*, ULONG);
792
793typedef PVOID(__stdcall* MapViewOfFile3_t)(HANDLE, HANDLE, PVOID, ULONG64,
794 SIZE_T, ULONG, ULONG,
795 MEM_EXTENDED_PARAMETER*, ULONG);
797
798typedef PVOID(__stdcall* UnmapViewOfFile2_t)(HANDLE, PVOID, ULONG);
800
801void OS::EnsureWin32MemoryAPILoaded() {
802 static bool loaded = false;
803 if (!loaded) {
804 VirtualAlloc2 = (VirtualAlloc2_t)GetProcAddress(
805 GetModuleHandle(L"kernelbase.dll"), "VirtualAlloc2");
806
807 MapViewOfFile3 = (MapViewOfFile3_t)GetProcAddress(
808 GetModuleHandle(L"kernelbase.dll"), "MapViewOfFile3");
809
810 UnmapViewOfFile2 = (UnmapViewOfFile2_t)GetProcAddress(
811 GetModuleHandle(L"kernelbase.dll"), "UnmapViewOfFile2");
812
813 loaded = true;
814 }
815}
816
817// static
819 static bool cet_enabled = UserShadowStackEnabled();
820 return cet_enabled;
821}
822
823// static
824size_t OS::AllocatePageSize() {
825 static size_t allocate_alignment = 0;
826 if (allocate_alignment == 0) {
827 SYSTEM_INFO info;
828 GetSystemInfo(&info);
829 allocate_alignment = info.dwAllocationGranularity;
830 }
831 return allocate_alignment;
832}
833
834// static
835size_t OS::CommitPageSize() {
836 static size_t page_size = 0;
837 if (page_size == 0) {
838 SYSTEM_INFO info;
839 GetSystemInfo(&info);
840 page_size = info.dwPageSize;
841 DCHECK_EQ(4096, page_size);
842 }
843 return page_size;
844}
845
846// static
847void OS::SetRandomMmapSeed(int64_t seed) {
848 if (seed) {
849 MutexGuard guard(rng_mutex.Pointer());
850 GetPlatformRandomNumberGenerator()->SetSeed(seed);
851 }
852}
853
854// static
855void* OS::GetRandomMmapAddr() {
856// The address range used to randomize RWX allocations in OS::Allocate
857// Try not to map pages into the default range that windows loads DLLs
858// Use a multiple of 64k to prevent committing unused memory.
859// Note: This does not guarantee RWX regions will be within the
860// range kAllocationRandomAddressMin to kAllocationRandomAddressMax
861#ifdef V8_HOST_ARCH_64_BIT
862 static const uintptr_t kAllocationRandomAddressMin = 0x0000000080000000;
863 static const uintptr_t kAllocationRandomAddressMax = 0x000003FFFFFF0000;
864#else
865 static const uintptr_t kAllocationRandomAddressMin = 0x04000000;
866 static const uintptr_t kAllocationRandomAddressMax = 0x3FFF0000;
867#endif
868 uintptr_t address;
869 {
870 MutexGuard guard(rng_mutex.Pointer());
871 GetPlatformRandomNumberGenerator()->NextBytes(&address, sizeof(address));
872 }
873 address <<= kPageSizeBits;
874 address += kAllocationRandomAddressMin;
875 address &= kAllocationRandomAddressMax;
876 return reinterpret_cast<void*>(address);
877}
878
879namespace {
880
882 switch (access) {
885 return PAGE_NOACCESS;
887 return PAGE_READONLY;
889 return PAGE_READWRITE;
891 if (IsWindows10OrGreater())
892 return PAGE_EXECUTE_READWRITE | PAGE_TARGETS_INVALID;
893 return PAGE_EXECUTE_READWRITE;
895 if (IsWindows10OrGreater())
896 return PAGE_EXECUTE_READ | PAGE_TARGETS_INVALID;
897 return PAGE_EXECUTE_READ;
898 }
899 UNREACHABLE();
900}
901
902// Desired access parameter for MapViewOfFile
903DWORD GetFileViewAccessFromMemoryPermission(OS::MemoryPermission access) {
904 switch (access) {
908 return FILE_MAP_READ;
910 return FILE_MAP_READ | FILE_MAP_WRITE;
911 default:
912 // Execute access is not supported
913 break;
914 }
915 UNREACHABLE();
916}
917
918void* VirtualAllocWrapper(void* address, size_t size, DWORD flags,
919 DWORD protect) {
920 if (VirtualAlloc2) {
921 return VirtualAlloc2(GetCurrentProcess(), address, size, flags, protect,
922 NULL, 0);
923 } else {
924 return VirtualAlloc(address, size, flags, protect);
925 }
926}
927
928uint8_t* VirtualAllocWithHint(size_t size, DWORD flags, DWORD protect,
929 void* hint) {
930 LPVOID base = VirtualAllocWrapper(hint, size, flags, protect);
931
932 // On failure, let the OS find an address to use.
933 if (hint && base == nullptr) {
934 base = VirtualAllocWrapper(nullptr, size, flags, protect);
935 }
936
937 return reinterpret_cast<uint8_t*>(base);
938}
939
940void* AllocateInternal(void* hint, size_t size, size_t alignment,
941 size_t page_size, DWORD flags, DWORD protect) {
942 // First, try an exact size aligned allocation.
943 uint8_t* base = VirtualAllocWithHint(size, flags, protect, hint);
944 if (base == nullptr) return nullptr; // Can't allocate, we're OOM.
945
946 // If address is suitably aligned, we're done.
947 uint8_t* aligned_base = reinterpret_cast<uint8_t*>(
948 RoundUp(reinterpret_cast<uintptr_t>(base), alignment));
949 if (base == aligned_base) return reinterpret_cast<void*>(base);
950
951 // Otherwise, free it and try a larger allocation.
952 CHECK(VirtualFree(base, 0, MEM_RELEASE));
953
954 // Clear the hint. It's unlikely we can allocate at this address.
955 hint = nullptr;
956
957 // Add the maximum misalignment so we are guaranteed an aligned base address
958 // in the allocated region.
959 size_t padded_size = size + (alignment - page_size);
960 const int kMaxAttempts = 3;
961 aligned_base = nullptr;
962 for (int i = 0; i < kMaxAttempts; ++i) {
963 base = VirtualAllocWithHint(padded_size, flags, protect, hint);
964 if (base == nullptr) return nullptr; // Can't allocate, we're OOM.
965
966 // Try to trim the allocation by freeing the padded allocation and then
967 // calling VirtualAlloc at the aligned base.
968 CHECK(VirtualFree(base, 0, MEM_RELEASE));
969 aligned_base = reinterpret_cast<uint8_t*>(
970 RoundUp(reinterpret_cast<uintptr_t>(base), alignment));
971 base = reinterpret_cast<uint8_t*>(
972 VirtualAllocWrapper(aligned_base, size, flags, protect));
973 // We might not get the reduced allocation due to a race. In that case,
974 // base will be nullptr.
975 if (base != nullptr) break;
976 }
977 DCHECK_IMPLIES(base, base == aligned_base);
978 return reinterpret_cast<void*>(base);
979}
980
981void CheckIsOOMError(int error) {
982 // We expect one of ERROR_NOT_ENOUGH_MEMORY or ERROR_COMMITMENT_LIMIT. We'd
983 // still like to get the actual error code when it's not one of the expected
984 // errors, so use the construct below to achieve that.
985 if (error != ERROR_NOT_ENOUGH_MEMORY) CHECK_EQ(ERROR_COMMITMENT_LIMIT, error);
986}
987
988} // namespace
989
990// static
991void* OS::Allocate(void* hint, size_t size, size_t alignment,
992 MemoryPermission access) {
993 size_t page_size = AllocatePageSize();
994 DCHECK_EQ(0, size % page_size);
995 DCHECK_EQ(0, alignment % page_size);
996 DCHECK_LE(page_size, alignment);
997 hint = AlignedAddress(hint, alignment);
998
999 DWORD flags = (access == OS::MemoryPermission::kNoAccess)
1000 ? MEM_RESERVE
1001 : MEM_RESERVE | MEM_COMMIT;
1002 DWORD protect = GetProtectionFromMemoryPermission(access);
1003
1004 return AllocateInternal(hint, size, alignment, page_size, flags, protect);
1005}
1006
1007// static
1008void OS::Free(void* address, size_t size) {
1009 DCHECK_EQ(0, reinterpret_cast<uintptr_t>(address) % AllocatePageSize());
1010 DCHECK_EQ(0, size % AllocatePageSize());
1011 USE(size);
1012 CHECK_NE(0, VirtualFree(address, 0, MEM_RELEASE));
1013}
1014
1015// static
1016void* OS::AllocateShared(void* hint, size_t size, MemoryPermission permission,
1017 PlatformSharedMemoryHandle handle, uint64_t offset) {
1018 DCHECK_EQ(0, reinterpret_cast<uintptr_t>(hint) % AllocatePageSize());
1019 DCHECK_EQ(0, size % AllocatePageSize());
1021
1022 DWORD off_hi = static_cast<DWORD>(offset >> 32);
1023 DWORD off_lo = static_cast<DWORD>(offset);
1024 DWORD access = GetFileViewAccessFromMemoryPermission(permission);
1025
1026 HANDLE file_mapping = FileMappingFromSharedMemoryHandle(handle);
1027 void* result =
1028 MapViewOfFileEx(file_mapping, access, off_hi, off_lo, size, hint);
1029
1030 if (!result) {
1031 // Retry without hint.
1032 result = MapViewOfFile(file_mapping, access, off_hi, off_lo, size);
1033 }
1034
1035 return result;
1036}
1037
1038// static
1039void OS::FreeShared(void* address, size_t size) {
1040 CHECK(UnmapViewOfFile(address));
1041}
1042
1043// static
1044void OS::Release(void* address, size_t size) {
1045 DCHECK_EQ(0, reinterpret_cast<uintptr_t>(address) % CommitPageSize());
1046 DCHECK_EQ(0, size % CommitPageSize());
1047 CHECK_NE(0, VirtualFree(address, size, MEM_DECOMMIT));
1048}
1049
1050// static
1051bool OS::SetPermissions(void* address, size_t size, MemoryPermission access) {
1052 DCHECK_EQ(0, reinterpret_cast<uintptr_t>(address) % CommitPageSize());
1053 DCHECK_EQ(0, size % CommitPageSize());
1054 if (access == MemoryPermission::kNoAccess) {
1055 return VirtualFree(address, size, MEM_DECOMMIT) != 0;
1056 }
1057 DWORD protect = GetProtectionFromMemoryPermission(access);
1058 void* result = VirtualAllocWrapper(address, size, MEM_COMMIT, protect);
1059
1060 // Any failure that's not OOM likely indicates a bug in the caller (e.g.
1061 // using an invalid mapping) so attempt to catch that here to facilitate
1062 // debugging of these failures.
1063 if (!result) CheckIsOOMError(GetLastError());
1064
1065 return result != nullptr;
1066}
1067
1068void OS::SetDataReadOnly(void* address, size_t size) {
1069 DCHECK_EQ(0, reinterpret_cast<uintptr_t>(address) % CommitPageSize());
1070 DCHECK_EQ(0, size % CommitPageSize());
1071
1072 DWORD old_protection;
1073 CHECK(VirtualProtect(address, size, PAGE_READONLY, &old_protection));
1074 CHECK(old_protection == PAGE_READWRITE || old_protection == PAGE_WRITECOPY);
1075}
1076
1077// static
1078bool OS::RecommitPages(void* address, size_t size, MemoryPermission access) {
1079 return SetPermissions(address, size, access);
1080}
1081
1082// static
1083bool OS::DiscardSystemPages(void* address, size_t size) {
1084 // On Windows, discarded pages are not returned to the system immediately and
1085 // not guaranteed to be zeroed when returned to the application.
1086 using DiscardVirtualMemoryFunction =
1087 DWORD(WINAPI*)(PVOID virtualAddress, SIZE_T size);
1088 static std::atomic<DiscardVirtualMemoryFunction> discard_virtual_memory(
1089 reinterpret_cast<DiscardVirtualMemoryFunction>(-1));
1090 if (discard_virtual_memory ==
1091 reinterpret_cast<DiscardVirtualMemoryFunction>(-1))
1092 discard_virtual_memory =
1093 reinterpret_cast<DiscardVirtualMemoryFunction>(GetProcAddress(
1094 GetModuleHandle(L"Kernel32.dll"), "DiscardVirtualMemory"));
1095 // Use DiscardVirtualMemory when available because it releases faster than
1096 // MEM_RESET.
1097 DiscardVirtualMemoryFunction discard_function = discard_virtual_memory.load();
1098 if (discard_function) {
1099 DWORD ret = discard_function(address, size);
1100 if (!ret) return true;
1101 }
1102 // DiscardVirtualMemory is buggy in Win10 SP0, so fall back to MEM_RESET on
1103 // failure.
1104 void* ptr = VirtualAllocWrapper(address, size, MEM_RESET, PAGE_READWRITE);
1105 CHECK(ptr);
1106 return ptr;
1107}
1108
1109// static
1110bool OS::DecommitPages(void* address, size_t size) {
1111 DCHECK_EQ(0, reinterpret_cast<uintptr_t>(address) % CommitPageSize());
1112 DCHECK_EQ(0, size % CommitPageSize());
1113 // https://docs.microsoft.com/en-us/windows/win32/api/memoryapi/nf-memoryapi-virtualfree:
1114 // "If a page is decommitted but not released, its state changes to reserved.
1115 // Subsequently, you can call VirtualAlloc to commit it, or VirtualFree to
1116 // release it. Attempts to read from or write to a reserved page results in an
1117 // access violation exception."
1118 // https://docs.microsoft.com/en-us/windows/win32/api/memoryapi/nf-memoryapi-virtualalloc
1119 // for MEM_COMMIT: "The function also guarantees that when the caller later
1120 // initially accesses the memory, the contents will be zero."
1121 return VirtualFree(address, size, MEM_DECOMMIT) != 0;
1122}
1123
1124// static
1125bool OS::SealPages(void* address, size_t size) { return false; }
1126
1127// static
1129 return VirtualAlloc2 != nullptr && MapViewOfFile3 != nullptr &&
1130 UnmapViewOfFile2 != nullptr;
1131}
1132
1133// static
1134std::optional<AddressSpaceReservation> OS::CreateAddressSpaceReservation(
1135 void* hint, size_t size, size_t alignment,
1136 MemoryPermission max_permission) {
1138
1139 size_t page_size = AllocatePageSize();
1140 DCHECK_EQ(0, size % page_size);
1141 DCHECK_EQ(0, alignment % page_size);
1142 DCHECK_LE(page_size, alignment);
1143 hint = AlignedAddress(hint, alignment);
1144
1145 // On Windows, address space reservations are backed by placeholder mappings.
1146 void* reservation =
1147 AllocateInternal(hint, size, alignment, page_size,
1148 MEM_RESERVE | MEM_RESERVE_PLACEHOLDER, PAGE_NOACCESS);
1149 if (!reservation) return {};
1150
1151 return AddressSpaceReservation(reservation, size);
1152}
1153
1154// static
1155void OS::FreeAddressSpaceReservation(AddressSpaceReservation reservation) {
1156 OS::Free(reservation.base(), reservation.size());
1157}
1158
1159// static
1161 HANDLE handle = CreateFileMapping(INVALID_HANDLE_VALUE, nullptr,
1162 PAGE_READWRITE, 0, size, nullptr);
1163 if (!handle) return kInvalidSharedMemoryHandle;
1164 return SharedMemoryHandleFromFileMapping(handle);
1165}
1166
1167// static
1170 HANDLE file_mapping = FileMappingFromSharedMemoryHandle(handle);
1171 CHECK(CloseHandle(file_mapping));
1172}
1173
1174// static
1175bool OS::HasLazyCommits() {
1176 // TODO(alph): implement for the platform.
1177 return false;
1178}
1179
1180void OS::Sleep(TimeDelta interval) {
1181 ::Sleep(static_cast<DWORD>(interval.InMilliseconds()));
1182}
1183
1187 Close();
1188 timer_ = other.timer_;
1189 other.timer_ = NULL;
1190}
1192 V8_NOEXCEPT {
1193 Close();
1194 timer_ = other.timer_;
1195 other.timer_ = NULL;
1196 return *this;
1197}
1198bool PreciseSleepTimer::IsInitialized() const { return timer_ != NULL; }
1200 if (timer_ != NULL) {
1201 CloseHandle(timer_);
1202 timer_ = NULL;
1203 }
1204}
1205
1207 Close();
1208 // This flag allows precise sleep times, but is only available since Windows
1209 // 10 version 1803.
1210 DWORD flags = CREATE_WAITABLE_TIMER_HIGH_RESOLUTION;
1211 // The TIMER_MODIFY_STATE permission allows setting the timer, and SYNCHRONIZE
1212 // allows waiting for it.
1213 DWORD desired_access = TIMER_MODIFY_STATE | SYNCHRONIZE;
1214 timer_ =
1215 CreateWaitableTimerExW(NULL, // Cannot be inherited by child processes
1216 NULL, // Cannot be looked up by name
1217 flags, desired_access);
1218}
1219
1221 // Time is specified in 100 nanosecond intervals. Negative values indicate
1222 // relative time.
1223 LARGE_INTEGER due_time;
1224 due_time.QuadPart = -interval.InMicroseconds() * 10;
1225 LONG period = 0; // Not periodic; wake only once
1226 PTIMERAPCROUTINE completion_routine = NULL;
1227 LPVOID arg_to_completion_routine = NULL;
1228 BOOL resume = false; // No need to wake system from sleep
1229 CHECK(SetWaitableTimer(timer_, &due_time, period, completion_routine,
1230 arg_to_completion_routine, resume));
1231
1232 DWORD timeout_interval = INFINITE; // Return only when the object is signaled
1233 CHECK_EQ(WAIT_OBJECT_0, WaitForSingleObject(timer_, timeout_interval));
1234}
1235
1236void OS::Abort() {
1237 // Give a chance to debug the failure.
1238 if (IsDebuggerPresent()) {
1239 DebugBreak();
1240 }
1241
1242 // Before aborting, make sure to flush output buffers.
1243 fflush(stdout);
1244 fflush(stderr);
1245
1246 switch (g_abort_mode) {
1248 ExitProcess(0);
1250 ExitProcess(-1);
1254 break;
1255 }
1256
1257 // Make sure function doesn't return.
1258 ExitProcess(3);
1259}
1260
1261
1262void OS::DebugBreak() {
1263#if V8_CC_MSVC
1264 // To avoid Visual Studio runtime support the following code can be used
1265 // instead
1266 // __asm { int 3 }
1267 __debugbreak();
1268#else
1269 ::DebugBreak();
1270#endif
1271}
1272
1273
1275 public:
1276 Win32MemoryMappedFile(HANDLE file, HANDLE file_mapping, void* memory,
1277 size_t size)
1278 : file_(file),
1279 file_mapping_(file_mapping),
1280 memory_(memory),
1281 size_(size) {}
1282 ~Win32MemoryMappedFile() final;
1283 void* memory() const final { return memory_; }
1284 size_t size() const final { return size_; }
1285
1286 private:
1289 void* const memory_;
1290 size_t const size_;
1291};
1292
1293
1294// static
1296 FileMode mode) {
1297 // Open a physical file.
1298 DWORD access = GENERIC_READ;
1299 if (mode == FileMode::kReadWrite) {
1300 access |= GENERIC_WRITE;
1301 }
1302
1303 std::wstring utf16_name = ConvertUtf8StringToUtf16(name);
1304 HANDLE file = CreateFileW(utf16_name.c_str(), access,
1305 FILE_SHARE_READ | FILE_SHARE_WRITE, nullptr,
1306 OPEN_EXISTING, 0, nullptr);
1307 if (file == INVALID_HANDLE_VALUE) return nullptr;
1308
1309 DWORD size = GetFileSize(file, nullptr);
1310 if (size == 0) return new Win32MemoryMappedFile(file, nullptr, nullptr, 0);
1311
1312 DWORD protection =
1313 (mode == FileMode::kReadOnly) ? PAGE_READONLY : PAGE_READWRITE;
1314 // Create a file mapping for the physical file.
1315 HANDLE file_mapping =
1316 CreateFileMapping(file, nullptr, protection, 0, size, nullptr);
1317 if (file_mapping == nullptr) return nullptr;
1318
1319 // Map a view of the file into memory.
1320 DWORD view_access =
1321 (mode == FileMode::kReadOnly) ? FILE_MAP_READ : FILE_MAP_ALL_ACCESS;
1322 void* memory = MapViewOfFile(file_mapping, view_access, 0, 0, size);
1323 return new Win32MemoryMappedFile(file, file_mapping, memory, size);
1324}
1325
1326// static
1328 size_t size, void* initial) {
1329 std::wstring utf16_name = ConvertUtf8StringToUtf16(name);
1330 // Open a physical file.
1331 HANDLE file = CreateFileW(utf16_name.c_str(), GENERIC_READ | GENERIC_WRITE,
1332 FILE_SHARE_READ | FILE_SHARE_WRITE, nullptr,
1333 OPEN_ALWAYS, 0, nullptr);
1334 if (file == nullptr) return nullptr;
1335 if (size == 0) return new Win32MemoryMappedFile(file, nullptr, nullptr, 0);
1336 // Create a file mapping for the physical file.
1337 HANDLE file_mapping = CreateFileMapping(file, nullptr, PAGE_READWRITE, 0,
1338 static_cast<DWORD>(size), nullptr);
1339 if (file_mapping == nullptr) return nullptr;
1340 // Map a view of the file into memory.
1341 void* memory = MapViewOfFile(file_mapping, FILE_MAP_ALL_ACCESS, 0, 0, size);
1342 if (memory) memmove(memory, initial, size);
1343 return new Win32MemoryMappedFile(file, file_mapping, memory, size);
1344}
1345
1346
1348 if (memory_) UnmapViewOfFile(memory_);
1349 if (file_mapping_) CloseHandle(file_mapping_);
1350 CloseHandle(file_);
1351}
1352
1353std::optional<AddressSpaceReservation>
1355 void* address, size_t size, OS::MemoryPermission max_permission) {
1356 // Nothing to do, the sub reservation must already have been split by now.
1357 DCHECK(Contains(address, size));
1358 DCHECK_EQ(0, size % OS::AllocatePageSize());
1359 DCHECK_EQ(0, reinterpret_cast<uintptr_t>(address) % OS::AllocatePageSize());
1360
1361 return AddressSpaceReservation(address, size);
1362}
1363
1365 AddressSpaceReservation reservation) {
1366 // Nothing to do.
1367 // Pages allocated inside the reservation must've already been freed.
1368 return true;
1369}
1370
1371bool AddressSpaceReservation::SplitPlaceholder(void* address, size_t size) {
1372 DCHECK(Contains(address, size));
1373 return VirtualFree(address, size, MEM_RELEASE | MEM_PRESERVE_PLACEHOLDER);
1374}
1375
1376bool AddressSpaceReservation::MergePlaceholders(void* address, size_t size) {
1377 DCHECK(Contains(address, size));
1378 return VirtualFree(address, size, MEM_RELEASE | MEM_COALESCE_PLACEHOLDERS);
1379}
1380
1381bool AddressSpaceReservation::Allocate(void* address, size_t size,
1382 OS::MemoryPermission access) {
1383 DCHECK(Contains(address, size));
1385 DWORD flags = (access == OS::MemoryPermission::kNoAccess)
1386 ? MEM_RESERVE | MEM_REPLACE_PLACEHOLDER
1387 : MEM_RESERVE | MEM_COMMIT | MEM_REPLACE_PLACEHOLDER;
1388 DWORD protect = GetProtectionFromMemoryPermission(access);
1389 return VirtualAlloc2(GetCurrentProcess(), address, size, flags, protect,
1390 nullptr, 0);
1391}
1392
1393bool AddressSpaceReservation::Free(void* address, size_t size) {
1394 DCHECK(Contains(address, size));
1395 return VirtualFree(address, size, MEM_RELEASE | MEM_PRESERVE_PLACEHOLDER);
1396}
1397
1398bool AddressSpaceReservation::AllocateShared(void* address, size_t size,
1399 OS::MemoryPermission access,
1401 uint64_t offset) {
1402 DCHECK(Contains(address, size));
1404
1405 DWORD protect = GetProtectionFromMemoryPermission(access);
1406 HANDLE file_mapping = FileMappingFromSharedMemoryHandle(handle);
1407 return MapViewOfFile3(file_mapping, GetCurrentProcess(), address, offset,
1408 size, MEM_REPLACE_PLACEHOLDER, protect, nullptr, 0);
1409}
1410
1411bool AddressSpaceReservation::FreeShared(void* address, size_t size) {
1412 DCHECK(Contains(address, size));
1414
1415 return UnmapViewOfFile2(GetCurrentProcess(), address,
1416 MEM_PRESERVE_PLACEHOLDER);
1417}
1418
1419bool AddressSpaceReservation::SetPermissions(void* address, size_t size,
1420 OS::MemoryPermission access) {
1421 DCHECK(Contains(address, size));
1422 return OS::SetPermissions(address, size, access);
1423}
1424
1425bool AddressSpaceReservation::RecommitPages(void* address, size_t size,
1426 OS::MemoryPermission access) {
1427 DCHECK(Contains(address, size));
1428 return OS::RecommitPages(address, size, access);
1429}
1430
1431bool AddressSpaceReservation::DiscardSystemPages(void* address, size_t size) {
1432 DCHECK(Contains(address, size));
1433 return OS::DiscardSystemPages(address, size);
1434}
1435
1436bool AddressSpaceReservation::DecommitPages(void* address, size_t size) {
1437 DCHECK(Contains(address, size));
1438 return OS::DecommitPages(address, size);
1439}
1440
1441// The following code loads functions defined in DbhHelp.h and TlHelp32.h
1442// dynamically. This is to avoid being depending on dbghelp.dll and
1443// tlhelp32.dll when running (the functions in tlhelp32.dll have been moved to
1444// kernel32.dll at some point so loading functions defines in TlHelp32.h
1445// dynamically might not be necessary any more - for some versions of Windows?).
1446
1447// Function pointers to functions dynamically loaded from dbghelp.dll.
1448#define DBGHELP_FUNCTION_LIST(V) \
1449 V(SymInitialize) \
1450 V(SymGetOptions) \
1451 V(SymSetOptions) \
1452 V(SymGetSearchPath) \
1453 V(SymLoadModule64) \
1454 V(StackWalk64) \
1455 V(SymGetSymFromAddr64) \
1456 V(SymGetLineFromAddr64) \
1457 V(SymFunctionTableAccess64) \
1458 V(SymGetModuleBase64)
1459
1460// Function pointers to functions dynamically loaded from dbghelp.dll.
1461#define TLHELP32_FUNCTION_LIST(V) \
1462 V(CreateToolhelp32Snapshot) \
1463 V(Module32FirstW) \
1464 V(Module32NextW)
1465
1466// Define the decoration to use for the type and variable name used for
1467// dynamically loaded DLL function..
1468#define DLL_FUNC_TYPE(name) _##name##_
1469#define DLL_FUNC_VAR(name) _##name
1470
1471// Define the type for each dynamically loaded DLL function. The function
1472// definitions are copied from DbgHelp.h and TlHelp32.h. The IN and VOID macros
1473// from the Windows include files are redefined here to have the function
1474// definitions to be as close to the ones in the original .h files as possible.
1475#ifndef IN
1476#define IN
1477#endif
1478#ifndef VOID
1479#define VOID void
1480#endif
1481
1482// DbgHelp isn't supported on MinGW yet
1483#ifndef __MINGW32__
1484// DbgHelp.h functions.
1485using DLL_FUNC_TYPE(SymInitialize) = BOOL(__stdcall*)(IN HANDLE hProcess,
1486 IN PSTR UserSearchPath,
1487 IN BOOL fInvadeProcess);
1488using DLL_FUNC_TYPE(SymGetOptions) = DWORD(__stdcall*)(VOID);
1489using DLL_FUNC_TYPE(SymSetOptions) = DWORD(__stdcall*)(IN DWORD SymOptions);
1490using DLL_FUNC_TYPE(SymGetSearchPath) = BOOL(__stdcall*)(
1491 IN HANDLE hProcess, OUT PSTR SearchPath, IN DWORD SearchPathLength);
1492using DLL_FUNC_TYPE(SymLoadModule64) = DWORD64(__stdcall*)(
1493 IN HANDLE hProcess, IN HANDLE hFile, IN PSTR ImageName, IN PSTR ModuleName,
1494 IN DWORD64 BaseOfDll, IN DWORD SizeOfDll);
1495using DLL_FUNC_TYPE(StackWalk64) = BOOL(__stdcall*)(
1496 DWORD MachineType, HANDLE hProcess, HANDLE hThread,
1497 LPSTACKFRAME64 StackFrame, PVOID ContextRecord,
1498 PREAD_PROCESS_MEMORY_ROUTINE64 ReadMemoryRoutine,
1499 PFUNCTION_TABLE_ACCESS_ROUTINE64 FunctionTableAccessRoutine,
1500 PGET_MODULE_BASE_ROUTINE64 GetModuleBaseRoutine,
1501 PTRANSLATE_ADDRESS_ROUTINE64 TranslateAddress);
1502using DLL_FUNC_TYPE(SymGetSymFromAddr64) = BOOL(__stdcall*)(
1503 IN HANDLE hProcess, IN DWORD64 qwAddr, OUT PDWORD64 pdwDisplacement,
1504 OUT PIMAGEHLP_SYMBOL64 Symbol);
1505using DLL_FUNC_TYPE(SymGetLineFromAddr64) =
1506 BOOL(__stdcall*)(IN HANDLE hProcess, IN DWORD64 qwAddr,
1507 OUT PDWORD pdwDisplacement, OUT PIMAGEHLP_LINE64 Line64);
1508// DbgHelp.h typedefs. Implementation found in dbghelp.dll.
1509using DLL_FUNC_TYPE(SymFunctionTableAccess64) = PVOID(__stdcall*)(
1510 HANDLE hProcess,
1511 DWORD64 AddrBase); // DbgHelp.h typedef PFUNCTION_TABLE_ACCESS_ROUTINE64
1512using DLL_FUNC_TYPE(SymGetModuleBase64) = DWORD64(__stdcall*)(
1513 HANDLE hProcess,
1514 DWORD64 AddrBase); // DbgHelp.h typedef PGET_MODULE_BASE_ROUTINE64
1515
1516// TlHelp32.h functions.
1517using DLL_FUNC_TYPE(CreateToolhelp32Snapshot) =
1518 HANDLE(__stdcall*)(DWORD dwFlags, DWORD th32ProcessID);
1519using DLL_FUNC_TYPE(Module32FirstW) = BOOL(__stdcall*)(HANDLE hSnapshot,
1520 LPMODULEENTRY32W lpme);
1521using DLL_FUNC_TYPE(Module32NextW) = BOOL(__stdcall*)(HANDLE hSnapshot,
1522 LPMODULEENTRY32W lpme);
1523
1524#undef IN
1525#undef VOID
1526
1527// Declare a variable for each dynamically loaded DLL function.
1528#define DEF_DLL_FUNCTION(name) DLL_FUNC_TYPE(name) DLL_FUNC_VAR(name) = nullptr;
1531#undef DEF_DLL_FUNCTION
1532
1533// Load the functions. This function has a lot of "ugly" macros in order to
1534// keep down code duplication.
1535
1537 static bool dbghelp_loaded = false;
1538
1539 if (dbghelp_loaded) return true;
1540
1541 HMODULE module;
1542
1543 // Load functions from the dbghelp.dll module.
1544 module = LoadLibrary(TEXT("dbghelp.dll"));
1545 if (module == nullptr) {
1546 return false;
1547 }
1548
1549#define LOAD_DLL_FUNC(name) \
1550 DLL_FUNC_VAR(name) = \
1551 reinterpret_cast<DLL_FUNC_TYPE(name)>(GetProcAddress(module, #name));
1552
1554
1555#undef LOAD_DLL_FUNC
1556
1557 // Load functions from the kernel32.dll module (the TlHelp32.h function used
1558 // to be in tlhelp32.dll but are now moved to kernel32.dll).
1559 module = LoadLibrary(TEXT("kernel32.dll"));
1560 if (module == nullptr) {
1561 return false;
1562 }
1563
1564#define LOAD_DLL_FUNC(name) \
1565 DLL_FUNC_VAR(name) = \
1566 reinterpret_cast<DLL_FUNC_TYPE(name)>(GetProcAddress(module, #name));
1567
1569
1570#undef LOAD_DLL_FUNC
1571
1572 // Check that all functions where loaded.
1573bool result =
1574#define DLL_FUNC_LOADED(name) (DLL_FUNC_VAR(name) != nullptr)&&
1575
1578
1579#undef DLL_FUNC_LOADED
1580 true;
1581
1582 dbghelp_loaded = result;
1583 return result;
1584 // NOTE: The modules are never unloaded and will stay around until the
1585 // application is closed.
1586}
1587
1588#undef DBGHELP_FUNCTION_LIST
1589#undef TLHELP32_FUNCTION_LIST
1590#undef DLL_FUNC_VAR
1591#undef DLL_FUNC_TYPE
1592
1593
1594// Load the symbols for generating stack traces.
1595static std::vector<OS::SharedLibraryAddress> LoadSymbols(
1596 HANDLE process_handle) {
1597 static std::vector<OS::SharedLibraryAddress> result;
1598
1599 static bool symbols_loaded = false;
1600
1601 if (symbols_loaded) return result;
1602
1603 BOOL ok;
1604
1605 // Initialize the symbol engine.
1606 ok = _SymInitialize(process_handle, // hProcess
1607 nullptr, // UserSearchPath
1608 false); // fInvadeProcess
1609 if (!ok) return result;
1610
1611 DWORD options = _SymGetOptions();
1612 options |= SYMOPT_LOAD_LINES;
1613 options |= SYMOPT_FAIL_CRITICAL_ERRORS;
1614 options = _SymSetOptions(options);
1615
1616 char buf[OS::kStackWalkMaxNameLen] = {0};
1617 ok = _SymGetSearchPath(process_handle, buf, OS::kStackWalkMaxNameLen);
1618 if (!ok) {
1619 int err = GetLastError();
1620 OS::Print("%d\n", err);
1621 return result;
1622 }
1623
1624 HANDLE snapshot = _CreateToolhelp32Snapshot(
1625 TH32CS_SNAPMODULE, // dwFlags
1626 GetCurrentProcessId()); // th32ProcessId
1627 if (snapshot == INVALID_HANDLE_VALUE) return result;
1628 MODULEENTRY32W module_entry;
1629 module_entry.dwSize = sizeof(module_entry); // Set the size of the structure.
1630 BOOL cont = _Module32FirstW(snapshot, &module_entry);
1631 while (cont) {
1632 DWORD64 base;
1633 // NOTE the SymLoadModule64 function has the peculiarity of accepting a
1634 // both unicode and ASCII strings even though the parameter is PSTR.
1635 base = _SymLoadModule64(
1636 process_handle, // hProcess
1637 0, // hFile
1638 reinterpret_cast<PSTR>(module_entry.szExePath), // ImageName
1639 reinterpret_cast<PSTR>(module_entry.szModule), // ModuleName
1640 reinterpret_cast<DWORD64>(module_entry.modBaseAddr), // BaseOfDll
1641 module_entry.modBaseSize); // SizeOfDll
1642 if (base == 0) {
1643 int err = GetLastError();
1644 if (err != ERROR_MOD_NOT_FOUND &&
1645 err != ERROR_INVALID_HANDLE) {
1646 result.clear();
1647 return result;
1648 }
1649 }
1650 int lib_name_length = WideCharToMultiByte(
1651 CP_UTF8, 0, module_entry.szExePath, -1, nullptr, 0, nullptr, nullptr);
1652 std::string lib_name(lib_name_length, 0);
1653 WideCharToMultiByte(CP_UTF8, 0, module_entry.szExePath, -1, &lib_name[0],
1654 lib_name_length, nullptr, nullptr);
1656 lib_name, reinterpret_cast<uintptr_t>(module_entry.modBaseAddr),
1657 reinterpret_cast<uintptr_t>(module_entry.modBaseAddr +
1658 module_entry.modBaseSize)));
1659 cont = _Module32NextW(snapshot, &module_entry);
1660 }
1661 CloseHandle(snapshot);
1662
1663 symbols_loaded = true;
1664 return result;
1665}
1666
1667
1668std::vector<OS::SharedLibraryAddress> OS::GetSharedLibraryAddresses() {
1669 // SharedLibraryEvents are logged when loading symbol information.
1670 // Only the shared libraries loaded at the time of the call to
1671 // GetSharedLibraryAddresses are logged. DLLs loaded after
1672 // initialization are not accounted for.
1673 if (!LoadDbgHelpAndTlHelp32()) return std::vector<OS::SharedLibraryAddress>();
1674 HANDLE process_handle = GetCurrentProcess();
1675 return LoadSymbols(process_handle);
1676}
1677
1678void OS::SignalCodeMovingGC() {}
1679
1680#else // __MINGW32__
1681std::vector<OS::SharedLibraryAddress> OS::GetSharedLibraryAddresses() {
1682 return std::vector<OS::SharedLibraryAddress>();
1683}
1684
1685void OS::SignalCodeMovingGC() {}
1686#endif // __MINGW32__
1687
1688
1690#ifdef _WIN64
1691 return 16; // Windows 64-bit ABI requires the stack to be 16-byte aligned.
1692#elif defined(__MINGW32__)
1693 // With gcc 4.4 the tree vectorization optimizer can generate code
1694 // that requires 16 byte alignment such as movdqa on x86.
1695 return 16;
1696#else
1697 return 8; // Floating-point math runs faster with 8-byte alignment.
1698#endif
1699}
1700
1701#if defined(V8_OS_WIN)
1702void EnsureConsoleOutputWin32() {
1703 UINT new_flags =
1704 SEM_FAILCRITICALERRORS | SEM_NOGPFAULTERRORBOX | SEM_NOOPENFILEERRORBOX;
1705 UINT existing_flags = SetErrorMode(new_flags);
1706 SetErrorMode(existing_flags | new_flags);
1707#if defined(_MSC_VER)
1708 _CrtSetReportMode(_CRT_WARN, _CRTDBG_MODE_DEBUG | _CRTDBG_MODE_FILE);
1709 _CrtSetReportFile(_CRT_WARN, _CRTDBG_FILE_STDERR);
1710 _CrtSetReportMode(_CRT_ASSERT, _CRTDBG_MODE_DEBUG | _CRTDBG_MODE_FILE);
1711 _CrtSetReportFile(_CRT_ASSERT, _CRTDBG_FILE_STDERR);
1712 _CrtSetReportMode(_CRT_ERROR, _CRTDBG_MODE_DEBUG | _CRTDBG_MODE_FILE);
1713 _CrtSetReportFile(_CRT_ERROR, _CRTDBG_FILE_STDERR);
1714 _set_error_mode(_OUT_TO_STDERR);
1715#endif // defined(_MSC_VER)
1716}
1717#endif // defined(V8_OS_WIN)
1718
1719// ----------------------------------------------------------------------------
1720// Win32 thread support.
1721
1722// Definition of invalid thread handle and id.
1723static const HANDLE kNoThread = INVALID_HANDLE_VALUE;
1724
1725// Entry point for threads. The supplied argument is a pointer to the thread
1726// object. The entry function dispatches to the run method in the thread
1727// object. It is important that this function has __stdcall calling
1728// convention.
1729static unsigned int __stdcall ThreadEntry(void* arg) {
1730 Thread* thread = reinterpret_cast<Thread*>(arg);
1731 thread->NotifyStartedAndRun();
1732 return 0;
1733}
1734
1735
1737 public:
1738 explicit PlatformData(HANDLE thread) : thread_(thread) {}
1740 unsigned thread_id_;
1741};
1742
1743
1744// Initialize a Win32 thread object. The thread has an invalid thread
1745// handle until it is started.
1746
1747Thread::Thread(const Options& options)
1748 : stack_size_(options.stack_size()), start_semaphore_(nullptr) {
1750 set_name(options.name());
1751}
1752
1753
1754void Thread::set_name(const char* name) {
1755 OS::StrNCpy(name_, sizeof(name_), name, strlen(name));
1756 name_[sizeof(name_) - 1] = '\0';
1757}
1758
1759
1760// Close our own handle for the thread.
1762 if (data_->thread_ != kNoThread) CloseHandle(data_->thread_);
1763 delete data_;
1764}
1765
1766
1767// Create a new thread. It is important to use _beginthreadex() instead of
1768// the Win32 function CreateThread(), because the CreateThread() does not
1769// initialize thread specific structures in the C runtime library.
1770bool Thread::Start() {
1771 uintptr_t result = _beginthreadex(nullptr, static_cast<unsigned>(stack_size_),
1772 ThreadEntry, this, 0, &data_->thread_id_);
1773 data_->thread_ = reinterpret_cast<HANDLE>(result);
1774 return result != 0;
1775}
1776
1777// Wait for thread to terminate.
1778void Thread::Join() {
1779 if (data_->thread_id_ != GetCurrentThreadId()) {
1780 WaitForSingleObject(data_->thread_, INFINITE);
1781 }
1782}
1783
1784
1786 DWORD result = TlsAlloc();
1787 DCHECK(result != TLS_OUT_OF_INDEXES);
1788 return static_cast<LocalStorageKey>(result);
1789}
1790
1791
1793 BOOL result = TlsFree(static_cast<DWORD>(key));
1794 USE(result);
1795 DCHECK(result);
1796}
1797
1798
1800 return TlsGetValue(static_cast<DWORD>(key));
1801}
1802
1803
1804void Thread::SetThreadLocal(LocalStorageKey key, void* value) {
1805 BOOL result = TlsSetValue(static_cast<DWORD>(key), value);
1806 USE(result);
1807 DCHECK(result);
1808}
1809
1811
1812std::optional<OS::MemoryRange> OS::GetFirstFreeMemoryRangeWithin(
1813 OS::Address boundary_start, OS::Address boundary_end, size_t minimum_size,
1814 size_t alignment) {
1815 // Search for the virtual memory (vm) ranges within the boundary.
1816 // If a range is free and larger than {minimum_size}, then push it to the
1817 // returned vector.
1818 uintptr_t vm_start = RoundUp(boundary_start, alignment);
1819 uintptr_t vm_end = 0;
1820 MEMORY_BASIC_INFORMATION mi;
1821 // This loop will terminate once the scanning reaches the higher address
1822 // to the end of boundary or the function VirtualQuery fails.
1823 while (vm_start < boundary_end &&
1824 VirtualQuery(reinterpret_cast<LPCVOID>(vm_start), &mi, sizeof(mi)) !=
1825 0) {
1826 vm_start = reinterpret_cast<uintptr_t>(mi.BaseAddress);
1827 vm_end = vm_start + mi.RegionSize;
1828 if (mi.State == MEM_FREE) {
1829 // The available area is the overlap of the virtual memory range and
1830 // boundary. Push the overlapped memory range to the vector if there is
1831 // enough space.
1832 const uintptr_t overlap_start =
1833 RoundUp(std::max(vm_start, boundary_start), alignment);
1834 const uintptr_t overlap_end =
1835 RoundDown(std::min(vm_end, boundary_end), alignment);
1836 if (overlap_start < overlap_end &&
1837 overlap_end - overlap_start >= minimum_size) {
1838 return OS::MemoryRange{overlap_start, overlap_end};
1839 }
1840 }
1841 // Continue to visit the next virtual memory range.
1842 vm_start = vm_end;
1843 }
1844
1845 return {};
1846}
1847
1848// static
1849Stack::StackSlot Stack::ObtainCurrentThreadStackStart() {
1850#if defined(V8_TARGET_ARCH_X64)
1851 return reinterpret_cast<void*>(
1852 reinterpret_cast<NT_TIB64*>(NtCurrentTeb())->StackBase);
1853#elif defined(V8_TARGET_ARCH_32_BIT)
1854 return reinterpret_cast<void*>(
1855 reinterpret_cast<NT_TIB*>(NtCurrentTeb())->StackBase);
1856#elif defined(V8_TARGET_ARCH_ARM64)
1857 // Windows 8 and later, see
1858 // https://docs.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-getcurrentthreadstacklimits
1859 ULONG_PTR lowLimit, highLimit;
1860 ::GetCurrentThreadStackLimits(&lowLimit, &highLimit);
1861 return reinterpret_cast<void*>(highLimit);
1862#else
1863#error Unsupported ObtainCurrentThreadStackStart.
1864#endif
1865}
1866
1867// static
1868Stack::StackSlot Stack::GetCurrentStackPosition() {
1869#if V8_CC_MSVC
1870 return _AddressOfReturnAddress();
1871#else
1872 return __builtin_frame_address(0);
1873#endif
1874}
1875
1876} // namespace base
1877} // namespace v8
constexpr int kPageSizeBits
V8_WARN_UNUSED_RESULT bool DiscardSystemPages(void *address, size_t size)
V8_WARN_UNUSED_RESULT bool Allocate(void *address, size_t size, OS::MemoryPermission access)
V8_WARN_UNUSED_RESULT bool RecommitPages(void *address, size_t size, OS::MemoryPermission access)
V8_WARN_UNUSED_RESULT bool Free(void *address, size_t size)
V8_WARN_UNUSED_RESULT bool SetPermissions(void *address, size_t size, OS::MemoryPermission access)
V8_WARN_UNUSED_RESULT bool DecommitPages(void *address, size_t size)
V8_WARN_UNUSED_RESULT bool FreeShared(void *address, size_t size)
V8_WARN_UNUSED_RESULT std::optional< AddressSpaceReservation > CreateSubReservation(void *address, size_t size, OS::MemoryPermission max_permission)
V8_WARN_UNUSED_RESULT bool AllocateShared(void *address, size_t size, OS::MemoryPermission access, PlatformSharedMemoryHandle handle, uint64_t offset)
static V8_WARN_UNUSED_RESULT bool FreeSubReservation(AddressSpaceReservation reservation)
static MemoryMappedFile * create(const char *name, size_t size, void *initial)
static MemoryMappedFile * open(const char *name, FileMode mode=FileMode::kReadWrite)
static void Sleep(TimeDelta interval)
static V8_WARN_UNUSED_RESULT void * AllocateShared(size_t size, MemoryPermission access)
static void * GetRandomMmapAddr()
static V8_WARN_UNUSED_RESULT bool SealPages(void *address, size_t size)
static void SignalCodeMovingGC()
static static va_list args
Definition platform.h:200
static bool HasLazyCommits()
static V8_WARN_UNUSED_RESULT bool CanReserveAddressSpace()
static V8_WARN_UNUSED_RESULT bool DiscardSystemPages(void *address, size_t size)
static size_t AllocatePageSize()
static void ExitProcess(int exit_code)
static void SetDataReadOnly(void *address, size_t size)
static void Abort()
static bool IsHardwareEnforcedShadowStacksEnabled()
static void FreeAddressSpaceReservation(AddressSpaceReservation reservation)
static const char *const LogFileOpenMode
Definition platform.h:194
static const int kStackWalkMaxNameLen
Definition platform.h:244
static int GetCurrentThreadIdInternal()
static int GetLastError()
static PlatformSharedMemoryHandle CreateSharedMemoryHandleForTesting(size_t size)
static void FreeShared(void *address, size_t size)
static V8_WARN_UNUSED_RESULT bool SetPermissions(void *address, size_t size, MemoryPermission access)
static FILE * OpenTemporaryFile()
static FILE * FOpen(const char *path, const char *mode)
static void Initialize(AbortMode abort_mode, const char *const gc_fake_mmap)
static V8_WARN_UNUSED_RESULT bool DecommitPages(void *address, size_t size)
static int GetCurrentProcessId()
static size_t CommitPageSize()
static int GetPeakMemoryUsageKb()
static void Release(void *address, size_t size)
static V8_WARN_UNUSED_RESULT bool RecommitPages(void *address, size_t size, MemoryPermission access)
static std::vector< SharedLibraryAddress > GetSharedLibraryAddresses()
static char DirectorySeparator()
static void StrNCpy(char *dest, int length, const char *src, size_t n)
static int GetUserTime(uint32_t *secs, uint32_t *usecs)
static int GetCurrentThreadId()
Definition platform.cc:29
static int ActivationFrameAlignment()
uintptr_t Address
Definition platform.h:315
static V8_WARN_UNUSED_RESULT void * Allocate(void *address, size_t size, size_t alignment, MemoryPermission access)
static void DestroySharedMemoryHandle(PlatformSharedMemoryHandle handle)
static TimezoneCache * CreateTimezoneCache()
static double TimeCurrentMillis()
static int length
Definition platform.h:267
static bool isDirectorySeparator(const char ch)
static void SetRandomMmapSeed(int64_t seed)
friend class MemoryMappedFile
Definition platform.h:365
static V8_WARN_UNUSED_RESULT std::optional< AddressSpaceReservation > CreateAddressSpaceReservation(void *hint, size_t size, size_t alignment, MemoryPermission max_permission)
friend class AddressSpaceReservation
Definition platform.h:364
static void Free(void *address, size_t size)
static std::optional< MemoryRange > GetFirstFreeMemoryRangeWithin(Address boundary_start, Address boundary_end, size_t minimum_size, size_t alignment)
static bool Remove(const char *path)
static void AdjustSchedulingParams()
static void DebugBreak()
void Sleep(TimeDelta interval) const
PreciseSleepTimer & operator=(const PreciseSleepTimer &other)=delete
static V8_NOINLINE StackSlot GetCurrentStackPosition()
static Stack::StackSlot ObtainCurrentThreadStackStart()
Thread(const Options &options)
V8_WARN_UNUSED_RESULT bool Start()
int32_t LocalStorageKey
Definition platform.h:541
static void DeleteThreadLocalKey(LocalStorageKey key)
PlatformData * data_
Definition platform.h:633
static LocalStorageKey CreateThreadLocalKey()
static void * GetThreadLocal(LocalStorageKey key)
void set_name(const char *name)
char name_[kMaxThreadNameLength]
Definition platform.h:635
void NotifyStartedAndRun()
Definition platform.h:625
static void SetThreadLocal(LocalStorageKey key, void *value)
static Time Now()
double ToJsTime() const
Definition time.cc:502
Win32MemoryMappedFile(HANDLE file, HANDLE file_mapping, void *memory, size_t size)
static const int64_t kTimeScaler
bool InDST(WindowsTimezoneCache *cache)
static const bool kShortTzNames
int64_t LocalOffset(WindowsTimezoneCache *cache)
int64_t DaylightSavingsOffset(WindowsTimezoneCache *cache)
static const int64_t kMsPerMinute
char * LocalTimezone(WindowsTimezoneCache *cache)
static const int64_t kTimeEpoc
double LocalTimeOffset(double time, bool is_utc) override
const char * LocalTimezone(double time) override
void Clear(TimeZoneDetection) override
double DaylightSavingsOffset(double time) override
TIME_ZONE_INFORMATION tzinfo_
const char * GuessTimezoneNameFromBias(int bias)
uint32_t count
Handle< SharedFunctionInfo > info
refactor address components for immediate indexing make OptimizeMaglevOnNextCall optimize to turbofan instead of maglev filter for tracing turbofan compilation trace turbo cfg trace TurboFan s graph trimmer trace TurboFan s control equivalence trace TurboFan s register allocator trace stack load store counters for optimized code in run fuzzing &&concurrent_recompilation trace_turbo trace_turbo_scheduled trace_turbo_stack_accesses verify TurboFan machine graph of code stubs enable FixedArray bounds checks print TurboFan statistics of wasm compilations maximum cumulative size of bytecode considered for inlining scale factor of bytecode size used to calculate the inlining budget * KB
std::string filename
#define IMMEDIATE_CRASH()
int32_t offset
double hour
ZoneVector< RpoNumber > & result
#define DEFINE_LAZY_LEAKY_OBJECT_GETTER(T, FunctionName,...)
base::ElapsedTimer timer_
int n
Definition mul-fft.cc:296
#define LAZY_MUTEX_INITIALIZER
Definition mutex.h:105
MapViewOfFile3_t MapViewOfFile3
int GetProtectionFromMemoryPermission(OS::MemoryPermission access)
PVOID(__stdcall * VirtualAlloc2_t)(HANDLE, PVOID, SIZE_T, ULONG, ULONG, MEM_EXTENDED_PARAMETER *, ULONG)
@ kExitWithFailureAndIgnoreDcheckFailures
@ kExitWithSuccessAndIgnoreDcheckFailures
PVOID(__stdcall * MapViewOfFile3_t)(HANDLE, HANDLE, PVOID, ULONG64, SIZE_T, ULONG, ULONG, MEM_EXTENDED_PARAMETER *, ULONG)
static std::wstring ConvertUtf8StringToUtf16(const char *str)
static void * ThreadEntry(void *arg)
VirtualAlloc2_t VirtualAlloc2
static bool LoadDbgHelpAndTlHelp32()
UnmapViewOfFile2_t UnmapViewOfFile2
PVOID(__stdcall * UnmapViewOfFile2_t)(HANDLE, PVOID, ULONG)
static std::vector< OS::SharedLibraryAddress > LoadSymbols(HANDLE process_handle)
static bool HasConsole()
AbortMode g_abort_mode
Definition abort-mode.cc:10
V8_BASE_EXPORT int const char va_list args
Definition strings.h:23
LockGuard< Mutex > MutexGuard
Definition mutex.h:219
static OutputMode output_mode
static const pthread_t kNoThread
int VSNPrintF(Vector< char > str, const char *format, va_list args)
Definition strings.cc:16
static void VPrintHelper(FILE *stream, const char *format, va_list args)
V8_INLINE IndirectHandle< T > handle(Tagged< T > object, Isolate *isolate)
Definition handles-inl.h:72
static constexpr PlatformSharedMemoryHandle kInvalidSharedMemoryHandle
intptr_t PlatformSharedMemoryHandle
#define DLL_FUNC_LOADED(name)
#define TLHELP32_FUNCTION_LIST(V)
#define DEF_DLL_FUNCTION(name)
#define VOID
#define LOAD_DLL_FUNC(name)
#define IN
#define DLL_FUNC_TYPE(name)
#define DBGHELP_FUNCTION_LIST(V)
#define V8_NOEXCEPT
#define UNREACHABLE()
Definition logging.h:67
#define DCHECK_LE(v1, v2)
Definition logging.h:490
#define CHECK(condition)
Definition logging.h:124
#define CHECK_GT(lhs, rhs)
#define DCHECK_IMPLIES(v1, v2)
Definition logging.h:493
#define DCHECK_NE(v1, v2)
Definition logging.h:486
#define CHECK_NE(lhs, rhs)
#define CHECK_EQ(lhs, rhs)
#define DCHECK(condition)
Definition logging.h:482
#define DCHECK_EQ(v1, v2)
Definition logging.h:485
#define USE(...)
Definition macros.h:293
constexpr T RoundUp(T x, intptr_t m)
Definition macros.h:387
void * AlignedAddress(void *address, size_t alignment)
Definition macros.h:407
constexpr T RoundDown(T x, intptr_t m)
Definition macros.h:371
std::unique_ptr< ValueMirror > key
int BOOL
long LONG
void * PVOID
struct _RTL_CRITICAL_SECTION CRITICAL_SECTION
#define WINAPI
void * HANDLE
void * LPVOID
__w64 unsigned long ULONG_PTR
struct _RTL_SRWLOCK SRWLOCK
struct _RTL_CONDITION_VARIABLE CONDITION_VARIABLE
unsigned long DWORD