v8
V8 is Google’s open source high-performance JavaScript and WebAssembly engine, written in C++.
Loading...
Searching...
No Matches
platform-cygwin.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 Cygwin goes here. For the POSIX-compatible
6// parts, the implementation is in platform-posix.cc.
7
8#include <errno.h>
9#include <pthread.h>
10#include <semaphore.h>
11#include <stdarg.h>
12#include <strings.h> // index
13#include <sys/mman.h> // mmap & munmap
14#include <sys/time.h>
15#include <unistd.h> // sysconf
16
17#include <cmath>
18
19#undef MAP_TYPE
20
21#include "src/base/macros.h"
25
26namespace v8 {
27namespace base {
28
29namespace {
30
31// The memory allocation implementation is taken from platform-win32.cc.
32
34 switch (access) {
37 return PAGE_NOACCESS;
39 return PAGE_READONLY;
41 return PAGE_READWRITE;
43 return PAGE_EXECUTE_READWRITE;
45 return PAGE_EXECUTE_READ;
46 }
48}
49
50uint8_t* RandomizedVirtualAlloc(size_t size, DWORD flags, DWORD protect,
51 void* hint) {
52 LPVOID base = nullptr;
53
54 // For executable or reserved pages try to use the address hint.
55 if (protect != PAGE_READWRITE) {
56 base = VirtualAlloc(hint, size, flags, protect);
57 }
58
59 // If that fails, let the OS find an address to use.
60 if (base == nullptr) {
61 base = VirtualAlloc(nullptr, size, flags, protect);
62 }
63
64 return reinterpret_cast<uint8_t*>(base);
65}
66
67} // namespace
68
70 const char* LocalTimezone(double time) override;
71
72 double LocalTimeOffset(double time_ms, bool is_utc) override;
73
75};
76
77const char* CygwinTimezoneCache::LocalTimezone(double time) {
78 if (std::isnan(time)) return "";
79 time_t tv = static_cast<time_t>(std::floor(time / msPerSecond));
80 struct tm tm;
81 struct tm* t = localtime_r(&tv, &tm);
82 if (nullptr == t) return "";
83 return tzname[0]; // The location of the timezone string on Cygwin.
84}
85
86double LocalTimeOffset(double time_ms, bool is_utc) {
87 // On Cygwin, struct tm does not contain a tm_gmtoff field.
88 time_t utc = time(nullptr);
89 DCHECK_NE(utc, -1);
90 struct tm tm;
91 struct tm* loc = localtime_r(&utc, &tm);
92 DCHECK_NOT_NULL(loc);
93 // time - localtime includes any daylight savings offset, so subtract it.
94 return static_cast<double>((mktime(loc) - utc) * msPerSecond -
95 (loc->tm_isdst > 0 ? 3600 * msPerSecond : 0));
96}
97
98// static
99void* OS::Allocate(void* hint, size_t size, size_t alignment,
100 MemoryPermission access) {
101 size_t page_size = AllocatePageSize();
102 DCHECK_EQ(0, size % page_size);
103 DCHECK_EQ(0, alignment % page_size);
104 DCHECK_LE(page_size, alignment);
105 hint = AlignedAddress(hint, alignment);
106
107 DWORD flags = (access == OS::MemoryPermission::kNoAccess)
108 ? MEM_RESERVE
109 : MEM_RESERVE | MEM_COMMIT;
111
112 // First, try an exact size aligned allocation.
113 uint8_t* base = RandomizedVirtualAlloc(size, flags, protect, hint);
114 if (base == nullptr) return nullptr; // Can't allocate, we're OOM.
115
116 // If address is suitably aligned, we're done.
117 uint8_t* aligned_base = RoundUp(base, alignment);
118 if (base == aligned_base) return reinterpret_cast<void*>(base);
119
120 // Otherwise, free it and try a larger allocation.
121 Free(base, size);
122
123 // Clear the hint. It's unlikely we can allocate at this address.
124 hint = nullptr;
125
126 // Add the maximum misalignment so we are guaranteed an aligned base address
127 // in the allocated region.
128 size_t padded_size = size + (alignment - page_size);
129 const int kMaxAttempts = 3;
130 aligned_base = nullptr;
131 for (int i = 0; i < kMaxAttempts; ++i) {
132 base = RandomizedVirtualAlloc(padded_size, flags, protect, hint);
133 if (base == nullptr) return nullptr; // Can't allocate, we're OOM.
134
135 // Try to trim the allocation by freeing the padded allocation and then
136 // calling VirtualAlloc at the aligned base.
137 Free(base, padded_size);
138 aligned_base = RoundUp(base, alignment);
139 base = reinterpret_cast<uint8_t*>(
140 VirtualAlloc(aligned_base, size, flags, protect));
141 // We might not get the reduced allocation due to a race. In that case,
142 // base will be nullptr.
143 if (base != nullptr) break;
144 }
145 DCHECK_IMPLIES(base, base == aligned_base);
146 return reinterpret_cast<void*>(base);
147}
148
149// static
150void OS::Free(void* address, const size_t size) {
151 DCHECK_EQ(0, static_cast<uintptr_t>(address) % AllocatePageSize());
152 DCHECK_EQ(0, size % AllocatePageSize());
153 USE(size);
154 CHECK_NE(0, VirtualFree(address, 0, MEM_RELEASE));
155}
156
157// static
158void OS::Release(void* address, size_t size) {
159 DCHECK_EQ(0, reinterpret_cast<uintptr_t>(address) % CommitPageSize());
160 DCHECK_EQ(0, size % CommitPageSize());
161 CHECK_NE(0, VirtualFree(address, size, MEM_DECOMMIT));
162}
163
164// static
165bool OS::SetPermissions(void* address, size_t size, MemoryPermission access) {
166 DCHECK_EQ(0, reinterpret_cast<uintptr_t>(address) % CommitPageSize());
167 DCHECK_EQ(0, size % CommitPageSize());
168 if (access == MemoryPermission::kNoAccess) {
169 return VirtualFree(address, size, MEM_DECOMMIT) != 0;
170 }
172 return VirtualAlloc(address, size, MEM_COMMIT, protect) != nullptr;
173}
174
175// static
176bool OS::RecommitPages(void* address, size_t size, MemoryPermission access) {
177 return SetPermissions(address, size, access);
178}
179
180// static
181bool OS::DiscardSystemPages(void* address, size_t size) {
182 // On Windows, discarded pages are not returned to the system immediately and
183 // not guaranteed to be zeroed when returned to the application.
184 using DiscardVirtualMemoryFunction =
185 DWORD(WINAPI*)(PVOID virtualAddress, SIZE_T size);
186 static std::atomic<DiscardVirtualMemoryFunction> discard_virtual_memory(
187 reinterpret_cast<DiscardVirtualMemoryFunction>(-1));
188 if (discard_virtual_memory ==
189 reinterpret_cast<DiscardVirtualMemoryFunction>(-1))
190 discard_virtual_memory =
191 reinterpret_cast<DiscardVirtualMemoryFunction>(GetProcAddress(
192 GetModuleHandle(L"Kernel32.dll"), "DiscardVirtualMemory"));
193 // Use DiscardVirtualMemory when available because it releases faster than
194 // MEM_RESET.
195 DiscardVirtualMemoryFunction discard_function = discard_virtual_memory.load();
196 if (discard_function) {
197 DWORD ret = discard_function(address, size);
198 if (!ret) return true;
199 }
200 // DiscardVirtualMemory is buggy in Win10 SP0, so fall back to MEM_RESET on
201 // failure.
202 void* ptr = VirtualAlloc(address, size, MEM_RESET, PAGE_READWRITE);
203 CHECK(ptr);
204 return ptr;
205}
206
207// static
208bool OS::SealPages(void* address, size_t size) { return false; }
209
210// static
212 // TODO(alph): implement for the platform.
213 return false;
214}
215
216std::vector<OS::SharedLibraryAddress> OS::GetSharedLibraryAddresses() {
217 std::vector<SharedLibraryAddresses> result;
218 // This function assumes that the layout of the file is as follows:
219 // hex_start_addr-hex_end_addr rwxp <unused data> [binary_file_name]
220 // If we encounter an unexpected situation we abort scanning further entries.
221 FILE* fp = fopen("/proc/self/maps", "r");
222 if (fp == nullptr) return result;
223
224 // Allocate enough room to be able to store a full file name.
225 const int kLibNameLen = FILENAME_MAX + 1;
226 char* lib_name = reinterpret_cast<char*>(malloc(kLibNameLen));
227
228 // This loop will terminate once the scanning hits an EOF.
229 while (true) {
230 uintptr_t start, end;
231 char attr_r, attr_w, attr_x, attr_p;
232 // Parse the addresses and permission bits at the beginning of the line.
233 if (fscanf(fp, "%" V8PRIxPTR "-%" V8PRIxPTR, &start, &end) != 2) break;
234 if (fscanf(fp, " %c%c%c%c", &attr_r, &attr_w, &attr_x, &attr_p) != 4) break;
235
236 int c;
237 if (attr_r == 'r' && attr_w != 'w' && attr_x == 'x') {
238 // Found a read-only executable entry. Skip characters until we reach
239 // the beginning of the filename or the end of the line.
240 do {
241 c = getc(fp);
242 } while ((c != EOF) && (c != '\n') && (c != '/'));
243 if (c == EOF) break; // EOF: Was unexpected, just exit.
244
245 // Process the filename if found.
246 if (c == '/') {
247 ungetc(c, fp); // Push the '/' back into the stream to be read below.
248
249 // Read to the end of the line. Exit if the read fails.
250 if (fgets(lib_name, kLibNameLen, fp) == nullptr) break;
251
252 // Drop the newline character read by fgets. We do not need to check
253 // for a zero-length string because we know that we at least read the
254 // '/' character.
255 lib_name[strlen(lib_name) - 1] = '\0';
256 } else {
257 // No library name found, just record the raw address range.
258 snprintf(lib_name, kLibNameLen, "%08" V8PRIxPTR "-%08" V8PRIxPTR, start,
259 end);
260 }
261 result.push_back(SharedLibraryAddress(lib_name, start, end));
262 } else {
263 // Entry not describing executable data. Skip to end of line to set up
264 // reading the next entry.
265 do {
266 c = getc(fp);
267 } while ((c != EOF) && (c != '\n'));
268 if (c == EOF) break;
269 }
270 }
271 free(lib_name);
272 fclose(fp);
273 return result;
274}
275
277 // Nothing to do on Cygwin.
278}
279
281
282std::optional<OS::MemoryRange> OS::GetFirstFreeMemoryRangeWithin(
283 OS::Address boundary_start, OS::Address boundary_end, size_t minimum_size,
284 size_t alignment) {
285 return std::nullopt;
286}
287
288} // namespace base
289} // namespace v8
double LocalTimeOffset(double time_ms, bool is_utc) override
const char * LocalTimezone(double time) override
static V8_WARN_UNUSED_RESULT bool SealPages(void *address, size_t size)
static void SignalCodeMovingGC()
static bool HasLazyCommits()
static V8_WARN_UNUSED_RESULT bool DiscardSystemPages(void *address, size_t size)
static size_t AllocatePageSize()
static V8_WARN_UNUSED_RESULT bool SetPermissions(void *address, size_t size, MemoryPermission access)
static size_t CommitPageSize()
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()
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 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 void AdjustSchedulingParams()
int start
int end
TimeRecord time
ZoneVector< RpoNumber > & result
int GetProtectionFromMemoryPermission(OS::MemoryPermission access)
double LocalTimeOffset(double time_ms, bool is_utc)
#define UNREACHABLE()
Definition logging.h:67
#define DCHECK_LE(v1, v2)
Definition logging.h:490
#define CHECK(condition)
Definition logging.h:124
#define DCHECK_NOT_NULL(val)
Definition logging.h:492
#define DCHECK_IMPLIES(v1, v2)
Definition logging.h:493
#define DCHECK_NE(v1, v2)
Definition logging.h:486
#define CHECK_NE(lhs, rhs)
#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
#define V8PRIxPTR
Definition macros.h:331
void * PVOID
#define WINAPI
void * LPVOID
unsigned long DWORD