• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 // This module contains the platform-specific code. This make the rest of the
6 // code less dependent on operating system, compilers and runtime libraries.
7 // This module does specifically not deal with differences between different
8 // processor architecture.
9 // The platform classes have the same definition for all platforms. The
10 // implementation for a particular platform is put in platform_<os>.cc.
11 // The build system then uses the implementation for the target platform.
12 //
13 // This design has been chosen because it is simple and fast. Alternatively,
14 // the platform dependent classes could have been implemented using abstract
15 // superclasses with virtual methods and having specializations for each
16 // platform. This design was rejected because it was more complicated and
17 // slower. It would require factory methods for selecting the right
18 // implementation and the overhead of virtual methods for performance
19 // sensitive like mutex locking/unlocking.
20 
21 #ifndef V8_BASE_PLATFORM_PLATFORM_H_
22 #define V8_BASE_PLATFORM_PLATFORM_H_
23 
24 #include <cstdarg>
25 #include <cstdint>
26 #include <string>
27 #include <vector>
28 
29 #include "include/v8-platform.h"
30 #include "src/base/base-export.h"
31 #include "src/base/build_config.h"
32 #include "src/base/compiler-specific.h"
33 #include "src/base/optional.h"
34 #include "src/base/platform/mutex.h"
35 #include "src/base/platform/semaphore.h"
36 #include "testing/gtest/include/gtest/gtest_prod.h"  // nogncheck
37 
38 #if V8_OS_QNX
39 #include "src/base/qnx-math.h"
40 #endif
41 
42 #if V8_OS_FUCHSIA
43 #include <zircon/types.h>
44 #endif  // V8_OS_FUCHSIA
45 
46 #ifdef V8_USE_ADDRESS_SANITIZER
47 #include <sanitizer/asan_interface.h>
48 #endif  // V8_USE_ADDRESS_SANITIZER
49 
50 #ifndef V8_NO_FAST_TLS
51 #if V8_CC_MSVC && V8_HOST_ARCH_IA32
52 // __readfsdword is supposed to be declared in intrin.h but it is missing from
53 // some versions of that file. See https://bugs.llvm.org/show_bug.cgi?id=51188
54 // And, intrin.h is a very expensive header that we want to avoid here, and
55 // the cheaper intrin0.h is not available for all build configurations. That is
56 // why we declare this intrinsic.
57 extern "C" unsigned long __readfsdword(unsigned long);  // NOLINT(runtime/int)
58 #endif                                       // V8_CC_MSVC && V8_HOST_ARCH_IA32
59 #endif                                       // V8_NO_FAST_TLS
60 
61 namespace v8 {
62 
63 namespace base {
64 
65 // ----------------------------------------------------------------------------
66 // Fast TLS support
67 
68 #ifndef V8_NO_FAST_TLS
69 
70 #if V8_CC_MSVC && V8_HOST_ARCH_IA32
71 
72 #define V8_FAST_TLS_SUPPORTED 1
73 
74 V8_INLINE intptr_t InternalGetExistingThreadLocal(intptr_t index);
75 
InternalGetExistingThreadLocal(intptr_t index)76 inline intptr_t InternalGetExistingThreadLocal(intptr_t index) {
77   const intptr_t kTibInlineTlsOffset = 0xE10;
78   const intptr_t kTibExtraTlsOffset = 0xF94;
79   const intptr_t kMaxInlineSlots = 64;
80   const intptr_t kMaxSlots = kMaxInlineSlots + 1024;
81   const intptr_t kSystemPointerSize = sizeof(void*);
82   DCHECK(0 <= index && index < kMaxSlots);
83   USE(kMaxSlots);
84   if (index < kMaxInlineSlots) {
85     return static_cast<intptr_t>(
86         __readfsdword(kTibInlineTlsOffset + kSystemPointerSize * index));
87   }
88   intptr_t extra = static_cast<intptr_t>(__readfsdword(kTibExtraTlsOffset));
89   if (!extra) return 0;
90   return *reinterpret_cast<intptr_t*>(extra + kSystemPointerSize *
91                                                   (index - kMaxInlineSlots));
92 }
93 
94 #elif defined(__APPLE__) && (V8_HOST_ARCH_IA32 || V8_HOST_ARCH_X64)
95 
96 // tvOS simulator does not use intptr_t as TLS key.
97 #if !defined(V8_OS_STARBOARD) || !defined(TARGET_OS_SIMULATOR)
98 
99 #define V8_FAST_TLS_SUPPORTED 1
100 
101 extern V8_BASE_EXPORT intptr_t kMacTlsBaseOffset;
102 
103 V8_INLINE intptr_t InternalGetExistingThreadLocal(intptr_t index);
104 
105 inline intptr_t InternalGetExistingThreadLocal(intptr_t index) {
106   intptr_t result;
107 #if V8_HOST_ARCH_IA32
108   asm("movl %%gs:(%1,%2,4), %0;"
109       :"=r"(result)  // Output must be a writable register.
110       :"r"(kMacTlsBaseOffset), "r"(index));
111 #else
112   asm("movq %%gs:(%1,%2,8), %0;"
113       :"=r"(result)
114       :"r"(kMacTlsBaseOffset), "r"(index));
115 #endif
116   return result;
117 }
118 
119 #endif  // !defined(V8_OS_STARBOARD) || !defined(TARGET_OS_SIMULATOR)
120 
121 #endif
122 
123 #endif  // V8_NO_FAST_TLS
124 
125 class AddressSpaceReservation;
126 class PageAllocator;
127 class TimezoneCache;
128 class VirtualAddressSpace;
129 class VirtualAddressSubspace;
130 
131 // ----------------------------------------------------------------------------
132 // OS
133 //
134 // This class has static methods for the different platform specific
135 // functions. Add methods here to cope with differences between the
136 // supported platforms.
137 
138 class V8_BASE_EXPORT OS {
139  public:
140   // Initialize the OS class.
141   // - hard_abort: If true, OS::Abort() will crash instead of aborting.
142   // - gc_fake_mmap: Name of the file for fake gc mmap used in ll_prof.
143   static void Initialize(bool hard_abort, const char* const gc_fake_mmap);
144 
145 #if V8_OS_WIN
146   // On Windows, ensure the newer memory API is loaded if available.  This
147   // includes function like VirtualAlloc2 and MapViewOfFile3.
148   // TODO(chromium:1218005) this should probably happen as part of Initialize,
149   // but that is currently invoked too late, after the sandbox is initialized.
150   // However, eventually the sandbox initialization will probably happen as
151   // part of V8::Initialize, at which point this function can probably be
152   // merged into OS::Initialize.
153   static void EnsureWin32MemoryAPILoaded();
154 #endif
155 
156   // Returns the accumulated user time for thread. This routine
157   // can be used for profiling. The implementation should
158   // strive for high-precision timer resolution, preferable
159   // micro-second resolution.
160   static int GetUserTime(uint32_t* secs,  uint32_t* usecs);
161 
162   // Returns current time as the number of milliseconds since
163   // 00:00:00 UTC, January 1, 1970.
164   static double TimeCurrentMillis();
165 
166   static TimezoneCache* CreateTimezoneCache();
167 
168   // Returns last OS error.
169   static int GetLastError();
170 
171   static FILE* FOpen(const char* path, const char* mode);
172   static bool Remove(const char* path);
173 
174   static char DirectorySeparator();
175   static bool isDirectorySeparator(const char ch);
176 
177   // Opens a temporary file, the file is auto removed on close.
178   static FILE* OpenTemporaryFile();
179 
180   // Log file open mode is platform-dependent due to line ends issues.
181   static const char* const LogFileOpenMode;
182 
183   // Print output to console. This is mostly used for debugging output.
184   // On platforms that has standard terminal output, the output
185   // should go to stdout.
186   static PRINTF_FORMAT(1, 2) void Print(const char* format, ...);
187   static PRINTF_FORMAT(1, 0) void VPrint(const char* format, va_list args);
188 
189   // Print output to a file. This is mostly used for debugging output.
190   static PRINTF_FORMAT(2, 3) void FPrint(FILE* out, const char* format, ...);
191   static PRINTF_FORMAT(2, 0) void VFPrint(FILE* out, const char* format,
192                                           va_list args);
193 
194   // Print error output to console. This is mostly used for error message
195   // output. On platforms that has standard terminal output, the output
196   // should go to stderr.
197   static PRINTF_FORMAT(1, 2) void PrintError(const char* format, ...);
198   static PRINTF_FORMAT(1, 0) void VPrintError(const char* format, va_list args);
199 
200   // Memory permissions. These should be kept in sync with the ones in
201   // v8::PageAllocator and v8::PagePermissions.
202   enum class MemoryPermission {
203     kNoAccess,
204     kRead,
205     kReadWrite,
206     kReadWriteExecute,
207     kReadExecute,
208     // TODO(jkummerow): Remove this when Wasm has a platform-independent
209     // w^x implementation.
210     kNoAccessWillJitLater
211   };
212 
213   // Helpers to create shared memory objects. Currently only used for testing.
214   static PlatformSharedMemoryHandle CreateSharedMemoryHandleForTesting(
215       size_t size);
216   static void DestroySharedMemoryHandle(PlatformSharedMemoryHandle handle);
217 
218   static bool HasLazyCommits();
219 
220   // Sleep for a specified time interval.
221   static void Sleep(TimeDelta interval);
222 
223   // Abort the current process.
224   [[noreturn]] static void Abort();
225 
226   // Debug break.
227   static void DebugBreak();
228 
229   // Walk the stack.
230   static const int kStackWalkError = -1;
231   static const int kStackWalkMaxNameLen = 256;
232   static const int kStackWalkMaxTextLen = 256;
233   struct StackFrame {
234     void* address;
235     char text[kStackWalkMaxTextLen];
236   };
237 
238   class V8_BASE_EXPORT MemoryMappedFile {
239    public:
240     enum class FileMode { kReadOnly, kReadWrite };
241 
242     virtual ~MemoryMappedFile() = default;
243     virtual void* memory() const = 0;
244     virtual size_t size() const = 0;
245 
246     static MemoryMappedFile* open(const char* name,
247                                   FileMode mode = FileMode::kReadWrite);
248     static MemoryMappedFile* create(const char* name, size_t size,
249                                     void* initial);
250   };
251 
252   // Safe formatting print. Ensures that str is always null-terminated.
253   // Returns the number of chars written, or -1 if output was truncated.
254   static PRINTF_FORMAT(3, 4) int SNPrintF(char* str, int length,
255                                           const char* format, ...);
256   static PRINTF_FORMAT(3, 0) int VSNPrintF(char* str, int length,
257                                            const char* format, va_list args);
258 
259   static void StrNCpy(char* dest, int length, const char* src, size_t n);
260 
261   // Support for the profiler.  Can do nothing, in which case ticks
262   // occurring in shared libraries will not be properly accounted for.
263   struct SharedLibraryAddress {
SharedLibraryAddressSharedLibraryAddress264     SharedLibraryAddress(const std::string& library_path, uintptr_t start,
265                          uintptr_t end)
266         : library_path(library_path), start(start), end(end), aslr_slide(0) {}
SharedLibraryAddressSharedLibraryAddress267     SharedLibraryAddress(const std::string& library_path, uintptr_t start,
268                          uintptr_t end, intptr_t aslr_slide)
269         : library_path(library_path),
270           start(start),
271           end(end),
272           aslr_slide(aslr_slide) {}
273 
274     std::string library_path;
275     uintptr_t start;
276     uintptr_t end;
277     intptr_t aslr_slide;
278   };
279 
280   static std::vector<SharedLibraryAddress> GetSharedLibraryAddresses();
281 
282   // Support for the profiler.  Notifies the external profiling
283   // process that a code moving garbage collection starts.  Can do
284   // nothing, in which case the code objects must not move (e.g., by
285   // using --never-compact) if accurate profiling is desired.
286   static void SignalCodeMovingGC();
287 
288   // Support runtime detection of whether the hard float option of the
289   // EABI is used.
290   static bool ArmUsingHardFloat();
291 
292   // Returns the activation frame alignment constraint or zero if
293   // the platform doesn't care. Guaranteed to be a power of two.
294   static int ActivationFrameAlignment();
295 
296   static int GetCurrentProcessId();
297 
298   static int GetCurrentThreadId();
299 
300   static void AdjustSchedulingParams();
301 
302   using Address = uintptr_t;
303 
304   struct MemoryRange {
305     uintptr_t start = 0;
306     uintptr_t end = 0;
307   };
308 
309   // Find gaps between existing virtual memory ranges that have enough space
310   // to place a region with minimum_size within (boundary_start, boundary_end)
311   static std::vector<MemoryRange> GetFreeMemoryRangesWithin(
312       Address boundary_start, Address boundary_end, size_t minimum_size,
313       size_t alignment);
314 
315   [[noreturn]] static void ExitProcess(int exit_code);
316 
317   // Whether the platform supports mapping a given address in another location
318   // in the address space.
IsRemapPageSupported()319   V8_WARN_UNUSED_RESULT static constexpr bool IsRemapPageSupported() {
320 #ifdef V8_OS_MACOS
321     return true;
322 #else
323     return false;
324 #endif
325   }
326 
327   // Remaps already-mapped memory at |new_address| with |access| permissions.
328   //
329   // Both the source and target addresses must be page-aligned, and |size| must
330   // be a multiple of the system page size.  If there is already memory mapped
331   // at the target address, it is replaced by the new mapping.
332   //
333   // Must not be called if |IsRemapPagesSupported()| return false.
334   // Returns true for success.
335   V8_WARN_UNUSED_RESULT static bool RemapPages(const void* address, size_t size,
336                                                void* new_address,
337                                                MemoryPermission access);
338 
339  private:
340   // These classes use the private memory management API below.
341   friend class AddressSpaceReservation;
342   friend class MemoryMappedFile;
343   friend class PosixMemoryMappedFile;
344   friend class v8::base::PageAllocator;
345   friend class v8::base::VirtualAddressSpace;
346   friend class v8::base::VirtualAddressSubspace;
347   FRIEND_TEST(OS, RemapPages);
348 
349   static size_t AllocatePageSize();
350 
351   static size_t CommitPageSize();
352 
353   static void SetRandomMmapSeed(int64_t seed);
354 
355   static void* GetRandomMmapAddr();
356 
357   V8_WARN_UNUSED_RESULT static void* Allocate(void* address, size_t size,
358                                               size_t alignment,
359                                               MemoryPermission access);
360 
361   V8_WARN_UNUSED_RESULT static void* AllocateShared(size_t size,
362                                                     MemoryPermission access);
363 
364   V8_WARN_UNUSED_RESULT static void* RemapShared(void* old_address,
365                                                  void* new_address,
366                                                  size_t size);
367 
368   static void Free(void* address, size_t size);
369 
370   V8_WARN_UNUSED_RESULT static void* AllocateShared(
371       void* address, size_t size, OS::MemoryPermission access,
372       PlatformSharedMemoryHandle handle, uint64_t offset);
373 
374   static void FreeShared(void* address, size_t size);
375 
376   static void Release(void* address, size_t size);
377 
378   V8_WARN_UNUSED_RESULT static bool SetPermissions(void* address, size_t size,
379                                                    MemoryPermission access);
380 
381   V8_WARN_UNUSED_RESULT static bool DiscardSystemPages(void* address,
382                                                        size_t size);
383 
384   V8_WARN_UNUSED_RESULT static bool DecommitPages(void* address, size_t size);
385 
386   V8_WARN_UNUSED_RESULT static bool CanReserveAddressSpace();
387 
388   V8_WARN_UNUSED_RESULT static Optional<AddressSpaceReservation>
389   CreateAddressSpaceReservation(void* hint, size_t size, size_t alignment,
390                                 MemoryPermission max_permission);
391 
392   static void FreeAddressSpaceReservation(AddressSpaceReservation reservation);
393 
394   static const int msPerSecond = 1000;
395 
396 #if V8_OS_POSIX
397   static const char* GetGCFakeMMapFile();
398 #endif
399 
400   DISALLOW_IMPLICIT_CONSTRUCTORS(OS);
401 };
402 
403 #if (defined(_WIN32) || defined(_WIN64))
404 V8_BASE_EXPORT void EnsureConsoleOutputWin32();
405 #endif  // (defined(_WIN32) || defined(_WIN64))
406 
EnsureConsoleOutput()407 inline void EnsureConsoleOutput() {
408 #if (defined(_WIN32) || defined(_WIN64))
409   // Windows requires extra calls to send assert output to the console
410   // rather than a dialog box.
411   EnsureConsoleOutputWin32();
412 #endif  // (defined(_WIN32) || defined(_WIN64))
413 }
414 
415 // ----------------------------------------------------------------------------
416 // AddressSpaceReservation
417 //
418 // This class provides the same memory management functions as OS but operates
419 // inside a previously reserved contiguous region of virtual address space.
420 //
421 // Reserved address space in which no pages have been allocated is guaranteed
422 // to be inaccessible and cause a fault on access. As such, creating guard
423 // regions requires no further action.
424 class V8_BASE_EXPORT AddressSpaceReservation {
425  public:
426   using Address = uintptr_t;
427 
base()428   void* base() const { return base_; }
size()429   size_t size() const { return size_; }
430 
Contains(void * region_addr,size_t region_size)431   bool Contains(void* region_addr, size_t region_size) const {
432     Address base = reinterpret_cast<Address>(base_);
433     Address region_base = reinterpret_cast<Address>(region_addr);
434     return (region_base >= base) &&
435            ((region_base + region_size) <= (base + size_));
436   }
437 
438   V8_WARN_UNUSED_RESULT bool Allocate(void* address, size_t size,
439                                       OS::MemoryPermission access);
440 
441   V8_WARN_UNUSED_RESULT bool Free(void* address, size_t size);
442 
443   V8_WARN_UNUSED_RESULT bool AllocateShared(void* address, size_t size,
444                                             OS::MemoryPermission access,
445                                             PlatformSharedMemoryHandle handle,
446                                             uint64_t offset);
447 
448   V8_WARN_UNUSED_RESULT bool FreeShared(void* address, size_t size);
449 
450   V8_WARN_UNUSED_RESULT bool SetPermissions(void* address, size_t size,
451                                             OS::MemoryPermission access);
452 
453   V8_WARN_UNUSED_RESULT bool DiscardSystemPages(void* address, size_t size);
454 
455   V8_WARN_UNUSED_RESULT bool DecommitPages(void* address, size_t size);
456 
457   V8_WARN_UNUSED_RESULT Optional<AddressSpaceReservation> CreateSubReservation(
458       void* address, size_t size, OS::MemoryPermission max_permission);
459 
460   V8_WARN_UNUSED_RESULT static bool FreeSubReservation(
461       AddressSpaceReservation reservation);
462 
463 #if V8_OS_WIN
464   // On Windows, the placeholder mappings backing address space reservations
465   // need to be split and merged as page allocations can only replace an entire
466   // placeholder mapping, not parts of it. This must be done by the users of
467   // this API as it requires a RegionAllocator (or equivalent) to keep track of
468   // sub-regions and decide when to split and when to coalesce multiple free
469   // regions into a single one.
470   V8_WARN_UNUSED_RESULT bool SplitPlaceholder(void* address, size_t size);
471   V8_WARN_UNUSED_RESULT bool MergePlaceholders(void* address, size_t size);
472 #endif  // V8_OS_WIN
473 
474  private:
475   friend class OS;
476 
477 #if V8_OS_FUCHSIA
AddressSpaceReservation(void * base,size_t size,zx_handle_t vmar)478   AddressSpaceReservation(void* base, size_t size, zx_handle_t vmar)
479       : base_(base), size_(size), vmar_(vmar) {}
480 #else
AddressSpaceReservation(void * base,size_t size)481   AddressSpaceReservation(void* base, size_t size) : base_(base), size_(size) {}
482 #endif  // V8_OS_FUCHSIA
483 
484   void* base_ = nullptr;
485   size_t size_ = 0;
486 
487 #if V8_OS_FUCHSIA
488   // On Fuchsia, address space reservations are backed by VMARs.
489   zx_handle_t vmar_ = ZX_HANDLE_INVALID;
490 #endif  // V8_OS_FUCHSIA
491 };
492 
493 // ----------------------------------------------------------------------------
494 // Thread
495 //
496 // Thread objects are used for creating and running threads. When the start()
497 // method is called the new thread starts running the run() method in the new
498 // thread. The Thread object should not be deallocated before the thread has
499 // terminated.
500 
501 class V8_BASE_EXPORT Thread {
502  public:
503   // Opaque data type for thread-local storage keys.
504 #if V8_OS_STARBOARD
505   using LocalStorageKey = SbThreadLocalKey;
506 #else
507   using LocalStorageKey = int32_t;
508 #endif
509 
510   class Options {
511    public:
Options()512     Options() : name_("v8:<unknown>"), stack_size_(0) {}
513     explicit Options(const char* name, int stack_size = 0)
name_(name)514         : name_(name), stack_size_(stack_size) {}
515 
name()516     const char* name() const { return name_; }
stack_size()517     int stack_size() const { return stack_size_; }
518 
519    private:
520     const char* name_;
521     int stack_size_;
522   };
523 
524   // Create new thread.
525   explicit Thread(const Options& options);
526   Thread(const Thread&) = delete;
527   Thread& operator=(const Thread&) = delete;
528   virtual ~Thread();
529 
530   // Start new thread by calling the Run() method on the new thread.
531   V8_WARN_UNUSED_RESULT bool Start();
532 
533   // Start new thread and wait until Run() method is called on the new thread.
StartSynchronously()534   bool StartSynchronously() {
535     start_semaphore_ = new Semaphore(0);
536     if (!Start()) return false;
537     start_semaphore_->Wait();
538     delete start_semaphore_;
539     start_semaphore_ = nullptr;
540     return true;
541   }
542 
543   // Wait until thread terminates.
544   void Join();
545 
name()546   inline const char* name() const {
547     return name_;
548   }
549 
550   // Abstract method for run handler.
551   virtual void Run() = 0;
552 
553   // Thread-local storage.
554   static LocalStorageKey CreateThreadLocalKey();
555   static void DeleteThreadLocalKey(LocalStorageKey key);
556   static void* GetThreadLocal(LocalStorageKey key);
557   static void SetThreadLocal(LocalStorageKey key, void* value);
HasThreadLocal(LocalStorageKey key)558   static bool HasThreadLocal(LocalStorageKey key) {
559     return GetThreadLocal(key) != nullptr;
560   }
561 
562 #ifdef V8_FAST_TLS_SUPPORTED
GetExistingThreadLocal(LocalStorageKey key)563   static inline void* GetExistingThreadLocal(LocalStorageKey key) {
564     void* result = reinterpret_cast<void*>(
565         InternalGetExistingThreadLocal(static_cast<intptr_t>(key)));
566     DCHECK(result == GetThreadLocal(key));
567     return result;
568   }
569 #else
GetExistingThreadLocal(LocalStorageKey key)570   static inline void* GetExistingThreadLocal(LocalStorageKey key) {
571     return GetThreadLocal(key);
572   }
573 #endif
574 
575   // The thread name length is limited to 16 based on Linux's implementation of
576   // prctl().
577   static const int kMaxThreadNameLength = 16;
578 
579   class PlatformData;
data()580   PlatformData* data() { return data_; }
581 
NotifyStartedAndRun()582   void NotifyStartedAndRun() {
583     if (start_semaphore_) start_semaphore_->Signal();
584     Run();
585   }
586 
587  private:
588   void set_name(const char* name);
589 
590   PlatformData* data_;
591 
592   char name_[kMaxThreadNameLength];
593   int stack_size_;
594   Semaphore* start_semaphore_;
595 };
596 
597 // TODO(v8:10354): Make use of the stack utilities here in V8.
598 class V8_BASE_EXPORT Stack {
599  public:
600   // Convenience wrapper to use stack slots as unsigned values or void*
601   // pointers.
602   struct StackSlot {
603     // NOLINTNEXTLINE
StackSlotStackSlot604     StackSlot(void* value) : value(reinterpret_cast<uintptr_t>(value)) {}
StackSlotStackSlot605     StackSlot(uintptr_t value) : value(value) {}  // NOLINT
606 
607     // NOLINTNEXTLINE
608     operator void*() const { return reinterpret_cast<void*>(value); }
uintptr_tStackSlot609     operator uintptr_t() const { return value; }  // NOLINT
610 
611     uintptr_t value;
612   };
613 
614   // Gets the start of the stack of the current thread.
615   static StackSlot GetStackStart();
616 
617   // Returns the current stack top. Works correctly with ASAN and SafeStack.
618   // GetCurrentStackPosition() should not be inlined, because it works on stack
619   // frames if it were inlined into a function with a huge stack frame it would
620   // return an address significantly above the actual current stack position.
621   static V8_NOINLINE StackSlot GetCurrentStackPosition();
622 
623   // Returns the real stack frame if slot is part of a fake frame, and slot
624   // otherwise.
GetRealStackAddressForSlot(StackSlot slot)625   static StackSlot GetRealStackAddressForSlot(StackSlot slot) {
626 #ifdef V8_USE_ADDRESS_SANITIZER
627     // ASAN fetches the real stack deeper in the __asan_addr_is_in_fake_stack()
628     // call (precisely, deeper in __asan_stack_malloc_()), which results in a
629     // real frame that could be outside of stack bounds. Adjust for this
630     // impreciseness here.
631     constexpr size_t kAsanRealFrameOffsetBytes = 32;
632     void* real_frame = __asan_addr_is_in_fake_stack(
633         __asan_get_current_fake_stack(), slot, nullptr, nullptr);
634     return real_frame
635                ? (static_cast<char*>(real_frame) + kAsanRealFrameOffsetBytes)
636                : slot;
637 #endif  // V8_USE_ADDRESS_SANITIZER
638     return slot;
639   }
640 };
641 
642 }  // namespace base
643 }  // namespace v8
644 
645 #endif  // V8_BASE_PLATFORM_PLATFORM_H_
646