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