blob: b21166d6ce5cf643f1d73044d70f354e0cda02aa [file] [log] [blame]
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00001// Copyright 2012 the V8 project authors. All rights reserved.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002// Redistribution and use in source and binary forms, with or without
3// modification, are permitted provided that the following conditions are
4// met:
5//
6// * Redistributions of source code must retain the above copyright
7// notice, this list of conditions and the following disclaimer.
8// * Redistributions in binary form must reproduce the above
9// copyright notice, this list of conditions and the following
10// disclaimer in the documentation and/or other materials provided
11// with the distribution.
12// * Neither the name of Google Inc. nor the names of its
13// contributors may be used to endorse or promote products derived
14// from this software without specific prior written permission.
15//
16// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000028// Platform specific code for MacOS goes here. For the POSIX comaptible parts
29// the implementation is in platform-posix.cc.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000030
lrn@chromium.org5d00b602011-01-05 09:51:43 +000031#include <dlfcn.h>
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000032#include <unistd.h>
33#include <sys/mman.h>
34#include <mach/mach_init.h>
kasperl@chromium.orge959c182009-07-27 08:59:04 +000035#include <mach-o/dyld.h>
36#include <mach-o/getsect.h>
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000037
38#include <AvailabilityMacros.h>
39
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000040#include <pthread.h>
41#include <semaphore.h>
42#include <signal.h>
kmillikin@chromium.org9155e252010-05-26 13:27:57 +000043#include <libkern/OSAtomic.h>
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000044#include <mach/mach.h>
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000045#include <mach/semaphore.h>
46#include <mach/task.h>
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +000047#include <mach/vm_statistics.h>
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000048#include <sys/time.h>
49#include <sys/resource.h>
ager@chromium.org381abbb2009-02-25 13:23:22 +000050#include <sys/types.h>
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000051#include <sys/sysctl.h>
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000052#include <stdarg.h>
53#include <stdlib.h>
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000054#include <string.h>
ager@chromium.org381abbb2009-02-25 13:23:22 +000055#include <errno.h>
56
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000057#undef MAP_TYPE
58
59#include "v8.h"
60
danno@chromium.org8c0a43f2012-04-03 08:37:53 +000061#include "platform-posix.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000062#include "platform.h"
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +000063#include "simulator.h"
kasperl@chromium.orga5551262010-12-07 12:49:48 +000064#include "vm-state-inl.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000065
ager@chromium.org5aa501c2009-06-23 07:57:28 +000066// Manually define these here as weak imports, rather than including execinfo.h.
67// This lets us launch on 10.4 which does not have these calls.
68extern "C" {
69 extern int backtrace(void**, int) __attribute__((weak_import));
70 extern char** backtrace_symbols(void* const*, int)
71 __attribute__((weak_import));
72 extern void backtrace_symbols_fd(void* const*, int, int)
73 __attribute__((weak_import));
74}
75
76
kasperl@chromium.org71affb52009-05-26 05:44:31 +000077namespace v8 {
78namespace internal {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000079
ulan@chromium.org2efb9002012-01-19 15:36:35 +000080// 0 is never a valid thread id on MacOSX since a pthread_t is
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000081// a pointer.
82static const pthread_t kNoThread = (pthread_t) 0;
83
84
85double ceiling(double x) {
86 // Correct Mac OS X Leopard 'ceil' behavior.
87 if (-1.0 < x && x < 0.0) {
88 return -0.0;
89 } else {
90 return ceil(x);
91 }
92}
93
94
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000095static Mutex* limit_mutex = NULL;
96
97
danno@chromium.org8c0a43f2012-04-03 08:37:53 +000098void OS::PostSetUp() {
fschneider@chromium.org7d10be52012-04-10 12:30:14 +000099 POSIXPostSetUp();
danno@chromium.org8c0a43f2012-04-03 08:37:53 +0000100}
101
102
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000103// We keep the lowest and highest addresses mapped as a quick way of
104// determining that pointers are outside the heap (used mostly in assertions
ulan@chromium.org2efb9002012-01-19 15:36:35 +0000105// and verification). The estimate is conservative, i.e., not all addresses in
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000106// 'allocated' space are actually allocated to our heap. The range is
107// [lowest, highest), inclusive on the low and and exclusive on the high end.
108static void* lowest_ever_allocated = reinterpret_cast<void*>(-1);
109static void* highest_ever_allocated = reinterpret_cast<void*>(0);
110
111
112static void UpdateAllocatedSpaceLimits(void* address, int size) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000113 ASSERT(limit_mutex != NULL);
114 ScopedLock lock(limit_mutex);
115
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000116 lowest_ever_allocated = Min(lowest_ever_allocated, address);
117 highest_ever_allocated =
118 Max(highest_ever_allocated,
119 reinterpret_cast<void*>(reinterpret_cast<char*>(address) + size));
120}
121
122
123bool OS::IsOutsideAllocatedSpace(void* address) {
124 return address < lowest_ever_allocated || address >= highest_ever_allocated;
125}
126
127
128size_t OS::AllocateAlignment() {
kasper.lund7276f142008-07-30 08:49:36 +0000129 return getpagesize();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000130}
131
132
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +0000133// Constants used for mmap.
134// kMmapFd is used to pass vm_alloc flags to tag the region with the user
135// defined tag 255 This helps identify V8-allocated regions in memory analysis
136// tools like vmmap(1).
137static const int kMmapFd = VM_MAKE_TAG(255);
138static const off_t kMmapFdOffset = 0;
139
140
kasper.lund7276f142008-07-30 08:49:36 +0000141void* OS::Allocate(const size_t requested,
142 size_t* allocated,
kasperl@chromium.orgf5aa8372009-03-24 14:47:14 +0000143 bool is_executable) {
kasper.lund7276f142008-07-30 08:49:36 +0000144 const size_t msize = RoundUp(requested, getpagesize());
kasperl@chromium.orgf5aa8372009-03-24 14:47:14 +0000145 int prot = PROT_READ | PROT_WRITE | (is_executable ? PROT_EXEC : 0);
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +0000146 void* mbase = mmap(OS::GetRandomMmapAddr(),
147 msize,
148 prot,
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +0000149 MAP_PRIVATE | MAP_ANON,
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +0000150 kMmapFd,
151 kMmapFdOffset);
kasper.lund7276f142008-07-30 08:49:36 +0000152 if (mbase == MAP_FAILED) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000153 LOG(Isolate::Current(), StringEvent("OS::Allocate", "mmap failed"));
kasper.lund7276f142008-07-30 08:49:36 +0000154 return NULL;
155 }
156 *allocated = msize;
157 UpdateAllocatedSpaceLimits(mbase, msize);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000158 return mbase;
159}
160
161
kasperl@chromium.orgf5aa8372009-03-24 14:47:14 +0000162void OS::Free(void* address, const size_t size) {
kasper.lund7276f142008-07-30 08:49:36 +0000163 // TODO(1240712): munmap has a return value which is ignored here.
ager@chromium.orga1645e22009-09-09 19:27:10 +0000164 int result = munmap(address, size);
165 USE(result);
166 ASSERT(result == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000167}
168
169
ager@chromium.org32912102009-01-16 10:38:43 +0000170void OS::Sleep(int milliseconds) {
171 usleep(1000 * milliseconds);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000172}
173
174
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +0000175int OS::NumberOfCores() {
176 return sysconf(_SC_NPROCESSORS_ONLN);
177}
178
179
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000180void OS::Abort() {
181 // Redirect to std abort to signal abnormal program termination
182 abort();
183}
184
185
kasper.lund7276f142008-07-30 08:49:36 +0000186void OS::DebugBreak() {
187 asm("int $3");
188}
189
190
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +0000191void OS::DumpBacktrace() {
192 // Currently unsupported.
193}
194
195
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000196class PosixMemoryMappedFile : public OS::MemoryMappedFile {
197 public:
198 PosixMemoryMappedFile(FILE* file, void* memory, int size)
199 : file_(file), memory_(memory), size_(size) { }
200 virtual ~PosixMemoryMappedFile();
201 virtual void* memory() { return memory_; }
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +0000202 virtual int size() { return size_; }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000203 private:
204 FILE* file_;
205 void* memory_;
206 int size_;
207};
208
209
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +0000210OS::MemoryMappedFile* OS::MemoryMappedFile::open(const char* name) {
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +0000211 FILE* file = fopen(name, "r+");
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +0000212 if (file == NULL) return NULL;
213
214 fseek(file, 0, SEEK_END);
215 int size = ftell(file);
216
217 void* memory =
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +0000218 mmap(OS::GetRandomMmapAddr(),
219 size,
220 PROT_READ | PROT_WRITE,
221 MAP_SHARED,
222 fileno(file),
223 0);
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +0000224 return new PosixMemoryMappedFile(file, memory, size);
225}
226
227
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000228OS::MemoryMappedFile* OS::MemoryMappedFile::create(const char* name, int size,
229 void* initial) {
230 FILE* file = fopen(name, "w+");
231 if (file == NULL) return NULL;
lrn@chromium.org303ada72010-10-27 09:33:13 +0000232 int result = fwrite(initial, size, 1, file);
233 if (result < 1) {
234 fclose(file);
235 return NULL;
236 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000237 void* memory =
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +0000238 mmap(OS::GetRandomMmapAddr(),
239 size,
240 PROT_READ | PROT_WRITE,
241 MAP_SHARED,
242 fileno(file),
243 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000244 return new PosixMemoryMappedFile(file, memory, size);
245}
246
247
248PosixMemoryMappedFile::~PosixMemoryMappedFile() {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000249 if (memory_) OS::Free(memory_, size_);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000250 fclose(file_);
251}
252
253
254void OS::LogSharedLibraryAddresses() {
kasperl@chromium.orge959c182009-07-27 08:59:04 +0000255 unsigned int images_count = _dyld_image_count();
256 for (unsigned int i = 0; i < images_count; ++i) {
257 const mach_header* header = _dyld_get_image_header(i);
258 if (header == NULL) continue;
ager@chromium.orga1645e22009-09-09 19:27:10 +0000259#if V8_HOST_ARCH_X64
260 uint64_t size;
261 char* code_ptr = getsectdatafromheader_64(
262 reinterpret_cast<const mach_header_64*>(header),
263 SEG_TEXT,
264 SECT_TEXT,
265 &size);
266#else
kasperl@chromium.orge959c182009-07-27 08:59:04 +0000267 unsigned int size;
268 char* code_ptr = getsectdatafromheader(header, SEG_TEXT, SECT_TEXT, &size);
ager@chromium.orga1645e22009-09-09 19:27:10 +0000269#endif
kasperl@chromium.orge959c182009-07-27 08:59:04 +0000270 if (code_ptr == NULL) continue;
271 const uintptr_t slide = _dyld_get_image_vmaddr_slide(i);
272 const uintptr_t start = reinterpret_cast<uintptr_t>(code_ptr) + slide;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000273 LOG(Isolate::Current(),
274 SharedLibraryEvent(_dyld_get_image_name(i), start, start + size));
kasperl@chromium.orge959c182009-07-27 08:59:04 +0000275 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000276}
277
278
whesse@chromium.org4a5224e2010-10-20 12:37:07 +0000279void OS::SignalCodeMovingGC() {
280}
281
282
ager@chromium.orgc4c92722009-11-18 14:12:51 +0000283uint64_t OS::CpuFeaturesImpliedByPlatform() {
284 // MacOSX requires all these to install so we can assume they are present.
285 // These constants are defined by the CPUid instructions.
286 const uint64_t one = 1;
287 return (one << SSE2) | (one << CMOV) | (one << RDTSC) | (one << CPUID);
288}
289
290
ager@chromium.org236ad962008-09-25 09:45:57 +0000291int OS::ActivationFrameAlignment() {
292 // OS X activation frames must be 16 byte-aligned; see "Mac OS X ABI
293 // Function Call Guide".
294 return 16;
295}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000296
297
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000298const char* OS::LocalTimezone(double time) {
ulan@chromium.org77ca49a2013-04-22 09:43:56 +0000299 if (std::isnan(time)) return "";
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000300 time_t tv = static_cast<time_t>(floor(time/msPerSecond));
301 struct tm* t = localtime(&tv);
302 if (NULL == t) return "";
303 return t->tm_zone;
304}
305
306
307double OS::LocalTimeOffset() {
308 time_t tv = time(NULL);
309 struct tm* t = localtime(&tv);
310 // tm_gmtoff includes any daylight savings offset, so subtract it.
311 return static_cast<double>(t->tm_gmtoff * msPerSecond -
312 (t->tm_isdst > 0 ? 3600 * msPerSecond : 0));
313}
314
315
ager@chromium.org65dad4b2009-04-23 08:48:43 +0000316int OS::StackWalk(Vector<StackFrame> frames) {
ager@chromium.org5aa501c2009-06-23 07:57:28 +0000317 // If weak link to execinfo lib has failed, ie because we are on 10.4, abort.
318 if (backtrace == NULL)
319 return 0;
320
ager@chromium.org65dad4b2009-04-23 08:48:43 +0000321 int frames_size = frames.length();
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +0000322 ScopedVector<void*> addresses(frames_size);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000323
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +0000324 int frames_count = backtrace(addresses.start(), frames_size);
325
326 char** symbols = backtrace_symbols(addresses.start(), frames_count);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000327 if (symbols == NULL) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000328 return kStackWalkError;
329 }
330
331 for (int i = 0; i < frames_count; i++) {
332 frames[i].address = addresses[i];
333 // Format a text representation of the frame based on the information
334 // available.
kasperl@chromium.orgb9123622008-09-17 14:05:56 +0000335 SNPrintF(MutableCStrVector(frames[i].text,
336 kStackWalkMaxTextLen),
337 "%s",
338 symbols[i]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000339 // Make sure line termination is in place.
340 frames[i].text[kStackWalkMaxTextLen - 1] = '\0';
341 }
342
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000343 free(symbols);
344
345 return frames_count;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000346}
347
348
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000349VirtualMemory::VirtualMemory() : address_(NULL), size_(0) { }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000350
351
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000352VirtualMemory::VirtualMemory(size_t size)
353 : address_(ReserveRegion(size)), size_(size) { }
354
355
356VirtualMemory::VirtualMemory(size_t size, size_t alignment)
357 : address_(NULL), size_(0) {
358 ASSERT(IsAligned(alignment, static_cast<intptr_t>(OS::AllocateAlignment())));
359 size_t request_size = RoundUp(size + alignment,
360 static_cast<intptr_t>(OS::AllocateAlignment()));
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +0000361 void* reservation = mmap(OS::GetRandomMmapAddr(),
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000362 request_size,
363 PROT_NONE,
364 MAP_PRIVATE | MAP_ANON | MAP_NORESERVE,
365 kMmapFd,
366 kMmapFdOffset);
367 if (reservation == MAP_FAILED) return;
368
369 Address base = static_cast<Address>(reservation);
370 Address aligned_base = RoundUp(base, alignment);
371 ASSERT_LE(base, aligned_base);
372
373 // Unmap extra memory reserved before and after the desired block.
374 if (aligned_base != base) {
375 size_t prefix_size = static_cast<size_t>(aligned_base - base);
376 OS::Free(base, prefix_size);
377 request_size -= prefix_size;
378 }
379
380 size_t aligned_size = RoundUp(size, OS::AllocateAlignment());
381 ASSERT_LE(aligned_size, request_size);
382
383 if (aligned_size != request_size) {
384 size_t suffix_size = request_size - aligned_size;
385 OS::Free(aligned_base + aligned_size, suffix_size);
386 request_size -= suffix_size;
387 }
388
389 ASSERT(aligned_size == request_size);
390
391 address_ = static_cast<void*>(aligned_base);
392 size_ = aligned_size;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000393}
394
395
396VirtualMemory::~VirtualMemory() {
397 if (IsReserved()) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000398 bool result = ReleaseRegion(address(), size());
399 ASSERT(result);
400 USE(result);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000401 }
402}
403
404
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000405bool VirtualMemory::IsReserved() {
406 return address_ != NULL;
407}
408
409
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000410void VirtualMemory::Reset() {
411 address_ = NULL;
412 size_ = 0;
413}
414
415
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000416bool VirtualMemory::Commit(void* address, size_t size, bool is_executable) {
417 return CommitRegion(address, size, is_executable);
418}
419
420
421bool VirtualMemory::Uncommit(void* address, size_t size) {
422 return UncommitRegion(address, size);
423}
424
425
426bool VirtualMemory::Guard(void* address) {
427 OS::Guard(address, OS::CommitPageSize());
428 return true;
429}
430
431
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000432void* VirtualMemory::ReserveRegion(size_t size) {
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +0000433 void* result = mmap(OS::GetRandomMmapAddr(),
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000434 size,
435 PROT_NONE,
436 MAP_PRIVATE | MAP_ANON | MAP_NORESERVE,
437 kMmapFd,
438 kMmapFdOffset);
439
440 if (result == MAP_FAILED) return NULL;
441
442 return result;
443}
444
445
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000446bool VirtualMemory::CommitRegion(void* address,
447 size_t size,
448 bool is_executable) {
kasperl@chromium.orgf5aa8372009-03-24 14:47:14 +0000449 int prot = PROT_READ | PROT_WRITE | (is_executable ? PROT_EXEC : 0);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000450 if (MAP_FAILED == mmap(address,
451 size,
452 prot,
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000453 MAP_PRIVATE | MAP_ANON | MAP_FIXED,
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000454 kMmapFd,
455 kMmapFdOffset)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000456 return false;
457 }
458
459 UpdateAllocatedSpaceLimits(address, size);
460 return true;
461}
462
463
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000464bool VirtualMemory::UncommitRegion(void* address, size_t size) {
465 return mmap(address,
466 size,
467 PROT_NONE,
ager@chromium.orga1645e22009-09-09 19:27:10 +0000468 MAP_PRIVATE | MAP_ANON | MAP_NORESERVE | MAP_FIXED,
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000469 kMmapFd,
470 kMmapFdOffset) != MAP_FAILED;
471}
472
473
474bool VirtualMemory::ReleaseRegion(void* address, size_t size) {
475 return munmap(address, size) == 0;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000476}
477
kasperl@chromium.orgf5aa8372009-03-24 14:47:14 +0000478
danno@chromium.org72204d52012-10-31 10:02:10 +0000479bool VirtualMemory::HasLazyCommits() {
480 return false;
481}
482
483
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +0000484class Thread::PlatformData : public Malloced {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000485 public:
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +0000486 PlatformData() : thread_(kNoThread) {}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000487 pthread_t thread_; // Thread handle for pthread.
488};
489
yangguo@chromium.org659ceec2012-01-26 07:37:54 +0000490
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000491Thread::Thread(const Options& options)
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +0000492 : data_(new PlatformData),
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000493 stack_size_(options.stack_size()),
494 start_semaphore_(NULL) {
yangguo@chromium.org659ceec2012-01-26 07:37:54 +0000495 set_name(options.name());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000496}
497
498
499Thread::~Thread() {
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +0000500 delete data_;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000501}
502
503
lrn@chromium.org5d00b602011-01-05 09:51:43 +0000504static void SetThreadName(const char* name) {
505 // pthread_setname_np is only available in 10.6 or later, so test
506 // for it at runtime.
507 int (*dynamic_pthread_setname_np)(const char*);
508 *reinterpret_cast<void**>(&dynamic_pthread_setname_np) =
509 dlsym(RTLD_DEFAULT, "pthread_setname_np");
510 if (!dynamic_pthread_setname_np)
511 return;
512
513 // Mac OS X does not expose the length limit of the name, so hardcode it.
514 static const int kMaxNameLength = 63;
515 USE(kMaxNameLength);
516 ASSERT(Thread::kMaxThreadNameLength <= kMaxNameLength);
517 dynamic_pthread_setname_np(name);
518}
519
520
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000521static void* ThreadEntry(void* arg) {
522 Thread* thread = reinterpret_cast<Thread*>(arg);
523 // This is also initialized by the first argument to pthread_create() but we
524 // don't know which thread will run first (the original thread or the new
525 // one) so we initialize it here too.
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +0000526 thread->data()->thread_ = pthread_self();
lrn@chromium.org5d00b602011-01-05 09:51:43 +0000527 SetThreadName(thread->name());
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +0000528 ASSERT(thread->data()->thread_ != kNoThread);
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000529 thread->NotifyStartedAndRun();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000530 return NULL;
531}
532
533
lrn@chromium.org5d00b602011-01-05 09:51:43 +0000534void Thread::set_name(const char* name) {
535 strncpy(name_, name, sizeof(name_));
536 name_[sizeof(name_) - 1] = '\0';
537}
538
539
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000540void Thread::Start() {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000541 pthread_attr_t* attr_ptr = NULL;
542 pthread_attr_t attr;
543 if (stack_size_ > 0) {
544 pthread_attr_init(&attr);
545 pthread_attr_setstacksize(&attr, static_cast<size_t>(stack_size_));
546 attr_ptr = &attr;
547 }
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +0000548 pthread_create(&data_->thread_, attr_ptr, ThreadEntry, this);
549 ASSERT(data_->thread_ != kNoThread);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000550}
551
552
553void Thread::Join() {
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +0000554 pthread_join(data_->thread_, NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000555}
556
557
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000558#ifdef V8_FAST_TLS_SUPPORTED
559
560static Atomic32 tls_base_offset_initialized = 0;
561intptr_t kMacTlsBaseOffset = 0;
562
563// It's safe to do the initialization more that once, but it has to be
564// done at least once.
565static void InitializeTlsBaseOffset() {
566 const size_t kBufferSize = 128;
567 char buffer[kBufferSize];
568 size_t buffer_size = kBufferSize;
569 int ctl_name[] = { CTL_KERN , KERN_OSRELEASE };
570 if (sysctl(ctl_name, 2, buffer, &buffer_size, NULL, 0) != 0) {
571 V8_Fatal(__FILE__, __LINE__, "V8 failed to get kernel version");
572 }
573 // The buffer now contains a string of the form XX.YY.ZZ, where
574 // XX is the major kernel version component.
575 // Make sure the buffer is 0-terminated.
576 buffer[kBufferSize - 1] = '\0';
577 char* period_pos = strchr(buffer, '.');
578 *period_pos = '\0';
579 int kernel_version_major =
580 static_cast<int>(strtol(buffer, NULL, 10)); // NOLINT
581 // The constants below are taken from pthreads.s from the XNU kernel
582 // sources archive at www.opensource.apple.com.
583 if (kernel_version_major < 11) {
584 // 8.x.x (Tiger), 9.x.x (Leopard), 10.x.x (Snow Leopard) have the
585 // same offsets.
586#if defined(V8_HOST_ARCH_IA32)
587 kMacTlsBaseOffset = 0x48;
588#else
589 kMacTlsBaseOffset = 0x60;
590#endif
591 } else {
592 // 11.x.x (Lion) changed the offset.
593 kMacTlsBaseOffset = 0;
594 }
595
596 Release_Store(&tls_base_offset_initialized, 1);
597}
598
599static void CheckFastTls(Thread::LocalStorageKey key) {
600 void* expected = reinterpret_cast<void*>(0x1234CAFE);
601 Thread::SetThreadLocal(key, expected);
602 void* actual = Thread::GetExistingThreadLocal(key);
603 if (expected != actual) {
604 V8_Fatal(__FILE__, __LINE__,
605 "V8 failed to initialize fast TLS on current kernel");
606 }
607 Thread::SetThreadLocal(key, NULL);
608}
609
610#endif // V8_FAST_TLS_SUPPORTED
611
612
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000613Thread::LocalStorageKey Thread::CreateThreadLocalKey() {
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000614#ifdef V8_FAST_TLS_SUPPORTED
615 bool check_fast_tls = false;
616 if (tls_base_offset_initialized == 0) {
617 check_fast_tls = true;
618 InitializeTlsBaseOffset();
619 }
620#endif
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000621 pthread_key_t key;
622 int result = pthread_key_create(&key, NULL);
623 USE(result);
624 ASSERT(result == 0);
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000625 LocalStorageKey typed_key = static_cast<LocalStorageKey>(key);
626#ifdef V8_FAST_TLS_SUPPORTED
627 // If we just initialized fast TLS support, make sure it works.
628 if (check_fast_tls) CheckFastTls(typed_key);
629#endif
630 return typed_key;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000631}
632
633
634void Thread::DeleteThreadLocalKey(LocalStorageKey key) {
635 pthread_key_t pthread_key = static_cast<pthread_key_t>(key);
636 int result = pthread_key_delete(pthread_key);
637 USE(result);
638 ASSERT(result == 0);
639}
640
641
642void* Thread::GetThreadLocal(LocalStorageKey key) {
643 pthread_key_t pthread_key = static_cast<pthread_key_t>(key);
644 return pthread_getspecific(pthread_key);
645}
646
647
648void Thread::SetThreadLocal(LocalStorageKey key, void* value) {
649 pthread_key_t pthread_key = static_cast<pthread_key_t>(key);
650 pthread_setspecific(pthread_key, value);
651}
652
653
654void Thread::YieldCPU() {
655 sched_yield();
656}
657
658
659class MacOSMutex : public Mutex {
660 public:
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000661 MacOSMutex() {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000662 pthread_mutexattr_t attr;
663 pthread_mutexattr_init(&attr);
664 pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);
kasperl@chromium.orge959c182009-07-27 08:59:04 +0000665 pthread_mutex_init(&mutex_, &attr);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000666 }
667
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000668 virtual ~MacOSMutex() { pthread_mutex_destroy(&mutex_); }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000669
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000670 virtual int Lock() { return pthread_mutex_lock(&mutex_); }
671 virtual int Unlock() { return pthread_mutex_unlock(&mutex_); }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000672
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000673 virtual bool TryLock() {
674 int result = pthread_mutex_trylock(&mutex_);
675 // Return false if the lock is busy and locking failed.
676 if (result == EBUSY) {
677 return false;
678 }
679 ASSERT(result == 0); // Verify no other errors.
680 return true;
681 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000682
683 private:
684 pthread_mutex_t mutex_;
685};
686
687
688Mutex* OS::CreateMutex() {
689 return new MacOSMutex();
690}
691
692
693class MacOSSemaphore : public Semaphore {
694 public:
695 explicit MacOSSemaphore(int count) {
yangguo@chromium.org46839fb2012-08-28 09:06:19 +0000696 int r;
697 r = semaphore_create(mach_task_self(),
698 &semaphore_,
699 SYNC_POLICY_FIFO,
700 count);
701 ASSERT(r == KERN_SUCCESS);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000702 }
703
704 ~MacOSSemaphore() {
yangguo@chromium.org46839fb2012-08-28 09:06:19 +0000705 int r;
706 r = semaphore_destroy(mach_task_self(), semaphore_);
707 ASSERT(r == KERN_SUCCESS);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000708 }
709
yangguo@chromium.org46839fb2012-08-28 09:06:19 +0000710 void Wait() {
711 int r;
712 do {
713 r = semaphore_wait(semaphore_);
714 ASSERT(r == KERN_SUCCESS || r == KERN_ABORTED);
715 } while (r == KERN_ABORTED);
716 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000717
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000718 bool Wait(int timeout);
719
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000720 void Signal() { semaphore_signal(semaphore_); }
721
722 private:
723 semaphore_t semaphore_;
724};
725
726
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000727bool MacOSSemaphore::Wait(int timeout) {
728 mach_timespec_t ts;
729 ts.tv_sec = timeout / 1000000;
730 ts.tv_nsec = (timeout % 1000000) * 1000;
731 return semaphore_timedwait(semaphore_, ts) != KERN_OPERATION_TIMED_OUT;
732}
733
734
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000735Semaphore* OS::CreateSemaphore(int count) {
736 return new MacOSSemaphore(count);
737}
738
ager@chromium.org381abbb2009-02-25 13:23:22 +0000739
fschneider@chromium.org7d10be52012-04-10 12:30:14 +0000740void OS::SetUp() {
741 // Seed the random number generator. We preserve microsecond resolution.
742 uint64_t seed = Ticks() ^ (getpid() << 16);
743 srandom(static_cast<unsigned int>(seed));
744 limit_mutex = CreateMutex();
fschneider@chromium.org7d10be52012-04-10 12:30:14 +0000745}
746
747
erik.corry@gmail.comed49e962012-04-17 11:57:53 +0000748void OS::TearDown() {
erik.corry@gmail.comed49e962012-04-17 11:57:53 +0000749 delete limit_mutex;
750}
751
752
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000753} } // namespace v8::internal