blob: 5e0e78dbf8f141baaa6777d2112f5123f8b3e8a5 [file] [log] [blame]
ager@chromium.org9258b6b2008-09-11 09:11:10 +00001// Copyright 2006-2008 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
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000031#include <unistd.h>
32#include <sys/mman.h>
33#include <mach/mach_init.h>
kasperl@chromium.orge959c182009-07-27 08:59:04 +000034#include <mach-o/dyld.h>
35#include <mach-o/getsect.h>
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000036
37#include <AvailabilityMacros.h>
38
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000039#include <pthread.h>
40#include <semaphore.h>
41#include <signal.h>
kmillikin@chromium.org9155e252010-05-26 13:27:57 +000042#include <libkern/OSAtomic.h>
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000043#include <mach/mach.h>
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000044#include <mach/semaphore.h>
45#include <mach/task.h>
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +000046#include <mach/vm_statistics.h>
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000047#include <sys/time.h>
48#include <sys/resource.h>
ager@chromium.org381abbb2009-02-25 13:23:22 +000049#include <sys/types.h>
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000050#include <stdarg.h>
51#include <stdlib.h>
52
ager@chromium.org381abbb2009-02-25 13:23:22 +000053#include <errno.h>
54
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000055#undef MAP_TYPE
56
57#include "v8.h"
58
59#include "platform.h"
60
ager@chromium.org5aa501c2009-06-23 07:57:28 +000061// Manually define these here as weak imports, rather than including execinfo.h.
62// This lets us launch on 10.4 which does not have these calls.
63extern "C" {
64 extern int backtrace(void**, int) __attribute__((weak_import));
65 extern char** backtrace_symbols(void* const*, int)
66 __attribute__((weak_import));
67 extern void backtrace_symbols_fd(void* const*, int, int)
68 __attribute__((weak_import));
69}
70
71
kasperl@chromium.org71affb52009-05-26 05:44:31 +000072namespace v8 {
73namespace internal {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000074
75// 0 is never a valid thread id on MacOSX since a ptread_t is
76// a pointer.
77static const pthread_t kNoThread = (pthread_t) 0;
78
79
80double ceiling(double x) {
81 // Correct Mac OS X Leopard 'ceil' behavior.
82 if (-1.0 < x && x < 0.0) {
83 return -0.0;
84 } else {
85 return ceil(x);
86 }
87}
88
89
90void OS::Setup() {
91 // Seed the random number generator.
ager@chromium.org9258b6b2008-09-11 09:11:10 +000092 // Convert the current time to a 64-bit integer first, before converting it
93 // to an unsigned. Going directly will cause an overflow and the seed to be
94 // set to all ones. The seed will be identical for different instances that
95 // call this setup code within the same millisecond.
96 uint64_t seed = static_cast<uint64_t>(TimeCurrentMillis());
97 srandom(static_cast<unsigned int>(seed));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000098}
99
100
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000101// We keep the lowest and highest addresses mapped as a quick way of
102// determining that pointers are outside the heap (used mostly in assertions
103// and verification). The estimate is conservative, ie, not all addresses in
104// 'allocated' space are actually allocated to our heap. The range is
105// [lowest, highest), inclusive on the low and and exclusive on the high end.
106static void* lowest_ever_allocated = reinterpret_cast<void*>(-1);
107static void* highest_ever_allocated = reinterpret_cast<void*>(0);
108
109
110static void UpdateAllocatedSpaceLimits(void* address, int size) {
111 lowest_ever_allocated = Min(lowest_ever_allocated, address);
112 highest_ever_allocated =
113 Max(highest_ever_allocated,
114 reinterpret_cast<void*>(reinterpret_cast<char*>(address) + size));
115}
116
117
118bool OS::IsOutsideAllocatedSpace(void* address) {
119 return address < lowest_ever_allocated || address >= highest_ever_allocated;
120}
121
122
123size_t OS::AllocateAlignment() {
kasper.lund7276f142008-07-30 08:49:36 +0000124 return getpagesize();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000125}
126
127
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +0000128// Constants used for mmap.
129// kMmapFd is used to pass vm_alloc flags to tag the region with the user
130// defined tag 255 This helps identify V8-allocated regions in memory analysis
131// tools like vmmap(1).
132static const int kMmapFd = VM_MAKE_TAG(255);
133static const off_t kMmapFdOffset = 0;
134
135
kasper.lund7276f142008-07-30 08:49:36 +0000136void* OS::Allocate(const size_t requested,
137 size_t* allocated,
kasperl@chromium.orgf5aa8372009-03-24 14:47:14 +0000138 bool is_executable) {
kasper.lund7276f142008-07-30 08:49:36 +0000139 const size_t msize = RoundUp(requested, getpagesize());
kasperl@chromium.orgf5aa8372009-03-24 14:47:14 +0000140 int prot = PROT_READ | PROT_WRITE | (is_executable ? PROT_EXEC : 0);
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +0000141 void* mbase = mmap(NULL, msize, prot,
142 MAP_PRIVATE | MAP_ANON,
143 kMmapFd, kMmapFdOffset);
kasper.lund7276f142008-07-30 08:49:36 +0000144 if (mbase == MAP_FAILED) {
145 LOG(StringEvent("OS::Allocate", "mmap failed"));
146 return NULL;
147 }
148 *allocated = msize;
149 UpdateAllocatedSpaceLimits(mbase, msize);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000150 return mbase;
151}
152
153
kasperl@chromium.orgf5aa8372009-03-24 14:47:14 +0000154void OS::Free(void* address, const size_t size) {
kasper.lund7276f142008-07-30 08:49:36 +0000155 // TODO(1240712): munmap has a return value which is ignored here.
ager@chromium.orga1645e22009-09-09 19:27:10 +0000156 int result = munmap(address, size);
157 USE(result);
158 ASSERT(result == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000159}
160
161
kasperl@chromium.orgf5aa8372009-03-24 14:47:14 +0000162#ifdef ENABLE_HEAP_PROTECTION
163
164void OS::Protect(void* address, size_t size) {
165 UNIMPLEMENTED();
166}
167
168
169void OS::Unprotect(void* address, size_t size, bool is_executable) {
170 UNIMPLEMENTED();
171}
172
173#endif
174
175
ager@chromium.org32912102009-01-16 10:38:43 +0000176void OS::Sleep(int milliseconds) {
177 usleep(1000 * milliseconds);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000178}
179
180
181void OS::Abort() {
182 // Redirect to std abort to signal abnormal program termination
183 abort();
184}
185
186
kasper.lund7276f142008-07-30 08:49:36 +0000187void OS::DebugBreak() {
188 asm("int $3");
189}
190
191
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000192class PosixMemoryMappedFile : public OS::MemoryMappedFile {
193 public:
194 PosixMemoryMappedFile(FILE* file, void* memory, int size)
195 : file_(file), memory_(memory), size_(size) { }
196 virtual ~PosixMemoryMappedFile();
197 virtual void* memory() { return memory_; }
198 private:
199 FILE* file_;
200 void* memory_;
201 int size_;
202};
203
204
205OS::MemoryMappedFile* OS::MemoryMappedFile::create(const char* name, int size,
206 void* initial) {
207 FILE* file = fopen(name, "w+");
208 if (file == NULL) return NULL;
lrn@chromium.org303ada72010-10-27 09:33:13 +0000209 int result = fwrite(initial, size, 1, file);
210 if (result < 1) {
211 fclose(file);
212 return NULL;
213 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000214 void* memory =
215 mmap(0, size, PROT_READ | PROT_WRITE, MAP_SHARED, fileno(file), 0);
216 return new PosixMemoryMappedFile(file, memory, size);
217}
218
219
220PosixMemoryMappedFile::~PosixMemoryMappedFile() {
221 if (memory_) munmap(memory_, size_);
222 fclose(file_);
223}
224
225
226void OS::LogSharedLibraryAddresses() {
kasperl@chromium.orge959c182009-07-27 08:59:04 +0000227#ifdef ENABLE_LOGGING_AND_PROFILING
228 unsigned int images_count = _dyld_image_count();
229 for (unsigned int i = 0; i < images_count; ++i) {
230 const mach_header* header = _dyld_get_image_header(i);
231 if (header == NULL) continue;
ager@chromium.orga1645e22009-09-09 19:27:10 +0000232#if V8_HOST_ARCH_X64
233 uint64_t size;
234 char* code_ptr = getsectdatafromheader_64(
235 reinterpret_cast<const mach_header_64*>(header),
236 SEG_TEXT,
237 SECT_TEXT,
238 &size);
239#else
kasperl@chromium.orge959c182009-07-27 08:59:04 +0000240 unsigned int size;
241 char* code_ptr = getsectdatafromheader(header, SEG_TEXT, SECT_TEXT, &size);
ager@chromium.orga1645e22009-09-09 19:27:10 +0000242#endif
kasperl@chromium.orge959c182009-07-27 08:59:04 +0000243 if (code_ptr == NULL) continue;
244 const uintptr_t slide = _dyld_get_image_vmaddr_slide(i);
245 const uintptr_t start = reinterpret_cast<uintptr_t>(code_ptr) + slide;
246 LOG(SharedLibraryEvent(_dyld_get_image_name(i), start, start + size));
247 }
248#endif // ENABLE_LOGGING_AND_PROFILING
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000249}
250
251
whesse@chromium.org4a5224e2010-10-20 12:37:07 +0000252void OS::SignalCodeMovingGC() {
253}
254
255
ager@chromium.orgc4c92722009-11-18 14:12:51 +0000256uint64_t OS::CpuFeaturesImpliedByPlatform() {
257 // MacOSX requires all these to install so we can assume they are present.
258 // These constants are defined by the CPUid instructions.
259 const uint64_t one = 1;
260 return (one << SSE2) | (one << CMOV) | (one << RDTSC) | (one << CPUID);
261}
262
263
ager@chromium.org236ad962008-09-25 09:45:57 +0000264int OS::ActivationFrameAlignment() {
265 // OS X activation frames must be 16 byte-aligned; see "Mac OS X ABI
266 // Function Call Guide".
267 return 16;
268}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000269
270
kmillikin@chromium.org9155e252010-05-26 13:27:57 +0000271void OS::ReleaseStore(volatile AtomicWord* ptr, AtomicWord value) {
272 OSMemoryBarrier();
273 *ptr = value;
274}
275
276
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000277const char* OS::LocalTimezone(double time) {
278 if (isnan(time)) return "";
279 time_t tv = static_cast<time_t>(floor(time/msPerSecond));
280 struct tm* t = localtime(&tv);
281 if (NULL == t) return "";
282 return t->tm_zone;
283}
284
285
286double OS::LocalTimeOffset() {
287 time_t tv = time(NULL);
288 struct tm* t = localtime(&tv);
289 // tm_gmtoff includes any daylight savings offset, so subtract it.
290 return static_cast<double>(t->tm_gmtoff * msPerSecond -
291 (t->tm_isdst > 0 ? 3600 * msPerSecond : 0));
292}
293
294
ager@chromium.org65dad4b2009-04-23 08:48:43 +0000295int OS::StackWalk(Vector<StackFrame> frames) {
ager@chromium.org5aa501c2009-06-23 07:57:28 +0000296 // If weak link to execinfo lib has failed, ie because we are on 10.4, abort.
297 if (backtrace == NULL)
298 return 0;
299
ager@chromium.org65dad4b2009-04-23 08:48:43 +0000300 int frames_size = frames.length();
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +0000301 ScopedVector<void*> addresses(frames_size);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000302
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +0000303 int frames_count = backtrace(addresses.start(), frames_size);
304
305 char** symbols = backtrace_symbols(addresses.start(), frames_count);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000306 if (symbols == NULL) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000307 return kStackWalkError;
308 }
309
310 for (int i = 0; i < frames_count; i++) {
311 frames[i].address = addresses[i];
312 // Format a text representation of the frame based on the information
313 // available.
kasperl@chromium.orgb9123622008-09-17 14:05:56 +0000314 SNPrintF(MutableCStrVector(frames[i].text,
315 kStackWalkMaxTextLen),
316 "%s",
317 symbols[i]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000318 // Make sure line termination is in place.
319 frames[i].text[kStackWalkMaxTextLen - 1] = '\0';
320 }
321
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000322 free(symbols);
323
324 return frames_count;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000325}
326
327
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000328
329
ager@chromium.org9258b6b2008-09-11 09:11:10 +0000330VirtualMemory::VirtualMemory(size_t size) {
331 address_ = mmap(NULL, size, PROT_NONE,
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000332 MAP_PRIVATE | MAP_ANON | MAP_NORESERVE,
333 kMmapFd, kMmapFdOffset);
334 size_ = size;
335}
336
337
338VirtualMemory::~VirtualMemory() {
339 if (IsReserved()) {
340 if (0 == munmap(address(), size())) address_ = MAP_FAILED;
341 }
342}
343
344
345bool VirtualMemory::IsReserved() {
346 return address_ != MAP_FAILED;
347}
348
349
kasperl@chromium.orgf5aa8372009-03-24 14:47:14 +0000350bool VirtualMemory::Commit(void* address, size_t size, bool is_executable) {
351 int prot = PROT_READ | PROT_WRITE | (is_executable ? PROT_EXEC : 0);
kasper.lund7276f142008-07-30 08:49:36 +0000352 if (MAP_FAILED == mmap(address, size, prot,
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000353 MAP_PRIVATE | MAP_ANON | MAP_FIXED,
354 kMmapFd, kMmapFdOffset)) {
355 return false;
356 }
357
358 UpdateAllocatedSpaceLimits(address, size);
359 return true;
360}
361
362
363bool VirtualMemory::Uncommit(void* address, size_t size) {
364 return mmap(address, size, PROT_NONE,
ager@chromium.orga1645e22009-09-09 19:27:10 +0000365 MAP_PRIVATE | MAP_ANON | MAP_NORESERVE | MAP_FIXED,
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000366 kMmapFd, kMmapFdOffset) != MAP_FAILED;
367}
368
kasperl@chromium.orgf5aa8372009-03-24 14:47:14 +0000369
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000370class ThreadHandle::PlatformData : public Malloced {
371 public:
372 explicit PlatformData(ThreadHandle::Kind kind) {
373 Initialize(kind);
374 }
375
376 void Initialize(ThreadHandle::Kind kind) {
377 switch (kind) {
378 case ThreadHandle::SELF: thread_ = pthread_self(); break;
379 case ThreadHandle::INVALID: thread_ = kNoThread; break;
380 }
381 }
382 pthread_t thread_; // Thread handle for pthread.
383};
384
385
386
387ThreadHandle::ThreadHandle(Kind kind) {
388 data_ = new PlatformData(kind);
389}
390
391
392void ThreadHandle::Initialize(ThreadHandle::Kind kind) {
393 data_->Initialize(kind);
394}
395
396
397ThreadHandle::~ThreadHandle() {
398 delete data_;
399}
400
401
402bool ThreadHandle::IsSelf() const {
403 return pthread_equal(data_->thread_, pthread_self());
404}
405
406
407bool ThreadHandle::IsValid() const {
408 return data_->thread_ != kNoThread;
409}
410
411
412Thread::Thread() : ThreadHandle(ThreadHandle::INVALID) {
413}
414
415
416Thread::~Thread() {
417}
418
419
420static void* ThreadEntry(void* arg) {
421 Thread* thread = reinterpret_cast<Thread*>(arg);
422 // This is also initialized by the first argument to pthread_create() but we
423 // don't know which thread will run first (the original thread or the new
424 // one) so we initialize it here too.
425 thread->thread_handle_data()->thread_ = pthread_self();
426 ASSERT(thread->IsValid());
427 thread->Run();
428 return NULL;
429}
430
431
432void Thread::Start() {
433 pthread_create(&thread_handle_data()->thread_, NULL, ThreadEntry, this);
434}
435
436
437void Thread::Join() {
438 pthread_join(thread_handle_data()->thread_, NULL);
439}
440
441
442Thread::LocalStorageKey Thread::CreateThreadLocalKey() {
443 pthread_key_t key;
444 int result = pthread_key_create(&key, NULL);
445 USE(result);
446 ASSERT(result == 0);
447 return static_cast<LocalStorageKey>(key);
448}
449
450
451void Thread::DeleteThreadLocalKey(LocalStorageKey key) {
452 pthread_key_t pthread_key = static_cast<pthread_key_t>(key);
453 int result = pthread_key_delete(pthread_key);
454 USE(result);
455 ASSERT(result == 0);
456}
457
458
459void* Thread::GetThreadLocal(LocalStorageKey key) {
460 pthread_key_t pthread_key = static_cast<pthread_key_t>(key);
461 return pthread_getspecific(pthread_key);
462}
463
464
465void Thread::SetThreadLocal(LocalStorageKey key, void* value) {
466 pthread_key_t pthread_key = static_cast<pthread_key_t>(key);
467 pthread_setspecific(pthread_key, value);
468}
469
470
471void Thread::YieldCPU() {
472 sched_yield();
473}
474
475
476class MacOSMutex : public Mutex {
477 public:
478
479 MacOSMutex() {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000480 pthread_mutexattr_t attr;
481 pthread_mutexattr_init(&attr);
482 pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);
kasperl@chromium.orge959c182009-07-27 08:59:04 +0000483 pthread_mutex_init(&mutex_, &attr);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000484 }
485
486 ~MacOSMutex() { pthread_mutex_destroy(&mutex_); }
487
488 int Lock() { return pthread_mutex_lock(&mutex_); }
489
490 int Unlock() { return pthread_mutex_unlock(&mutex_); }
491
492 private:
493 pthread_mutex_t mutex_;
494};
495
496
497Mutex* OS::CreateMutex() {
498 return new MacOSMutex();
499}
500
501
502class MacOSSemaphore : public Semaphore {
503 public:
504 explicit MacOSSemaphore(int count) {
505 semaphore_create(mach_task_self(), &semaphore_, SYNC_POLICY_FIFO, count);
506 }
507
508 ~MacOSSemaphore() {
509 semaphore_destroy(mach_task_self(), semaphore_);
510 }
511
kasper.lund7276f142008-07-30 08:49:36 +0000512 // The MacOS mach semaphore documentation claims it does not have spurious
513 // wakeups, the way pthreads semaphores do. So the code from the linux
514 // platform is not needed here.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000515 void Wait() { semaphore_wait(semaphore_); }
516
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000517 bool Wait(int timeout);
518
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000519 void Signal() { semaphore_signal(semaphore_); }
520
521 private:
522 semaphore_t semaphore_;
523};
524
525
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000526bool MacOSSemaphore::Wait(int timeout) {
527 mach_timespec_t ts;
528 ts.tv_sec = timeout / 1000000;
529 ts.tv_nsec = (timeout % 1000000) * 1000;
530 return semaphore_timedwait(semaphore_, ts) != KERN_OPERATION_TIMED_OUT;
531}
532
533
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000534Semaphore* OS::CreateSemaphore(int count) {
535 return new MacOSSemaphore(count);
536}
537
ager@chromium.org381abbb2009-02-25 13:23:22 +0000538
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000539#ifdef ENABLE_LOGGING_AND_PROFILING
540
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000541class Sampler::PlatformData : public Malloced {
542 public:
543 explicit PlatformData(Sampler* sampler)
544 : sampler_(sampler),
545 task_self_(mach_task_self()),
546 profiled_thread_(0),
547 sampler_thread_(0) {
548 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000549
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000550 Sampler* sampler_;
551 // Note: for profiled_thread_ Mach primitives are used instead of PThread's
552 // because the latter doesn't provide thread manipulation primitives required.
553 // For details, consult "Mac OS X Internals" book, Section 7.3.
554 mach_port_t task_self_;
555 thread_act_t profiled_thread_;
556 pthread_t sampler_thread_;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000557
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000558 // Sampler thread handler.
559 void Runner() {
whesse@chromium.org4a5224e2010-10-20 12:37:07 +0000560 // Loop until the sampler is disengaged, keeping the specified
561 // sampling frequency.
lrn@chromium.org25156de2010-04-06 13:10:27 +0000562 for ( ; sampler_->IsActive(); OS::Sleep(sampler_->interval_)) {
lrn@chromium.org25156de2010-04-06 13:10:27 +0000563 TickSample sample_obj;
ricow@chromium.orgc9c80822010-04-21 08:22:37 +0000564 TickSample* sample = CpuProfiler::TickSampleEvent();
ager@chromium.org357bf652010-04-12 11:30:10 +0000565 if (sample == NULL) sample = &sample_obj;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000566
whesse@chromium.org4a5224e2010-10-20 12:37:07 +0000567 // If the sampler runs in sync with the JS thread, we try to
568 // suspend it. If we fail, we skip the current sample.
569 if (sampler_->IsSynchronous()) {
570 if (KERN_SUCCESS != thread_suspend(profiled_thread_)) continue;
571 }
572
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000573 // We always sample the VM state.
ager@chromium.org357bf652010-04-12 11:30:10 +0000574 sample->state = VMState::current_state();
whesse@chromium.org4a5224e2010-10-20 12:37:07 +0000575
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000576 // If profiling, we record the pc and sp of the profiled thread.
whesse@chromium.org4a5224e2010-10-20 12:37:07 +0000577 if (sampler_->IsProfiling()) {
kasperl@chromium.orgb3284ad2009-05-18 06:12:45 +0000578#if V8_HOST_ARCH_X64
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000579 thread_state_flavor_t flavor = x86_THREAD_STATE64;
580 x86_thread_state64_t state;
581 mach_msg_type_number_t count = x86_THREAD_STATE64_COUNT;
christian.plesner.hansen@gmail.com5a6af922009-08-12 14:20:51 +0000582#if __DARWIN_UNIX03
583#define REGISTER_FIELD(name) __r ## name
584#else
585#define REGISTER_FIELD(name) r ## name
586#endif // __DARWIN_UNIX03
kasperl@chromium.orgb3284ad2009-05-18 06:12:45 +0000587#elif V8_HOST_ARCH_IA32
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000588 thread_state_flavor_t flavor = i386_THREAD_STATE;
589 i386_thread_state_t state;
590 mach_msg_type_number_t count = i386_THREAD_STATE_COUNT;
christian.plesner.hansen@gmail.com5a6af922009-08-12 14:20:51 +0000591#if __DARWIN_UNIX03
592#define REGISTER_FIELD(name) __e ## name
593#else
594#define REGISTER_FIELD(name) e ## name
595#endif // __DARWIN_UNIX03
kasperl@chromium.orgb3284ad2009-05-18 06:12:45 +0000596#else
597#error Unsupported Mac OS X host architecture.
christian.plesner.hansen@gmail.com5a6af922009-08-12 14:20:51 +0000598#endif // V8_HOST_ARCH
599
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000600 if (thread_get_state(profiled_thread_,
601 flavor,
602 reinterpret_cast<natural_t*>(&state),
603 &count) == KERN_SUCCESS) {
ager@chromium.org357bf652010-04-12 11:30:10 +0000604 sample->pc = reinterpret_cast<Address>(state.REGISTER_FIELD(ip));
605 sample->sp = reinterpret_cast<Address>(state.REGISTER_FIELD(sp));
606 sample->fp = reinterpret_cast<Address>(state.REGISTER_FIELD(bp));
607 sampler_->SampleStack(sample);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000608 }
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000609 }
610
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000611 // Invoke tick handler with program counter and stack pointer.
lrn@chromium.org25156de2010-04-06 13:10:27 +0000612 sampler_->Tick(sample);
whesse@chromium.org4a5224e2010-10-20 12:37:07 +0000613
614 // If the sampler runs in sync with the JS thread, we have to
615 // remember to resume it.
616 if (sampler_->IsSynchronous()) thread_resume(profiled_thread_);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000617 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000618 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000619};
620
christian.plesner.hansen@gmail.com5a6af922009-08-12 14:20:51 +0000621#undef REGISTER_FIELD
622
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000623
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000624// Entry point for sampler thread.
625static void* SamplerEntry(void* arg) {
626 Sampler::PlatformData* data =
627 reinterpret_cast<Sampler::PlatformData*>(arg);
628 data->Runner();
629 return 0;
630}
631
632
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000633Sampler::Sampler(int interval, bool profiling)
whesse@chromium.org4a5224e2010-10-20 12:37:07 +0000634 : interval_(interval),
635 profiling_(profiling),
636 synchronous_(profiling),
637 active_(false) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000638 data_ = new PlatformData(this);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000639}
640
641
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000642Sampler::~Sampler() {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000643 delete data_;
644}
645
646
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000647void Sampler::Start() {
whesse@chromium.org4a5224e2010-10-20 12:37:07 +0000648 // If we are starting a synchronous sampler, we need to be able to
649 // access the calling thread.
650 if (IsSynchronous()) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000651 data_->profiled_thread_ = mach_thread_self();
652 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000653
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000654 // Create sampler thread with high priority.
655 // According to POSIX spec, when SCHED_FIFO policy is used, a thread
656 // runs until it exits or blocks.
657 pthread_attr_t sched_attr;
658 sched_param fifo_param;
659 pthread_attr_init(&sched_attr);
660 pthread_attr_setinheritsched(&sched_attr, PTHREAD_EXPLICIT_SCHED);
661 pthread_attr_setschedpolicy(&sched_attr, SCHED_FIFO);
662 fifo_param.sched_priority = sched_get_priority_max(SCHED_FIFO);
663 pthread_attr_setschedparam(&sched_attr, &fifo_param);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000664
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000665 active_ = true;
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000666 pthread_create(&data_->sampler_thread_, &sched_attr, SamplerEntry, data_);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000667}
668
669
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000670void Sampler::Stop() {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000671 // Seting active to false triggers termination of the sampler
672 // thread.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000673 active_ = false;
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000674
675 // Wait for sampler thread to terminate.
676 pthread_join(data_->sampler_thread_, NULL);
677
678 // Deallocate Mach port for thread.
whesse@chromium.org4a5224e2010-10-20 12:37:07 +0000679 if (IsSynchronous()) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000680 mach_port_deallocate(data_->task_self_, data_->profiled_thread_);
681 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000682}
683
684#endif // ENABLE_LOGGING_AND_PROFILING
685
686} } // namespace v8::internal