• 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 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   // Allocates a region of memory that is inaccessible. On Windows this reserves
182   // but does not commit the memory. On Linux, it is equivalent to a call to
183   // Allocate() followed by Guard().
184   static void* AllocateGuarded(const size_t requested);
185 
186   // This is the granularity at which the ProtectCode(...) call can set page
187   // permissions.
188   static intptr_t CommitPageSize();
189 
190   // Mark code segments non-writable.
191   static void ProtectCode(void* address, const size_t size);
192 
193   // Assign memory as a guard page so that access will cause an exception.
194   static void Guard(void* address, const size_t size);
195 
196   // Make a region of memory readable and writable.
197   static void Unprotect(void* address, const size_t size);
198 
199   // Generate a random address to be used for hinting mmap().
200   static void* GetRandomMmapAddr();
201 
202   // Get the Alignment guaranteed by Allocate().
203   static size_t AllocateAlignment();
204 
205   // Sleep for a specified time interval.
206   static void Sleep(TimeDelta interval);
207 
208   // Abort the current process.
209   V8_NORETURN static void Abort();
210 
211   // Debug break.
212   static void DebugBreak();
213 
214   // Walk the stack.
215   static const int kStackWalkError = -1;
216   static const int kStackWalkMaxNameLen = 256;
217   static const int kStackWalkMaxTextLen = 256;
218   struct StackFrame {
219     void* address;
220     char text[kStackWalkMaxTextLen];
221   };
222 
223   class V8_BASE_EXPORT MemoryMappedFile {
224    public:
~MemoryMappedFile()225     virtual ~MemoryMappedFile() {}
226     virtual void* memory() const = 0;
227     virtual size_t size() const = 0;
228 
229     static MemoryMappedFile* open(const char* name);
230     static MemoryMappedFile* create(const char* name, size_t size,
231                                     void* initial);
232   };
233 
234   // Safe formatting print. Ensures that str is always null-terminated.
235   // Returns the number of chars written, or -1 if output was truncated.
236   static PRINTF_FORMAT(3, 4) int SNPrintF(char* str, int length,
237                                           const char* format, ...);
238   static PRINTF_FORMAT(3, 0) int VSNPrintF(char* str, int length,
239                                            const char* format, va_list args);
240 
241   static char* StrChr(char* str, int c);
242   static void StrNCpy(char* dest, int length, const char* src, size_t n);
243 
244   // Support for the profiler.  Can do nothing, in which case ticks
245   // occuring in shared libraries will not be properly accounted for.
246   struct SharedLibraryAddress {
SharedLibraryAddressSharedLibraryAddress247     SharedLibraryAddress(const std::string& library_path, uintptr_t start,
248                          uintptr_t end)
249         : library_path(library_path), start(start), end(end), aslr_slide(0) {}
SharedLibraryAddressSharedLibraryAddress250     SharedLibraryAddress(const std::string& library_path, uintptr_t start,
251                          uintptr_t end, intptr_t aslr_slide)
252         : library_path(library_path),
253           start(start),
254           end(end),
255           aslr_slide(aslr_slide) {}
256 
257     std::string library_path;
258     uintptr_t start;
259     uintptr_t end;
260     intptr_t aslr_slide;
261   };
262 
263   static std::vector<SharedLibraryAddress> GetSharedLibraryAddresses();
264 
265   // Support for the profiler.  Notifies the external profiling
266   // process that a code moving garbage collection starts.  Can do
267   // nothing, in which case the code objects must not move (e.g., by
268   // using --never-compact) if accurate profiling is desired.
269   static void SignalCodeMovingGC();
270 
271   // Support runtime detection of whether the hard float option of the
272   // EABI is used.
273   static bool ArmUsingHardFloat();
274 
275   // Returns the activation frame alignment constraint or zero if
276   // the platform doesn't care. Guaranteed to be a power of two.
277   static int ActivationFrameAlignment();
278 
279   static int GetCurrentProcessId();
280 
281   static int GetCurrentThreadId();
282 
283  private:
284   static const int msPerSecond = 1000;
285 
286 #if V8_OS_POSIX
287   static const char* GetGCFakeMMapFile();
288 #endif
289 
290   DISALLOW_IMPLICIT_CONSTRUCTORS(OS);
291 };
292 
293 
294 // Represents and controls an area of reserved memory.
295 // Control of the reserved memory can be assigned to another VirtualMemory
296 // object by assignment or copy-contructing. This removes the reserved memory
297 // from the original object.
298 class V8_BASE_EXPORT VirtualMemory {
299  public:
300   // Empty VirtualMemory object, controlling no reserved memory.
301   VirtualMemory();
302 
303   // Reserves virtual memory with size.
304   explicit VirtualMemory(size_t size);
305 
306   // Reserves virtual memory containing an area of the given size that
307   // is aligned per alignment. This may not be at the position returned
308   // by address().
309   VirtualMemory(size_t size, size_t alignment);
310 
311   // Construct a virtual memory by assigning it some already mapped address
312   // and size.
VirtualMemory(void * address,size_t size)313   VirtualMemory(void* address, size_t size) : address_(address), size_(size) {}
314 
315   // Releases the reserved memory, if any, controlled by this VirtualMemory
316   // object.
317   ~VirtualMemory();
318 
319   // Returns whether the memory has been reserved.
320   bool IsReserved();
321 
322   // Initialize or resets an embedded VirtualMemory object.
323   void Reset();
324 
325   // Returns the start address of the reserved memory.
326   // If the memory was reserved with an alignment, this address is not
327   // necessarily aligned. The user might need to round it up to a multiple of
328   // the alignment to get the start of the aligned block.
address()329   void* address() {
330     DCHECK(IsReserved());
331     return address_;
332   }
333 
334   // Returns the size of the reserved memory. The returned value is only
335   // meaningful when IsReserved() returns true.
336   // If the memory was reserved with an alignment, this size may be larger
337   // than the requested size.
size()338   size_t size() { return size_; }
339 
340   // Commits real memory. Returns whether the operation succeeded.
341   bool Commit(void* address, size_t size, bool is_executable);
342 
343   // Uncommit real memory.  Returns whether the operation succeeded.
344   bool Uncommit(void* address, size_t size);
345 
346   // Creates a single guard page at the given address.
347   bool Guard(void* address);
348 
349   // Releases the memory after |free_start|.
ReleasePartial(void * free_start)350   void ReleasePartial(void* free_start) {
351     DCHECK(IsReserved());
352     // Notice: Order is important here. The VirtualMemory object might live
353     // inside the allocated region.
354     size_t size = size_ - (reinterpret_cast<size_t>(free_start) -
355                            reinterpret_cast<size_t>(address_));
356     CHECK(InVM(free_start, size));
357     DCHECK_LT(address_, free_start);
358     DCHECK_LT(free_start, reinterpret_cast<void*>(
359                               reinterpret_cast<size_t>(address_) + size_));
360     bool result = ReleasePartialRegion(address_, size_, free_start, size);
361     USE(result);
362     DCHECK(result);
363     size_ -= size;
364   }
365 
Release()366   void Release() {
367     DCHECK(IsReserved());
368     // Notice: Order is important here. The VirtualMemory object might live
369     // inside the allocated region.
370     void* address = address_;
371     size_t size = size_;
372     CHECK(InVM(address, size));
373     Reset();
374     bool result = ReleaseRegion(address, size);
375     USE(result);
376     DCHECK(result);
377   }
378 
379   // Assign control of the reserved region to a different VirtualMemory object.
380   // The old object is no longer functional (IsReserved() returns false).
TakeControl(VirtualMemory * from)381   void TakeControl(VirtualMemory* from) {
382     DCHECK(!IsReserved());
383     address_ = from->address_;
384     size_ = from->size_;
385     from->Reset();
386   }
387 
388   static void* ReserveRegion(size_t size);
389 
390   static bool CommitRegion(void* base, size_t size, bool is_executable);
391 
392   static bool UncommitRegion(void* base, size_t size);
393 
394   // Must be called with a base pointer that has been returned by ReserveRegion
395   // and the same size it was reserved with.
396   static bool ReleaseRegion(void* base, size_t size);
397 
398   // Must be called with a base pointer that has been returned by ReserveRegion
399   // and the same size it was reserved with.
400   // [free_start, free_start + free_size] is the memory that will be released.
401   static bool ReleasePartialRegion(void* base, size_t size, void* free_start,
402                                    size_t free_size);
403 
404   // Returns true if OS performs lazy commits, i.e. the memory allocation call
405   // defers actual physical memory allocation till the first memory access.
406   // Otherwise returns false.
407   static bool HasLazyCommits();
408 
409  private:
InVM(void * address,size_t size)410   bool InVM(void* address, size_t size) {
411     return (reinterpret_cast<uintptr_t>(address_) <=
412             reinterpret_cast<uintptr_t>(address)) &&
413            ((reinterpret_cast<uintptr_t>(address_) + size_) >=
414             (reinterpret_cast<uintptr_t>(address) + size));
415   }
416 
417   void* address_;  // Start address of the virtual memory.
418   size_t size_;  // Size of the virtual memory.
419 };
420 
421 
422 // ----------------------------------------------------------------------------
423 // Thread
424 //
425 // Thread objects are used for creating and running threads. When the start()
426 // method is called the new thread starts running the run() method in the new
427 // thread. The Thread object should not be deallocated before the thread has
428 // terminated.
429 
430 class V8_BASE_EXPORT Thread {
431  public:
432   // Opaque data type for thread-local storage keys.
433   typedef int32_t LocalStorageKey;
434 
435   class Options {
436    public:
Options()437     Options() : name_("v8:<unknown>"), stack_size_(0) {}
438     explicit Options(const char* name, int stack_size = 0)
name_(name)439         : name_(name), stack_size_(stack_size) {}
440 
name()441     const char* name() const { return name_; }
stack_size()442     int stack_size() const { return stack_size_; }
443 
444    private:
445     const char* name_;
446     int stack_size_;
447   };
448 
449   // Create new thread.
450   explicit Thread(const Options& options);
451   virtual ~Thread();
452 
453   // Start new thread by calling the Run() method on the new thread.
454   void Start();
455 
456   // Start new thread and wait until Run() method is called on the new thread.
StartSynchronously()457   void StartSynchronously() {
458     start_semaphore_ = new Semaphore(0);
459     Start();
460     start_semaphore_->Wait();
461     delete start_semaphore_;
462     start_semaphore_ = NULL;
463   }
464 
465   // Wait until thread terminates.
466   void Join();
467 
name()468   inline const char* name() const {
469     return name_;
470   }
471 
472   // Abstract method for run handler.
473   virtual void Run() = 0;
474 
475   // Thread-local storage.
476   static LocalStorageKey CreateThreadLocalKey();
477   static void DeleteThreadLocalKey(LocalStorageKey key);
478   static void* GetThreadLocal(LocalStorageKey key);
GetThreadLocalInt(LocalStorageKey key)479   static int GetThreadLocalInt(LocalStorageKey key) {
480     return static_cast<int>(reinterpret_cast<intptr_t>(GetThreadLocal(key)));
481   }
482   static void SetThreadLocal(LocalStorageKey key, void* value);
SetThreadLocalInt(LocalStorageKey key,int value)483   static void SetThreadLocalInt(LocalStorageKey key, int value) {
484     SetThreadLocal(key, reinterpret_cast<void*>(static_cast<intptr_t>(value)));
485   }
HasThreadLocal(LocalStorageKey key)486   static bool HasThreadLocal(LocalStorageKey key) {
487     return GetThreadLocal(key) != NULL;
488   }
489 
490 #ifdef V8_FAST_TLS_SUPPORTED
GetExistingThreadLocal(LocalStorageKey key)491   static inline void* GetExistingThreadLocal(LocalStorageKey key) {
492     void* result = reinterpret_cast<void*>(
493         InternalGetExistingThreadLocal(static_cast<intptr_t>(key)));
494     DCHECK(result == GetThreadLocal(key));
495     return result;
496   }
497 #else
GetExistingThreadLocal(LocalStorageKey key)498   static inline void* GetExistingThreadLocal(LocalStorageKey key) {
499     return GetThreadLocal(key);
500   }
501 #endif
502 
503   // The thread name length is limited to 16 based on Linux's implementation of
504   // prctl().
505   static const int kMaxThreadNameLength = 16;
506 
507   class PlatformData;
data()508   PlatformData* data() { return data_; }
509 
NotifyStartedAndRun()510   void NotifyStartedAndRun() {
511     if (start_semaphore_) start_semaphore_->Signal();
512     Run();
513   }
514 
515  private:
516   void set_name(const char* name);
517 
518   PlatformData* data_;
519 
520   char name_[kMaxThreadNameLength];
521   int stack_size_;
522   Semaphore* start_semaphore_;
523 
524   DISALLOW_COPY_AND_ASSIGN(Thread);
525 };
526 
527 }  // namespace base
528 }  // namespace v8
529 
530 #endif  // V8_BASE_PLATFORM_PLATFORM_H_
531