Home | History | Annotate | Download | only in src
      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)
     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 
     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);
    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 {
    262     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.
    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.
    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 
    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).
    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:
    416     Options() : name_("v8:<unknown>"), stack_size_(0) {}
    417     Options(const char* name, int stack_size = 0)
    418         : name_(name), stack_size_(stack_size) {}
    419 
    420     const char* name() const { return name_; }
    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.
    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 
    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);
    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);
    462   static void SetThreadLocalInt(LocalStorageKey key, int value) {
    463     SetThreadLocal(key, reinterpret_cast<void*>(static_cast<intptr_t>(value)));
    464   }
    465   static bool HasThreadLocal(LocalStorageKey key) {
    466     return GetThreadLocal(key) != NULL;
    467   }
    468 
    469 #ifdef V8_FAST_TLS_SUPPORTED
    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
    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;
    491   PlatformData* data() { return data_; }
    492 
    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