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 namespace base {
40 
41 // ----------------------------------------------------------------------------
42 // Fast TLS support
43 
44 #ifndef V8_NO_FAST_TLS
45 
46 #if V8_CC_MSVC && V8_HOST_ARCH_IA32
47 
48 #define V8_FAST_TLS_SUPPORTED 1
49 
50 INLINE(intptr_t InternalGetExistingThreadLocal(intptr_t index));
51 
InternalGetExistingThreadLocal(intptr_t index)52 inline intptr_t InternalGetExistingThreadLocal(intptr_t index) {
53   const intptr_t kTibInlineTlsOffset = 0xE10;
54   const intptr_t kTibExtraTlsOffset = 0xF94;
55   const intptr_t kMaxInlineSlots = 64;
56   const intptr_t kMaxSlots = kMaxInlineSlots + 1024;
57   const intptr_t kPointerSize = sizeof(void*);
58   DCHECK(0 <= index && index < kMaxSlots);
59   if (index < kMaxInlineSlots) {
60     return static_cast<intptr_t>(__readfsdword(kTibInlineTlsOffset +
61                                                kPointerSize * index));
62   }
63   intptr_t extra = static_cast<intptr_t>(__readfsdword(kTibExtraTlsOffset));
64   DCHECK(extra != 0);
65   return *reinterpret_cast<intptr_t*>(extra +
66                                       kPointerSize * (index - kMaxInlineSlots));
67 }
68 
69 #elif defined(__APPLE__) && (V8_HOST_ARCH_IA32 || V8_HOST_ARCH_X64)
70 
71 #define V8_FAST_TLS_SUPPORTED 1
72 
73 extern V8_BASE_EXPORT intptr_t kMacTlsBaseOffset;
74 
75 INLINE(intptr_t InternalGetExistingThreadLocal(intptr_t index));
76 
77 inline intptr_t InternalGetExistingThreadLocal(intptr_t index) {
78   intptr_t result;
79 #if V8_HOST_ARCH_IA32
80   asm("movl %%gs:(%1,%2,4), %0;"
81       :"=r"(result)  // Output must be a writable register.
82       :"r"(kMacTlsBaseOffset), "r"(index));
83 #else
84   asm("movq %%gs:(%1,%2,8), %0;"
85       :"=r"(result)
86       :"r"(kMacTlsBaseOffset), "r"(index));
87 #endif
88   return result;
89 }
90 
91 #endif
92 
93 #endif  // V8_NO_FAST_TLS
94 
95 
96 class TimezoneCache;
97 
98 
99 // ----------------------------------------------------------------------------
100 // OS
101 //
102 // This class has static methods for the different platform specific
103 // functions. Add methods here to cope with differences between the
104 // supported platforms.
105 
106 class V8_BASE_EXPORT OS {
107  public:
108   // Initialize the OS class.
109   // - random_seed: Used for the GetRandomMmapAddress() if non-zero.
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(int64_t random_seed,
113                          bool hard_abort,
114                          const char* const gc_fake_mmap);
115 
116   // Returns the accumulated user time for thread. This routine
117   // can be used for profiling. The implementation should
118   // strive for high-precision timer resolution, preferable
119   // micro-second resolution.
120   static int GetUserTime(uint32_t* secs,  uint32_t* usecs);
121 
122   // Returns current time as the number of milliseconds since
123   // 00:00:00 UTC, January 1, 1970.
124   static double TimeCurrentMillis();
125 
126   static TimezoneCache* CreateTimezoneCache();
127   static void DisposeTimezoneCache(TimezoneCache* cache);
128   static void ClearTimezoneCache(TimezoneCache* cache);
129 
130   // Returns a string identifying the current time zone. The
131   // timestamp is used for determining if DST is in effect.
132   static const char* LocalTimezone(double time, TimezoneCache* cache);
133 
134   // Returns the local time offset in milliseconds east of UTC without
135   // taking daylight savings time into account.
136   static double LocalTimeOffset(TimezoneCache* cache);
137 
138   // Returns the daylight savings offset for the given time.
139   static double DaylightSavingsOffset(double time, TimezoneCache* cache);
140 
141   // Returns last OS error.
142   static int GetLastError();
143 
144   static FILE* FOpen(const char* path, const char* mode);
145   static bool Remove(const char* path);
146 
147   static char DirectorySeparator();
148   static bool isDirectorySeparator(const char ch);
149 
150   // Opens a temporary file, the file is auto removed on close.
151   static FILE* OpenTemporaryFile();
152 
153   // Log file open mode is platform-dependent due to line ends issues.
154   static const char* const LogFileOpenMode;
155 
156   // Print output to console. This is mostly used for debugging output.
157   // On platforms that has standard terminal output, the output
158   // should go to stdout.
159   static PRINTF_FORMAT(1, 2) void Print(const char* format, ...);
160   static PRINTF_FORMAT(1, 0) void VPrint(const char* format, va_list args);
161 
162   // Print output to a file. This is mostly used for debugging output.
163   static PRINTF_FORMAT(2, 3) void FPrint(FILE* out, const char* format, ...);
164   static PRINTF_FORMAT(2, 0) void VFPrint(FILE* out, const char* format,
165                                           va_list args);
166 
167   // Print error output to console. This is mostly used for error message
168   // output. On platforms that has standard terminal output, the output
169   // should go to stderr.
170   static PRINTF_FORMAT(1, 2) void PrintError(const char* format, ...);
171   static PRINTF_FORMAT(1, 0) void VPrintError(const char* format, va_list args);
172 
173   // Allocate/Free memory used by JS heap. Pages are readable/writable, but
174   // they are not guaranteed to be executable unless 'executable' is true.
175   // Returns the address of allocated memory, or NULL if failed.
176   static void* Allocate(const size_t requested,
177                         size_t* allocated,
178                         bool is_executable);
179   static void Free(void* address, const size_t size);
180 
181   // This is the granularity at which the ProtectCode(...) call can set page
182   // permissions.
183   static intptr_t CommitPageSize();
184 
185   // Mark code segments non-writable.
186   static void ProtectCode(void* address, const size_t size);
187 
188   // Assign memory as a guard page so that access will cause an exception.
189   static void Guard(void* address, const size_t size);
190 
191   // Generate a random address to be used for hinting mmap().
192   static void* GetRandomMmapAddr();
193 
194   // Get the Alignment guaranteed by Allocate().
195   static size_t AllocateAlignment();
196 
197   // Sleep for a specified time interval.
198   static void Sleep(TimeDelta interval);
199 
200   // Abort the current process.
201   V8_NORETURN static void Abort();
202 
203   // Debug break.
204   static void DebugBreak();
205 
206   // Walk the stack.
207   static const int kStackWalkError = -1;
208   static const int kStackWalkMaxNameLen = 256;
209   static const int kStackWalkMaxTextLen = 256;
210   struct StackFrame {
211     void* address;
212     char text[kStackWalkMaxTextLen];
213   };
214 
215   class V8_BASE_EXPORT MemoryMappedFile {
216    public:
~MemoryMappedFile()217     virtual ~MemoryMappedFile() {}
218     virtual void* memory() const = 0;
219     virtual size_t size() const = 0;
220 
221     static MemoryMappedFile* open(const char* name);
222     static MemoryMappedFile* create(const char* name, size_t size,
223                                     void* initial);
224   };
225 
226   // Safe formatting print. Ensures that str is always null-terminated.
227   // Returns the number of chars written, or -1 if output was truncated.
228   static PRINTF_FORMAT(3, 4) int SNPrintF(char* str, int length,
229                                           const char* format, ...);
230   static PRINTF_FORMAT(3, 0) int VSNPrintF(char* str, int length,
231                                            const char* format, va_list args);
232 
233   static char* StrChr(char* str, int c);
234   static void StrNCpy(char* dest, int length, const char* src, size_t n);
235 
236   // Support for the profiler.  Can do nothing, in which case ticks
237   // occuring in shared libraries will not be properly accounted for.
238   struct SharedLibraryAddress {
SharedLibraryAddressSharedLibraryAddress239     SharedLibraryAddress(const std::string& library_path, uintptr_t start,
240                          uintptr_t end)
241         : library_path(library_path), start(start), end(end), aslr_slide(0) {}
SharedLibraryAddressSharedLibraryAddress242     SharedLibraryAddress(const std::string& library_path, uintptr_t start,
243                          uintptr_t end, intptr_t aslr_slide)
244         : library_path(library_path),
245           start(start),
246           end(end),
247           aslr_slide(aslr_slide) {}
248 
249     std::string library_path;
250     uintptr_t start;
251     uintptr_t end;
252     intptr_t aslr_slide;
253   };
254 
255   static std::vector<SharedLibraryAddress> GetSharedLibraryAddresses();
256 
257   // Support for the profiler.  Notifies the external profiling
258   // process that a code moving garbage collection starts.  Can do
259   // nothing, in which case the code objects must not move (e.g., by
260   // using --never-compact) if accurate profiling is desired.
261   static void SignalCodeMovingGC();
262 
263   // Support runtime detection of whether the hard float option of the
264   // EABI is used.
265   static bool ArmUsingHardFloat();
266 
267   // Returns the activation frame alignment constraint or zero if
268   // the platform doesn't care. Guaranteed to be a power of two.
269   static int ActivationFrameAlignment();
270 
271   static int GetCurrentProcessId();
272 
273   static int GetCurrentThreadId();
274 
275  private:
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 
286 // Represents and controls an area of reserved memory.
287 // Control of the reserved memory can be assigned to another VirtualMemory
288 // object by assignment or copy-contructing. This removes the reserved memory
289 // from the original object.
290 class V8_BASE_EXPORT VirtualMemory {
291  public:
292   // Empty VirtualMemory object, controlling no reserved memory.
293   VirtualMemory();
294 
295   // Reserves virtual memory with size.
296   explicit VirtualMemory(size_t size);
297 
298   // Reserves virtual memory containing an area of the given size that
299   // is aligned per alignment. This may not be at the position returned
300   // by address().
301   VirtualMemory(size_t size, size_t alignment);
302 
303   // Construct a virtual memory by assigning it some already mapped address
304   // and size.
VirtualMemory(void * address,size_t size)305   VirtualMemory(void* address, size_t size) : address_(address), size_(size) {}
306 
307   // Releases the reserved memory, if any, controlled by this VirtualMemory
308   // object.
309   ~VirtualMemory();
310 
311   // Returns whether the memory has been reserved.
312   bool IsReserved();
313 
314   // Initialize or resets an embedded VirtualMemory object.
315   void Reset();
316 
317   // Returns the start address of the reserved memory.
318   // If the memory was reserved with an alignment, this address is not
319   // necessarily aligned. The user might need to round it up to a multiple of
320   // the alignment to get the start of the aligned block.
address()321   void* address() {
322     DCHECK(IsReserved());
323     return address_;
324   }
325 
326   // Returns the size of the reserved memory. The returned value is only
327   // meaningful when IsReserved() returns true.
328   // If the memory was reserved with an alignment, this size may be larger
329   // than the requested size.
size()330   size_t size() { return size_; }
331 
332   // Commits real memory. Returns whether the operation succeeded.
333   bool Commit(void* address, size_t size, bool is_executable);
334 
335   // Uncommit real memory.  Returns whether the operation succeeded.
336   bool Uncommit(void* address, size_t size);
337 
338   // Creates a single guard page at the given address.
339   bool Guard(void* address);
340 
341   // Releases the memory after |free_start|.
ReleasePartial(void * free_start)342   void ReleasePartial(void* free_start) {
343     DCHECK(IsReserved());
344     // Notice: Order is important here. The VirtualMemory object might live
345     // inside the allocated region.
346     size_t size = size_ - (reinterpret_cast<size_t>(free_start) -
347                            reinterpret_cast<size_t>(address_));
348     CHECK(InVM(free_start, size));
349     DCHECK_LT(address_, free_start);
350     DCHECK_LT(free_start, reinterpret_cast<void*>(
351                               reinterpret_cast<size_t>(address_) + size_));
352     bool result = ReleasePartialRegion(address_, size_, free_start, size);
353     USE(result);
354     DCHECK(result);
355     size_ -= size;
356   }
357 
Release()358   void Release() {
359     DCHECK(IsReserved());
360     // Notice: Order is important here. The VirtualMemory object might live
361     // inside the allocated region.
362     void* address = address_;
363     size_t size = size_;
364     CHECK(InVM(address, size));
365     Reset();
366     bool result = ReleaseRegion(address, size);
367     USE(result);
368     DCHECK(result);
369   }
370 
371   // Assign control of the reserved region to a different VirtualMemory object.
372   // The old object is no longer functional (IsReserved() returns false).
TakeControl(VirtualMemory * from)373   void TakeControl(VirtualMemory* from) {
374     DCHECK(!IsReserved());
375     address_ = from->address_;
376     size_ = from->size_;
377     from->Reset();
378   }
379 
380   static void* ReserveRegion(size_t size);
381 
382   static bool CommitRegion(void* base, size_t size, bool is_executable);
383 
384   static bool UncommitRegion(void* base, size_t size);
385 
386   // Must be called with a base pointer that has been returned by ReserveRegion
387   // and the same size it was reserved with.
388   static bool ReleaseRegion(void* base, size_t size);
389 
390   // Must be called with a base pointer that has been returned by ReserveRegion
391   // and the same size it was reserved with.
392   // [free_start, free_start + free_size] is the memory that will be released.
393   static bool ReleasePartialRegion(void* base, size_t size, void* free_start,
394                                    size_t free_size);
395 
396   // Returns true if OS performs lazy commits, i.e. the memory allocation call
397   // defers actual physical memory allocation till the first memory access.
398   // Otherwise returns false.
399   static bool HasLazyCommits();
400 
401  private:
InVM(void * address,size_t size)402   bool InVM(void* address, size_t size) {
403     return (reinterpret_cast<uintptr_t>(address_) <=
404             reinterpret_cast<uintptr_t>(address)) &&
405            ((reinterpret_cast<uintptr_t>(address_) + size_) >=
406             (reinterpret_cast<uintptr_t>(address) + size));
407   }
408 
409   void* address_;  // Start address of the virtual memory.
410   size_t size_;  // Size of the virtual memory.
411 };
412 
413 
414 // ----------------------------------------------------------------------------
415 // Thread
416 //
417 // Thread objects are used for creating and running threads. When the start()
418 // method is called the new thread starts running the run() method in the new
419 // thread. The Thread object should not be deallocated before the thread has
420 // terminated.
421 
422 class V8_BASE_EXPORT Thread {
423  public:
424   // Opaque data type for thread-local storage keys.
425   typedef int32_t LocalStorageKey;
426 
427   class Options {
428    public:
Options()429     Options() : name_("v8:<unknown>"), stack_size_(0) {}
430     explicit Options(const char* name, int stack_size = 0)
name_(name)431         : name_(name), stack_size_(stack_size) {}
432 
name()433     const char* name() const { return name_; }
stack_size()434     int stack_size() const { return stack_size_; }
435 
436    private:
437     const char* name_;
438     int stack_size_;
439   };
440 
441   // Create new thread.
442   explicit Thread(const Options& options);
443   virtual ~Thread();
444 
445   // Start new thread by calling the Run() method on the new thread.
446   void Start();
447 
448   // Start new thread and wait until Run() method is called on the new thread.
StartSynchronously()449   void StartSynchronously() {
450     start_semaphore_ = new Semaphore(0);
451     Start();
452     start_semaphore_->Wait();
453     delete start_semaphore_;
454     start_semaphore_ = NULL;
455   }
456 
457   // Wait until thread terminates.
458   void Join();
459 
name()460   inline const char* name() const {
461     return name_;
462   }
463 
464   // Abstract method for run handler.
465   virtual void Run() = 0;
466 
467   // Thread-local storage.
468   static LocalStorageKey CreateThreadLocalKey();
469   static void DeleteThreadLocalKey(LocalStorageKey key);
470   static void* GetThreadLocal(LocalStorageKey key);
GetThreadLocalInt(LocalStorageKey key)471   static int GetThreadLocalInt(LocalStorageKey key) {
472     return static_cast<int>(reinterpret_cast<intptr_t>(GetThreadLocal(key)));
473   }
474   static void SetThreadLocal(LocalStorageKey key, void* value);
SetThreadLocalInt(LocalStorageKey key,int value)475   static void SetThreadLocalInt(LocalStorageKey key, int value) {
476     SetThreadLocal(key, reinterpret_cast<void*>(static_cast<intptr_t>(value)));
477   }
HasThreadLocal(LocalStorageKey key)478   static bool HasThreadLocal(LocalStorageKey key) {
479     return GetThreadLocal(key) != NULL;
480   }
481 
482 #ifdef V8_FAST_TLS_SUPPORTED
GetExistingThreadLocal(LocalStorageKey key)483   static inline void* GetExistingThreadLocal(LocalStorageKey key) {
484     void* result = reinterpret_cast<void*>(
485         InternalGetExistingThreadLocal(static_cast<intptr_t>(key)));
486     DCHECK(result == GetThreadLocal(key));
487     return result;
488   }
489 #else
GetExistingThreadLocal(LocalStorageKey key)490   static inline void* GetExistingThreadLocal(LocalStorageKey key) {
491     return GetThreadLocal(key);
492   }
493 #endif
494 
495   // The thread name length is limited to 16 based on Linux's implementation of
496   // prctl().
497   static const int kMaxThreadNameLength = 16;
498 
499   class PlatformData;
data()500   PlatformData* data() { return data_; }
501 
NotifyStartedAndRun()502   void NotifyStartedAndRun() {
503     if (start_semaphore_) start_semaphore_->Signal();
504     Run();
505   }
506 
507  private:
508   void set_name(const char* name);
509 
510   PlatformData* data_;
511 
512   char name_[kMaxThreadNameLength];
513   int stack_size_;
514   Semaphore* start_semaphore_;
515 
516   DISALLOW_COPY_AND_ASSIGN(Thread);
517 };
518 
519 }  // namespace base
520 }  // namespace v8
521 
522 #endif  // V8_BASE_PLATFORM_PLATFORM_H_
523