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