• 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_PLATFORM_H_
22 #define V8_PLATFORM_H_
23 
24 #include <stdarg.h>
25 #include <string>
26 #include <vector>
27 
28 #include "src/base/build_config.h"
29 #include "src/platform/mutex.h"
30 #include "src/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/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/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 internal {
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   ASSERT(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   ASSERT(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   // Returns the accumulated user time for thread. This routine
145   // can be used for profiling. The implementation should
146   // strive for high-precision timer resolution, preferable
147   // micro-second resolution.
148   static int GetUserTime(uint32_t* secs,  uint32_t* usecs);
149 
150   // Returns current time as the number of milliseconds since
151   // 00:00:00 UTC, January 1, 1970.
152   static double TimeCurrentMillis();
153 
154   static TimezoneCache* CreateTimezoneCache();
155   static void DisposeTimezoneCache(TimezoneCache* cache);
156   static void ClearTimezoneCache(TimezoneCache* cache);
157 
158   // Returns a string identifying the current time zone. The
159   // timestamp is used for determining if DST is in effect.
160   static const char* LocalTimezone(double time, TimezoneCache* cache);
161 
162   // Returns the local time offset in milliseconds east of UTC without
163   // taking daylight savings time into account.
164   static double LocalTimeOffset(TimezoneCache* cache);
165 
166   // Returns the daylight savings offset for the given time.
167   static double DaylightSavingsOffset(double time, TimezoneCache* cache);
168 
169   // Returns last OS error.
170   static int GetLastError();
171 
172   static FILE* FOpen(const char* path, const char* mode);
173   static bool Remove(const char* path);
174 
175   // Opens a temporary file, the file is auto removed on close.
176   static FILE* OpenTemporaryFile();
177 
178   // Log file open mode is platform-dependent due to line ends issues.
179   static const char* const LogFileOpenMode;
180 
181   // Print output to console. This is mostly used for debugging output.
182   // On platforms that has standard terminal output, the output
183   // should go to stdout.
184   static void Print(const char* format, ...);
185   static void VPrint(const char* format, va_list args);
186 
187   // Print output to a file. This is mostly used for debugging output.
188   static void FPrint(FILE* out, const char* format, ...);
189   static void VFPrint(FILE* out, const char* format, va_list args);
190 
191   // Print error output to console. This is mostly used for error message
192   // output. On platforms that has standard terminal output, the output
193   // should go to stderr.
194   static void PrintError(const char* format, ...);
195   static void VPrintError(const char* format, va_list args);
196 
197   // Allocate/Free memory used by JS heap. Pages are readable/writable, but
198   // they are not guaranteed to be executable unless 'executable' is true.
199   // Returns the address of allocated memory, or NULL if failed.
200   static void* Allocate(const size_t requested,
201                         size_t* allocated,
202                         bool is_executable);
203   static void Free(void* address, const size_t size);
204 
205   // This is the granularity at which the ProtectCode(...) call can set page
206   // permissions.
207   static intptr_t CommitPageSize();
208 
209   // Mark code segments non-writable.
210   static void ProtectCode(void* address, const size_t size);
211 
212   // Assign memory as a guard page so that access will cause an exception.
213   static void Guard(void* address, const size_t size);
214 
215   // Generate a random address to be used for hinting mmap().
216   static void* GetRandomMmapAddr();
217 
218   // Get the Alignment guaranteed by Allocate().
219   static size_t AllocateAlignment();
220 
221   // Sleep for a number of milliseconds.
222   static void Sleep(const int milliseconds);
223 
224   // Abort the current process.
225   static void Abort();
226 
227   // Debug break.
228   static void DebugBreak();
229 
230   // Walk the stack.
231   static const int kStackWalkError = -1;
232   static const int kStackWalkMaxNameLen = 256;
233   static const int kStackWalkMaxTextLen = 256;
234   struct StackFrame {
235     void* address;
236     char text[kStackWalkMaxTextLen];
237   };
238 
239   class MemoryMappedFile {
240    public:
241     static MemoryMappedFile* open(const char* name);
242     static MemoryMappedFile* create(const char* name, int size, void* initial);
~MemoryMappedFile()243     virtual ~MemoryMappedFile() { }
244     virtual void* memory() = 0;
245     virtual int size() = 0;
246   };
247 
248   // Safe formatting print. Ensures that str is always null-terminated.
249   // Returns the number of chars written, or -1 if output was truncated.
250   static int SNPrintF(char* str, int length, const char* format, ...);
251   static int VSNPrintF(char* str,
252                        int length,
253                        const char* format,
254                        va_list args);
255 
256   static char* StrChr(char* str, int c);
257   static void StrNCpy(char* dest, int length, const char* src, size_t n);
258 
259   // Support for the profiler.  Can do nothing, in which case ticks
260   // occuring in shared libraries will not be properly accounted for.
261   struct SharedLibraryAddress {
SharedLibraryAddressSharedLibraryAddress262     SharedLibraryAddress(
263         const std::string& library_path, uintptr_t start, uintptr_t end)
264         : library_path(library_path), start(start), end(end) {}
265 
266     std::string library_path;
267     uintptr_t start;
268     uintptr_t end;
269   };
270 
271   static std::vector<SharedLibraryAddress> GetSharedLibraryAddresses();
272 
273   // Support for the profiler.  Notifies the external profiling
274   // process that a code moving garbage collection starts.  Can do
275   // nothing, in which case the code objects must not move (e.g., by
276   // using --never-compact) if accurate profiling is desired.
277   static void SignalCodeMovingGC();
278 
279   // Returns the number of processors online.
280   static int NumberOfProcessorsOnline();
281 
282   // The total amount of physical memory available on the current system.
283   static uint64_t TotalPhysicalMemory();
284 
285   // Maximum size of the virtual memory.  0 means there is no artificial
286   // limit.
287   static intptr_t MaxVirtualMemory();
288 
289   // Returns the double constant NAN
290   static double nan_value();
291 
292   // Support runtime detection of whether the hard float option of the
293   // EABI is used.
294   static bool ArmUsingHardFloat();
295 
296   // Returns the activation frame alignment constraint or zero if
297   // the platform doesn't care. Guaranteed to be a power of two.
298   static int ActivationFrameAlignment();
299 
300   static int GetCurrentProcessId();
301 
302  private:
303   static const int msPerSecond = 1000;
304 
305   DISALLOW_IMPLICIT_CONSTRUCTORS(OS);
306 };
307 
308 // Represents and controls an area of reserved memory.
309 // Control of the reserved memory can be assigned to another VirtualMemory
310 // object by assignment or copy-contructing. This removes the reserved memory
311 // from the original object.
312 class VirtualMemory {
313  public:
314   // Empty VirtualMemory object, controlling no reserved memory.
315   VirtualMemory();
316 
317   // Reserves virtual memory with size.
318   explicit VirtualMemory(size_t size);
319 
320   // Reserves virtual memory containing an area of the given size that
321   // is aligned per alignment. This may not be at the position returned
322   // by address().
323   VirtualMemory(size_t size, size_t alignment);
324 
325   // Releases the reserved memory, if any, controlled by this VirtualMemory
326   // object.
327   ~VirtualMemory();
328 
329   // Returns whether the memory has been reserved.
330   bool IsReserved();
331 
332   // Initialize or resets an embedded VirtualMemory object.
333   void Reset();
334 
335   // Returns the start address of the reserved memory.
336   // If the memory was reserved with an alignment, this address is not
337   // necessarily aligned. The user might need to round it up to a multiple of
338   // the alignment to get the start of the aligned block.
address()339   void* address() {
340     ASSERT(IsReserved());
341     return address_;
342   }
343 
344   // Returns the size of the reserved memory. The returned value is only
345   // meaningful when IsReserved() returns true.
346   // If the memory was reserved with an alignment, this size may be larger
347   // than the requested size.
size()348   size_t size() { return size_; }
349 
350   // Commits real memory. Returns whether the operation succeeded.
351   bool Commit(void* address, size_t size, bool is_executable);
352 
353   // Uncommit real memory.  Returns whether the operation succeeded.
354   bool Uncommit(void* address, size_t size);
355 
356   // Creates a single guard page at the given address.
357   bool Guard(void* address);
358 
Release()359   void Release() {
360     ASSERT(IsReserved());
361     // Notice: Order is important here. The VirtualMemory object might live
362     // inside the allocated region.
363     void* address = address_;
364     size_t size = size_;
365     Reset();
366     bool result = ReleaseRegion(address, size);
367     USE(result);
368     ASSERT(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     ASSERT(!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   // Returns true if OS performs lazy commits, i.e. the memory allocation call
391   // defers actual physical memory allocation till the first memory access.
392   // Otherwise returns false.
393   static bool HasLazyCommits();
394 
395  private:
396   void* address_;  // Start address of the virtual memory.
397   size_t size_;  // Size of the virtual memory.
398 };
399 
400 
401 // ----------------------------------------------------------------------------
402 // Thread
403 //
404 // Thread objects are used for creating and running threads. When the start()
405 // method is called the new thread starts running the run() method in the new
406 // thread. The Thread object should not be deallocated before the thread has
407 // terminated.
408 
409 class Thread {
410  public:
411   // Opaque data type for thread-local storage keys.
412   typedef int32_t LocalStorageKey;
413 
414   class Options {
415    public:
Options()416     Options() : name_("v8:<unknown>"), stack_size_(0) {}
417     Options(const char* name, int stack_size = 0)
name_(name)418         : name_(name), stack_size_(stack_size) {}
419 
name()420     const char* name() const { return name_; }
stack_size()421     int stack_size() const { return stack_size_; }
422 
423    private:
424     const char* name_;
425     int stack_size_;
426   };
427 
428   // Create new thread.
429   explicit Thread(const Options& options);
430   virtual ~Thread();
431 
432   // Start new thread by calling the Run() method on the new thread.
433   void Start();
434 
435   // Start new thread and wait until Run() method is called on the new thread.
StartSynchronously()436   void StartSynchronously() {
437     start_semaphore_ = new Semaphore(0);
438     Start();
439     start_semaphore_->Wait();
440     delete start_semaphore_;
441     start_semaphore_ = NULL;
442   }
443 
444   // Wait until thread terminates.
445   void Join();
446 
name()447   inline const char* name() const {
448     return name_;
449   }
450 
451   // Abstract method for run handler.
452   virtual void Run() = 0;
453 
454   // Thread-local storage.
455   static LocalStorageKey CreateThreadLocalKey();
456   static void DeleteThreadLocalKey(LocalStorageKey key);
457   static void* GetThreadLocal(LocalStorageKey key);
GetThreadLocalInt(LocalStorageKey key)458   static int GetThreadLocalInt(LocalStorageKey key) {
459     return static_cast<int>(reinterpret_cast<intptr_t>(GetThreadLocal(key)));
460   }
461   static void SetThreadLocal(LocalStorageKey key, void* value);
SetThreadLocalInt(LocalStorageKey key,int value)462   static void SetThreadLocalInt(LocalStorageKey key, int value) {
463     SetThreadLocal(key, reinterpret_cast<void*>(static_cast<intptr_t>(value)));
464   }
HasThreadLocal(LocalStorageKey key)465   static bool HasThreadLocal(LocalStorageKey key) {
466     return GetThreadLocal(key) != NULL;
467   }
468 
469 #ifdef V8_FAST_TLS_SUPPORTED
GetExistingThreadLocal(LocalStorageKey key)470   static inline void* GetExistingThreadLocal(LocalStorageKey key) {
471     void* result = reinterpret_cast<void*>(
472         InternalGetExistingThreadLocal(static_cast<intptr_t>(key)));
473     ASSERT(result == GetThreadLocal(key));
474     return result;
475   }
476 #else
GetExistingThreadLocal(LocalStorageKey key)477   static inline void* GetExistingThreadLocal(LocalStorageKey key) {
478     return GetThreadLocal(key);
479   }
480 #endif
481 
482   // A hint to the scheduler to let another thread run.
483   static void YieldCPU();
484 
485 
486   // The thread name length is limited to 16 based on Linux's implementation of
487   // prctl().
488   static const int kMaxThreadNameLength = 16;
489 
490   class PlatformData;
data()491   PlatformData* data() { return data_; }
492 
NotifyStartedAndRun()493   void NotifyStartedAndRun() {
494     if (start_semaphore_) start_semaphore_->Signal();
495     Run();
496   }
497 
498  private:
499   void set_name(const char* name);
500 
501   PlatformData* data_;
502 
503   char name_[kMaxThreadNameLength];
504   int stack_size_;
505   Semaphore* start_semaphore_;
506 
507   DISALLOW_COPY_AND_ASSIGN(Thread);
508 };
509 
510 } }  // namespace v8::internal
511 
512 #endif  // V8_PLATFORM_H_
513