• 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 "src/base/base-export.h"
30 #include "src/base/build_config.h"
31 #include "src/base/compiler-specific.h"
32 #include "src/base/platform/mutex.h"
33 #include "src/base/platform/semaphore.h"
34 
35 #if V8_OS_QNX
36 #include "src/base/qnx-math.h"
37 #endif
38 
39 #ifdef V8_USE_ADDRESS_SANITIZER
40 #include <sanitizer/asan_interface.h>
41 #endif  // V8_USE_ADDRESS_SANITIZER
42 
43 namespace v8 {
44 
45 namespace base {
46 
47 // ----------------------------------------------------------------------------
48 // Fast TLS support
49 
50 #ifndef V8_NO_FAST_TLS
51 
52 #if V8_CC_MSVC && V8_HOST_ARCH_IA32
53 
54 #define V8_FAST_TLS_SUPPORTED 1
55 
56 V8_INLINE intptr_t InternalGetExistingThreadLocal(intptr_t index);
57 
InternalGetExistingThreadLocal(intptr_t index)58 inline intptr_t InternalGetExistingThreadLocal(intptr_t index) {
59   const intptr_t kTibInlineTlsOffset = 0xE10;
60   const intptr_t kTibExtraTlsOffset = 0xF94;
61   const intptr_t kMaxInlineSlots = 64;
62   const intptr_t kMaxSlots = kMaxInlineSlots + 1024;
63   const intptr_t kSystemPointerSize = sizeof(void*);
64   DCHECK(0 <= index && index < kMaxSlots);
65   USE(kMaxSlots);
66   if (index < kMaxInlineSlots) {
67     return static_cast<intptr_t>(
68         __readfsdword(kTibInlineTlsOffset + kSystemPointerSize * index));
69   }
70   intptr_t extra = static_cast<intptr_t>(__readfsdword(kTibExtraTlsOffset));
71   DCHECK_NE(extra, 0);
72   return *reinterpret_cast<intptr_t*>(extra + kSystemPointerSize *
73                                                   (index - kMaxInlineSlots));
74 }
75 
76 #elif defined(__APPLE__) && (V8_HOST_ARCH_IA32 || V8_HOST_ARCH_X64)
77 
78 // tvOS simulator does not use intptr_t as TLS key.
79 #if !defined(V8_OS_STARBOARD) || !defined(TARGET_OS_SIMULATOR)
80 
81 #define V8_FAST_TLS_SUPPORTED 1
82 
83 extern V8_BASE_EXPORT intptr_t kMacTlsBaseOffset;
84 
85 V8_INLINE intptr_t InternalGetExistingThreadLocal(intptr_t index);
86 
87 inline intptr_t InternalGetExistingThreadLocal(intptr_t index) {
88   intptr_t result;
89 #if V8_HOST_ARCH_IA32
90   asm("movl %%gs:(%1,%2,4), %0;"
91       :"=r"(result)  // Output must be a writable register.
92       :"r"(kMacTlsBaseOffset), "r"(index));
93 #else
94   asm("movq %%gs:(%1,%2,8), %0;"
95       :"=r"(result)
96       :"r"(kMacTlsBaseOffset), "r"(index));
97 #endif
98   return result;
99 }
100 
101 #endif  // !defined(V8_OS_STARBOARD) || !defined(TARGET_OS_SIMULATOR)
102 
103 #endif
104 
105 #endif  // V8_NO_FAST_TLS
106 
107 class PageAllocator;
108 class TimezoneCache;
109 
110 // ----------------------------------------------------------------------------
111 // OS
112 //
113 // This class has static methods for the different platform specific
114 // functions. Add methods here to cope with differences between the
115 // supported platforms.
116 
117 class V8_BASE_EXPORT OS {
118  public:
119   // Initialize the OS class.
120   // - hard_abort: If true, OS::Abort() will crash instead of aborting.
121   // - gc_fake_mmap: Name of the file for fake gc mmap used in ll_prof.
122   static void Initialize(bool hard_abort, const char* const gc_fake_mmap);
123 
124   // Returns the accumulated user time for thread. This routine
125   // can be used for profiling. The implementation should
126   // strive for high-precision timer resolution, preferable
127   // micro-second resolution.
128   static int GetUserTime(uint32_t* secs,  uint32_t* usecs);
129 
130   // Returns current time as the number of milliseconds since
131   // 00:00:00 UTC, January 1, 1970.
132   static double TimeCurrentMillis();
133 
134   static TimezoneCache* CreateTimezoneCache();
135 
136   // Returns last OS error.
137   static int GetLastError();
138 
139   static FILE* FOpen(const char* path, const char* mode);
140   static bool Remove(const char* path);
141 
142   static char DirectorySeparator();
143   static bool isDirectorySeparator(const char ch);
144 
145   // Opens a temporary file, the file is auto removed on close.
146   static FILE* OpenTemporaryFile();
147 
148   // Log file open mode is platform-dependent due to line ends issues.
149   static const char* const LogFileOpenMode;
150 
151   // Print output to console. This is mostly used for debugging output.
152   // On platforms that has standard terminal output, the output
153   // should go to stdout.
154   static PRINTF_FORMAT(1, 2) void Print(const char* format, ...);
155   static PRINTF_FORMAT(1, 0) void VPrint(const char* format, va_list args);
156 
157   // Print output to a file. This is mostly used for debugging output.
158   static PRINTF_FORMAT(2, 3) void FPrint(FILE* out, const char* format, ...);
159   static PRINTF_FORMAT(2, 0) void VFPrint(FILE* out, const char* format,
160                                           va_list args);
161 
162   // Print error output to console. This is mostly used for error message
163   // output. On platforms that has standard terminal output, the output
164   // should go to stderr.
165   static PRINTF_FORMAT(1, 2) void PrintError(const char* format, ...);
166   static PRINTF_FORMAT(1, 0) void VPrintError(const char* format, va_list args);
167 
168   // Memory permissions. These should be kept in sync with the ones in
169   // v8::PageAllocator.
170   enum class MemoryPermission {
171     kNoAccess,
172     kRead,
173     kReadWrite,
174     // TODO(hpayer): Remove this flag. Memory should never be rwx.
175     kReadWriteExecute,
176     kReadExecute,
177     // TODO(jkummerow): Remove this when Wasm has a platform-independent
178     // w^x implementation.
179     kNoAccessWillJitLater
180   };
181 
182   static bool HasLazyCommits();
183 
184   // Sleep for a specified time interval.
185   static void Sleep(TimeDelta interval);
186 
187   // Abort the current process.
188   [[noreturn]] static void Abort();
189 
190   // Debug break.
191   static void DebugBreak();
192 
193   // Walk the stack.
194   static const int kStackWalkError = -1;
195   static const int kStackWalkMaxNameLen = 256;
196   static const int kStackWalkMaxTextLen = 256;
197   struct StackFrame {
198     void* address;
199     char text[kStackWalkMaxTextLen];
200   };
201 
202   class V8_BASE_EXPORT MemoryMappedFile {
203    public:
204     enum class FileMode { kReadOnly, kReadWrite };
205 
206     virtual ~MemoryMappedFile() = default;
207     virtual void* memory() const = 0;
208     virtual size_t size() const = 0;
209 
210     static MemoryMappedFile* open(const char* name,
211                                   FileMode mode = FileMode::kReadWrite);
212     static MemoryMappedFile* create(const char* name, size_t size,
213                                     void* initial);
214   };
215 
216   // Safe formatting print. Ensures that str is always null-terminated.
217   // Returns the number of chars written, or -1 if output was truncated.
218   static PRINTF_FORMAT(3, 4) int SNPrintF(char* str, int length,
219                                           const char* format, ...);
220   static PRINTF_FORMAT(3, 0) int VSNPrintF(char* str, int length,
221                                            const char* format, va_list args);
222 
223   static void StrNCpy(char* dest, int length, const char* src, size_t n);
224 
225   // Support for the profiler.  Can do nothing, in which case ticks
226   // occurring in shared libraries will not be properly accounted for.
227   struct SharedLibraryAddress {
SharedLibraryAddressSharedLibraryAddress228     SharedLibraryAddress(const std::string& library_path, uintptr_t start,
229                          uintptr_t end)
230         : library_path(library_path), start(start), end(end), aslr_slide(0) {}
SharedLibraryAddressSharedLibraryAddress231     SharedLibraryAddress(const std::string& library_path, uintptr_t start,
232                          uintptr_t end, intptr_t aslr_slide)
233         : library_path(library_path),
234           start(start),
235           end(end),
236           aslr_slide(aslr_slide) {}
237 
238     std::string library_path;
239     uintptr_t start;
240     uintptr_t end;
241     intptr_t aslr_slide;
242   };
243 
244   static std::vector<SharedLibraryAddress> GetSharedLibraryAddresses();
245 
246   // Support for the profiler.  Notifies the external profiling
247   // process that a code moving garbage collection starts.  Can do
248   // nothing, in which case the code objects must not move (e.g., by
249   // using --never-compact) if accurate profiling is desired.
250   static void SignalCodeMovingGC();
251 
252   // Support runtime detection of whether the hard float option of the
253   // EABI is used.
254   static bool ArmUsingHardFloat();
255 
256   // Returns the activation frame alignment constraint or zero if
257   // the platform doesn't care. Guaranteed to be a power of two.
258   static int ActivationFrameAlignment();
259 
260   static int GetCurrentProcessId();
261 
262   static int GetCurrentThreadId();
263 
264   static void AdjustSchedulingParams();
265 
266   static void ExitProcess(int exit_code);
267 
268  private:
269   // These classes use the private memory management API below.
270   friend class MemoryMappedFile;
271   friend class PosixMemoryMappedFile;
272   friend class v8::base::PageAllocator;
273 
274   static size_t AllocatePageSize();
275 
276   static size_t CommitPageSize();
277 
278   static void SetRandomMmapSeed(int64_t seed);
279 
280   static void* GetRandomMmapAddr();
281 
282   V8_WARN_UNUSED_RESULT static void* Allocate(void* address, size_t size,
283                                               size_t alignment,
284                                               MemoryPermission access);
285 
286   V8_WARN_UNUSED_RESULT static void* AllocateShared(size_t size,
287                                                     MemoryPermission access);
288 
289   V8_WARN_UNUSED_RESULT static void* RemapShared(void* old_address,
290                                                  void* new_address,
291                                                  size_t size);
292 
293   V8_WARN_UNUSED_RESULT static bool Free(void* address, const size_t size);
294 
295   V8_WARN_UNUSED_RESULT static bool Release(void* address, size_t size);
296 
297   V8_WARN_UNUSED_RESULT static bool SetPermissions(void* address, size_t size,
298                                                    MemoryPermission access);
299 
300   V8_WARN_UNUSED_RESULT static bool DiscardSystemPages(void* address,
301                                                        size_t size);
302 
303   static const int msPerSecond = 1000;
304 
305 #if V8_OS_POSIX
306   static const char* GetGCFakeMMapFile();
307 #endif
308 
309   DISALLOW_IMPLICIT_CONSTRUCTORS(OS);
310 };
311 
312 #if (defined(_WIN32) || defined(_WIN64))
313 V8_BASE_EXPORT void EnsureConsoleOutputWin32();
314 #endif  // (defined(_WIN32) || defined(_WIN64))
315 
EnsureConsoleOutput()316 inline void EnsureConsoleOutput() {
317 #if (defined(_WIN32) || defined(_WIN64))
318   // Windows requires extra calls to send assert output to the console
319   // rather than a dialog box.
320   EnsureConsoleOutputWin32();
321 #endif  // (defined(_WIN32) || defined(_WIN64))
322 }
323 
324 // ----------------------------------------------------------------------------
325 // Thread
326 //
327 // Thread objects are used for creating and running threads. When the start()
328 // method is called the new thread starts running the run() method in the new
329 // thread. The Thread object should not be deallocated before the thread has
330 // terminated.
331 
332 class V8_BASE_EXPORT Thread {
333  public:
334   // Opaque data type for thread-local storage keys.
335 #if V8_OS_STARBOARD
336   using LocalStorageKey = SbThreadLocalKey;
337 #else
338   using LocalStorageKey = int32_t;
339 #endif
340 
341   class Options {
342    public:
Options()343     Options() : name_("v8:<unknown>"), stack_size_(0) {}
344     explicit Options(const char* name, int stack_size = 0)
name_(name)345         : name_(name), stack_size_(stack_size) {}
346 
name()347     const char* name() const { return name_; }
stack_size()348     int stack_size() const { return stack_size_; }
349 
350    private:
351     const char* name_;
352     int stack_size_;
353   };
354 
355   // Create new thread.
356   explicit Thread(const Options& options);
357   Thread(const Thread&) = delete;
358   Thread& operator=(const Thread&) = delete;
359   virtual ~Thread();
360 
361   // Start new thread by calling the Run() method on the new thread.
362   V8_WARN_UNUSED_RESULT bool Start();
363 
364   // Start new thread and wait until Run() method is called on the new thread.
StartSynchronously()365   bool StartSynchronously() {
366     start_semaphore_ = new Semaphore(0);
367     if (!Start()) return false;
368     start_semaphore_->Wait();
369     delete start_semaphore_;
370     start_semaphore_ = nullptr;
371     return true;
372   }
373 
374   // Wait until thread terminates.
375   void Join();
376 
name()377   inline const char* name() const {
378     return name_;
379   }
380 
381   // Abstract method for run handler.
382   virtual void Run() = 0;
383 
384   // Thread-local storage.
385   static LocalStorageKey CreateThreadLocalKey();
386   static void DeleteThreadLocalKey(LocalStorageKey key);
387   static void* GetThreadLocal(LocalStorageKey key);
GetThreadLocalInt(LocalStorageKey key)388   static int GetThreadLocalInt(LocalStorageKey key) {
389     return static_cast<int>(reinterpret_cast<intptr_t>(GetThreadLocal(key)));
390   }
391   static void SetThreadLocal(LocalStorageKey key, void* value);
SetThreadLocalInt(LocalStorageKey key,int value)392   static void SetThreadLocalInt(LocalStorageKey key, int value) {
393     SetThreadLocal(key, reinterpret_cast<void*>(static_cast<intptr_t>(value)));
394   }
HasThreadLocal(LocalStorageKey key)395   static bool HasThreadLocal(LocalStorageKey key) {
396     return GetThreadLocal(key) != nullptr;
397   }
398 
399 #ifdef V8_FAST_TLS_SUPPORTED
GetExistingThreadLocal(LocalStorageKey key)400   static inline void* GetExistingThreadLocal(LocalStorageKey key) {
401     void* result = reinterpret_cast<void*>(
402         InternalGetExistingThreadLocal(static_cast<intptr_t>(key)));
403     DCHECK(result == GetThreadLocal(key));
404     return result;
405   }
406 #else
GetExistingThreadLocal(LocalStorageKey key)407   static inline void* GetExistingThreadLocal(LocalStorageKey key) {
408     return GetThreadLocal(key);
409   }
410 #endif
411 
412   // The thread name length is limited to 16 based on Linux's implementation of
413   // prctl().
414   static const int kMaxThreadNameLength = 16;
415 
416   class PlatformData;
data()417   PlatformData* data() { return data_; }
418 
NotifyStartedAndRun()419   void NotifyStartedAndRun() {
420     if (start_semaphore_) start_semaphore_->Signal();
421     Run();
422   }
423 
424  private:
425   void set_name(const char* name);
426 
427   PlatformData* data_;
428 
429   char name_[kMaxThreadNameLength];
430   int stack_size_;
431   Semaphore* start_semaphore_;
432 };
433 
434 // TODO(v8:10354): Make use of the stack utilities here in V8.
435 class V8_BASE_EXPORT Stack {
436  public:
437   // Convenience wrapper to use stack slots as unsigned values or void*
438   // pointers.
439   struct StackSlot {
440     // NOLINTNEXTLINE
StackSlotStackSlot441     StackSlot(void* value) : value(reinterpret_cast<uintptr_t>(value)) {}
StackSlotStackSlot442     StackSlot(uintptr_t value) : value(value) {}  // NOLINT
443 
444     // NOLINTNEXTLINE
445     operator void*() const { return reinterpret_cast<void*>(value); }
uintptr_tStackSlot446     operator uintptr_t() const { return value; }  // NOLINT
447 
448     uintptr_t value;
449   };
450 
451   // Gets the start of the stack of the current thread.
452   static StackSlot GetStackStart();
453 
454   // Returns the current stack top. Works correctly with ASAN and SafeStack.
455   // GetCurrentStackPosition() should not be inlined, because it works on stack
456   // frames if it were inlined into a function with a huge stack frame it would
457   // return an address significantly above the actual current stack position.
458   static V8_NOINLINE StackSlot GetCurrentStackPosition();
459 
460   // Returns the real stack frame if slot is part of a fake frame, and slot
461   // otherwise.
GetRealStackAddressForSlot(StackSlot slot)462   static StackSlot GetRealStackAddressForSlot(StackSlot slot) {
463 #ifdef V8_USE_ADDRESS_SANITIZER
464     // ASAN fetches the real stack deeper in the __asan_addr_is_in_fake_stack()
465     // call (precisely, deeper in __asan_stack_malloc_()), which results in a
466     // real frame that could be outside of stack bounds. Adjust for this
467     // impreciseness here.
468     constexpr size_t kAsanRealFrameOffsetBytes = 32;
469     void* real_frame = __asan_addr_is_in_fake_stack(
470         __asan_get_current_fake_stack(), slot, nullptr, nullptr);
471     return real_frame
472                ? (static_cast<char*>(real_frame) + kAsanRealFrameOffsetBytes)
473                : slot;
474 #endif  // V8_USE_ADDRESS_SANITIZER
475     return slot;
476   }
477 };
478 
479 }  // namespace base
480 }  // namespace v8
481 
482 #endif  // V8_BASE_PLATFORM_PLATFORM_H_
483