~evarlast/ubuntu/utopic/mongodb/upstart-workaround-debian-bug-718702

« back to all changes in this revision

Viewing changes to src/third_party/v8/src/platform-macos.cc

  • Committer: Package Import Robot
  • Author(s): James Page, James Page, Robie Basak
  • Date: 2013-05-29 17:44:42 UTC
  • mfrom: (44.1.7 sid)
  • Revision ID: package-import@ubuntu.com-20130529174442-z0a4qmoww4y0t458
Tags: 1:2.4.3-1ubuntu1
[ James Page ]
* Merge from Debian unstable, remaining changes:
  - Enable SSL support:
    + d/control: Add libssl-dev to BD's.
    + d/rules: Enabled --ssl option.
    + d/mongodb.conf: Add example SSL configuration options.
  - d/mongodb-server.mongodb.upstart: Add upstart configuration.
  - d/rules: Don't strip binaries during scons build for Ubuntu.
  - d/control: Add armhf to target archs.
  - d/p/SConscript.client.patch: fixup install of client libraries.
  - d/p/0010-install-libs-to-usr-lib-not-usr-lib64-Closes-588557.patch:
    Install libraries to lib not lib64.
* Dropped changes:
  - d/p/arm-support.patch: Included in Debian.
  - d/p/double-alignment.patch: Included in Debian.
  - d/rules,control: Debian also builds with avaliable system libraries
    now.
* Fix FTBFS due to gcc and boost upgrades in saucy:
  - d/p/0008-ignore-unused-local-typedefs.patch: Add -Wno-unused-typedefs
    to unbreak building with g++-4.8.
  - d/p/0009-boost-1.53.patch: Fixup signed/unsigned casting issue.

[ Robie Basak ]
* d/p/0011-Use-a-signed-char-to-store-BSONType-enumerations.patch: Fixup
  build failure on ARM due to missing signed'ness of char cast.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
// Copyright 2012 the V8 project authors. All rights reserved.
 
2
// 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 MacOS goes here. For the POSIX comaptible parts
 
29
// the implementation is in platform-posix.cc.
 
30
 
 
31
#include <dlfcn.h>
 
32
#include <unistd.h>
 
33
#include <sys/mman.h>
 
34
#include <mach/mach_init.h>
 
35
#include <mach-o/dyld.h>
 
36
#include <mach-o/getsect.h>
 
37
 
 
38
#include <AvailabilityMacros.h>
 
39
 
 
40
#include <pthread.h>
 
41
#include <semaphore.h>
 
42
#include <signal.h>
 
43
#include <libkern/OSAtomic.h>
 
44
#include <mach/mach.h>
 
45
#include <mach/semaphore.h>
 
46
#include <mach/task.h>
 
47
#include <mach/vm_statistics.h>
 
48
#include <sys/time.h>
 
49
#include <sys/resource.h>
 
50
#include <sys/types.h>
 
51
#include <sys/sysctl.h>
 
52
#include <stdarg.h>
 
53
#include <stdlib.h>
 
54
#include <string.h>
 
55
#include <errno.h>
 
56
 
 
57
#undef MAP_TYPE
 
58
 
 
59
#include "v8.h"
 
60
 
 
61
#include "platform-posix.h"
 
62
#include "platform.h"
 
63
#include "vm-state-inl.h"
 
64
 
 
65
// Manually define these here as weak imports, rather than including execinfo.h.
 
66
// This lets us launch on 10.4 which does not have these calls.
 
67
extern "C" {
 
68
  extern int backtrace(void**, int) __attribute__((weak_import));
 
69
  extern char** backtrace_symbols(void* const*, int)
 
70
      __attribute__((weak_import));
 
71
  extern void backtrace_symbols_fd(void* const*, int, int)
 
72
      __attribute__((weak_import));
 
73
}
 
74
 
 
75
 
 
76
namespace v8 {
 
77
namespace internal {
 
78
 
 
79
// 0 is never a valid thread id on MacOSX since a pthread_t is
 
80
// a pointer.
 
81
static const pthread_t kNoThread = (pthread_t) 0;
 
82
 
 
83
 
 
84
double ceiling(double x) {
 
85
  // Correct Mac OS X Leopard 'ceil' behavior.
 
86
  if (-1.0 < x && x < 0.0) {
 
87
    return -0.0;
 
88
  } else {
 
89
    return ceil(x);
 
90
  }
 
91
}
 
92
 
 
93
 
 
94
static Mutex* limit_mutex = NULL;
 
95
 
 
96
 
 
97
void OS::PostSetUp() {
 
98
  POSIXPostSetUp();
 
99
}
 
100
 
 
101
 
 
102
// We keep the lowest and highest addresses mapped as a quick way of
 
103
// determining that pointers are outside the heap (used mostly in assertions
 
104
// and verification).  The estimate is conservative, i.e., not all addresses in
 
105
// 'allocated' space are actually allocated to our heap.  The range is
 
106
// [lowest, highest), inclusive on the low and and exclusive on the high end.
 
107
static void* lowest_ever_allocated = reinterpret_cast<void*>(-1);
 
108
static void* highest_ever_allocated = reinterpret_cast<void*>(0);
 
109
 
 
110
 
 
111
static void UpdateAllocatedSpaceLimits(void* address, int size) {
 
112
  ASSERT(limit_mutex != NULL);
 
113
  ScopedLock lock(limit_mutex);
 
114
 
 
115
  lowest_ever_allocated = Min(lowest_ever_allocated, address);
 
116
  highest_ever_allocated =
 
117
      Max(highest_ever_allocated,
 
118
          reinterpret_cast<void*>(reinterpret_cast<char*>(address) + size));
 
119
}
 
120
 
 
121
 
 
122
bool OS::IsOutsideAllocatedSpace(void* address) {
 
123
  return address < lowest_ever_allocated || address >= highest_ever_allocated;
 
124
}
 
125
 
 
126
 
 
127
size_t OS::AllocateAlignment() {
 
128
  return getpagesize();
 
129
}
 
130
 
 
131
 
 
132
// Constants used for mmap.
 
133
// kMmapFd is used to pass vm_alloc flags to tag the region with the user
 
134
// defined tag 255 This helps identify V8-allocated regions in memory analysis
 
135
// tools like vmmap(1).
 
136
static const int kMmapFd = VM_MAKE_TAG(255);
 
137
static const off_t kMmapFdOffset = 0;
 
138
 
 
139
 
 
140
void* OS::Allocate(const size_t requested,
 
141
                   size_t* allocated,
 
142
                   bool is_executable) {
 
143
  const size_t msize = RoundUp(requested, getpagesize());
 
144
  int prot = PROT_READ | PROT_WRITE | (is_executable ? PROT_EXEC : 0);
 
145
  void* mbase = mmap(OS::GetRandomMmapAddr(),
 
146
                     msize,
 
147
                     prot,
 
148
                     MAP_PRIVATE | MAP_ANON,
 
149
                     kMmapFd,
 
150
                     kMmapFdOffset);
 
151
  if (mbase == MAP_FAILED) {
 
152
    LOG(Isolate::Current(), StringEvent("OS::Allocate", "mmap failed"));
 
153
    return NULL;
 
154
  }
 
155
  *allocated = msize;
 
156
  UpdateAllocatedSpaceLimits(mbase, msize);
 
157
  return mbase;
 
158
}
 
159
 
 
160
 
 
161
void OS::Free(void* address, const size_t size) {
 
162
  // TODO(1240712): munmap has a return value which is ignored here.
 
163
  int result = munmap(address, size);
 
164
  USE(result);
 
165
  ASSERT(result == 0);
 
166
}
 
167
 
 
168
 
 
169
void OS::Sleep(int milliseconds) {
 
170
  usleep(1000 * milliseconds);
 
171
}
 
172
 
 
173
 
 
174
void OS::Abort() {
 
175
  // Redirect to std abort to signal abnormal program termination
 
176
  abort();
 
177
}
 
178
 
 
179
 
 
180
void OS::DebugBreak() {
 
181
  asm("int $3");
 
182
}
 
183
 
 
184
 
 
185
class PosixMemoryMappedFile : public OS::MemoryMappedFile {
 
186
 public:
 
187
  PosixMemoryMappedFile(FILE* file, void* memory, int size)
 
188
    : file_(file), memory_(memory), size_(size) { }
 
189
  virtual ~PosixMemoryMappedFile();
 
190
  virtual void* memory() { return memory_; }
 
191
  virtual int size() { return size_; }
 
192
 private:
 
193
  FILE* file_;
 
194
  void* memory_;
 
195
  int size_;
 
196
};
 
197
 
 
198
 
 
199
OS::MemoryMappedFile* OS::MemoryMappedFile::open(const char* name) {
 
200
  FILE* file = fopen(name, "r+");
 
201
  if (file == NULL) return NULL;
 
202
 
 
203
  fseek(file, 0, SEEK_END);
 
204
  int size = ftell(file);
 
205
 
 
206
  void* memory =
 
207
      mmap(OS::GetRandomMmapAddr(),
 
208
           size,
 
209
           PROT_READ | PROT_WRITE,
 
210
           MAP_SHARED,
 
211
           fileno(file),
 
212
           0);
 
213
  return new PosixMemoryMappedFile(file, memory, size);
 
214
}
 
215
 
 
216
 
 
217
OS::MemoryMappedFile* OS::MemoryMappedFile::create(const char* name, int size,
 
218
    void* initial) {
 
219
  FILE* file = fopen(name, "w+");
 
220
  if (file == NULL) return NULL;
 
221
  int result = fwrite(initial, size, 1, file);
 
222
  if (result < 1) {
 
223
    fclose(file);
 
224
    return NULL;
 
225
  }
 
226
  void* memory =
 
227
      mmap(OS::GetRandomMmapAddr(),
 
228
          size,
 
229
          PROT_READ | PROT_WRITE,
 
230
          MAP_SHARED,
 
231
          fileno(file),
 
232
          0);
 
233
  return new PosixMemoryMappedFile(file, memory, size);
 
234
}
 
235
 
 
236
 
 
237
PosixMemoryMappedFile::~PosixMemoryMappedFile() {
 
238
  if (memory_) OS::Free(memory_, size_);
 
239
  fclose(file_);
 
240
}
 
241
 
 
242
 
 
243
void OS::LogSharedLibraryAddresses() {
 
244
  unsigned int images_count = _dyld_image_count();
 
245
  for (unsigned int i = 0; i < images_count; ++i) {
 
246
    const mach_header* header = _dyld_get_image_header(i);
 
247
    if (header == NULL) continue;
 
248
#if V8_HOST_ARCH_X64
 
249
    uint64_t size;
 
250
    char* code_ptr = getsectdatafromheader_64(
 
251
        reinterpret_cast<const mach_header_64*>(header),
 
252
        SEG_TEXT,
 
253
        SECT_TEXT,
 
254
        &size);
 
255
#else
 
256
    unsigned int size;
 
257
    char* code_ptr = getsectdatafromheader(header, SEG_TEXT, SECT_TEXT, &size);
 
258
#endif
 
259
    if (code_ptr == NULL) continue;
 
260
    const uintptr_t slide = _dyld_get_image_vmaddr_slide(i);
 
261
    const uintptr_t start = reinterpret_cast<uintptr_t>(code_ptr) + slide;
 
262
    LOG(Isolate::Current(),
 
263
        SharedLibraryEvent(_dyld_get_image_name(i), start, start + size));
 
264
  }
 
265
}
 
266
 
 
267
 
 
268
void OS::SignalCodeMovingGC() {
 
269
}
 
270
 
 
271
 
 
272
uint64_t OS::CpuFeaturesImpliedByPlatform() {
 
273
  // MacOSX requires all these to install so we can assume they are present.
 
274
  // These constants are defined by the CPUid instructions.
 
275
  const uint64_t one = 1;
 
276
  return (one << SSE2) | (one << CMOV) | (one << RDTSC) | (one << CPUID);
 
277
}
 
278
 
 
279
 
 
280
int OS::ActivationFrameAlignment() {
 
281
  // OS X activation frames must be 16 byte-aligned; see "Mac OS X ABI
 
282
  // Function Call Guide".
 
283
  return 16;
 
284
}
 
285
 
 
286
 
 
287
void OS::ReleaseStore(volatile AtomicWord* ptr, AtomicWord value) {
 
288
  OSMemoryBarrier();
 
289
  *ptr = value;
 
290
}
 
291
 
 
292
 
 
293
const char* OS::LocalTimezone(double time) {
 
294
  if (isnan(time)) return "";
 
295
  time_t tv = static_cast<time_t>(floor(time/msPerSecond));
 
296
  struct tm* t = localtime(&tv);
 
297
  if (NULL == t) return "";
 
298
  return t->tm_zone;
 
299
}
 
300
 
 
301
 
 
302
double OS::LocalTimeOffset() {
 
303
  time_t tv = time(NULL);
 
304
  struct tm* t = localtime(&tv);
 
305
  // tm_gmtoff includes any daylight savings offset, so subtract it.
 
306
  return static_cast<double>(t->tm_gmtoff * msPerSecond -
 
307
                             (t->tm_isdst > 0 ? 3600 * msPerSecond : 0));
 
308
}
 
309
 
 
310
 
 
311
int OS::StackWalk(Vector<StackFrame> frames) {
 
312
  // If weak link to execinfo lib has failed, ie because we are on 10.4, abort.
 
313
  if (backtrace == NULL)
 
314
    return 0;
 
315
 
 
316
  int frames_size = frames.length();
 
317
  ScopedVector<void*> addresses(frames_size);
 
318
 
 
319
  int frames_count = backtrace(addresses.start(), frames_size);
 
320
 
 
321
  char** symbols = backtrace_symbols(addresses.start(), frames_count);
 
322
  if (symbols == NULL) {
 
323
    return kStackWalkError;
 
324
  }
 
325
 
 
326
  for (int i = 0; i < frames_count; i++) {
 
327
    frames[i].address = addresses[i];
 
328
    // Format a text representation of the frame based on the information
 
329
    // available.
 
330
    SNPrintF(MutableCStrVector(frames[i].text,
 
331
                               kStackWalkMaxTextLen),
 
332
             "%s",
 
333
             symbols[i]);
 
334
    // Make sure line termination is in place.
 
335
    frames[i].text[kStackWalkMaxTextLen - 1] = '\0';
 
336
  }
 
337
 
 
338
  free(symbols);
 
339
 
 
340
  return frames_count;
 
341
}
 
342
 
 
343
 
 
344
VirtualMemory::VirtualMemory() : address_(NULL), size_(0) { }
 
345
 
 
346
 
 
347
VirtualMemory::VirtualMemory(size_t size)
 
348
    : address_(ReserveRegion(size)), size_(size) { }
 
349
 
 
350
 
 
351
VirtualMemory::VirtualMemory(size_t size, size_t alignment)
 
352
    : address_(NULL), size_(0) {
 
353
  ASSERT(IsAligned(alignment, static_cast<intptr_t>(OS::AllocateAlignment())));
 
354
  size_t request_size = RoundUp(size + alignment,
 
355
                                static_cast<intptr_t>(OS::AllocateAlignment()));
 
356
  void* reservation = mmap(OS::GetRandomMmapAddr(),
 
357
                           request_size,
 
358
                           PROT_NONE,
 
359
                           MAP_PRIVATE | MAP_ANON | MAP_NORESERVE,
 
360
                           kMmapFd,
 
361
                           kMmapFdOffset);
 
362
  if (reservation == MAP_FAILED) return;
 
363
 
 
364
  Address base = static_cast<Address>(reservation);
 
365
  Address aligned_base = RoundUp(base, alignment);
 
366
  ASSERT_LE(base, aligned_base);
 
367
 
 
368
  // Unmap extra memory reserved before and after the desired block.
 
369
  if (aligned_base != base) {
 
370
    size_t prefix_size = static_cast<size_t>(aligned_base - base);
 
371
    OS::Free(base, prefix_size);
 
372
    request_size -= prefix_size;
 
373
  }
 
374
 
 
375
  size_t aligned_size = RoundUp(size, OS::AllocateAlignment());
 
376
  ASSERT_LE(aligned_size, request_size);
 
377
 
 
378
  if (aligned_size != request_size) {
 
379
    size_t suffix_size = request_size - aligned_size;
 
380
    OS::Free(aligned_base + aligned_size, suffix_size);
 
381
    request_size -= suffix_size;
 
382
  }
 
383
 
 
384
  ASSERT(aligned_size == request_size);
 
385
 
 
386
  address_ = static_cast<void*>(aligned_base);
 
387
  size_ = aligned_size;
 
388
}
 
389
 
 
390
 
 
391
VirtualMemory::~VirtualMemory() {
 
392
  if (IsReserved()) {
 
393
    bool result = ReleaseRegion(address(), size());
 
394
    ASSERT(result);
 
395
    USE(result);
 
396
  }
 
397
}
 
398
 
 
399
 
 
400
void VirtualMemory::Reset() {
 
401
  address_ = NULL;
 
402
  size_ = 0;
 
403
}
 
404
 
 
405
 
 
406
void* VirtualMemory::ReserveRegion(size_t size) {
 
407
  void* result = mmap(OS::GetRandomMmapAddr(),
 
408
                      size,
 
409
                      PROT_NONE,
 
410
                      MAP_PRIVATE | MAP_ANON | MAP_NORESERVE,
 
411
                      kMmapFd,
 
412
                      kMmapFdOffset);
 
413
 
 
414
  if (result == MAP_FAILED) return NULL;
 
415
 
 
416
  return result;
 
417
}
 
418
 
 
419
 
 
420
bool VirtualMemory::IsReserved() {
 
421
  return address_ != NULL;
 
422
}
 
423
 
 
424
 
 
425
bool VirtualMemory::Commit(void* address, size_t size, bool is_executable) {
 
426
  return CommitRegion(address, size, is_executable);
 
427
}
 
428
 
 
429
 
 
430
bool VirtualMemory::Guard(void* address) {
 
431
  OS::Guard(address, OS::CommitPageSize());
 
432
  return true;
 
433
}
 
434
 
 
435
 
 
436
bool VirtualMemory::CommitRegion(void* address,
 
437
                                 size_t size,
 
438
                                 bool is_executable) {
 
439
  int prot = PROT_READ | PROT_WRITE | (is_executable ? PROT_EXEC : 0);
 
440
  if (MAP_FAILED == mmap(address,
 
441
                         size,
 
442
                         prot,
 
443
                         MAP_PRIVATE | MAP_ANON | MAP_FIXED,
 
444
                         kMmapFd,
 
445
                         kMmapFdOffset)) {
 
446
    return false;
 
447
  }
 
448
 
 
449
  UpdateAllocatedSpaceLimits(address, size);
 
450
  return true;
 
451
}
 
452
 
 
453
 
 
454
bool VirtualMemory::Uncommit(void* address, size_t size) {
 
455
  return UncommitRegion(address, size);
 
456
}
 
457
 
 
458
 
 
459
bool VirtualMemory::UncommitRegion(void* address, size_t size) {
 
460
  return mmap(address,
 
461
              size,
 
462
              PROT_NONE,
 
463
              MAP_PRIVATE | MAP_ANON | MAP_NORESERVE | MAP_FIXED,
 
464
              kMmapFd,
 
465
              kMmapFdOffset) != MAP_FAILED;
 
466
}
 
467
 
 
468
 
 
469
bool VirtualMemory::ReleaseRegion(void* address, size_t size) {
 
470
  return munmap(address, size) == 0;
 
471
}
 
472
 
 
473
 
 
474
class Thread::PlatformData : public Malloced {
 
475
 public:
 
476
  PlatformData() : thread_(kNoThread) {}
 
477
  pthread_t thread_;  // Thread handle for pthread.
 
478
};
 
479
 
 
480
 
 
481
Thread::Thread(const Options& options)
 
482
    : data_(new PlatformData),
 
483
      stack_size_(options.stack_size()) {
 
484
  set_name(options.name());
 
485
}
 
486
 
 
487
 
 
488
Thread::~Thread() {
 
489
  delete data_;
 
490
}
 
491
 
 
492
 
 
493
static void SetThreadName(const char* name) {
 
494
  // pthread_setname_np is only available in 10.6 or later, so test
 
495
  // for it at runtime.
 
496
  int (*dynamic_pthread_setname_np)(const char*);
 
497
  *reinterpret_cast<void**>(&dynamic_pthread_setname_np) =
 
498
    dlsym(RTLD_DEFAULT, "pthread_setname_np");
 
499
  if (!dynamic_pthread_setname_np)
 
500
    return;
 
501
 
 
502
  // Mac OS X does not expose the length limit of the name, so hardcode it.
 
503
  static const int kMaxNameLength = 63;
 
504
  USE(kMaxNameLength);
 
505
  ASSERT(Thread::kMaxThreadNameLength <= kMaxNameLength);
 
506
  dynamic_pthread_setname_np(name);
 
507
}
 
508
 
 
509
 
 
510
static void* ThreadEntry(void* arg) {
 
511
  Thread* thread = reinterpret_cast<Thread*>(arg);
 
512
  // This is also initialized by the first argument to pthread_create() but we
 
513
  // don't know which thread will run first (the original thread or the new
 
514
  // one) so we initialize it here too.
 
515
  thread->data()->thread_ = pthread_self();
 
516
  SetThreadName(thread->name());
 
517
  ASSERT(thread->data()->thread_ != kNoThread);
 
518
  thread->Run();
 
519
  return NULL;
 
520
}
 
521
 
 
522
 
 
523
void Thread::set_name(const char* name) {
 
524
  strncpy(name_, name, sizeof(name_));
 
525
  name_[sizeof(name_) - 1] = '\0';
 
526
}
 
527
 
 
528
 
 
529
void Thread::Start() {
 
530
  pthread_attr_t* attr_ptr = NULL;
 
531
  pthread_attr_t attr;
 
532
  if (stack_size_ > 0) {
 
533
    pthread_attr_init(&attr);
 
534
    pthread_attr_setstacksize(&attr, static_cast<size_t>(stack_size_));
 
535
    attr_ptr = &attr;
 
536
  }
 
537
  pthread_create(&data_->thread_, attr_ptr, ThreadEntry, this);
 
538
  ASSERT(data_->thread_ != kNoThread);
 
539
}
 
540
 
 
541
 
 
542
void Thread::Join() {
 
543
  pthread_join(data_->thread_, NULL);
 
544
}
 
545
 
 
546
 
 
547
#ifdef V8_FAST_TLS_SUPPORTED
 
548
 
 
549
static Atomic32 tls_base_offset_initialized = 0;
 
550
intptr_t kMacTlsBaseOffset = 0;
 
551
 
 
552
// It's safe to do the initialization more that once, but it has to be
 
553
// done at least once.
 
554
static void InitializeTlsBaseOffset() {
 
555
  const size_t kBufferSize = 128;
 
556
  char buffer[kBufferSize];
 
557
  size_t buffer_size = kBufferSize;
 
558
  int ctl_name[] = { CTL_KERN , KERN_OSRELEASE };
 
559
  if (sysctl(ctl_name, 2, buffer, &buffer_size, NULL, 0) != 0) {
 
560
    V8_Fatal(__FILE__, __LINE__, "V8 failed to get kernel version");
 
561
  }
 
562
  // The buffer now contains a string of the form XX.YY.ZZ, where
 
563
  // XX is the major kernel version component.
 
564
  // Make sure the buffer is 0-terminated.
 
565
  buffer[kBufferSize - 1] = '\0';
 
566
  char* period_pos = strchr(buffer, '.');
 
567
  *period_pos = '\0';
 
568
  int kernel_version_major =
 
569
      static_cast<int>(strtol(buffer, NULL, 10));  // NOLINT
 
570
  // The constants below are taken from pthreads.s from the XNU kernel
 
571
  // sources archive at www.opensource.apple.com.
 
572
  if (kernel_version_major < 11) {
 
573
    // 8.x.x (Tiger), 9.x.x (Leopard), 10.x.x (Snow Leopard) have the
 
574
    // same offsets.
 
575
#if defined(V8_HOST_ARCH_IA32)
 
576
    kMacTlsBaseOffset = 0x48;
 
577
#else
 
578
    kMacTlsBaseOffset = 0x60;
 
579
#endif
 
580
  } else {
 
581
    // 11.x.x (Lion) changed the offset.
 
582
    kMacTlsBaseOffset = 0;
 
583
  }
 
584
 
 
585
  Release_Store(&tls_base_offset_initialized, 1);
 
586
}
 
587
 
 
588
static void CheckFastTls(Thread::LocalStorageKey key) {
 
589
  void* expected = reinterpret_cast<void*>(0x1234CAFE);
 
590
  Thread::SetThreadLocal(key, expected);
 
591
  void* actual = Thread::GetExistingThreadLocal(key);
 
592
  if (expected != actual) {
 
593
    V8_Fatal(__FILE__, __LINE__,
 
594
             "V8 failed to initialize fast TLS on current kernel");
 
595
  }
 
596
  Thread::SetThreadLocal(key, NULL);
 
597
}
 
598
 
 
599
#endif  // V8_FAST_TLS_SUPPORTED
 
600
 
 
601
 
 
602
Thread::LocalStorageKey Thread::CreateThreadLocalKey() {
 
603
#ifdef V8_FAST_TLS_SUPPORTED
 
604
  bool check_fast_tls = false;
 
605
  if (tls_base_offset_initialized == 0) {
 
606
    check_fast_tls = true;
 
607
    InitializeTlsBaseOffset();
 
608
  }
 
609
#endif
 
610
  pthread_key_t key;
 
611
  int result = pthread_key_create(&key, NULL);
 
612
  USE(result);
 
613
  ASSERT(result == 0);
 
614
  LocalStorageKey typed_key = static_cast<LocalStorageKey>(key);
 
615
#ifdef V8_FAST_TLS_SUPPORTED
 
616
  // If we just initialized fast TLS support, make sure it works.
 
617
  if (check_fast_tls) CheckFastTls(typed_key);
 
618
#endif
 
619
  return typed_key;
 
620
}
 
621
 
 
622
 
 
623
void Thread::DeleteThreadLocalKey(LocalStorageKey key) {
 
624
  pthread_key_t pthread_key = static_cast<pthread_key_t>(key);
 
625
  int result = pthread_key_delete(pthread_key);
 
626
  USE(result);
 
627
  ASSERT(result == 0);
 
628
}
 
629
 
 
630
 
 
631
void* Thread::GetThreadLocal(LocalStorageKey key) {
 
632
  pthread_key_t pthread_key = static_cast<pthread_key_t>(key);
 
633
  return pthread_getspecific(pthread_key);
 
634
}
 
635
 
 
636
 
 
637
void Thread::SetThreadLocal(LocalStorageKey key, void* value) {
 
638
  pthread_key_t pthread_key = static_cast<pthread_key_t>(key);
 
639
  pthread_setspecific(pthread_key, value);
 
640
}
 
641
 
 
642
 
 
643
void Thread::YieldCPU() {
 
644
  sched_yield();
 
645
}
 
646
 
 
647
 
 
648
class MacOSMutex : public Mutex {
 
649
 public:
 
650
  MacOSMutex() {
 
651
    pthread_mutexattr_t attr;
 
652
    pthread_mutexattr_init(&attr);
 
653
    pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);
 
654
    pthread_mutex_init(&mutex_, &attr);
 
655
  }
 
656
 
 
657
  virtual ~MacOSMutex() { pthread_mutex_destroy(&mutex_); }
 
658
 
 
659
  virtual int Lock() { return pthread_mutex_lock(&mutex_); }
 
660
  virtual int Unlock() { return pthread_mutex_unlock(&mutex_); }
 
661
 
 
662
  virtual bool TryLock() {
 
663
    int result = pthread_mutex_trylock(&mutex_);
 
664
    // Return false if the lock is busy and locking failed.
 
665
    if (result == EBUSY) {
 
666
      return false;
 
667
    }
 
668
    ASSERT(result == 0);  // Verify no other errors.
 
669
    return true;
 
670
  }
 
671
 
 
672
 private:
 
673
  pthread_mutex_t mutex_;
 
674
};
 
675
 
 
676
 
 
677
Mutex* OS::CreateMutex() {
 
678
  return new MacOSMutex();
 
679
}
 
680
 
 
681
 
 
682
class MacOSSemaphore : public Semaphore {
 
683
 public:
 
684
  explicit MacOSSemaphore(int count) {
 
685
    semaphore_create(mach_task_self(), &semaphore_, SYNC_POLICY_FIFO, count);
 
686
  }
 
687
 
 
688
  ~MacOSSemaphore() {
 
689
    semaphore_destroy(mach_task_self(), semaphore_);
 
690
  }
 
691
 
 
692
  // The MacOS mach semaphore documentation claims it does not have spurious
 
693
  // wakeups, the way pthreads semaphores do.  So the code from the linux
 
694
  // platform is not needed here.
 
695
  void Wait() { semaphore_wait(semaphore_); }
 
696
 
 
697
  bool Wait(int timeout);
 
698
 
 
699
  void Signal() { semaphore_signal(semaphore_); }
 
700
 
 
701
 private:
 
702
  semaphore_t semaphore_;
 
703
};
 
704
 
 
705
 
 
706
bool MacOSSemaphore::Wait(int timeout) {
 
707
  mach_timespec_t ts;
 
708
  ts.tv_sec = timeout / 1000000;
 
709
  ts.tv_nsec = (timeout % 1000000) * 1000;
 
710
  return semaphore_timedwait(semaphore_, ts) != KERN_OPERATION_TIMED_OUT;
 
711
}
 
712
 
 
713
 
 
714
Semaphore* OS::CreateSemaphore(int count) {
 
715
  return new MacOSSemaphore(count);
 
716
}
 
717
 
 
718
 
 
719
class Sampler::PlatformData : public Malloced {
 
720
 public:
 
721
  PlatformData() : profiled_thread_(mach_thread_self()) {}
 
722
 
 
723
  ~PlatformData() {
 
724
    // Deallocate Mach port for thread.
 
725
    mach_port_deallocate(mach_task_self(), profiled_thread_);
 
726
  }
 
727
 
 
728
  thread_act_t profiled_thread() { return profiled_thread_; }
 
729
 
 
730
 private:
 
731
  // Note: for profiled_thread_ Mach primitives are used instead of PThread's
 
732
  // because the latter doesn't provide thread manipulation primitives required.
 
733
  // For details, consult "Mac OS X Internals" book, Section 7.3.
 
734
  thread_act_t profiled_thread_;
 
735
};
 
736
 
 
737
 
 
738
class SamplerThread : public Thread {
 
739
 public:
 
740
  static const int kSamplerThreadStackSize = 64 * KB;
 
741
 
 
742
  explicit SamplerThread(int interval)
 
743
      : Thread(Thread::Options("SamplerThread", kSamplerThreadStackSize)),
 
744
        interval_(interval) {}
 
745
 
 
746
  static void SetUp() { if (!mutex_) mutex_ = OS::CreateMutex(); }
 
747
  static void TearDown() { delete mutex_; }
 
748
 
 
749
  static void AddActiveSampler(Sampler* sampler) {
 
750
    ScopedLock lock(mutex_);
 
751
    SamplerRegistry::AddActiveSampler(sampler);
 
752
    if (instance_ == NULL) {
 
753
      instance_ = new SamplerThread(sampler->interval());
 
754
      instance_->Start();
 
755
    } else {
 
756
      ASSERT(instance_->interval_ == sampler->interval());
 
757
    }
 
758
  }
 
759
 
 
760
  static void RemoveActiveSampler(Sampler* sampler) {
 
761
    ScopedLock lock(mutex_);
 
762
    SamplerRegistry::RemoveActiveSampler(sampler);
 
763
    if (SamplerRegistry::GetState() == SamplerRegistry::HAS_NO_SAMPLERS) {
 
764
      RuntimeProfiler::StopRuntimeProfilerThreadBeforeShutdown(instance_);
 
765
      delete instance_;
 
766
      instance_ = NULL;
 
767
    }
 
768
  }
 
769
 
 
770
  // Implement Thread::Run().
 
771
  virtual void Run() {
 
772
    SamplerRegistry::State state;
 
773
    while ((state = SamplerRegistry::GetState()) !=
 
774
           SamplerRegistry::HAS_NO_SAMPLERS) {
 
775
      bool cpu_profiling_enabled =
 
776
          (state == SamplerRegistry::HAS_CPU_PROFILING_SAMPLERS);
 
777
      bool runtime_profiler_enabled = RuntimeProfiler::IsEnabled();
 
778
      // When CPU profiling is enabled both JavaScript and C++ code is
 
779
      // profiled. We must not suspend.
 
780
      if (!cpu_profiling_enabled) {
 
781
        if (rate_limiter_.SuspendIfNecessary()) continue;
 
782
      }
 
783
      if (cpu_profiling_enabled) {
 
784
        if (!SamplerRegistry::IterateActiveSamplers(&DoCpuProfile, this)) {
 
785
          return;
 
786
        }
 
787
      }
 
788
      if (runtime_profiler_enabled) {
 
789
        if (!SamplerRegistry::IterateActiveSamplers(&DoRuntimeProfile, NULL)) {
 
790
          return;
 
791
        }
 
792
      }
 
793
      OS::Sleep(interval_);
 
794
    }
 
795
  }
 
796
 
 
797
  static void DoCpuProfile(Sampler* sampler, void* raw_sampler_thread) {
 
798
    if (!sampler->isolate()->IsInitialized()) return;
 
799
    if (!sampler->IsProfiling()) return;
 
800
    SamplerThread* sampler_thread =
 
801
        reinterpret_cast<SamplerThread*>(raw_sampler_thread);
 
802
    sampler_thread->SampleContext(sampler);
 
803
  }
 
804
 
 
805
  static void DoRuntimeProfile(Sampler* sampler, void* ignored) {
 
806
    if (!sampler->isolate()->IsInitialized()) return;
 
807
    sampler->isolate()->runtime_profiler()->NotifyTick();
 
808
  }
 
809
 
 
810
  void SampleContext(Sampler* sampler) {
 
811
    thread_act_t profiled_thread = sampler->platform_data()->profiled_thread();
 
812
    TickSample sample_obj;
 
813
    TickSample* sample = CpuProfiler::TickSampleEvent(sampler->isolate());
 
814
    if (sample == NULL) sample = &sample_obj;
 
815
 
 
816
    if (KERN_SUCCESS != thread_suspend(profiled_thread)) return;
 
817
 
 
818
#if V8_HOST_ARCH_X64
 
819
    thread_state_flavor_t flavor = x86_THREAD_STATE64;
 
820
    x86_thread_state64_t state;
 
821
    mach_msg_type_number_t count = x86_THREAD_STATE64_COUNT;
 
822
#if __DARWIN_UNIX03
 
823
#define REGISTER_FIELD(name) __r ## name
 
824
#else
 
825
#define REGISTER_FIELD(name) r ## name
 
826
#endif  // __DARWIN_UNIX03
 
827
#elif V8_HOST_ARCH_IA32
 
828
    thread_state_flavor_t flavor = i386_THREAD_STATE;
 
829
    i386_thread_state_t state;
 
830
    mach_msg_type_number_t count = i386_THREAD_STATE_COUNT;
 
831
#if __DARWIN_UNIX03
 
832
#define REGISTER_FIELD(name) __e ## name
 
833
#else
 
834
#define REGISTER_FIELD(name) e ## name
 
835
#endif  // __DARWIN_UNIX03
 
836
#else
 
837
#error Unsupported Mac OS X host architecture.
 
838
#endif  // V8_HOST_ARCH
 
839
 
 
840
    if (thread_get_state(profiled_thread,
 
841
                         flavor,
 
842
                         reinterpret_cast<natural_t*>(&state),
 
843
                         &count) == KERN_SUCCESS) {
 
844
      sample->state = sampler->isolate()->current_vm_state();
 
845
      sample->pc = reinterpret_cast<Address>(state.REGISTER_FIELD(ip));
 
846
      sample->sp = reinterpret_cast<Address>(state.REGISTER_FIELD(sp));
 
847
      sample->fp = reinterpret_cast<Address>(state.REGISTER_FIELD(bp));
 
848
      sampler->SampleStack(sample);
 
849
      sampler->Tick(sample);
 
850
    }
 
851
    thread_resume(profiled_thread);
 
852
  }
 
853
 
 
854
  const int interval_;
 
855
  RuntimeProfilerRateLimiter rate_limiter_;
 
856
 
 
857
  // Protects the process wide state below.
 
858
  static Mutex* mutex_;
 
859
  static SamplerThread* instance_;
 
860
 
 
861
 private:
 
862
  DISALLOW_COPY_AND_ASSIGN(SamplerThread);
 
863
};
 
864
 
 
865
#undef REGISTER_FIELD
 
866
 
 
867
 
 
868
Mutex* SamplerThread::mutex_ = NULL;
 
869
SamplerThread* SamplerThread::instance_ = NULL;
 
870
 
 
871
 
 
872
void OS::SetUp() {
 
873
  // Seed the random number generator. We preserve microsecond resolution.
 
874
  uint64_t seed = Ticks() ^ (getpid() << 16);
 
875
  srandom(static_cast<unsigned int>(seed));
 
876
  limit_mutex = CreateMutex();
 
877
  SamplerThread::SetUp();
 
878
}
 
879
 
 
880
 
 
881
void OS::TearDown() {
 
882
  SamplerThread::TearDown();
 
883
  delete limit_mutex;
 
884
}
 
885
 
 
886
 
 
887
Sampler::Sampler(Isolate* isolate, int interval)
 
888
    : isolate_(isolate),
 
889
      interval_(interval),
 
890
      profiling_(false),
 
891
      active_(false),
 
892
      samples_taken_(0) {
 
893
  data_ = new PlatformData;
 
894
}
 
895
 
 
896
 
 
897
Sampler::~Sampler() {
 
898
  ASSERT(!IsActive());
 
899
  delete data_;
 
900
}
 
901
 
 
902
 
 
903
void Sampler::Start() {
 
904
  ASSERT(!IsActive());
 
905
  SetActive(true);
 
906
  SamplerThread::AddActiveSampler(this);
 
907
}
 
908
 
 
909
 
 
910
void Sampler::Stop() {
 
911
  ASSERT(IsActive());
 
912
  SamplerThread::RemoveActiveSampler(this);
 
913
  SetActive(false);
 
914
}
 
915
 
 
916
 
 
917
} }  // namespace v8::internal