1 // Copyright 2012 the V8 project authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 // Platform-specific code for POSIX goes here. This is not a platform on its
6 // own, but contains the parts which are the same across the POSIX platforms
7 // Linux, MacOS, FreeBSD, OpenBSD, NetBSD and QNX.
8 
9 #include <errno.h>
10 #include <limits.h>
11 #include <pthread.h>
12 #if defined(__DragonFly__) || defined(__FreeBSD__) || defined(__OpenBSD__)
13 #include <pthread_np.h>  // for pthread_set_name_np
14 #endif
15 #include <sched.h>  // for sched_yield
16 #include <stdio.h>
17 #include <time.h>
18 #include <unistd.h>
19 
20 #include <sys/mman.h>
21 #include <sys/stat.h>
22 #include <sys/time.h>
23 #include <sys/types.h>
24 #if defined(__APPLE__) || defined(__DragonFly__) || defined(__FreeBSD__) || \
25     defined(__NetBSD__) || defined(__OpenBSD__)
26 #include <sys/sysctl.h>  // NOLINT, for sysctl
27 #endif
28 
29 #if defined(ANDROID) && !defined(V8_ANDROID_LOG_STDOUT)
30 #define LOG_TAG "v8"
31 #include <android/log.h>  // NOLINT
32 #endif
33 
34 #include <cmath>
35 #include <cstdlib>
36 
37 #include "src/base/platform/platform-posix.h"
38 
39 #include "src/base/lazy-instance.h"
40 #include "src/base/macros.h"
41 #include "src/base/platform/platform.h"
42 #include "src/base/platform/time.h"
43 #include "src/base/utils/random-number-generator.h"
44 
45 #ifdef V8_FAST_TLS_SUPPORTED
46 #include <atomic>
47 #endif
48 
49 #if V8_OS_MACOSX
50 #include <dlfcn.h>
51 #include <mach/mach.h>
52 #endif
53 
54 #if V8_OS_LINUX
55 #include <sys/prctl.h>  // NOLINT, for prctl
56 #endif
57 
58 #if defined(V8_OS_FUCHSIA)
59 #include <zircon/process.h>
60 #else
61 #include <sys/resource.h>
62 #endif
63 
64 #if !defined(_AIX) && !defined(V8_OS_FUCHSIA)
65 #include <sys/syscall.h>
66 #endif
67 
68 #if V8_OS_FREEBSD || V8_OS_MACOSX || V8_OS_OPENBSD || V8_OS_SOLARIS || V8_OS_DRAGONFLYBSD
69 #define MAP_ANONYMOUS MAP_ANON
70 #endif
71 
72 #if defined(V8_OS_SOLARIS)
73 #if (defined(_POSIX_C_SOURCE) && _POSIX_C_SOURCE > 2) || defined(__EXTENSIONS__)
74 extern "C" int madvise(caddr_t, size_t, int);
75 #else
76 extern int madvise(caddr_t, size_t, int);
77 #endif
78 #endif
79 
80 #ifndef MADV_FREE
81 #define MADV_FREE MADV_DONTNEED
82 #endif
83 
84 #if defined(V8_LIBC_GLIBC)
85 extern "C" void* __libc_stack_end;  // NOLINT
86 #endif
87 
88 namespace v8 {
89 namespace base {
90 
91 namespace {
92 
93 // 0 is never a valid thread id.
94 const pthread_t kNoThread = static_cast<pthread_t>(0);
95 
96 bool g_hard_abort = false;
97 
98 const char* g_gc_fake_mmap = nullptr;
99 
100 DEFINE_LAZY_LEAKY_OBJECT_GETTER(RandomNumberGenerator,
101                                 GetPlatformRandomNumberGenerator)
102 static LazyMutex rng_mutex = LAZY_MUTEX_INITIALIZER;
103 
104 #if !V8_OS_FUCHSIA
105 #if V8_OS_MACOSX
106 // kMmapFd is used to pass vm_alloc flags to tag the region with the user
107 // defined tag 255 This helps identify V8-allocated regions in memory analysis
108 // tools like vmmap(1).
109 const int kMmapFd = VM_MAKE_TAG(255);
110 #else   // !V8_OS_MACOSX
111 const int kMmapFd = -1;
112 #endif  // !V8_OS_MACOSX
113 
114 #if defined(V8_TARGET_OS_MACOSX) && V8_HOST_ARCH_ARM64
115 // During snapshot generation in cross builds, sysconf() runs on the Intel
116 // host and returns host page size, while the snapshot needs to use the
117 // target page size.
118 constexpr int kAppleArmPageSize = 1 << 14;
119 #endif
120 
121 const int kMmapFdOffset = 0;
122 
123 // TODO(v8:10026): Add the right permission flag to make executable pages
124 // guarded.
GetProtectionFromMemoryPermission(OS::MemoryPermission access)125 int GetProtectionFromMemoryPermission(OS::MemoryPermission access) {
126   switch (access) {
127     case OS::MemoryPermission::kNoAccess:
128     case OS::MemoryPermission::kNoAccessWillJitLater:
129       return PROT_NONE;
130     case OS::MemoryPermission::kRead:
131       return PROT_READ;
132     case OS::MemoryPermission::kReadWrite:
133       return PROT_READ | PROT_WRITE;
134     case OS::MemoryPermission::kReadWriteExecute:
135       return PROT_READ | PROT_WRITE | PROT_EXEC;
136     case OS::MemoryPermission::kReadExecute:
137       return PROT_READ | PROT_EXEC;
138   }
139   UNREACHABLE();
140 }
141 
142 enum class PageType { kShared, kPrivate };
143 
GetFlagsForMemoryPermission(OS::MemoryPermission access,PageType page_type)144 int GetFlagsForMemoryPermission(OS::MemoryPermission access,
145                                 PageType page_type) {
146   int flags = MAP_ANONYMOUS;
147   flags |= (page_type == PageType::kShared) ? MAP_SHARED : MAP_PRIVATE;
148   if (access == OS::MemoryPermission::kNoAccess) {
149 #if !V8_OS_AIX && !V8_OS_FREEBSD && !V8_OS_QNX && !V8_OS_DRAGONFLYBSD
150     flags |= MAP_NORESERVE;
151 #endif  // !V8_OS_AIX && !V8_OS_FREEBSD && !V8_OS_QNX && !V8_OS_DRAGONFLYBSD
152 #if V8_OS_QNX
153     flags |= MAP_LAZY;
154 #endif  // V8_OS_QNX
155   }
156 #if V8_OS_MACOSX && V8_HOST_ARCH_ARM64 && defined(MAP_JIT)
157   if (access == OS::MemoryPermission::kNoAccessWillJitLater) {
158     flags |= MAP_JIT;
159   }
160 #endif
161   return flags;
162 }
163 
Allocate(void * hint,size_t size,OS::MemoryPermission access,PageType page_type)164 void* Allocate(void* hint, size_t size, OS::MemoryPermission access,
165                PageType page_type) {
166   int prot = GetProtectionFromMemoryPermission(access);
167   int flags = GetFlagsForMemoryPermission(access, page_type);
168   void* result = mmap(hint, size, prot, flags, kMmapFd, kMmapFdOffset);
169   if (result == MAP_FAILED) return nullptr;
170   return result;
171 }
172 
173 #endif  // !V8_OS_FUCHSIA
174 
175 }  // namespace
176 
177 #if V8_OS_LINUX || V8_OS_FREEBSD
178 #ifdef __arm__
179 
ArmUsingHardFloat()180 bool OS::ArmUsingHardFloat() {
181   // GCC versions 4.6 and above define __ARM_PCS or __ARM_PCS_VFP to specify
182   // the Floating Point ABI used (PCS stands for Procedure Call Standard).
183   // We use these as well as a couple of other defines to statically determine
184   // what FP ABI used.
185   // GCC versions 4.4 and below don't support hard-fp.
186   // GCC versions 4.5 may support hard-fp without defining __ARM_PCS or
187   // __ARM_PCS_VFP.
188 
189 #define GCC_VERSION \
190   (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__)
191 #if GCC_VERSION >= 40600 && !defined(__clang__)
192 #if defined(__ARM_PCS_VFP)
193   return true;
194 #else
195   return false;
196 #endif
197 
198 #elif GCC_VERSION < 40500 && !defined(__clang__)
199   return false;
200 
201 #else
202 #if defined(__ARM_PCS_VFP)
203   return true;
204 #elif defined(__ARM_PCS) || defined(__SOFTFP__) || defined(__SOFTFP) || \
205     !defined(__VFP_FP__)
206   return false;
207 #else
208 #error \
209     "Your version of compiler does not report the FP ABI compiled for."     \
210        "Please report it on this issue"                                        \
211        "http://code.google.com/p/v8/issues/detail?id=2140"
212 
213 #endif
214 #endif
215 #undef GCC_VERSION
216 }
217 
218 #endif  // def __arm__
219 #endif
220 
Initialize(bool hard_abort,const char * const gc_fake_mmap)221 void OS::Initialize(bool hard_abort, const char* const gc_fake_mmap) {
222   g_hard_abort = hard_abort;
223   g_gc_fake_mmap = gc_fake_mmap;
224 }
225 
ActivationFrameAlignment()226 int OS::ActivationFrameAlignment() {
227 #if V8_TARGET_ARCH_ARM
228   // On EABI ARM targets this is required for fp correctness in the
229   // runtime system.
230   return 8;
231 #elif V8_TARGET_ARCH_MIPS
232   return 8;
233 #elif V8_TARGET_ARCH_S390
234   return 8;
235 #else
236   // Otherwise we just assume 16 byte alignment, i.e.:
237   // - With gcc 4.4 the tree vectorization optimizer can generate code
238   //   that requires 16 byte alignment such as movdqa on x86.
239   // - Mac OS X, PPC and Solaris (64-bit) activation frames must
240   //   be 16 byte-aligned;  see "Mac OS X ABI Function Call Guide"
241   return 16;
242 #endif
243 }
244 
245 // static
AllocatePageSize()246 size_t OS::AllocatePageSize() {
247 #if defined(V8_TARGET_OS_MACOSX) && V8_HOST_ARCH_ARM64
248   return kAppleArmPageSize;
249 #else
250   static size_t page_size = static_cast<size_t>(sysconf(_SC_PAGESIZE));
251   return page_size;
252 #endif
253 }
254 
255 // static
CommitPageSize()256 size_t OS::CommitPageSize() {
257   // Commit and allocate page size are the same on posix.
258   return OS::AllocatePageSize();
259 }
260 
261 // static
SetRandomMmapSeed(int64_t seed)262 void OS::SetRandomMmapSeed(int64_t seed) {
263   if (seed) {
264     MutexGuard guard(rng_mutex.Pointer());
265     GetPlatformRandomNumberGenerator()->SetSeed(seed);
266   }
267 }
268 
269 // static
GetRandomMmapAddr()270 void* OS::GetRandomMmapAddr() {
271   uintptr_t raw_addr;
272   {
273     MutexGuard guard(rng_mutex.Pointer());
274     GetPlatformRandomNumberGenerator()->NextBytes(&raw_addr, sizeof(raw_addr));
275   }
276 #if V8_HOST_ARCH_ARM64
277 #if defined(V8_TARGET_OS_MACOSX)
278   DCHECK_EQ(1 << 14, AllocatePageSize());
279 #endif
280   // Keep the address page-aligned, AArch64 supports 4K, 16K and 64K
281   // configurations.
282   raw_addr = RoundDown(raw_addr, AllocatePageSize());
283 #endif
284 #if defined(V8_USE_ADDRESS_SANITIZER) || defined(MEMORY_SANITIZER) || \
285     defined(THREAD_SANITIZER) || defined(LEAK_SANITIZER)
286   // If random hint addresses interfere with address ranges hard coded in
287   // sanitizers, bad things happen. This address range is copied from TSAN
288   // source but works with all tools.
289   // See crbug.com/539863.
290   raw_addr &= 0x007fffff0000ULL;
291   raw_addr += 0x7e8000000000ULL;
292 #else
293 #if V8_TARGET_ARCH_X64 || V8_TARGET_ARCH_ARM64
294   // Currently available CPUs have 48 bits of virtual addressing.  Truncate
295   // the hint address to 46 bits to give the kernel a fighting chance of
296   // fulfilling our placement request.
297   raw_addr &= uint64_t{0x3FFFFFFFF000};
298 #elif V8_TARGET_ARCH_PPC64
299 #if V8_OS_AIX
300   // AIX: 64 bits of virtual addressing, but we limit address range to:
301   //   a) minimize Segment Lookaside Buffer (SLB) misses and
302   raw_addr &= uint64_t{0x3FFFF000};
303   // Use extra address space to isolate the mmap regions.
304   raw_addr += uint64_t{0x400000000000};
305 #elif V8_TARGET_BIG_ENDIAN
306   // Big-endian Linux: 42 bits of virtual addressing.
307   raw_addr &= uint64_t{0x03FFFFFFF000};
308 #else
309   // Little-endian Linux: 46 bits of virtual addressing.
310   raw_addr &= uint64_t{0x3FFFFFFF0000};
311 #endif
312 #elif V8_TARGET_ARCH_S390X
313   // Linux on Z uses bits 22-32 for Region Indexing, which translates to 42 bits
314   // of virtual addressing.  Truncate to 40 bits to allow kernel chance to
315   // fulfill request.
316   raw_addr &= uint64_t{0xFFFFFFF000};
317 #elif V8_TARGET_ARCH_S390
318   // 31 bits of virtual addressing.  Truncate to 29 bits to allow kernel chance
319   // to fulfill request.
320   raw_addr &= 0x1FFFF000;
321 #elif V8_TARGET_ARCH_MIPS64
322   // 42 bits of virtual addressing. Truncate to 40 bits to allow kernel chance
323   // to fulfill request.
324   raw_addr &= uint64_t{0xFFFFFF0000};
325 #else
326   raw_addr &= 0x3FFFF000;
327 
328 #ifdef __sun
329   // For our Solaris/illumos mmap hint, we pick a random address in the bottom
330   // half of the top half of the address space (that is, the third quarter).
331   // Because we do not MAP_FIXED, this will be treated only as a hint -- the
332   // system will not fail to mmap() because something else happens to already
333   // be mapped at our random address. We deliberately set the hint high enough
334   // to get well above the system's break (that is, the heap); Solaris and
335   // illumos will try the hint and if that fails allocate as if there were
336   // no hint at all. The high hint prevents the break from getting hemmed in
337   // at low values, ceding half of the address space to the system heap.
338   raw_addr += 0x80000000;
339 #elif V8_OS_AIX
340   // The range 0x30000000 - 0xD0000000 is available on AIX;
341   // choose the upper range.
342   raw_addr += 0x90000000;
343 #else
344   // The range 0x20000000 - 0x60000000 is relatively unpopulated across a
345   // variety of ASLR modes (PAE kernel, NX compat mode, etc) and on macos
346   // 10.6 and 10.7.
347   raw_addr += 0x20000000;
348 #endif
349 #endif
350 #endif
351   return reinterpret_cast<void*>(raw_addr);
352 }
353 
354 // TODO(bbudge) Move Cygwin and Fuchsia stuff into platform-specific files.
355 #if !V8_OS_CYGWIN && !V8_OS_FUCHSIA
356 // static
Allocate(void * hint,size_t size,size_t alignment,MemoryPermission access)357 void* OS::Allocate(void* hint, size_t size, size_t alignment,
358                    MemoryPermission access) {
359   size_t page_size = AllocatePageSize();
360   DCHECK_EQ(0, size % page_size);
361   DCHECK_EQ(0, alignment % page_size);
362   hint = AlignedAddress(hint, alignment);
363   // Add the maximum misalignment so we are guaranteed an aligned base address.
364   size_t request_size = size + (alignment - page_size);
365   request_size = RoundUp(request_size, OS::AllocatePageSize());
366   void* result = base::Allocate(hint, request_size, access, PageType::kPrivate);
367   if (result == nullptr) return nullptr;
368 
369   // Unmap memory allocated before the aligned base address.
370   uint8_t* base = static_cast<uint8_t*>(result);
371   uint8_t* aligned_base = reinterpret_cast<uint8_t*>(
372       RoundUp(reinterpret_cast<uintptr_t>(base), alignment));
373   if (aligned_base != base) {
374     DCHECK_LT(base, aligned_base);
375     size_t prefix_size = static_cast<size_t>(aligned_base - base);
376     CHECK(Free(base, prefix_size));
377     request_size -= prefix_size;
378   }
379   // Unmap memory allocated after the potentially unaligned end.
380   if (size != request_size) {
381     DCHECK_LT(size, request_size);
382     size_t suffix_size = request_size - size;
383     CHECK(Free(aligned_base + size, suffix_size));
384     request_size -= suffix_size;
385   }
386 
387   DCHECK_EQ(size, request_size);
388   return static_cast<void*>(aligned_base);
389 }
390 
391 // static
AllocateShared(size_t size,MemoryPermission access)392 void* OS::AllocateShared(size_t size, MemoryPermission access) {
393   DCHECK_EQ(0, size % AllocatePageSize());
394   return base::Allocate(nullptr, size, access, PageType::kShared);
395 }
396 
397 // static
Free(void * address,const size_t size)398 bool OS::Free(void* address, const size_t size) {
399   DCHECK_EQ(0, reinterpret_cast<uintptr_t>(address) % AllocatePageSize());
400   DCHECK_EQ(0, size % AllocatePageSize());
401   return munmap(address, size) == 0;
402 }
403 
404 // static
Release(void * address,size_t size)405 bool OS::Release(void* address, size_t size) {
406   DCHECK_EQ(0, reinterpret_cast<uintptr_t>(address) % CommitPageSize());
407   DCHECK_EQ(0, size % CommitPageSize());
408   return munmap(address, size) == 0;
409 }
410 
411 // static
SetPermissions(void * address,size_t size,MemoryPermission access)412 bool OS::SetPermissions(void* address, size_t size, MemoryPermission access) {
413   DCHECK_EQ(0, reinterpret_cast<uintptr_t>(address) % CommitPageSize());
414   DCHECK_EQ(0, size % CommitPageSize());
415 
416   int prot = GetProtectionFromMemoryPermission(access);
417   int ret = mprotect(address, size, prot);
418   if (ret == 0 && access == OS::MemoryPermission::kNoAccess) {
419     // This is advisory; ignore errors and continue execution.
420     USE(DiscardSystemPages(address, size));
421   }
422 
423 // For accounting purposes, we want to call MADV_FREE_REUSE on macOS after
424 // changing permissions away from OS::MemoryPermission::kNoAccess. Since this
425 // state is not kept at this layer, we always call this if access != kNoAccess.
426 // The cost is a syscall that effectively no-ops.
427 // TODO(erikchen): Fix this to only call MADV_FREE_REUSE when necessary.
428 // https://crbug.com/823915
429 #if defined(V8_OS_MACOSX)
430   if (access != OS::MemoryPermission::kNoAccess)
431     madvise(address, size, MADV_FREE_REUSE);
432 #endif
433 
434   return ret == 0;
435 }
436 
DiscardSystemPages(void * address,size_t size)437 bool OS::DiscardSystemPages(void* address, size_t size) {
438   DCHECK_EQ(0, reinterpret_cast<uintptr_t>(address) % CommitPageSize());
439   DCHECK_EQ(0, size % CommitPageSize());
440 #if defined(V8_OS_MACOSX)
441   // On OSX, MADV_FREE_REUSABLE has comparable behavior to MADV_FREE, but also
442   // marks the pages with the reusable bit, which allows both Activity Monitor
443   // and memory-infra to correctly track the pages.
444   int ret = madvise(address, size, MADV_FREE_REUSABLE);
445 #elif defined(_AIX) || defined(V8_OS_SOLARIS)
446   int ret = madvise(reinterpret_cast<caddr_t>(address), size, MADV_FREE);
447 #else
448   int ret = madvise(address, size, MADV_FREE);
449 #endif
450   if (ret != 0 && errno == ENOSYS)
451     return true;  // madvise is not available on all systems.
452   if (ret != 0 && errno == EINVAL) {
453 // MADV_FREE only works on Linux 4.5+ . If request failed, retry with older
454 // MADV_DONTNEED . Note that MADV_FREE being defined at compile time doesn't
455 // imply runtime support.
456 #if defined(_AIX) || defined(V8_OS_SOLARIS)
457     ret = madvise(reinterpret_cast<caddr_t>(address), size, MADV_DONTNEED);
458 #else
459     ret = madvise(address, size, MADV_DONTNEED);
460 #endif
461   }
462   return ret == 0;
463 }
464 
465 // static
HasLazyCommits()466 bool OS::HasLazyCommits() {
467 #if V8_OS_AIX || V8_OS_LINUX || V8_OS_MACOSX || V8_OS_FREEBSD || V8_OS_DRAGONFLYBSD
468   return true;
469 #else
470   // TODO(bbudge) Return true for all POSIX platforms.
471   return false;
472 #endif
473 }
474 #endif  // !V8_OS_CYGWIN && !V8_OS_FUCHSIA
475 
GetGCFakeMMapFile()476 const char* OS::GetGCFakeMMapFile() {
477   return g_gc_fake_mmap;
478 }
479 
480 
Sleep(TimeDelta interval)481 void OS::Sleep(TimeDelta interval) {
482   usleep(static_cast<useconds_t>(interval.InMicroseconds()));
483 }
484 
485 
Abort()486 void OS::Abort() {
487   if (g_hard_abort) {
488     V8_IMMEDIATE_CRASH();
489   }
490   // Redirect to std abort to signal abnormal program termination.
491   abort();
492 }
493 
494 
DebugBreak()495 void OS::DebugBreak() {
496 #if V8_HOST_ARCH_ARM
497   asm("bkpt 0");
498 #elif V8_HOST_ARCH_ARM64
499   asm("brk 0");
500 #elif V8_HOST_ARCH_MIPS
501   asm("break");
502 #elif V8_HOST_ARCH_MIPS64
503   asm("break");
504 #elif V8_HOST_ARCH_PPC || V8_HOST_ARCH_PPC64
505   asm("twge 2,2");
506 #elif V8_HOST_ARCH_IA32
507   asm("int $3");
508 #elif V8_HOST_ARCH_X64
509   asm("int $3");
510 #elif V8_HOST_ARCH_S390
511   // Software breakpoint instruction is 0x0001
512   asm volatile(".word 0x0001");
513 #else
514 #error Unsupported host architecture.
515 #endif
516 }
517 
518 
519 class PosixMemoryMappedFile final : public OS::MemoryMappedFile {
520  public:
PosixMemoryMappedFile(FILE * file,void * memory,size_t size)521   PosixMemoryMappedFile(FILE* file, void* memory, size_t size)
522       : file_(file), memory_(memory), size_(size) {}
523   ~PosixMemoryMappedFile() final;
memory() const524   void* memory() const final { return memory_; }
size() const525   size_t size() const final { return size_; }
526 
527  private:
528   FILE* const file_;
529   void* const memory_;
530   size_t const size_;
531 };
532 
533 
534 // static
open(const char * name,FileMode mode)535 OS::MemoryMappedFile* OS::MemoryMappedFile::open(const char* name,
536                                                  FileMode mode) {
537   const char* fopen_mode = (mode == FileMode::kReadOnly) ? "r" : "r+";
538   if (FILE* file = fopen(name, fopen_mode)) {
539     if (fseek(file, 0, SEEK_END) == 0) {
540       long size = ftell(file);  // NOLINT(runtime/int)
541       if (size == 0) return new PosixMemoryMappedFile(file, nullptr, 0);
542       if (size > 0) {
543         int prot = PROT_READ;
544         int flags = MAP_PRIVATE;
545         if (mode == FileMode::kReadWrite) {
546           prot |= PROT_WRITE;
547           flags = MAP_SHARED;
548         }
549         void* const memory =
550             mmap(OS::GetRandomMmapAddr(), size, prot, flags, fileno(file), 0);
551         if (memory != MAP_FAILED) {
552           return new PosixMemoryMappedFile(file, memory, size);
553         }
554       }
555     }
556     fclose(file);
557   }
558   return nullptr;
559 }
560 
561 // static
create(const char * name,size_t size,void * initial)562 OS::MemoryMappedFile* OS::MemoryMappedFile::create(const char* name,
563                                                    size_t size, void* initial) {
564   if (FILE* file = fopen(name, "w+")) {
565     if (size == 0) return new PosixMemoryMappedFile(file, nullptr, 0);
566     size_t result = fwrite(initial, 1, size, file);
567     if (result == size && !ferror(file)) {
568       void* memory = mmap(OS::GetRandomMmapAddr(), result,
569                           PROT_READ | PROT_WRITE, MAP_SHARED, fileno(file), 0);
570       if (memory != MAP_FAILED) {
571         return new PosixMemoryMappedFile(file, memory, result);
572       }
573     }
574     fclose(file);
575   }
576   return nullptr;
577 }
578 
579 
~PosixMemoryMappedFile()580 PosixMemoryMappedFile::~PosixMemoryMappedFile() {
581   if (memory_) CHECK(OS::Free(memory_, RoundUp(size_, OS::AllocatePageSize())));
582   fclose(file_);
583 }
584 
585 
GetCurrentProcessId()586 int OS::GetCurrentProcessId() {
587   return static_cast<int>(getpid());
588 }
589 
590 
GetCurrentThreadId()591 int OS::GetCurrentThreadId() {
592 #if V8_OS_MACOSX || (V8_OS_ANDROID && defined(__APPLE__))
593   return static_cast<int>(pthread_mach_thread_np(pthread_self()));
594 #elif V8_OS_LINUX
595   return static_cast<int>(syscall(__NR_gettid));
596 #elif V8_OS_ANDROID
597   return static_cast<int>(gettid());
598 #elif V8_OS_DRAGONFLYBSD || defined(__DragonFly__)
599   return static_cast<int>(lwp_gettid());
600 #elif V8_OS_FREEBSD
601   return static_cast<int>(pthread_getthreadid_np());
602 #elif V8_OS_NETBSD
603   return static_cast<int>(_lwp_self());
604 #elif V8_OS_AIX
605   return static_cast<int>(thread_self());
606 #elif V8_OS_FUCHSIA
607   return static_cast<int>(zx_thread_self());
608 #elif V8_OS_SOLARIS
609   return static_cast<int>(pthread_self());
610 #else
611   return static_cast<int>(reinterpret_cast<intptr_t>(pthread_self()));
612 #endif
613 }
614 
ExitProcess(int exit_code)615 void OS::ExitProcess(int exit_code) {
616   // Use _exit instead of exit to avoid races between isolate
617   // threads and static destructors.
618   fflush(stdout);
619   fflush(stderr);
620   _exit(exit_code);
621 }
622 
623 // ----------------------------------------------------------------------------
624 // POSIX date/time support.
625 //
626 
627 #if !defined(V8_OS_FUCHSIA)
GetUserTime(uint32_t * secs,uint32_t * usecs)628 int OS::GetUserTime(uint32_t* secs, uint32_t* usecs) {
629   struct rusage usage;
630 
631   if (getrusage(RUSAGE_SELF, &usage) < 0) return -1;
632   *secs = static_cast<uint32_t>(usage.ru_utime.tv_sec);
633   *usecs = static_cast<uint32_t>(usage.ru_utime.tv_usec);
634   return 0;
635 }
636 #endif
637 
TimeCurrentMillis()638 double OS::TimeCurrentMillis() {
639   return Time::Now().ToJsTime();
640 }
641 
DaylightSavingsOffset(double time)642 double PosixTimezoneCache::DaylightSavingsOffset(double time) {
643   if (std::isnan(time)) return std::numeric_limits<double>::quiet_NaN();
644   time_t tv = static_cast<time_t>(std::floor(time/msPerSecond));
645   struct tm tm;
646   struct tm* t = localtime_r(&tv, &tm);
647   if (nullptr == t) return std::numeric_limits<double>::quiet_NaN();
648   return t->tm_isdst > 0 ? 3600 * msPerSecond : 0;
649 }
650 
651 
GetLastError()652 int OS::GetLastError() {
653   return errno;
654 }
655 
656 
657 // ----------------------------------------------------------------------------
658 // POSIX stdio support.
659 //
660 
FOpen(const char * path,const char * mode)661 FILE* OS::FOpen(const char* path, const char* mode) {
662   FILE* file = fopen(path, mode);
663   if (file == nullptr) return nullptr;
664   struct stat file_stat;
665   if (fstat(fileno(file), &file_stat) != 0) {
666     fclose(file);
667     return nullptr;
668   }
669   bool is_regular_file = ((file_stat.st_mode & S_IFREG) != 0);
670   if (is_regular_file) return file;
671   fclose(file);
672   return nullptr;
673 }
674 
675 
Remove(const char * path)676 bool OS::Remove(const char* path) {
677   return (remove(path) == 0);
678 }
679 
DirectorySeparator()680 char OS::DirectorySeparator() { return '/'; }
681 
isDirectorySeparator(const char ch)682 bool OS::isDirectorySeparator(const char ch) {
683   return ch == DirectorySeparator();
684 }
685 
686 
OpenTemporaryFile()687 FILE* OS::OpenTemporaryFile() {
688   return tmpfile();
689 }
690 
691 const char* const OS::LogFileOpenMode = "w+";
692 
Print(const char * format,...)693 void OS::Print(const char* format, ...) {
694   va_list args;
695   va_start(args, format);
696   VPrint(format, args);
697   va_end(args);
698 }
699 
700 
VPrint(const char * format,va_list args)701 void OS::VPrint(const char* format, va_list args) {
702 #if defined(ANDROID) && !defined(V8_ANDROID_LOG_STDOUT)
703   __android_log_vprint(ANDROID_LOG_INFO, LOG_TAG, format, args);
704 #else
705   vprintf(format, args);
706 #endif
707 }
708 
709 
FPrint(FILE * out,const char * format,...)710 void OS::FPrint(FILE* out, const char* format, ...) {
711   va_list args;
712   va_start(args, format);
713   VFPrint(out, format, args);
714   va_end(args);
715 }
716 
717 
VFPrint(FILE * out,const char * format,va_list args)718 void OS::VFPrint(FILE* out, const char* format, va_list args) {
719 #if defined(ANDROID) && !defined(V8_ANDROID_LOG_STDOUT)
720   __android_log_vprint(ANDROID_LOG_INFO, LOG_TAG, format, args);
721 #else
722   vfprintf(out, format, args);
723 #endif
724 }
725 
726 
PrintError(const char * format,...)727 void OS::PrintError(const char* format, ...) {
728   va_list args;
729   va_start(args, format);
730   VPrintError(format, args);
731   va_end(args);
732 }
733 
734 
VPrintError(const char * format,va_list args)735 void OS::VPrintError(const char* format, va_list args) {
736 #if defined(ANDROID) && !defined(V8_ANDROID_LOG_STDOUT)
737   __android_log_vprint(ANDROID_LOG_ERROR, LOG_TAG, format, args);
738 #else
739   vfprintf(stderr, format, args);
740 #endif
741 }
742 
743 
SNPrintF(char * str,int length,const char * format,...)744 int OS::SNPrintF(char* str, int length, const char* format, ...) {
745   va_list args;
746   va_start(args, format);
747   int result = VSNPrintF(str, length, format, args);
748   va_end(args);
749   return result;
750 }
751 
752 
VSNPrintF(char * str,int length,const char * format,va_list args)753 int OS::VSNPrintF(char* str,
754                   int length,
755                   const char* format,
756                   va_list args) {
757   int n = vsnprintf(str, length, format, args);
758   if (n < 0 || n >= length) {
759     // If the length is zero, the assignment fails.
760     if (length > 0)
761       str[length - 1] = '\0';
762     return -1;
763   } else {
764     return n;
765   }
766 }
767 
768 
769 // ----------------------------------------------------------------------------
770 // POSIX string support.
771 //
772 
StrNCpy(char * dest,int length,const char * src,size_t n)773 void OS::StrNCpy(char* dest, int length, const char* src, size_t n) {
774   strncpy(dest, src, n);
775 }
776 
777 
778 // ----------------------------------------------------------------------------
779 // POSIX thread support.
780 //
781 
782 class Thread::PlatformData {
783  public:
PlatformData()784   PlatformData() : thread_(kNoThread) {}
785   pthread_t thread_;  // Thread handle for pthread.
786   // Synchronizes thread creation
787   Mutex thread_creation_mutex_;
788 };
789 
Thread(const Options & options)790 Thread::Thread(const Options& options)
791     : data_(new PlatformData),
792       stack_size_(options.stack_size()),
793       start_semaphore_(nullptr) {
794   if (stack_size_ > 0 && static_cast<size_t>(stack_size_) < PTHREAD_STACK_MIN) {
795     stack_size_ = PTHREAD_STACK_MIN;
796   }
797   set_name(options.name());
798 }
799 
800 
~Thread()801 Thread::~Thread() {
802   delete data_;
803 }
804 
805 
SetThreadName(const char * name)806 static void SetThreadName(const char* name) {
807 #if V8_OS_DRAGONFLYBSD || V8_OS_FREEBSD || V8_OS_OPENBSD
808   pthread_set_name_np(pthread_self(), name);
809 #elif V8_OS_NETBSD
810   STATIC_ASSERT(Thread::kMaxThreadNameLength <= PTHREAD_MAX_NAMELEN_NP);
811   pthread_setname_np(pthread_self(), "%s", name);
812 #elif V8_OS_MACOSX
813   // pthread_setname_np is only available in 10.6 or later, so test
814   // for it at runtime.
815   int (*dynamic_pthread_setname_np)(const char*);
816   *reinterpret_cast<void**>(&dynamic_pthread_setname_np) =
817     dlsym(RTLD_DEFAULT, "pthread_setname_np");
818   if (dynamic_pthread_setname_np == nullptr) return;
819 
820   // Mac OS X does not expose the length limit of the name, so hardcode it.
821   static const int kMaxNameLength = 63;
822   STATIC_ASSERT(Thread::kMaxThreadNameLength <= kMaxNameLength);
823   dynamic_pthread_setname_np(name);
824 #elif defined(PR_SET_NAME)
825   prctl(PR_SET_NAME,
826         reinterpret_cast<unsigned long>(name),  // NOLINT
827         0, 0, 0);
828 #endif
829 }
830 
831 
ThreadEntry(void * arg)832 static void* ThreadEntry(void* arg) {
833   Thread* thread = reinterpret_cast<Thread*>(arg);
834   // We take the lock here to make sure that pthread_create finished first since
835   // we don't know which thread will run first (the original thread or the new
836   // one).
837   { MutexGuard lock_guard(&thread->data()->thread_creation_mutex_); }
838   SetThreadName(thread->name());
839   DCHECK_NE(thread->data()->thread_, kNoThread);
840   thread->NotifyStartedAndRun();
841   return nullptr;
842 }
843 
844 
set_name(const char * name)845 void Thread::set_name(const char* name) {
846   strncpy(name_, name, sizeof(name_) - 1);
847   name_[sizeof(name_) - 1] = '\0';
848 }
849 
Start()850 bool Thread::Start() {
851   int result;
852   pthread_attr_t attr;
853   memset(&attr, 0, sizeof(attr));
854   result = pthread_attr_init(&attr);
855   if (result != 0) return false;
856   size_t stack_size = stack_size_;
857   if (stack_size == 0) {
858 #if V8_OS_MACOSX
859     // Default on Mac OS X is 512kB -- bump up to 1MB
860     stack_size = 1 * 1024 * 1024;
861 #elif V8_OS_AIX
862     // Default on AIX is 96kB -- bump up to 2MB
863     stack_size = 2 * 1024 * 1024;
864 #endif
865   }
866   if (stack_size > 0) {
867     result = pthread_attr_setstacksize(&attr, stack_size);
868     if (result != 0) return pthread_attr_destroy(&attr), false;
869   }
870   {
871     MutexGuard lock_guard(&data_->thread_creation_mutex_);
872     result = pthread_create(&data_->thread_, &attr, ThreadEntry, this);
873     if (result != 0 || data_->thread_ == kNoThread) {
874       return pthread_attr_destroy(&attr), false;
875     }
876   }
877   result = pthread_attr_destroy(&attr);
878   return result == 0;
879 }
880 
Join()881 void Thread::Join() { pthread_join(data_->thread_, nullptr); }
882 
PthreadKeyToLocalKey(pthread_key_t pthread_key)883 static Thread::LocalStorageKey PthreadKeyToLocalKey(pthread_key_t pthread_key) {
884 #if V8_OS_CYGWIN
885   // We need to cast pthread_key_t to Thread::LocalStorageKey in two steps
886   // because pthread_key_t is a pointer type on Cygwin. This will probably not
887   // work on 64-bit platforms, but Cygwin doesn't support 64-bit anyway.
888   STATIC_ASSERT(sizeof(Thread::LocalStorageKey) == sizeof(pthread_key_t));
889   intptr_t ptr_key = reinterpret_cast<intptr_t>(pthread_key);
890   return static_cast<Thread::LocalStorageKey>(ptr_key);
891 #else
892   return static_cast<Thread::LocalStorageKey>(pthread_key);
893 #endif
894 }
895 
896 
LocalKeyToPthreadKey(Thread::LocalStorageKey local_key)897 static pthread_key_t LocalKeyToPthreadKey(Thread::LocalStorageKey local_key) {
898 #if V8_OS_CYGWIN
899   STATIC_ASSERT(sizeof(Thread::LocalStorageKey) == sizeof(pthread_key_t));
900   intptr_t ptr_key = static_cast<intptr_t>(local_key);
901   return reinterpret_cast<pthread_key_t>(ptr_key);
902 #else
903   return static_cast<pthread_key_t>(local_key);
904 #endif
905 }
906 
907 
908 #ifdef V8_FAST_TLS_SUPPORTED
909 
910 static std::atomic<bool> tls_base_offset_initialized{false};
911 intptr_t kMacTlsBaseOffset = 0;
912 
913 // It's safe to do the initialization more that once, but it has to be
914 // done at least once.
InitializeTlsBaseOffset()915 static void InitializeTlsBaseOffset() {
916   const size_t kBufferSize = 128;
917   char buffer[kBufferSize];
918   size_t buffer_size = kBufferSize;
919   int ctl_name[] = { CTL_KERN , KERN_OSRELEASE };
920   if (sysctl(ctl_name, 2, buffer, &buffer_size, nullptr, 0) != 0) {
921     FATAL("V8 failed to get kernel version");
922   }
923   // The buffer now contains a string of the form XX.YY.ZZ, where
924   // XX is the major kernel version component.
925   // Make sure the buffer is 0-terminated.
926   buffer[kBufferSize - 1] = '\0';
927   char* period_pos = strchr(buffer, '.');
928   *period_pos = '\0';
929   int kernel_version_major =
930       static_cast<int>(strtol(buffer, nullptr, 10));  // NOLINT
931   // The constants below are taken from pthreads.s from the XNU kernel
932   // sources archive at www.opensource.apple.com.
933   if (kernel_version_major < 11) {
934     // 8.x.x (Tiger), 9.x.x (Leopard), 10.x.x (Snow Leopard) have the
935     // same offsets.
936 #if V8_HOST_ARCH_IA32
937     kMacTlsBaseOffset = 0x48;
938 #else
939     kMacTlsBaseOffset = 0x60;
940 #endif
941   } else {
942     // 11.x.x (Lion) changed the offset.
943     kMacTlsBaseOffset = 0;
944   }
945 
946   tls_base_offset_initialized.store(true, std::memory_order_release);
947 }
948 
949 
CheckFastTls(Thread::LocalStorageKey key)950 static void CheckFastTls(Thread::LocalStorageKey key) {
951   void* expected = reinterpret_cast<void*>(0x1234CAFE);
952   Thread::SetThreadLocal(key, expected);
953   void* actual = Thread::GetExistingThreadLocal(key);
954   if (expected != actual) {
955     FATAL("V8 failed to initialize fast TLS on current kernel");
956   }
957   Thread::SetThreadLocal(key, nullptr);
958 }
959 
960 #endif  // V8_FAST_TLS_SUPPORTED
961 
962 
CreateThreadLocalKey()963 Thread::LocalStorageKey Thread::CreateThreadLocalKey() {
964 #ifdef V8_FAST_TLS_SUPPORTED
965   bool check_fast_tls = false;
966   if (!tls_base_offset_initialized.load(std::memory_order_acquire)) {
967     check_fast_tls = true;
968     InitializeTlsBaseOffset();
969   }
970 #endif
971   pthread_key_t key;
972   int result = pthread_key_create(&key, nullptr);
973   DCHECK_EQ(0, result);
974   USE(result);
975   LocalStorageKey local_key = PthreadKeyToLocalKey(key);
976 #ifdef V8_FAST_TLS_SUPPORTED
977   // If we just initialized fast TLS support, make sure it works.
978   if (check_fast_tls) CheckFastTls(local_key);
979 #endif
980   return local_key;
981 }
982 
983 
DeleteThreadLocalKey(LocalStorageKey key)984 void Thread::DeleteThreadLocalKey(LocalStorageKey key) {
985   pthread_key_t pthread_key = LocalKeyToPthreadKey(key);
986   int result = pthread_key_delete(pthread_key);
987   DCHECK_EQ(0, result);
988   USE(result);
989 }
990 
991 
GetThreadLocal(LocalStorageKey key)992 void* Thread::GetThreadLocal(LocalStorageKey key) {
993   pthread_key_t pthread_key = LocalKeyToPthreadKey(key);
994   return pthread_getspecific(pthread_key);
995 }
996 
997 
SetThreadLocal(LocalStorageKey key,void * value)998 void Thread::SetThreadLocal(LocalStorageKey key, void* value) {
999   pthread_key_t pthread_key = LocalKeyToPthreadKey(key);
1000   int result = pthread_setspecific(pthread_key, value);
1001   DCHECK_EQ(0, result);
1002   USE(result);
1003 }
1004 
1005 // pthread_getattr_np used below is non portable (hence the _np suffix). We
1006 // keep this version in POSIX as most Linux-compatible derivatives will
1007 // support it. MacOS and FreeBSD are different here.
1008 #if !defined(V8_OS_FREEBSD) && !defined(V8_OS_MACOSX) && !defined(_AIX) && \
1009     !defined(V8_OS_SOLARIS) && !defined(V8_OS_DRAGONFLYBSD)
1010 
1011 // static
GetStackStart()1012 Stack::StackSlot Stack::GetStackStart() {
1013   pthread_attr_t attr;
1014   int error = pthread_getattr_np(pthread_self(), &attr);
1015   if (!error) {
1016     void* base;
1017     size_t size;
1018     error = pthread_attr_getstack(&attr, &base, &size);
1019     CHECK(!error);
1020     pthread_attr_destroy(&attr);
1021     return reinterpret_cast<uint8_t*>(base) + size;
1022   }
1023 
1024 #if defined(V8_LIBC_GLIBC)
1025   // pthread_getattr_np can fail for the main thread. In this case
1026   // just like NaCl we rely on the __libc_stack_end to give us
1027   // the start of the stack.
1028   // See https://code.google.com/p/nativeclient/issues/detail?id=3431.
1029   return __libc_stack_end;
1030 #endif  // !defined(V8_LIBC_GLIBC)
1031   return nullptr;
1032 }
1033 
1034 #endif  // !defined(V8_OS_FREEBSD) && !defined(V8_OS_MACOSX) &&
1035         // !defined(_AIX) && !defined(V8_OS_SOLARIS)
1036 
1037 // static
GetCurrentStackPosition()1038 Stack::StackSlot Stack::GetCurrentStackPosition() {
1039   return __builtin_frame_address(0);
1040 }
1041 
1042 #undef LOG_TAG
1043 #undef MAP_ANONYMOUS
1044 #undef MADV_FREE
1045 
1046 }  // namespace base
1047 }  // namespace v8
1048