v8
V8 is Google’s open source high-performance JavaScript and WebAssembly engine, written in C++.
Loading...
Searching...
No Matches
platform-posix.cc
Go to the documentation of this file.
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
13#include "src/base/logging.h"
14#if defined(__DragonFly__) || defined(__FreeBSD__) || defined(__OpenBSD__)
15#include <pthread_np.h> // for pthread_set_name_np
16#endif
17#include <fcntl.h>
18#include <sched.h> // for sched_yield
19#include <stdio.h>
20#include <sys/mman.h>
21#include <sys/stat.h>
22#include <sys/time.h>
23#include <sys/types.h>
24#include <time.h>
25#include <unistd.h>
26#if defined(__APPLE__) || defined(__DragonFly__) || defined(__FreeBSD__) || \
27 defined(__NetBSD__) || defined(__OpenBSD__)
28#include <sys/sysctl.h> // for sysctl
29#endif
30
31#if defined(ANDROID) && !defined(V8_ANDROID_LOG_STDOUT)
32#define LOG_TAG "v8"
33#include <android/log.h>
34#endif
35
36#include <cmath>
37#include <cstdlib>
38#include <optional>
39
41#include "src/base/macros.h"
47
48#ifdef V8_FAST_TLS_SUPPORTED
49#include <atomic>
50#endif
51
52#if V8_OS_DARWIN || V8_OS_LINUX
53#include <dlfcn.h> // for dlsym
54#endif
55
56#if V8_OS_DARWIN
57#include <mach/mach.h>
58#include <malloc/malloc.h>
59#elif V8_OS_OPENBSD
60#include <sys/malloc.h>
61#elif !V8_OS_ZOS
62#include <malloc.h>
63#endif
64
65#if V8_OS_LINUX
66#include <sys/prctl.h> // for prctl
67#endif
68
69#if defined(V8_OS_FUCHSIA)
70#include <zircon/process.h>
71#else
72#include <sys/resource.h>
73#endif
74
75#if !defined(_AIX) && !defined(V8_OS_FUCHSIA) && !V8_OS_ZOS
76#include <sys/syscall.h>
77#endif
78
79#if V8_OS_FREEBSD || V8_OS_DARWIN || V8_OS_OPENBSD || V8_OS_SOLARIS
80#define MAP_ANONYMOUS MAP_ANON
81#endif
82
83#if defined(V8_OS_SOLARIS)
84#if (defined(_POSIX_C_SOURCE) && _POSIX_C_SOURCE > 2) || defined(__EXTENSIONS__)
85extern "C" int madvise(caddr_t, size_t, int);
86#else
87extern int madvise(caddr_t, size_t, int);
88#endif
89#endif
90
91#ifndef MADV_FREE
92#define MADV_FREE MADV_DONTNEED
93#endif
94
95#if defined(V8_LIBC_GLIBC)
96extern "C" void* __libc_stack_end;
97#endif
98
99namespace v8 {
100namespace base {
101
102namespace {
103
104// 0 is never a valid thread id.
105#if V8_OS_ZOS
106const pthread_t kNoThread = {0}; // pthread_t is a struct on z/OS
107#else
108const pthread_t kNoThread = static_cast<pthread_t>(0);
109#endif
110
111const char* g_gc_fake_mmap = nullptr;
112
113DEFINE_LAZY_LEAKY_OBJECT_GETTER(RandomNumberGenerator,
114 GetPlatformRandomNumberGenerator)
115static LazyMutex rng_mutex = LAZY_MUTEX_INITIALIZER;
116
117#if !V8_OS_FUCHSIA && !V8_OS_ZOS
118#if V8_OS_DARWIN
119// kMmapFd is used to pass vm_alloc flags to tag the region with the user
120// defined tag 255 This helps identify V8-allocated regions in memory analysis
121// tools like vmmap(1).
122const int kMmapFd = VM_MAKE_TAG(255);
123#else // !V8_OS_DARWIN
124const int kMmapFd = -1;
125#endif // !V8_OS_DARWIN
126
127#if defined(V8_TARGET_OS_MACOS) && V8_HOST_ARCH_ARM64
128// During snapshot generation in cross builds, sysconf() runs on the Intel
129// host and returns host page size, while the snapshot needs to use the
130// target page size.
131constexpr int kAppleArmPageSize = 1 << 14;
132#endif
133
134const int kMmapFdOffset = 0;
135
136enum class PageType { kShared, kPrivate };
137
138int GetFlagsForMemoryPermission(OS::MemoryPermission access,
139 PageType page_type) {
140 int flags = MAP_ANONYMOUS;
141 flags |= (page_type == PageType::kShared) ? MAP_SHARED : MAP_PRIVATE;
142 if (access == OS::MemoryPermission::kNoAccess ||
144#if !V8_OS_AIX && !V8_OS_FREEBSD && !V8_OS_QNX
145 flags |= MAP_NORESERVE;
146#endif // !V8_OS_AIX && !V8_OS_FREEBSD && !V8_OS_QNX
147#if V8_OS_QNX
148 flags |= MAP_LAZY;
149#endif // V8_OS_QNX
150 }
151#if V8_OS_DARWIN
152 // MAP_JIT is required to obtain writable and executable pages when the
153 // hardened runtime/memory protection is enabled, which is optional (via code
154 // signing) on Intel-based Macs but mandatory on Apple silicon ones. See also
155 // https://developer.apple.com/documentation/apple-silicon/porting-just-in-time-compilers-to-apple-silicon.
158 flags |= MAP_JIT;
159 }
160#endif // V8_OS_DARWIN
161 return flags;
162}
163
164void* 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
171#if V8_OS_LINUX && V8_ENABLE_PRIVATE_MAPPING_FORK_OPTIMIZATION
172 // This is advisory, so we ignore errors.
173 madvise(result, size, MADV_DONTFORK);
174#endif
175
176#if ENABLE_HUGEPAGE
177 if (result != nullptr && size >= kHugePageSize) {
178 const uintptr_t huge_start =
179 RoundUp(reinterpret_cast<uintptr_t>(result), kHugePageSize);
180 const uintptr_t huge_end =
181 RoundDown(reinterpret_cast<uintptr_t>(result) + size, kHugePageSize);
182 if (huge_end > huge_start) {
183 // Bail out in case the aligned addresses do not provide a block of at
184 // least kHugePageSize size.
185 madvise(reinterpret_cast<void*>(huge_start), huge_end - huge_start,
186 MADV_HUGEPAGE);
187 }
188 }
189#endif
190
191 return result;
192}
193
194#endif // !V8_OS_FUCHSIA && !V8_OS_ZOS
195
196} // namespace
197
198// TODO(v8:10026): Add the right permission flag to make executable pages
199// guarded.
201 switch (access) {
204 return PROT_NONE;
206 return PROT_READ;
208 return PROT_READ | PROT_WRITE;
210 return PROT_READ | PROT_WRITE | PROT_EXEC;
212 return PROT_READ | PROT_EXEC;
213 }
214 UNREACHABLE();
215}
216
217#if V8_OS_LINUX || V8_OS_FREEBSD
218#ifdef __arm__
219
221 // GCC versions 4.6 and above define __ARM_PCS or __ARM_PCS_VFP to specify
222 // the Floating Point ABI used (PCS stands for Procedure Call Standard).
223 // We use these as well as a couple of other defines to statically determine
224 // what FP ABI used.
225 // GCC versions 4.4 and below don't support hard-fp.
226 // GCC versions 4.5 may support hard-fp without defining __ARM_PCS or
227 // __ARM_PCS_VFP.
228
229#define GCC_VERSION \
230 (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__)
231#if GCC_VERSION >= 40600 && !defined(__clang__)
232#if defined(__ARM_PCS_VFP)
233 return true;
234#else
235 return false;
236#endif
237
238#elif GCC_VERSION < 40500 && !defined(__clang__)
239 return false;
240
241#else
242#if defined(__ARM_PCS_VFP)
243 return true;
244#elif defined(__ARM_PCS) || defined(__SOFTFP__) || defined(__SOFTFP) || \
245 !defined(__VFP_FP__)
246 return false;
247#else
248#error \
249 "Your version of compiler does not report the FP ABI compiled for." \
250 "Please report it on this issue" \
251 "http://code.google.com/p/v8/issues/detail?id=2140"
252
253#endif
254#endif
255#undef GCC_VERSION
256}
257
258#endif // def __arm__
259#endif
260
262 const char* const gc_fake_mmap) {
263 g_abort_mode = abort_mode;
264 g_gc_fake_mmap = gc_fake_mmap;
265}
266
267#if !V8_OS_FUCHSIA
268void OS::Initialize(AbortMode abort_mode, const char* const gc_fake_mmap) {
269 PosixInitializeCommon(abort_mode, gc_fake_mmap);
270}
271#endif // !V8_OS_FUCHSIA
272
274
276#if V8_TARGET_ARCH_ARM
277 // On EABI ARM targets this is required for fp correctness in the
278 // runtime system.
279 return 8;
280#elif V8_TARGET_ARCH_MIPS
281 return 8;
282#elif V8_TARGET_ARCH_S390X
283 return 8;
284#else
285 // Otherwise we just assume 16 byte alignment, i.e.:
286 // - With gcc 4.4 the tree vectorization optimizer can generate code
287 // that requires 16 byte alignment such as movdqa on x86.
288 // - Mac OS X, PPC and Solaris (64-bit) activation frames must
289 // be 16 byte-aligned; see "Mac OS X ABI Function Call Guide"
290 return 16;
291#endif
292}
293
294// static
296#if defined(V8_TARGET_OS_MACOS) && V8_HOST_ARCH_ARM64
297 return kAppleArmPageSize;
298#else
299 static size_t page_size = static_cast<size_t>(sysconf(_SC_PAGESIZE));
300 return page_size;
301#endif
302}
303
304// static
306 // Commit and allocate page size are the same on posix.
307 return OS::AllocatePageSize();
308}
309
310// static
311void OS::SetRandomMmapSeed(int64_t seed) {
312 if (seed) {
313 MutexGuard guard(rng_mutex.Pointer());
314 GetPlatformRandomNumberGenerator()->SetSeed(seed);
315 }
316}
317
318// static
320 uintptr_t raw_addr;
321 {
322 MutexGuard guard(rng_mutex.Pointer());
323 GetPlatformRandomNumberGenerator()->NextBytes(&raw_addr, sizeof(raw_addr));
324 }
325#if V8_HOST_ARCH_ARM64
326#if defined(V8_TARGET_OS_MACOS)
327 DCHECK_EQ(1 << 14, AllocatePageSize());
328#endif
329 // Keep the address page-aligned, AArch64 supports 4K, 16K and 64K
330 // configurations.
331 raw_addr = RoundDown(raw_addr, AllocatePageSize());
332#endif
333#if defined(V8_USE_ADDRESS_SANITIZER) || defined(MEMORY_SANITIZER) || \
334 defined(THREAD_SANITIZER) || defined(LEAK_SANITIZER)
335 // If random hint addresses interfere with address ranges hard coded in
336 // sanitizers, bad things happen. This address range is copied from TSAN
337 // source but works with all tools.
338 // See crbug.com/539863.
339 raw_addr &= 0x007fffff0000ULL;
340 raw_addr += 0x7e8000000000ULL;
341#else
342#if V8_TARGET_ARCH_X64
343 // Currently available CPUs have 48 bits of virtual addressing. Truncate
344 // the hint address to 46 bits to give the kernel a fighting chance of
345 // fulfilling our placement request.
346 raw_addr &= uint64_t{0x3FFFFFFFF000};
347#elif V8_TARGET_ARCH_ARM64
348#if defined(V8_TARGET_OS_LINUX) || defined(V8_TARGET_OS_ANDROID)
349 // On Linux, the default virtual address space is limited to 39 bits when
350 // using 4KB pages, see arch/arm64/Kconfig. We truncate to 38 bits.
351 raw_addr &= uint64_t{0x3FFFFFF000};
352#else
353 // On macOS and elsewhere, we use 46 bits, same as on x64.
354 raw_addr &= uint64_t{0x3FFFFFFFF000};
355#endif
356#elif V8_TARGET_ARCH_PPC64
357#if V8_OS_AIX
358 // AIX: 64 bits of virtual addressing, but we limit address range to minimize
359 // Segment Lookaside Buffer (SLB) misses.
360 raw_addr &= uint64_t{0x3FFFF000};
361 // Use extra address space to isolate the mmap regions.
362 raw_addr += uint64_t{0x400000000000};
363#else
364 // Little-endian Linux: 46 bits of virtual addressing.
365 raw_addr &= uint64_t{0x3FFFFFFF0000};
366#endif
367#elif V8_TARGET_ARCH_S390X
368 // Linux on Z uses bits 22-32 for Region Indexing, which translates to 42 bits
369 // of virtual addressing. Truncate to 40 bits to allow kernel chance to
370 // fulfill request.
371 raw_addr &= uint64_t{0xFFFFFFF000};
372#elif V8_TARGET_ARCH_MIPS64
373 // 42 bits of virtual addressing. Truncate to 40 bits to allow kernel chance
374 // to fulfill request.
375 raw_addr &= uint64_t{0xFFFFFF0000};
376#elif V8_TARGET_ARCH_RISCV64
377 // TODO(RISCV): We need more information from the kernel to correctly mask
378 // this address for RISC-V. https://github.com/v8-riscv/v8/issues/375
379 raw_addr &= uint64_t{0xFFFFFF0000};
380#elif V8_TARGET_ARCH_RISCV32
381 // TODO(RISCV): We need more information from the kernel to correctly mask
382 // this address for RISC-V. https://github.com/v8-riscv/v8/issues/375
383 raw_addr &= 0x3FFFF000;
384#elif V8_TARGET_ARCH_LOONG64
385 // 40 or 47 bits of virtual addressing. Truncate to 38 bits to allow kernel
386 // chance to fulfill request.
387 raw_addr &= uint64_t{0x3FFFFF0000};
388#else
389 raw_addr &= 0x3FFFF000;
390
391#ifdef __sun
392 // For our Solaris/illumos mmap hint, we pick a random address in the bottom
393 // half of the top half of the address space (that is, the third quarter).
394 // Because we do not MAP_FIXED, this will be treated only as a hint -- the
395 // system will not fail to mmap() because something else happens to already
396 // be mapped at our random address. We deliberately set the hint high enough
397 // to get well above the system's break (that is, the heap); Solaris and
398 // illumos will try the hint and if that fails allocate as if there were
399 // no hint at all. The high hint prevents the break from getting hemmed in
400 // at low values, ceding half of the address space to the system heap.
401 raw_addr += 0x80000000;
402#elif V8_OS_AIX
403 // The range 0x30000000 - 0xD0000000 is available on AIX;
404 // choose the upper range.
405 raw_addr += 0x90000000;
406#else
407 // The range 0x20000000 - 0x60000000 is relatively unpopulated across a
408 // variety of ASLR modes (PAE kernel, NX compat mode, etc) and on macos
409 // 10.6 and 10.7.
410 raw_addr += 0x20000000;
411#endif
412#endif
413#endif
414 return reinterpret_cast<void*>(raw_addr);
415}
416
417// TODO(bbudge) Move Cygwin and Fuchsia stuff into platform-specific files.
418#if !V8_OS_CYGWIN && !V8_OS_FUCHSIA
419#if !V8_OS_ZOS
420// static
421void* OS::Allocate(void* hint, size_t size, size_t alignment,
422 MemoryPermission access) {
423 size_t page_size = AllocatePageSize();
424 DCHECK_EQ(0, size % page_size);
425 DCHECK_EQ(0, alignment % page_size);
426 hint = AlignedAddress(hint, alignment);
427 // Add the maximum misalignment so we are guaranteed an aligned base address.
428 size_t request_size = size + (alignment - page_size);
429 request_size = RoundUp(request_size, OS::AllocatePageSize());
430 void* result = base::Allocate(hint, request_size, access, PageType::kPrivate);
431 if (result == nullptr) return nullptr;
432
433 // Unmap memory allocated before the aligned base address.
434 uint8_t* base = static_cast<uint8_t*>(result);
435 uint8_t* aligned_base = reinterpret_cast<uint8_t*>(
436 RoundUp(reinterpret_cast<uintptr_t>(base), alignment));
437 if (aligned_base != base) {
438 DCHECK_LT(base, aligned_base);
439 size_t prefix_size = static_cast<size_t>(aligned_base - base);
440 Free(base, prefix_size);
441 request_size -= prefix_size;
442 }
443 // Unmap memory allocated after the potentially unaligned end.
444 if (size != request_size) {
445 DCHECK_LT(size, request_size);
446 size_t suffix_size = request_size - size;
447 Free(aligned_base + size, suffix_size);
448 request_size -= suffix_size;
449 }
450
451 DCHECK_EQ(size, request_size);
452 return static_cast<void*>(aligned_base);
453}
454
455// static
456void* OS::AllocateShared(size_t size, MemoryPermission access) {
457 DCHECK_EQ(0, size % AllocatePageSize());
458 return base::Allocate(nullptr, size, access, PageType::kShared);
459}
460
461// static
462void OS::Free(void* address, size_t size) {
463 DCHECK_EQ(0, reinterpret_cast<uintptr_t>(address) % AllocatePageSize());
464 DCHECK_EQ(0, size % AllocatePageSize());
465 CHECK_EQ(0, munmap(address, size));
466}
467
468// Darwin specific implementation in platform-darwin.cc.
469#if !defined(V8_OS_DARWIN)
470// static
471void* OS::AllocateShared(void* hint, size_t size, MemoryPermission access,
472 PlatformSharedMemoryHandle handle, uint64_t offset) {
473 DCHECK_EQ(0, size % AllocatePageSize());
474 int prot = GetProtectionFromMemoryPermission(access);
476 void* result = mmap(hint, size, prot, MAP_SHARED, fd, offset);
477 if (result == MAP_FAILED) return nullptr;
478 return result;
479}
480#endif // !defined(V8_OS_DARWIN)
481
482// static
483void OS::FreeShared(void* address, size_t size) {
484 DCHECK_EQ(0, size % AllocatePageSize());
485 CHECK_EQ(0, munmap(address, size));
486}
487
488// static
489void OS::Release(void* address, size_t size) {
490 DCHECK_EQ(0, reinterpret_cast<uintptr_t>(address) % CommitPageSize());
491 DCHECK_EQ(0, size % CommitPageSize());
492 CHECK_EQ(0, munmap(address, size));
493}
494
495// static
496bool OS::SetPermissions(void* address, size_t size, MemoryPermission access) {
497 DCHECK_EQ(0, reinterpret_cast<uintptr_t>(address) % CommitPageSize());
498 DCHECK_EQ(0, size % CommitPageSize());
499
500 int prot = GetProtectionFromMemoryPermission(access);
501 int ret = mprotect(address, size, prot);
502
503 // Setting permissions can fail if the limit of VMAs is exceeded.
504 // Any failure that's not OOM likely indicates a bug in the caller (e.g.
505 // using an invalid mapping) so attempt to catch that here to facilitate
506 // debugging of these failures.
507 if (ret != 0) CHECK_EQ(ENOMEM, errno);
508
509 // MacOS 11.2 on Apple Silicon refuses to switch permissions from
510 // rwx to none. Just use madvise instead.
511#if defined(V8_OS_DARWIN)
512 if (ret != 0 && access == OS::MemoryPermission::kNoAccess) {
513 ret = madvise(address, size, MADV_FREE_REUSABLE);
514 return ret == 0;
515 }
516#endif
517
518 if (ret == 0 && access == OS::MemoryPermission::kNoAccess) {
519 // This is advisory; ignore errors and continue execution.
520 USE(DiscardSystemPages(address, size));
521 }
522
523// For accounting purposes, we want to call MADV_FREE_REUSE on macOS after
524// changing permissions away from OS::MemoryPermission::kNoAccess. Since this
525// state is not kept at this layer, we always call this if access != kNoAccess.
526// The cost is a syscall that effectively no-ops.
527// TODO(erikchen): Fix this to only call MADV_FREE_REUSE when necessary.
528// https://crbug.com/823915
529#if defined(V8_OS_DARWIN)
530 if (access != OS::MemoryPermission::kNoAccess) {
531 madvise(address, size, MADV_FREE_REUSE);
532 }
533#endif
534
535 return ret == 0;
536}
537
538// static
539void OS::SetDataReadOnly(void* address, size_t size) {
540 CHECK_EQ(0, reinterpret_cast<uintptr_t>(address) % CommitPageSize());
541 CHECK_EQ(0, size % CommitPageSize());
542
543 if (mprotect(address, size, PROT_READ) != 0) {
544 FATAL("Failed to protect data memory at %p +%zu; error %d\n", address, size,
545 errno);
546 }
547}
548
549// static
550bool OS::RecommitPages(void* address, size_t size, MemoryPermission access) {
551 DCHECK_EQ(0, reinterpret_cast<uintptr_t>(address) % CommitPageSize());
552 DCHECK_EQ(0, size % CommitPageSize());
553
554#if defined(V8_OS_DARWIN)
555 while (madvise(address, size, MADV_FREE_REUSE) == -1 && errno == EAGAIN) {
556 }
557#endif // defined(V8_OS_DARWIN)
558 return true;
559}
560
561// static
562bool OS::DiscardSystemPages(void* address, size_t size) {
563 // Roughly based on PartitionAlloc's DiscardSystemPagesInternal
564 // (base/allocator/partition_allocator/page_allocator_internals_posix.h)
565 DCHECK_EQ(0, reinterpret_cast<uintptr_t>(address) % CommitPageSize());
566 DCHECK_EQ(0, size % CommitPageSize());
567#if defined(V8_OS_DARWIN)
568 // On OSX, MADV_FREE_REUSABLE has comparable behavior to MADV_FREE, but also
569 // marks the pages with the reusable bit, which allows both Activity Monitor
570 // and memory-infra to correctly track the pages.
571 int ret;
572 do {
573 ret = madvise(address, size, MADV_FREE_REUSABLE);
574 } while (ret != 0 && errno == EAGAIN);
575 if (ret) {
576 // MADV_FREE_REUSABLE sometimes fails, so fall back to MADV_DONTNEED.
577 ret = madvise(address, size, MADV_DONTNEED);
578 }
579#elif defined(_AIX) || defined(V8_OS_SOLARIS)
580 int ret = madvise(reinterpret_cast<caddr_t>(address), size, MADV_FREE);
581 if (ret != 0 && errno == ENOSYS) {
582 return true; // madvise is not available on all systems.
583 }
584 if (ret != 0 && errno == EINVAL) {
585 ret = madvise(reinterpret_cast<caddr_t>(address), size, MADV_DONTNEED);
586 }
587#else
588 int ret = madvise(address, size, MADV_DONTNEED);
589#endif
590 // madvise with MADV_DONTNEED only fails on illegal parameters. That's a bug
591 // in the caller.
592 CHECK_EQ(0, ret);
593 return true;
594}
595
596#if !defined(_AIX)
597// See AIX version for details.
598// static
599bool OS::DecommitPages(void* address, size_t size) {
600 DCHECK_EQ(0, reinterpret_cast<uintptr_t>(address) % CommitPageSize());
601 DCHECK_EQ(0, size % CommitPageSize());
602 // From https://pubs.opengroup.org/onlinepubs/9699919799/functions/mmap.html:
603 // "If a MAP_FIXED request is successful, then any previous mappings [...] for
604 // those whole pages containing any part of the address range [pa,pa+len)
605 // shall be removed, as if by an appropriate call to munmap(), before the new
606 // mapping is established." As a consequence, the memory will be
607 // zero-initialized on next access.
608 void* ret = mmap(address, size, PROT_NONE,
609 MAP_FIXED | MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
610 if (V8_UNLIKELY(ret == MAP_FAILED)) {
611 // Decommitting pages can fail if the limit of VMAs is exceeded.
612 CHECK_EQ(ENOMEM, errno);
613 return false;
614 }
615 CHECK_EQ(ret, address);
616 return true;
617}
618#endif // !defined(_AIX)
619#endif // !V8_OS_ZOS
620
621// static
622bool OS::SealPages(void* address, size_t size) {
623#ifdef V8_ENABLE_MEMORY_SEALING
624#if V8_OS_LINUX && defined(__NR_mseal)
625 long ret = syscall(__NR_mseal, address, size, 0);
626 return ret == 0;
627#else
628 return false;
629#endif
630#else // V8_ENABLE_MEMORY_SEALING
631 return false;
632#endif
633}
634
635// static
636bool OS::CanReserveAddressSpace() { return true; }
637
638// static
639std::optional<AddressSpaceReservation> OS::CreateAddressSpaceReservation(
640 void* hint, size_t size, size_t alignment,
641 MemoryPermission max_permission) {
642 // On POSIX, address space reservations are backed by private memory mappings.
644 if (max_permission == MemoryPermission::kReadWriteExecute) {
646 }
647
648 void* reservation = Allocate(hint, size, alignment, permission);
649 if (!reservation && permission == MemoryPermission::kNoAccessWillJitLater) {
650 // Retry without MAP_JIT, for example in case we are running on an old OS X.
651 permission = MemoryPermission::kNoAccess;
652 reservation = Allocate(hint, size, alignment, permission);
653 }
654
655 if (!reservation) return {};
656
657 return AddressSpaceReservation(reservation, size);
658}
659
660// static
661void OS::FreeAddressSpaceReservation(AddressSpaceReservation reservation) {
662 Free(reservation.base(), reservation.size());
663}
664
665// Darwin specific implementation in platform-darwin.cc.
666#if !defined(V8_OS_DARWIN)
667// static
668// Need to disable CFI_ICALL due to the indirect call to memfd_create.
671#if V8_OS_LINUX && !V8_OS_ANDROID
672 // Use memfd_create if available, otherwise mkstemp.
673 using memfd_create_t = int (*)(const char*, unsigned int);
674 memfd_create_t memfd_create =
675 reinterpret_cast<memfd_create_t>(dlsym(RTLD_DEFAULT, "memfd_create"));
676 int fd = -1;
677 if (memfd_create) {
678 fd = memfd_create("V8MemFDForTesting", 0);
679 }
680 if (fd == -1) {
681 char filename[] = "/tmp/v8_tmp_file_for_testing_XXXXXX";
682 fd = mkstemp(filename);
683 if (fd != -1) CHECK_EQ(0, unlink(filename));
684 }
685 if (fd == -1) return kInvalidSharedMemoryHandle;
686 CHECK_EQ(0, ftruncate(fd, size));
688#else
690#endif
691}
692
693// static
697 CHECK_EQ(0, close(fd));
698}
699#endif // !defined(V8_OS_DARWIN)
700
701#if !V8_OS_ZOS
702// static
703bool OS::HasLazyCommits() {
704#if V8_OS_AIX || V8_OS_LINUX || V8_OS_DARWIN
705 return true;
706#else
707 // TODO(bbudge) Return true for all POSIX platforms.
708 return false;
709#endif
710}
711#endif // !V8_OS_ZOS
712#endif // !V8_OS_CYGWIN && !V8_OS_FUCHSIA
713
714const char* OS::GetGCFakeMMapFile() {
715 return g_gc_fake_mmap;
716}
717
718
719void OS::Sleep(TimeDelta interval) {
720 usleep(static_cast<useconds_t>(interval.InMicroseconds()));
721}
722
723
724void OS::Abort() {
725 switch (g_abort_mode) {
727 _exit(0);
729 _exit(-1);
733 break;
734 }
735 // Redirect to std abort to signal abnormal program termination.
736 abort();
737}
738
739
741#if V8_HOST_ARCH_ARM
742 asm("bkpt 0");
743#elif V8_HOST_ARCH_ARM64
744 asm("brk 0");
745#elif V8_HOST_ARCH_MIPS
746 asm("break");
747#elif V8_HOST_ARCH_MIPS64
748 asm("break");
749#elif V8_HOST_ARCH_LOONG64
750 asm("break 0");
751#elif V8_HOST_ARCH_PPC64
752 asm("twge 2,2");
753#elif V8_HOST_ARCH_IA32
754 asm("int $3");
755#elif V8_HOST_ARCH_X64
756 asm("int $3");
757#elif V8_OS_ZOS
758 asm(" dc x'0001'");
759#elif V8_HOST_ARCH_S390X
760 // Software breakpoint instruction is 0x0001
761 asm volatile(".word 0x0001");
762#elif V8_HOST_ARCH_RISCV64
763 asm("ebreak");
764#elif V8_HOST_ARCH_RISCV32
765 asm("ebreak");
766#else
767#error Unsupported host architecture.
768#endif
769}
770
771#if !V8_OS_ZOS
772class PosixMemoryMappedFile final : public OS::MemoryMappedFile {
773 public:
774 PosixMemoryMappedFile(FILE* file, void* memory, size_t size)
775 : file_(file), memory_(memory), size_(size) {}
777 void* memory() const final { return memory_; }
778 size_t size() const final { return size_; }
779
780 private:
781 FILE* const file_;
782 void* const memory_;
783 size_t const size_;
784};
785
786
787// static
789 FileMode mode) {
790 const char* fopen_mode = (mode == FileMode::kReadOnly) ? "r" : "r+";
791 struct stat statbuf;
792 // Make sure path exists and is not a directory.
793 if (stat(name, &statbuf) == 0 && !S_ISDIR(statbuf.st_mode)) {
794 if (FILE* file = fopen(name, fopen_mode)) {
795 if (fseek(file, 0, SEEK_END) == 0) {
796 long size = ftell(file); // NOLINT(runtime/int)
797 if (size == 0) return new PosixMemoryMappedFile(file, nullptr, 0);
798 if (size > 0) {
799 int prot = PROT_READ;
800 int flags = MAP_PRIVATE;
801 if (mode == FileMode::kReadWrite) {
802 prot |= PROT_WRITE;
803 flags = MAP_SHARED;
804 }
805 void* const memory =
806 mmap(OS::GetRandomMmapAddr(), size, prot, flags, fileno(file), 0);
807 if (memory != MAP_FAILED) {
808 return new PosixMemoryMappedFile(file, memory, size);
809 }
810 }
811 }
812 fclose(file);
813 }
814 }
815 return nullptr;
816}
817
818// static
820 size_t size, void* initial) {
821 if (FILE* file = fopen(name, "w+")) {
822 if (size == 0) return new PosixMemoryMappedFile(file, nullptr, 0);
823 size_t result = fwrite(initial, 1, size, file);
824 if (result == size && !ferror(file)) {
825 void* memory = mmap(OS::GetRandomMmapAddr(), result,
826 PROT_READ | PROT_WRITE, MAP_SHARED, fileno(file), 0);
827 if (memory != MAP_FAILED) {
828 return new PosixMemoryMappedFile(file, memory, result);
829 }
830 }
831 fclose(file);
832 }
833 return nullptr;
834}
835
836
838 if (memory_) OS::Free(memory_, RoundUp(size_, OS::AllocatePageSize()));
839 fclose(file_);
840}
841#endif // !V8_OS_ZOS
842
844 return static_cast<int>(getpid());
845}
846
848#if V8_OS_DARWIN || (V8_OS_ANDROID && defined(__APPLE__))
849 return static_cast<int>(pthread_mach_thread_np(pthread_self()));
850#elif V8_OS_LINUX
851 return static_cast<int>(syscall(__NR_gettid));
852#elif V8_OS_ANDROID
853 return static_cast<int>(gettid());
854#elif V8_OS_AIX
855 return static_cast<int>(thread_self());
856#elif V8_OS_FUCHSIA
857 return static_cast<int>(zx_thread_self());
858#elif V8_OS_SOLARIS
859 return static_cast<int>(pthread_self());
860#elif V8_OS_ZOS
861 return gettid();
862#else
863 return static_cast<int>(reinterpret_cast<intptr_t>(pthread_self()));
864#endif
865}
866
867void OS::ExitProcess(int exit_code) {
868 // Use _exit instead of exit to avoid races between isolate
869 // threads and static destructors.
870 fflush(stdout);
871 fflush(stderr);
872 _exit(exit_code);
873}
874
875// ----------------------------------------------------------------------------
876// POSIX date/time support.
877//
878
879#if !defined(V8_OS_FUCHSIA)
880int OS::GetUserTime(uint32_t* secs, uint32_t* usecs) {
881 struct rusage usage;
882
883 if (getrusage(RUSAGE_SELF, &usage) < 0) return -1;
884 *secs = static_cast<uint32_t>(usage.ru_utime.tv_sec);
885 *usecs = static_cast<uint32_t>(usage.ru_utime.tv_usec);
886 return 0;
887}
888#endif
889
891#if defined(V8_OS_FUCHSIA)
892 // Fuchsia does not implement getrusage()
893 return -1;
894#elif defined(V8_OS_ZOS)
895 // TODO(v8:342445981): zos - rusage struct doesn't yet include ru_maxrss
896 return -1;
897#else
898 struct rusage usage;
899 if (getrusage(RUSAGE_SELF, &usage) < 0) return -1;
900
901#if defined(V8_OS_MACOS) || defined(V8_OS_IOS)
902 constexpr int KB = 1024;
903 // MacOS and iOS ru_maxrss count bytes
904 return static_cast<int>(usage.ru_maxrss / KB);
905#else
906 // Most other cases (at least Linux, IOS, return kilobytes)
907 return static_cast<int>(usage.ru_maxrss);
908#endif // defined(V8_OS_MACOS) || defined(V8_OS_IOS)
909#endif // defined(V8_OS_FUCHSIA)
910}
911
913 return Time::Now().ToJsTime();
914}
915
917 if (std::isnan(time)) return std::numeric_limits<double>::quiet_NaN();
918 time_t tv = static_cast<time_t>(std::floor(time/msPerSecond));
919 struct tm tm;
920 struct tm* t = localtime_r(&tv, &tm);
921 if (nullptr == t) return std::numeric_limits<double>::quiet_NaN();
922 return t->tm_isdst > 0 ? 3600 * msPerSecond : 0;
923}
924
925
927 return errno;
928}
929
930
931// ----------------------------------------------------------------------------
932// POSIX stdio support.
933//
934
935FILE* OS::FOpen(const char* path, const char* mode) {
936 FILE* file = fopen(path, mode);
937 if (file == nullptr) return nullptr;
938 struct stat file_stat;
939 if (fstat(fileno(file), &file_stat) != 0) {
940 fclose(file);
941 return nullptr;
942 }
943 bool is_regular_file = ((file_stat.st_mode & S_IFREG) != 0);
944 if (is_regular_file) return file;
945 fclose(file);
946 return nullptr;
947}
948
949
950bool OS::Remove(const char* path) {
951 return (remove(path) == 0);
952}
953
954char OS::DirectorySeparator() { return '/'; }
955
956bool OS::isDirectorySeparator(const char ch) {
957 return ch == DirectorySeparator();
958}
959
960
962 return tmpfile();
963}
964
965const char* const OS::LogFileOpenMode = "w+";
966
967void OS::Print(const char* format, ...) {
968 va_list args;
969 va_start(args, format);
970 VPrint(format, args);
971 va_end(args);
972}
973
974
975void OS::VPrint(const char* format, va_list args) {
976#if defined(ANDROID) && !defined(V8_ANDROID_LOG_STDOUT)
977 __android_log_vprint(ANDROID_LOG_INFO, LOG_TAG, format, args);
978#else
979 vprintf(format, args);
980#endif
981}
982
983
984void OS::FPrint(FILE* out, const char* format, ...) {
985 va_list args;
986 va_start(args, format);
987 VFPrint(out, format, args);
988 va_end(args);
989}
990
991
992void OS::VFPrint(FILE* out, const char* format, va_list args) {
993#if defined(ANDROID) && !defined(V8_ANDROID_LOG_STDOUT)
994 if (out == stdout) {
995 __android_log_vprint(ANDROID_LOG_INFO, LOG_TAG, format, args);
996 return;
997 }
998#endif
999 vfprintf(out, format, args);
1000}
1001
1002
1003void OS::PrintError(const char* format, ...) {
1004 va_list args;
1005 va_start(args, format);
1006 VPrintError(format, args);
1007 va_end(args);
1008 fflush(stderr);
1009}
1010
1011
1012void OS::VPrintError(const char* format, va_list args) {
1013#if defined(ANDROID) && !defined(V8_ANDROID_LOG_STDOUT)
1014 __android_log_vprint(ANDROID_LOG_ERROR, LOG_TAG, format, args);
1015#else
1016 vfprintf(stderr, format, args);
1017#endif
1018}
1019
1020
1021int OS::SNPrintF(char* str, int length, const char* format, ...) {
1022 va_list args;
1023 va_start(args, format);
1024 int result = VSNPrintF(str, length, format, args);
1025 va_end(args);
1026 return result;
1027}
1028
1029
1030int OS::VSNPrintF(char* str,
1031 int length,
1032 const char* format,
1033 va_list args) {
1034 int n = vsnprintf(str, length, format, args);
1035 if (n < 0 || n >= length) {
1036 // If the length is zero, the assignment fails.
1037 if (length > 0)
1038 str[length - 1] = '\0';
1039 return -1;
1040 } else {
1041 return n;
1042 }
1043}
1044
1045
1046// ----------------------------------------------------------------------------
1047// POSIX string support.
1048//
1049
1050void OS::StrNCpy(char* dest, int length, const char* src, size_t n) {
1051 strncpy(dest, src, n);
1052}
1053
1054// ----------------------------------------------------------------------------
1055// POSIX Address space reservation support.
1056//
1057
1058#if !V8_OS_CYGWIN && !V8_OS_FUCHSIA
1059
1060std::optional<AddressSpaceReservation>
1062 void* address, size_t size, OS::MemoryPermission max_permission) {
1063 DCHECK(Contains(address, size));
1064 DCHECK_EQ(0, size % OS::AllocatePageSize());
1065 DCHECK_EQ(0, reinterpret_cast<uintptr_t>(address) % OS::AllocatePageSize());
1066
1067 return AddressSpaceReservation(address, size);
1068}
1069
1071 AddressSpaceReservation reservation) {
1072 // Nothing to do.
1073 // Pages allocated inside the reservation must've already been freed.
1074 return true;
1075}
1076
1077bool AddressSpaceReservation::Allocate(void* address, size_t size,
1078 OS::MemoryPermission access) {
1079 // The region is already mmap'ed, so it just has to be made accessible now.
1080 DCHECK(Contains(address, size));
1081 if (access == OS::MemoryPermission::kNoAccess) {
1082 // Nothing to do. We don't want to call SetPermissions with kNoAccess here
1083 // as that will for example mark the pages as discardable, which is
1084 // probably not desired here.
1085 return true;
1086 }
1087 return OS::SetPermissions(address, size, access);
1088}
1089
1090bool AddressSpaceReservation::Free(void* address, size_t size) {
1091 DCHECK(Contains(address, size));
1092 return OS::DecommitPages(address, size);
1093}
1094
1095// z/OS specific implementation in platform-zos.cc.
1096#if !defined(V8_OS_ZOS)
1097// Darwin specific implementation in platform-darwin.cc.
1098#if !defined(V8_OS_DARWIN)
1099bool AddressSpaceReservation::AllocateShared(void* address, size_t size,
1100 OS::MemoryPermission access,
1102 uint64_t offset) {
1103 DCHECK(Contains(address, size));
1104 int prot = GetProtectionFromMemoryPermission(access);
1105 int fd = FileDescriptorFromSharedMemoryHandle(handle);
1106 return mmap(address, size, prot, MAP_SHARED | MAP_FIXED, fd, offset) !=
1107 MAP_FAILED;
1108}
1109#endif // !defined(V8_OS_DARWIN)
1110
1111bool AddressSpaceReservation::FreeShared(void* address, size_t size) {
1112 DCHECK(Contains(address, size));
1113 return mmap(address, size, PROT_NONE, MAP_FIXED | MAP_ANONYMOUS | MAP_PRIVATE,
1114 -1, 0) == address;
1115}
1116#endif // !V8_OS_ZOS
1117
1118bool AddressSpaceReservation::SetPermissions(void* address, size_t size,
1119 OS::MemoryPermission access) {
1120 DCHECK(Contains(address, size));
1121 return OS::SetPermissions(address, size, access);
1122}
1123
1124bool AddressSpaceReservation::RecommitPages(void* address, size_t size,
1125 OS::MemoryPermission access) {
1126 DCHECK(Contains(address, size));
1127 return OS::RecommitPages(address, size, access);
1128}
1129
1130bool AddressSpaceReservation::DiscardSystemPages(void* address, size_t size) {
1131 DCHECK(Contains(address, size));
1132 return OS::DiscardSystemPages(address, size);
1133}
1134
1135bool AddressSpaceReservation::DecommitPages(void* address, size_t size) {
1136 DCHECK(Contains(address, size));
1137 return OS::DecommitPages(address, size);
1138}
1139
1140#endif // !V8_OS_CYGWIN && !V8_OS_FUCHSIA
1141
1142// ----------------------------------------------------------------------------
1143// POSIX thread support.
1144//
1145
1146class Thread::PlatformData {
1147 public:
1148 PlatformData() : thread_(kNoThread) {}
1149 pthread_t thread_; // Thread handle for pthread.
1150 // Synchronizes thread creation
1152};
1153
1155 : data_(new PlatformData),
1156 stack_size_(options.stack_size()),
1157 priority_(options.priority()),
1158 start_semaphore_(nullptr) {
1159 const int min_stack_size = static_cast<int>(PTHREAD_STACK_MIN);
1160 if (stack_size_ > 0) stack_size_ = std::max(stack_size_, min_stack_size);
1161 set_name(options.name());
1162}
1163
1165 delete data_;
1166}
1167
1168
1169static void SetThreadName(const char* name) {
1170#if V8_OS_DRAGONFLYBSD || V8_OS_FREEBSD || V8_OS_OPENBSD
1171 pthread_set_name_np(pthread_self(), name);
1172#elif V8_OS_NETBSD
1173 static_assert(Thread::kMaxThreadNameLength <= PTHREAD_MAX_NAMELEN_NP);
1174 pthread_setname_np(pthread_self(), "%s", name);
1175#elif V8_OS_DARWIN
1176 // pthread_setname_np is only available in 10.6 or later, so test
1177 // for it at runtime.
1178 int (*dynamic_pthread_setname_np)(const char*);
1179 *reinterpret_cast<void**>(&dynamic_pthread_setname_np) =
1180 dlsym(RTLD_DEFAULT, "pthread_setname_np");
1181 if (dynamic_pthread_setname_np == nullptr) return;
1182
1183 // Mac OS X does not expose the length limit of the name, so hardcode it.
1184 static const int kMaxNameLength = 63;
1185 static_assert(Thread::kMaxThreadNameLength <= kMaxNameLength);
1186 dynamic_pthread_setname_np(name);
1187#elif defined(PR_SET_NAME)
1188 prctl(PR_SET_NAME,
1189 reinterpret_cast<unsigned long>(name), // NOLINT
1190 0, 0, 0);
1191#endif
1192}
1193
1194static void* ThreadEntry(void* arg) {
1195 Thread* thread = reinterpret_cast<Thread*>(arg);
1196 // We take the lock here to make sure that pthread_create finished first since
1197 // we don't know which thread will run first (the original thread or the new
1198 // one).
1199 { MutexGuard lock_guard(&thread->data()->thread_creation_mutex_); }
1200 SetThreadName(thread->name());
1201#if V8_OS_DARWIN
1202 switch (thread->priority()) {
1204 pthread_set_qos_class_self_np(QOS_CLASS_BACKGROUND, 0);
1205 break;
1207 pthread_set_qos_class_self_np(QOS_CLASS_USER_INITIATED, -1);
1208 break;
1210 pthread_set_qos_class_self_np(QOS_CLASS_USER_INITIATED, 0);
1211 break;
1213 break;
1214 }
1215#elif V8_OS_LINUX || V8_OS_ZOS
1216 switch (thread->priority()) {
1218 setpriority(PRIO_PROCESS, 0, 10);
1219 break;
1221 setpriority(PRIO_PROCESS, 0, 1);
1222 break;
1224 setpriority(PRIO_PROCESS, 0, 0);
1225 break;
1227 break;
1228 }
1229#endif
1230 DCHECK_NE(thread->data()->thread_, kNoThread);
1231 thread->NotifyStartedAndRun();
1232 return nullptr;
1233}
1234
1235
1236void Thread::set_name(const char* name) {
1237 strncpy(name_, name, sizeof(name_) - 1);
1238 name_[sizeof(name_) - 1] = '\0';
1239}
1240
1242 int result;
1243 pthread_attr_t attr;
1244 memset(&attr, 0, sizeof(attr));
1245 result = pthread_attr_init(&attr);
1246 if (result != 0) return false;
1247 size_t stack_size = stack_size_;
1248 if (stack_size == 0) {
1249#if V8_OS_DARWIN
1250 // Default on Mac OS X is 512kB -- bump up to 1MB
1251 stack_size = 1 * 1024 * 1024;
1252#elif V8_OS_AIX
1253 // Default on AIX is 96kB -- bump up to 2MB
1254 stack_size = 2 * 1024 * 1024;
1255#endif
1256 }
1257 if (stack_size > 0) {
1258 result = pthread_attr_setstacksize(&attr, stack_size);
1259 if (result != 0) return pthread_attr_destroy(&attr), false;
1260 }
1261 {
1263 result = pthread_create(&data_->thread_, &attr, ThreadEntry, this);
1264 if (result != 0 || data_->thread_ == kNoThread) {
1265 return pthread_attr_destroy(&attr), false;
1266 }
1267 }
1268 result = pthread_attr_destroy(&attr);
1269 return result == 0;
1270}
1271
1272void Thread::Join() { pthread_join(data_->thread_, nullptr); }
1273
1274static Thread::LocalStorageKey PthreadKeyToLocalKey(pthread_key_t pthread_key) {
1275#if V8_OS_CYGWIN
1276 // We need to cast pthread_key_t to Thread::LocalStorageKey in two steps
1277 // because pthread_key_t is a pointer type on Cygwin. This will probably not
1278 // work on 64-bit platforms, but Cygwin doesn't support 64-bit anyway.
1279 static_assert(sizeof(Thread::LocalStorageKey) == sizeof(pthread_key_t));
1280 intptr_t ptr_key = reinterpret_cast<intptr_t>(pthread_key);
1281 return static_cast<Thread::LocalStorageKey>(ptr_key);
1282#else
1283 return static_cast<Thread::LocalStorageKey>(pthread_key);
1284#endif
1285}
1286
1287
1288static pthread_key_t LocalKeyToPthreadKey(Thread::LocalStorageKey local_key) {
1289#if V8_OS_CYGWIN
1290 static_assert(sizeof(Thread::LocalStorageKey) == sizeof(pthread_key_t));
1291 intptr_t ptr_key = static_cast<intptr_t>(local_key);
1292 return reinterpret_cast<pthread_key_t>(ptr_key);
1293#else
1294 return static_cast<pthread_key_t>(local_key);
1295#endif
1296}
1297
1298#if defined(V8_FAST_TLS_SUPPORTED) && defined(DEBUG)
1299
1300static void CheckFastTls(Thread::LocalStorageKey key) {
1301 void* expected = reinterpret_cast<void*>(0x1234CAFE);
1302 Thread::SetThreadLocal(key, expected);
1303 void* actual = Thread::GetExistingThreadLocal(key);
1304 if (expected != actual) {
1305 FATAL("V8 failed to initialize fast TLS on current kernel");
1306 }
1307 Thread::SetThreadLocal(key, nullptr);
1308}
1309
1310#endif // defined(V8_FAST_TLS_SUPPORTED) && defined(DEBUG)
1311
1313 pthread_key_t key;
1314 int result = pthread_key_create(&key, nullptr);
1315 DCHECK_EQ(0, result);
1316 USE(result);
1318#if defined(V8_FAST_TLS_SUPPORTED) && defined(DEBUG)
1319 CheckFastTls(local_key);
1320#endif
1321 return local_key;
1322}
1323
1325 pthread_key_t pthread_key = LocalKeyToPthreadKey(key);
1326 int result = pthread_key_delete(pthread_key);
1327 DCHECK_EQ(0, result);
1328 USE(result);
1329}
1330
1331
1333 pthread_key_t pthread_key = LocalKeyToPthreadKey(key);
1334 return pthread_getspecific(pthread_key);
1335}
1336
1337
1339 pthread_key_t pthread_key = LocalKeyToPthreadKey(key);
1340 int result = pthread_setspecific(pthread_key, value);
1341 DCHECK_EQ(0, result);
1342 USE(result);
1343}
1344
1345// pthread_getattr_np used below is non portable (hence the _np suffix). We
1346// keep this version in POSIX as most Linux-compatible derivatives will
1347// support it. MacOS and FreeBSD are different here.
1348#if !defined(V8_OS_FREEBSD) && !defined(V8_OS_DARWIN) && !defined(_AIX) && \
1349 !defined(V8_OS_SOLARIS)
1350
1351namespace {
1352#if DEBUG
1353bool MainThreadIsCurrentThread() {
1354 // This method assumes the first time is called is from the main thread.
1355 // It returns true for subsequent calls only if they are called from the
1356 // same thread.
1357 static int main_thread_id = -1;
1358 if (main_thread_id == -1) {
1359 main_thread_id = OS::GetCurrentThreadId();
1360 }
1361 return main_thread_id == OS::GetCurrentThreadId();
1362}
1363#endif // DEBUG
1364} // namespace
1365
1366// static
1367Stack::StackSlot Stack::ObtainCurrentThreadStackStart() {
1368#if V8_OS_ZOS
1369 return __get_stack_start();
1370#elif V8_OS_OPENBSD
1371 stack_t stack;
1372 int error = pthread_stackseg_np(pthread_self(), &stack);
1373 if(error) {
1374 DCHECK(MainThreadIsCurrentThread());
1375 return nullptr;
1376 }
1377 void* stack_start = reinterpret_cast<uint8_t*>(stack.ss_sp) + stack.ss_size;
1378 return stack_start;
1379#else
1380 pthread_attr_t attr;
1381 int error = pthread_getattr_np(pthread_self(), &attr);
1382 if (error) {
1383 DCHECK(MainThreadIsCurrentThread());
1384#if defined(V8_LIBC_GLIBC)
1385 // pthread_getattr_np can fail for the main thread.
1386 // For the main thread we prefer using __libc_stack_end (if it exists) since
1387 // it generally provides a tighter limit for CSS.
1388 return __libc_stack_end;
1389#else
1390 return nullptr;
1391#endif // !defined(V8_LIBC_GLIBC)
1392 }
1393 void* base;
1394 size_t size;
1395 error = pthread_attr_getstack(&attr, &base, &size);
1396 CHECK(!error);
1397 pthread_attr_destroy(&attr);
1398 void* stack_start = reinterpret_cast<uint8_t*>(base) + size;
1399#if defined(V8_LIBC_GLIBC)
1400 // __libc_stack_end is process global and thus is only valid for
1401 // the main thread. Check whether this is the main thread by checking
1402 // __libc_stack_end is within the thread's stack.
1403 if ((base <= __libc_stack_end) && (__libc_stack_end <= stack_start)) {
1404 DCHECK(MainThreadIsCurrentThread());
1405 return __libc_stack_end;
1406 }
1407#endif // !defined(V8_LIBC_GLIBC)
1408 return stack_start;
1409#endif // V8_OS_ZOS
1410}
1411
1412#endif // !defined(V8_OS_FREEBSD) && !defined(V8_OS_DARWIN) &&
1413 // !defined(_AIX) && !defined(V8_OS_SOLARIS)
1414
1415// static
1417 return __builtin_frame_address(0);
1418}
1419
1420#undef LOG_TAG
1421#undef MAP_ANONYMOUS
1422#undef MADV_FREE
1423
1424} // namespace base
1425} // namespace v8
uint8_t data_[MAX_STACK_LENGTH]
V8_WARN_UNUSED_RESULT bool DiscardSystemPages(void *address, size_t size)
V8_WARN_UNUSED_RESULT bool Allocate(void *address, size_t size, OS::MemoryPermission access)
V8_WARN_UNUSED_RESULT bool RecommitPages(void *address, size_t size, OS::MemoryPermission access)
V8_WARN_UNUSED_RESULT bool Free(void *address, size_t size)
V8_WARN_UNUSED_RESULT bool SetPermissions(void *address, size_t size, OS::MemoryPermission access)
V8_WARN_UNUSED_RESULT bool DecommitPages(void *address, size_t size)
V8_WARN_UNUSED_RESULT bool FreeShared(void *address, size_t size)
V8_WARN_UNUSED_RESULT std::optional< AddressSpaceReservation > CreateSubReservation(void *address, size_t size, OS::MemoryPermission max_permission)
V8_WARN_UNUSED_RESULT bool AllocateShared(void *address, size_t size, OS::MemoryPermission access, PlatformSharedMemoryHandle handle, uint64_t offset)
static V8_WARN_UNUSED_RESULT bool FreeSubReservation(AddressSpaceReservation reservation)
static MemoryMappedFile * create(const char *name, size_t size, void *initial)
static MemoryMappedFile * open(const char *name, FileMode mode=FileMode::kReadWrite)
static void Sleep(TimeDelta interval)
friend class PosixMemoryMappedFile
Definition platform.h:366
static V8_WARN_UNUSED_RESULT void * AllocateShared(size_t size, MemoryPermission access)
static void * GetRandomMmapAddr()
static V8_WARN_UNUSED_RESULT bool SealPages(void *address, size_t size)
static bool ArmUsingHardFloat()
static static va_list args
Definition platform.h:200
static bool HasLazyCommits()
static V8_WARN_UNUSED_RESULT bool CanReserveAddressSpace()
static V8_WARN_UNUSED_RESULT bool DiscardSystemPages(void *address, size_t size)
static size_t AllocatePageSize()
static void ExitProcess(int exit_code)
static void SetDataReadOnly(void *address, size_t size)
static void Abort()
static bool IsHardwareEnforcedShadowStacksEnabled()
static void FreeAddressSpaceReservation(AddressSpaceReservation reservation)
static const char *const LogFileOpenMode
Definition platform.h:194
static int GetCurrentThreadIdInternal()
static int GetLastError()
static PlatformSharedMemoryHandle CreateSharedMemoryHandleForTesting(size_t size)
static void FreeShared(void *address, size_t size)
static V8_WARN_UNUSED_RESULT bool SetPermissions(void *address, size_t size, MemoryPermission access)
static FILE * OpenTemporaryFile()
static FILE * FOpen(const char *path, const char *mode)
static void Initialize(AbortMode abort_mode, const char *const gc_fake_mmap)
static V8_WARN_UNUSED_RESULT bool DecommitPages(void *address, size_t size)
static int GetCurrentProcessId()
static size_t CommitPageSize()
static int GetPeakMemoryUsageKb()
static void Release(void *address, size_t size)
static V8_WARN_UNUSED_RESULT bool RecommitPages(void *address, size_t size, MemoryPermission access)
static char DirectorySeparator()
static void StrNCpy(char *dest, int length, const char *src, size_t n)
static int GetUserTime(uint32_t *secs, uint32_t *usecs)
static int GetCurrentThreadId()
Definition platform.cc:29
static int ActivationFrameAlignment()
static V8_WARN_UNUSED_RESULT void * Allocate(void *address, size_t size, size_t alignment, MemoryPermission access)
static void DestroySharedMemoryHandle(PlatformSharedMemoryHandle handle)
static double TimeCurrentMillis()
static bool isDirectorySeparator(const char ch)
static void SetRandomMmapSeed(int64_t seed)
static V8_WARN_UNUSED_RESULT std::optional< AddressSpaceReservation > CreateAddressSpaceReservation(void *hint, size_t size, size_t alignment, MemoryPermission max_permission)
static const int msPerSecond
Definition platform.h:422
friend class AddressSpaceReservation
Definition platform.h:364
static void Free(void *address, size_t size)
static bool Remove(const char *path)
static void DebugBreak()
PosixMemoryMappedFile(FILE *file, void *memory, size_t size)
double DaylightSavingsOffset(double time_ms) override
static V8_NOINLINE StackSlot GetCurrentStackPosition()
static Stack::StackSlot ObtainCurrentThreadStackStart()
Thread(const Options &options)
V8_WARN_UNUSED_RESULT bool Start()
int32_t LocalStorageKey
Definition platform.h:541
static void DeleteThreadLocalKey(LocalStorageKey key)
PlatformData * data_
Definition platform.h:633
static LocalStorageKey CreateThreadLocalKey()
static void * GetThreadLocal(LocalStorageKey key)
void set_name(const char *name)
char name_[kMaxThreadNameLength]
Definition platform.h:635
static const int kMaxThreadNameLength
Definition platform.h:619
static void * GetExistingThreadLocal(LocalStorageKey key)
Definition platform.h:612
static void SetThreadLocal(LocalStorageKey key, void *value)
static Time Now()
double ToJsTime() const
Definition time.cc:502
const int size_
Definition assembler.cc:132
refactor address components for immediate indexing make OptimizeMaglevOnNextCall optimize to turbofan instead of maglev filter for tracing turbofan compilation trace turbo cfg trace TurboFan s graph trimmer trace TurboFan s control equivalence trace TurboFan s register allocator trace stack load store counters for optimized code in run fuzzing &&concurrent_recompilation trace_turbo trace_turbo_scheduled trace_turbo_stack_accesses verify TurboFan machine graph of code stubs enable FixedArray bounds checks print TurboFan statistics of wasm compilations maximum cumulative size of bytecode considered for inlining scale factor of bytecode size used to calculate the inlining budget * KB
other heap size flags(e.g. initial_heap_size) take precedence") DEFINE_SIZE_T( max_shared_heap_size
std::string filename
#define IMMEDIATE_CRASH()
int32_t offset
ZoneVector< RpoNumber > & result
ZoneStack< RpoNumber > & stack
#define DEFINE_LAZY_LEAKY_OBJECT_GETTER(T, FunctionName,...)
size_t priority
int n
Definition mul-fft.cc:296
#define LAZY_MUTEX_INITIALIZER
Definition mutex.h:105
int GetProtectionFromMemoryPermission(OS::MemoryPermission access)
@ kExitWithFailureAndIgnoreDcheckFailures
@ kExitWithSuccessAndIgnoreDcheckFailures
void * Allocate(void *address, size_t size, OS::MemoryPermission access)
static pthread_key_t LocalKeyToPthreadKey(Thread::LocalStorageKey local_key)
static void * ThreadEntry(void *arg)
static Thread::LocalStorageKey PthreadKeyToLocalKey(pthread_key_t pthread_key)
void PosixInitializeCommon(AbortMode abort_mode, const char *const gc_fake_mmap)
AbortMode g_abort_mode
Definition abort-mode.cc:10
static const pthread_t kNoThread
static void SetThreadName(const char *name)
int VSNPrintF(Vector< char > str, const char *format, va_list args)
Definition strings.cc:16
LazyStaticInstance< Mutex, DefaultConstructTrait< Mutex >, ThreadSafeInitOnceTrait >::type LazyMutex
Definition mutex.h:103
int FileDescriptorFromSharedMemoryHandle(PlatformSharedMemoryHandle handle)
PlatformSharedMemoryHandle SharedMemoryHandleFromFileDescriptor(int fd)
static constexpr PlatformSharedMemoryHandle kInvalidSharedMemoryHandle
intptr_t PlatformSharedMemoryHandle
#define MADV_FREE
#define UNREACHABLE()
Definition logging.h:67
#define FATAL(...)
Definition logging.h:47
#define CHECK(condition)
Definition logging.h:124
#define DCHECK_NE(v1, v2)
Definition logging.h:486
#define CHECK_EQ(lhs, rhs)
#define DCHECK(condition)
Definition logging.h:482
#define DCHECK_LT(v1, v2)
Definition logging.h:489
#define DCHECK_EQ(v1, v2)
Definition logging.h:485
#define USE(...)
Definition macros.h:293
#define DISABLE_CFI_ICALL
Definition macros.h:209
constexpr T RoundUp(T x, intptr_t m)
Definition macros.h:387
void * AlignedAddress(void *address, size_t alignment)
Definition macros.h:407
constexpr T RoundDown(T x, intptr_t m)
Definition macros.h:371
Symbol file
#define V8_UNLIKELY(condition)
Definition v8config.h:660
std::unique_ptr< ValueMirror > key