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
34namespace std {
35int 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
50int strncasecmp(const char* s1, const char* s2, int n);
51
52// Visual C++ 2013 and higher implement this function.
53#if (_MSC_VER < 1800)
54inline 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
74namespace v8 {
75namespace 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
86INLINE(intptr_t InternalGetExistingThreadLocal(intptr_t index));
87
88inline 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
109extern intptr_t kMacTlsBaseOffset;
110
111INLINE(intptr_t InternalGetExistingThreadLocal(intptr_t index));
112
113inline 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
132class 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
142class 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);
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 {
270    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.
316class 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.
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.
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
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).
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
413class Thread {
414 public:
415  // Opaque data type for thread-local storage keys.
416  typedef int32_t LocalStorageKey;
417
418  class Options {
419   public:
420    Options() : name_("v8:<unknown>"), stack_size_(0) {}
421    explicit Options(const char* name, int stack_size = 0)
422        : name_(name), stack_size_(stack_size) {}
423
424    const char* name() const { return name_; }
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.
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
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);
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);
466  static void SetThreadLocalInt(LocalStorageKey key, int value) {
467    SetThreadLocal(key, reinterpret_cast<void*>(static_cast<intptr_t>(value)));
468  }
469  static bool HasThreadLocal(LocalStorageKey key) {
470    return GetThreadLocal(key) != NULL;
471  }
472
473#ifdef V8_FAST_TLS_SUPPORTED
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
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;
495  PlatformData* data() { return data_; }
496
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