00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030 #include <ucontext.h>
00031 #include <unistd.h>
00032 #include <sys/mman.h>
00033 #include <mach/mach_init.h>
00034
00035 #include <AvailabilityMacros.h>
00036
00037 #ifdef MAC_OS_X_VERSION_10_5
00038 # include <execinfo.h>
00039 #endif
00040
00041 #include <pthread.h>
00042 #include <semaphore.h>
00043 #include <signal.h>
00044 #include <mach/semaphore.h>
00045 #include <mach/task.h>
00046 #include <sys/time.h>
00047 #include <sys/resource.h>
00048 #include <stdarg.h>
00049 #include <stdlib.h>
00050
00051 #undef MAP_TYPE
00052
00053 #include "v8.h"
00054
00055 #include "platform.h"
00056
00057 namespace v8 { namespace internal {
00058
00059
00060
00061 static const pthread_t kNoThread = (pthread_t) 0;
00062
00063
00064 double ceiling(double x) {
00065
00066 if (-1.0 < x && x < 0.0) {
00067 return -0.0;
00068 } else {
00069 return ceil(x);
00070 }
00071 }
00072
00073
00074 void OS::Setup() {
00075
00076
00077
00078
00079
00080 uint64_t seed = static_cast<uint64_t>(TimeCurrentMillis());
00081 srandom(static_cast<unsigned int>(seed));
00082 }
00083
00084
00085 int OS::GetUserTime(uint32_t* secs, uint32_t* usecs) {
00086 struct rusage usage;
00087
00088 if (getrusage(RUSAGE_SELF, &usage) < 0) return -1;
00089 *secs = usage.ru_utime.tv_sec;
00090 *usecs = usage.ru_utime.tv_usec;
00091 return 0;
00092 }
00093
00094
00095 double OS::TimeCurrentMillis() {
00096 struct timeval tv;
00097 if (gettimeofday(&tv, NULL) < 0) return 0.0;
00098 return (static_cast<double>(tv.tv_sec) * 1000) +
00099 (static_cast<double>(tv.tv_usec) / 1000);
00100 }
00101
00102
00103 int64_t OS::Ticks() {
00104
00105 struct timeval tv;
00106 if (gettimeofday(&tv, NULL) < 0)
00107 return 0;
00108 return (static_cast<int64_t>(tv.tv_sec) * 1000000) + tv.tv_usec;
00109 }
00110
00111
00112 char* OS::LocalTimezone(double time) {
00113 time_t tv = static_cast<time_t>(floor(time/msPerSecond));
00114 struct tm* t = localtime(&tv);
00115 return const_cast<char*>(t->tm_zone);
00116 }
00117
00118
00119 double OS::DaylightSavingsOffset(double time) {
00120 time_t tv = static_cast<time_t>(floor(time/msPerSecond));
00121 struct tm* t = localtime(&tv);
00122 return t->tm_isdst > 0 ? 3600 * msPerSecond : 0;
00123 }
00124
00125
00126 double OS::LocalTimeOffset() {
00127 time_t tv = time(NULL);
00128 struct tm* t = localtime(&tv);
00129
00130 return static_cast<double>(t->tm_gmtoff * msPerSecond -
00131 (t->tm_isdst > 0 ? 3600 * msPerSecond : 0));
00132 }
00133
00134
00135 FILE* OS::FOpen(const char* path, const char* mode) {
00136 return fopen(path, mode);
00137 }
00138
00139
00140 void OS::Print(const char* format, ...) {
00141 va_list args;
00142 va_start(args, format);
00143 VPrint(format, args);
00144 va_end(args);
00145 }
00146
00147
00148 void OS::VPrint(const char* format, va_list args) {
00149 vprintf(format, args);
00150 }
00151
00152
00153 void OS::PrintError(const char* format, ...) {
00154 va_list args;
00155 va_start(args, format);
00156 VPrintError(format, args);
00157 va_end(args);
00158 }
00159
00160
00161 void OS::VPrintError(const char* format, va_list args) {
00162 vfprintf(stderr, format, args);
00163 }
00164
00165
00166 int OS::SNPrintF(Vector<char> str, const char* format, ...) {
00167 va_list args;
00168 va_start(args, format);
00169 int result = VSNPrintF(str, format, args);
00170 va_end(args);
00171 return result;
00172 }
00173
00174
00175 int OS::VSNPrintF(Vector<char> str,
00176 const char* format,
00177 va_list args) {
00178 int n = vsnprintf(str.start(), str.length(), format, args);
00179 if (n < 0 || n >= str.length()) {
00180 str[str.length() - 1] = '\0';
00181 return -1;
00182 } else {
00183 return n;
00184 }
00185 }
00186
00187
00188 void OS::StrNCpy(Vector<char> dest, const char* src, size_t n) {
00189 strncpy(dest.start(), src, n);
00190 }
00191
00192
00193 void OS::WcsCpy(Vector<wchar_t> dest, const wchar_t* src) {
00194 wcscpy(dest.start(), src);
00195 }
00196
00197
00198 char *OS::StrDup(const char* str) {
00199 return strdup(str);
00200 }
00201
00202
00203
00204
00205
00206
00207
00208 static void* lowest_ever_allocated = reinterpret_cast<void*>(-1);
00209 static void* highest_ever_allocated = reinterpret_cast<void*>(0);
00210
00211
00212 static void UpdateAllocatedSpaceLimits(void* address, int size) {
00213 lowest_ever_allocated = Min(lowest_ever_allocated, address);
00214 highest_ever_allocated =
00215 Max(highest_ever_allocated,
00216 reinterpret_cast<void*>(reinterpret_cast<char*>(address) + size));
00217 }
00218
00219
00220 bool OS::IsOutsideAllocatedSpace(void* address) {
00221 return address < lowest_ever_allocated || address >= highest_ever_allocated;
00222 }
00223
00224
00225 size_t OS::AllocateAlignment() {
00226 return getpagesize();
00227 }
00228
00229
00230 void* OS::Allocate(const size_t requested,
00231 size_t* allocated,
00232 bool executable) {
00233 const size_t msize = RoundUp(requested, getpagesize());
00234 int prot = PROT_READ | PROT_WRITE | (executable ? PROT_EXEC : 0);
00235 void* mbase = mmap(NULL, msize, prot, MAP_PRIVATE | MAP_ANON, -1, 0);
00236 if (mbase == MAP_FAILED) {
00237 LOG(StringEvent("OS::Allocate", "mmap failed"));
00238 return NULL;
00239 }
00240 *allocated = msize;
00241 UpdateAllocatedSpaceLimits(mbase, msize);
00242 return mbase;
00243 }
00244
00245
00246 void OS::Free(void* buf, const size_t length) {
00247
00248 munmap(buf, length);
00249 }
00250
00251
00252 void OS::Sleep(int miliseconds) {
00253 usleep(1000 * miliseconds);
00254 }
00255
00256
00257 void OS::Abort() {
00258
00259 abort();
00260 }
00261
00262
00263 void OS::DebugBreak() {
00264 asm("int $3");
00265 }
00266
00267
00268 class PosixMemoryMappedFile : public OS::MemoryMappedFile {
00269 public:
00270 PosixMemoryMappedFile(FILE* file, void* memory, int size)
00271 : file_(file), memory_(memory), size_(size) { }
00272 virtual ~PosixMemoryMappedFile();
00273 virtual void* memory() { return memory_; }
00274 private:
00275 FILE* file_;
00276 void* memory_;
00277 int size_;
00278 };
00279
00280
00281 OS::MemoryMappedFile* OS::MemoryMappedFile::create(const char* name, int size,
00282 void* initial) {
00283 FILE* file = fopen(name, "w+");
00284 if (file == NULL) return NULL;
00285 fwrite(initial, size, 1, file);
00286 void* memory =
00287 mmap(0, size, PROT_READ | PROT_WRITE, MAP_SHARED, fileno(file), 0);
00288 return new PosixMemoryMappedFile(file, memory, size);
00289 }
00290
00291
00292 PosixMemoryMappedFile::~PosixMemoryMappedFile() {
00293 if (memory_) munmap(memory_, size_);
00294 fclose(file_);
00295 }
00296
00297
00298 void OS::LogSharedLibraryAddresses() {
00299
00300 }
00301
00302
00303 double OS::nan_value() {
00304 return NAN;
00305 }
00306
00307
00308 int OS::ActivationFrameAlignment() {
00309
00310
00311 return 16;
00312 }
00313
00314
00315 int OS::StackWalk(StackFrame* frames, int frames_size) {
00316 #ifndef MAC_OS_X_VERSION_10_5
00317 return 0;
00318 #else
00319 void** addresses = NewArray<void*>(frames_size);
00320 int frames_count = backtrace(addresses, frames_size);
00321
00322 char** symbols;
00323 symbols = backtrace_symbols(addresses, frames_count);
00324 if (symbols == NULL) {
00325 DeleteArray(addresses);
00326 return kStackWalkError;
00327 }
00328
00329 for (int i = 0; i < frames_count; i++) {
00330 frames[i].address = addresses[i];
00331
00332
00333 SNPrintF(MutableCStrVector(frames[i].text,
00334 kStackWalkMaxTextLen),
00335 "%s",
00336 symbols[i]);
00337
00338 frames[i].text[kStackWalkMaxTextLen - 1] = '\0';
00339 }
00340
00341 DeleteArray(addresses);
00342 free(symbols);
00343
00344 return frames_count;
00345 #endif
00346 }
00347
00348
00349
00350 static const int kMmapFd = -1;
00351 static const int kMmapFdOffset = 0;
00352
00353
00354 VirtualMemory::VirtualMemory(size_t size) {
00355 address_ = mmap(NULL, size, PROT_NONE,
00356 MAP_PRIVATE | MAP_ANON | MAP_NORESERVE,
00357 kMmapFd, kMmapFdOffset);
00358 size_ = size;
00359 }
00360
00361
00362 VirtualMemory::~VirtualMemory() {
00363 if (IsReserved()) {
00364 if (0 == munmap(address(), size())) address_ = MAP_FAILED;
00365 }
00366 }
00367
00368
00369 bool VirtualMemory::IsReserved() {
00370 return address_ != MAP_FAILED;
00371 }
00372
00373
00374 bool VirtualMemory::Commit(void* address, size_t size, bool executable) {
00375 int prot = PROT_READ | PROT_WRITE | (executable ? PROT_EXEC : 0);
00376 if (MAP_FAILED == mmap(address, size, prot,
00377 MAP_PRIVATE | MAP_ANON | MAP_FIXED,
00378 kMmapFd, kMmapFdOffset)) {
00379 return false;
00380 }
00381
00382 UpdateAllocatedSpaceLimits(address, size);
00383 return true;
00384 }
00385
00386
00387 bool VirtualMemory::Uncommit(void* address, size_t size) {
00388 return mmap(address, size, PROT_NONE,
00389 MAP_PRIVATE | MAP_ANON | MAP_NORESERVE,
00390 kMmapFd, kMmapFdOffset) != MAP_FAILED;
00391 }
00392
00393 class ThreadHandle::PlatformData : public Malloced {
00394 public:
00395 explicit PlatformData(ThreadHandle::Kind kind) {
00396 Initialize(kind);
00397 }
00398
00399 void Initialize(ThreadHandle::Kind kind) {
00400 switch (kind) {
00401 case ThreadHandle::SELF: thread_ = pthread_self(); break;
00402 case ThreadHandle::INVALID: thread_ = kNoThread; break;
00403 }
00404 }
00405 pthread_t thread_;
00406 };
00407
00408
00409
00410 ThreadHandle::ThreadHandle(Kind kind) {
00411 data_ = new PlatformData(kind);
00412 }
00413
00414
00415 void ThreadHandle::Initialize(ThreadHandle::Kind kind) {
00416 data_->Initialize(kind);
00417 }
00418
00419
00420 ThreadHandle::~ThreadHandle() {
00421 delete data_;
00422 }
00423
00424
00425 bool ThreadHandle::IsSelf() const {
00426 return pthread_equal(data_->thread_, pthread_self());
00427 }
00428
00429
00430 bool ThreadHandle::IsValid() const {
00431 return data_->thread_ != kNoThread;
00432 }
00433
00434
00435 Thread::Thread() : ThreadHandle(ThreadHandle::INVALID) {
00436 }
00437
00438
00439 Thread::~Thread() {
00440 }
00441
00442
00443 static void* ThreadEntry(void* arg) {
00444 Thread* thread = reinterpret_cast<Thread*>(arg);
00445
00446
00447
00448 thread->thread_handle_data()->thread_ = pthread_self();
00449 ASSERT(thread->IsValid());
00450 thread->Run();
00451 return NULL;
00452 }
00453
00454
00455 void Thread::Start() {
00456 pthread_create(&thread_handle_data()->thread_, NULL, ThreadEntry, this);
00457 }
00458
00459
00460 void Thread::Join() {
00461 pthread_join(thread_handle_data()->thread_, NULL);
00462 }
00463
00464
00465 Thread::LocalStorageKey Thread::CreateThreadLocalKey() {
00466 pthread_key_t key;
00467 int result = pthread_key_create(&key, NULL);
00468 USE(result);
00469 ASSERT(result == 0);
00470 return static_cast<LocalStorageKey>(key);
00471 }
00472
00473
00474 void Thread::DeleteThreadLocalKey(LocalStorageKey key) {
00475 pthread_key_t pthread_key = static_cast<pthread_key_t>(key);
00476 int result = pthread_key_delete(pthread_key);
00477 USE(result);
00478 ASSERT(result == 0);
00479 }
00480
00481
00482 void* Thread::GetThreadLocal(LocalStorageKey key) {
00483 pthread_key_t pthread_key = static_cast<pthread_key_t>(key);
00484 return pthread_getspecific(pthread_key);
00485 }
00486
00487
00488 void Thread::SetThreadLocal(LocalStorageKey key, void* value) {
00489 pthread_key_t pthread_key = static_cast<pthread_key_t>(key);
00490 pthread_setspecific(pthread_key, value);
00491 }
00492
00493
00494 void Thread::YieldCPU() {
00495 sched_yield();
00496 }
00497
00498
00499 class MacOSMutex : public Mutex {
00500 public:
00501
00502 MacOSMutex() {
00503
00504
00505 pthread_mutex_t m = PTHREAD_MUTEX_INITIALIZER;
00506 pthread_mutexattr_t attr;
00507 pthread_mutexattr_init(&attr);
00508 pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);
00509 pthread_mutex_init(&m, &attr);
00510 mutex_ = m;
00511 }
00512
00513 ~MacOSMutex() { pthread_mutex_destroy(&mutex_); }
00514
00515 int Lock() { return pthread_mutex_lock(&mutex_); }
00516
00517 int Unlock() { return pthread_mutex_unlock(&mutex_); }
00518
00519 private:
00520 pthread_mutex_t mutex_;
00521 };
00522
00523
00524 Mutex* OS::CreateMutex() {
00525 return new MacOSMutex();
00526 }
00527
00528
00529 class MacOSSemaphore : public Semaphore {
00530 public:
00531 explicit MacOSSemaphore(int count) {
00532 semaphore_create(mach_task_self(), &semaphore_, SYNC_POLICY_FIFO, count);
00533 }
00534
00535 ~MacOSSemaphore() {
00536 semaphore_destroy(mach_task_self(), semaphore_);
00537 }
00538
00539
00540
00541
00542 void Wait() { semaphore_wait(semaphore_); }
00543
00544 void Signal() { semaphore_signal(semaphore_); }
00545
00546 private:
00547 semaphore_t semaphore_;
00548 };
00549
00550
00551 Semaphore* OS::CreateSemaphore(int count) {
00552 return new MacOSSemaphore(count);
00553 }
00554
00555 #ifdef ENABLE_LOGGING_AND_PROFILING
00556
00557 static Sampler* active_sampler_ = NULL;
00558
00559 static void ProfilerSignalHandler(int signal, siginfo_t* info, void* context) {
00560 USE(info);
00561 if (signal != SIGPROF) return;
00562 if (active_sampler_ == NULL) return;
00563
00564 TickSample sample;
00565
00566
00567 if (active_sampler_->IsProfiling()) {
00568
00569 ucontext_t* ucontext = reinterpret_cast<ucontext_t*>(context);
00570 mcontext_t& mcontext = ucontext->uc_mcontext;
00571 #if __DARWIN_UNIX03
00572 sample.pc = mcontext->__ss.__eip;
00573 sample.sp = mcontext->__ss.__esp;
00574 #else // !__DARWIN_UNIX03
00575 sample.pc = mcontext->ss.eip;
00576 sample.sp = mcontext->ss.esp;
00577 #endif // __DARWIN_UNIX03
00578 }
00579
00580
00581 sample.state = Logger::state();
00582
00583 active_sampler_->Tick(&sample);
00584 }
00585
00586
00587 class Sampler::PlatformData : public Malloced {
00588 public:
00589 PlatformData() {
00590 signal_handler_installed_ = false;
00591 }
00592
00593 bool signal_handler_installed_;
00594 struct sigaction old_signal_handler_;
00595 struct itimerval old_timer_value_;
00596 };
00597
00598
00599 Sampler::Sampler(int interval, bool profiling)
00600 : interval_(interval), profiling_(profiling), active_(false) {
00601 data_ = new PlatformData();
00602 }
00603
00604
00605 Sampler::~Sampler() {
00606 delete data_;
00607 }
00608
00609
00610 void Sampler::Start() {
00611
00612
00613 if (active_sampler_ != NULL) return;
00614
00615
00616 struct sigaction sa;
00617 sa.sa_sigaction = ProfilerSignalHandler;
00618 sigemptyset(&sa.sa_mask);
00619 sa.sa_flags = SA_SIGINFO;
00620 if (sigaction(SIGPROF, &sa, &data_->old_signal_handler_) != 0) return;
00621 data_->signal_handler_installed_ = true;
00622
00623
00624 itimerval itimer;
00625 itimer.it_interval.tv_sec = interval_ / 1000;
00626 itimer.it_interval.tv_usec = (interval_ % 1000) * 1000;
00627 itimer.it_value.tv_sec = itimer.it_interval.tv_sec;
00628 itimer.it_value.tv_usec = itimer.it_interval.tv_usec;
00629 setitimer(ITIMER_PROF, &itimer, &data_->old_timer_value_);
00630
00631
00632 active_sampler_ = this;
00633 active_ = true;
00634 }
00635
00636
00637 void Sampler::Stop() {
00638
00639 if (data_->signal_handler_installed_) {
00640 setitimer(ITIMER_PROF, &data_->old_timer_value_, NULL);
00641 sigaction(SIGPROF, &data_->old_signal_handler_, 0);
00642 data_->signal_handler_installed_ = false;
00643 }
00644
00645
00646 active_sampler_ = NULL;
00647 active_ = false;
00648 }
00649
00650 #endif // ENABLE_LOGGING_AND_PROFILING
00651
00652 } }