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