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 <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)
     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 
     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);
    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.
    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.
    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 
    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:
    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