blob: 0076d567f8b29711f881c6da6dffdfd8023325fb [file] [log] [blame]
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00001// Copyright 2012 the V8 project authors. All rights reserved.
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +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 Cygwin goes here. For the POSIX comaptible parts
29// the implementation is in platform-posix.cc.
30
31#include <errno.h>
32#include <pthread.h>
33#include <semaphore.h>
34#include <stdarg.h>
35#include <strings.h> // index
36#include <sys/time.h>
37#include <sys/mman.h> // mmap & munmap
38#include <unistd.h> // sysconf
39
40#undef MAP_TYPE
41
42#include "v8.h"
43
44#include "platform.h"
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +000045#include "simulator.h"
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +000046#include "v8threads.h"
47#include "vm-state-inl.h"
48#include "win32-headers.h"
49
50namespace v8 {
51namespace internal {
52
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +000053
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +000054const char* OS::LocalTimezone(double time) {
ulan@chromium.org77ca49a2013-04-22 09:43:56 +000055 if (std::isnan(time)) return "";
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +000056 time_t tv = static_cast<time_t>(floor(time/msPerSecond));
57 struct tm* t = localtime(&tv);
58 if (NULL == t) return "";
59 return tzname[0]; // The location of the timezone string on Cygwin.
60}
61
62
63double OS::LocalTimeOffset() {
64 // On Cygwin, struct tm does not contain a tm_gmtoff field.
65 time_t utc = time(NULL);
66 ASSERT(utc != -1);
67 struct tm* loc = localtime(&utc);
68 ASSERT(loc != NULL);
69 // time - localtime includes any daylight savings offset, so subtract it.
70 return static_cast<double>((mktime(loc) - utc) * msPerSecond -
71 (loc->tm_isdst > 0 ? 3600 * msPerSecond : 0));
72}
73
74
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +000075void* OS::Allocate(const size_t requested,
76 size_t* allocated,
77 bool is_executable) {
78 const size_t msize = RoundUp(requested, sysconf(_SC_PAGESIZE));
79 int prot = PROT_READ | PROT_WRITE | (is_executable ? PROT_EXEC : 0);
80 void* mbase = mmap(NULL, msize, prot, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
81 if (mbase == MAP_FAILED) {
hpayer@chromium.orgc5d49712013-09-11 08:25:48 +000082 LOG(Isolate::Current(), StringEvent("OS::Allocate", "mmap failed"));
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +000083 return NULL;
84 }
85 *allocated = msize;
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +000086 return mbase;
87}
88
89
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +000090class PosixMemoryMappedFile : public OS::MemoryMappedFile {
91 public:
92 PosixMemoryMappedFile(FILE* file, void* memory, int size)
93 : file_(file), memory_(memory), size_(size) { }
94 virtual ~PosixMemoryMappedFile();
95 virtual void* memory() { return memory_; }
96 virtual int size() { return size_; }
97 private:
98 FILE* file_;
99 void* memory_;
100 int size_;
101};
102
103
104OS::MemoryMappedFile* OS::MemoryMappedFile::open(const char* name) {
105 FILE* file = fopen(name, "r+");
106 if (file == NULL) return NULL;
107
108 fseek(file, 0, SEEK_END);
109 int size = ftell(file);
110
111 void* memory =
112 mmap(0, size, PROT_READ | PROT_WRITE, MAP_SHARED, fileno(file), 0);
113 return new PosixMemoryMappedFile(file, memory, size);
114}
115
116
117OS::MemoryMappedFile* OS::MemoryMappedFile::create(const char* name, int size,
118 void* initial) {
119 FILE* file = fopen(name, "w+");
120 if (file == NULL) return NULL;
121 int result = fwrite(initial, size, 1, file);
122 if (result < 1) {
123 fclose(file);
124 return NULL;
125 }
126 void* memory =
127 mmap(0, size, PROT_READ | PROT_WRITE, MAP_SHARED, fileno(file), 0);
128 return new PosixMemoryMappedFile(file, memory, size);
129}
130
131
132PosixMemoryMappedFile::~PosixMemoryMappedFile() {
133 if (memory_) munmap(memory_, size_);
134 fclose(file_);
135}
136
137
dslomov@chromium.orge97852d2013-09-12 09:02:59 +0000138void OS::LogSharedLibraryAddresses(Isolate* isolate) {
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +0000139 // This function assumes that the layout of the file is as follows:
140 // hex_start_addr-hex_end_addr rwxp <unused data> [binary_file_name]
141 // If we encounter an unexpected situation we abort scanning further entries.
142 FILE* fp = fopen("/proc/self/maps", "r");
143 if (fp == NULL) return;
144
145 // Allocate enough room to be able to store a full file name.
146 const int kLibNameLen = FILENAME_MAX + 1;
147 char* lib_name = reinterpret_cast<char*>(malloc(kLibNameLen));
148
149 // This loop will terminate once the scanning hits an EOF.
150 while (true) {
151 uintptr_t start, end;
152 char attr_r, attr_w, attr_x, attr_p;
153 // Parse the addresses and permission bits at the beginning of the line.
154 if (fscanf(fp, "%" V8PRIxPTR "-%" V8PRIxPTR, &start, &end) != 2) break;
155 if (fscanf(fp, " %c%c%c%c", &attr_r, &attr_w, &attr_x, &attr_p) != 4) break;
156
157 int c;
158 if (attr_r == 'r' && attr_w != 'w' && attr_x == 'x') {
159 // Found a read-only executable entry. Skip characters until we reach
160 // the beginning of the filename or the end of the line.
161 do {
162 c = getc(fp);
163 } while ((c != EOF) && (c != '\n') && (c != '/'));
164 if (c == EOF) break; // EOF: Was unexpected, just exit.
165
166 // Process the filename if found.
167 if (c == '/') {
168 ungetc(c, fp); // Push the '/' back into the stream to be read below.
169
170 // Read to the end of the line. Exit if the read fails.
171 if (fgets(lib_name, kLibNameLen, fp) == NULL) break;
172
173 // Drop the newline character read by fgets. We do not need to check
174 // for a zero-length string because we know that we at least read the
175 // '/' character.
176 lib_name[strlen(lib_name) - 1] = '\0';
177 } else {
178 // No library name found, just record the raw address range.
179 snprintf(lib_name, kLibNameLen,
180 "%08" V8PRIxPTR "-%08" V8PRIxPTR, start, end);
181 }
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000182 LOG(isolate, SharedLibraryEvent(lib_name, start, end));
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +0000183 } else {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +0000184 // Entry not describing executable data. Skip to end of line to set up
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +0000185 // reading the next entry.
186 do {
187 c = getc(fp);
188 } while ((c != EOF) && (c != '\n'));
189 if (c == EOF) break;
190 }
191 }
192 free(lib_name);
193 fclose(fp);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +0000194}
195
196
197void OS::SignalCodeMovingGC() {
198 // Nothing to do on Cygwin.
199}
200
201
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000202// The VirtualMemory implementation is taken from platform-win32.cc.
203// The mmap-based virtual memory implementation as it is used on most posix
204// platforms does not work well because Cygwin does not support MAP_FIXED.
205// This causes VirtualMemory::Commit to not always commit the memory region
206// specified.
207
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000208static void* GetRandomAddr() {
209 Isolate* isolate = Isolate::UncheckedCurrent();
210 // Note that the current isolate isn't set up in a call path via
211 // CpuFeatures::Probe. We don't care about randomization in this case because
212 // the code page is immediately freed.
213 if (isolate != NULL) {
214 // The address range used to randomize RWX allocations in OS::Allocate
215 // Try not to map pages into the default range that windows loads DLLs
216 // Use a multiple of 64k to prevent committing unused memory.
217 // Note: This does not guarantee RWX regions will be within the
218 // range kAllocationRandomAddressMin to kAllocationRandomAddressMax
219#ifdef V8_HOST_ARCH_64_BIT
220 static const intptr_t kAllocationRandomAddressMin = 0x0000000080000000;
221 static const intptr_t kAllocationRandomAddressMax = 0x000003FFFFFF0000;
222#else
223 static const intptr_t kAllocationRandomAddressMin = 0x04000000;
224 static const intptr_t kAllocationRandomAddressMax = 0x3FFF0000;
225#endif
hpayer@chromium.orgc5d49712013-09-11 08:25:48 +0000226 uintptr_t address =
227 (isolate->random_number_generator()->NextInt() << kPageSizeBits) |
228 kAllocationRandomAddressMin;
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000229 address &= kAllocationRandomAddressMax;
230 return reinterpret_cast<void *>(address);
231 }
232 return NULL;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000233}
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +0000234
235
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000236static void* RandomizedVirtualAlloc(size_t size, int action, int protection) {
237 LPVOID base = NULL;
238
239 if (protection == PAGE_EXECUTE_READWRITE || protection == PAGE_NOACCESS) {
240 // For exectutable pages try and randomize the allocation address
241 for (size_t attempts = 0; base == NULL && attempts < 3; ++attempts) {
242 base = VirtualAlloc(GetRandomAddr(), size, action, protection);
243 }
244 }
245
246 // After three attempts give up and let the OS find an address to use.
247 if (base == NULL) base = VirtualAlloc(NULL, size, action, protection);
248
249 return base;
250}
251
252
253VirtualMemory::VirtualMemory() : address_(NULL), size_(0) { }
254
255
256VirtualMemory::VirtualMemory(size_t size)
257 : address_(ReserveRegion(size)), size_(size) { }
258
259
260VirtualMemory::VirtualMemory(size_t size, size_t alignment)
261 : address_(NULL), size_(0) {
262 ASSERT(IsAligned(alignment, static_cast<intptr_t>(OS::AllocateAlignment())));
263 size_t request_size = RoundUp(size + alignment,
264 static_cast<intptr_t>(OS::AllocateAlignment()));
265 void* address = ReserveRegion(request_size);
266 if (address == NULL) return;
267 Address base = RoundUp(static_cast<Address>(address), alignment);
268 // Try reducing the size by freeing and then reallocating a specific area.
269 bool result = ReleaseRegion(address, request_size);
270 USE(result);
271 ASSERT(result);
272 address = VirtualAlloc(base, size, MEM_RESERVE, PAGE_NOACCESS);
273 if (address != NULL) {
274 request_size = size;
275 ASSERT(base == static_cast<Address>(address));
276 } else {
277 // Resizing failed, just go with a bigger area.
278 address = ReserveRegion(request_size);
279 if (address == NULL) return;
280 }
281 address_ = address;
282 size_ = request_size;
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +0000283}
284
285
286VirtualMemory::~VirtualMemory() {
287 if (IsReserved()) {
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000288 bool result = ReleaseRegion(address_, size_);
289 ASSERT(result);
290 USE(result);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +0000291 }
292}
293
294
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000295bool VirtualMemory::IsReserved() {
296 return address_ != NULL;
297}
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +0000298
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000299
300void VirtualMemory::Reset() {
301 address_ = NULL;
302 size_ = 0;
303}
304
305
306bool VirtualMemory::Commit(void* address, size_t size, bool is_executable) {
307 return CommitRegion(address, size, is_executable);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +0000308}
309
310
311bool VirtualMemory::Uncommit(void* address, size_t size) {
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000312 ASSERT(IsReserved());
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000313 return UncommitRegion(address, size);
314}
315
316
317void* VirtualMemory::ReserveRegion(size_t size) {
318 return RandomizedVirtualAlloc(size, MEM_RESERVE, PAGE_NOACCESS);
319}
320
321
322bool VirtualMemory::CommitRegion(void* base, size_t size, bool is_executable) {
323 int prot = is_executable ? PAGE_EXECUTE_READWRITE : PAGE_READWRITE;
324 if (NULL == VirtualAlloc(base, size, MEM_COMMIT, prot)) {
325 return false;
326 }
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000327 return true;
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +0000328}
329
330
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +0000331bool VirtualMemory::Guard(void* address) {
332 if (NULL == VirtualAlloc(address,
333 OS::CommitPageSize(),
334 MEM_COMMIT,
hpayer@chromium.orgc5d49712013-09-11 08:25:48 +0000335 PAGE_NOACCESS)) {
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +0000336 return false;
337 }
338 return true;
339}
340
341
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000342bool VirtualMemory::UncommitRegion(void* base, size_t size) {
343 return VirtualFree(base, size, MEM_DECOMMIT) != 0;
344}
345
346
347bool VirtualMemory::ReleaseRegion(void* base, size_t size) {
348 return VirtualFree(base, 0, MEM_RELEASE) != 0;
349}
350
351
danno@chromium.org72204d52012-10-31 10:02:10 +0000352bool VirtualMemory::HasLazyCommits() {
353 // TODO(alph): implement for the platform.
354 return false;
355}
356
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +0000357} } // namespace v8::internal