Home | History | Annotate | Download | only in platform
      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 
     36 namespace v8 {
     37 namespace 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 
     48 INLINE(intptr_t InternalGetExistingThreadLocal(intptr_t index));
     49 
     50 inline 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 
     71 extern intptr_t kMacTlsBaseOffset;
     72 
     73 INLINE(intptr_t InternalGetExistingThreadLocal(intptr_t index));
     74 
     75 inline 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 
     94 class 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 
    104 class 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.
    280 class 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 
    385 class 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