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