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   // Allocates a region of memory that is inaccessible. On Windows this reserves
    182   // but does not commit the memory. On Linux, it is equivalent to a call to
    183   // Allocate() followed by Guard().
    184   static void* AllocateGuarded(const size_t requested);
    185 
    186   // This is the granularity at which the ProtectCode(...) call can set page
    187   // permissions.
    188   static intptr_t CommitPageSize();
    189 
    190   // Mark code segments non-writable.
    191   static void ProtectCode(void* address, const size_t size);
    192 
    193   // Assign memory as a guard page so that access will cause an exception.
    194   static void Guard(void* address, const size_t size);
    195 
    196   // Make a region of memory readable and writable.
    197   static void Unprotect(void* address, const size_t size);
    198 
    199   // Generate a random address to be used for hinting mmap().
    200   static void* GetRandomMmapAddr();
    201 
    202   // Get the Alignment guaranteed by Allocate().
    203   static size_t AllocateAlignment();
    204 
    205   // Sleep for a specified time interval.
    206   static void Sleep(TimeDelta interval);
    207 
    208   // Abort the current process.
    209   V8_NORETURN static void Abort();
    210 
    211   // Debug break.
    212   static void DebugBreak();
    213 
    214   // Walk the stack.
    215   static const int kStackWalkError = -1;
    216   static const int kStackWalkMaxNameLen = 256;
    217   static const int kStackWalkMaxTextLen = 256;
    218   struct StackFrame {
    219     void* address;
    220     char text[kStackWalkMaxTextLen];
    221   };
    222 
    223   class V8_BASE_EXPORT MemoryMappedFile {
    224    public:
    225     virtual ~MemoryMappedFile() {}
    226     virtual void* memory() const = 0;
    227     virtual size_t size() const = 0;
    228 
    229     static MemoryMappedFile* open(const char* name);
    230     static MemoryMappedFile* create(const char* name, size_t size,
    231                                     void* initial);
    232   };
    233 
    234   // Safe formatting print. Ensures that str is always null-terminated.
    235   // Returns the number of chars written, or -1 if output was truncated.
    236   static PRINTF_FORMAT(3, 4) int SNPrintF(char* str, int length,
    237                                           const char* format, ...);
    238   static PRINTF_FORMAT(3, 0) int VSNPrintF(char* str, int length,
    239                                            const char* format, va_list args);
    240 
    241   static char* StrChr(char* str, int c);
    242   static void StrNCpy(char* dest, int length, const char* src, size_t n);
    243 
    244   // Support for the profiler.  Can do nothing, in which case ticks
    245   // occuring in shared libraries will not be properly accounted for.
    246   struct SharedLibraryAddress {
    247     SharedLibraryAddress(const std::string& library_path, uintptr_t start,
    248                          uintptr_t end)
    249         : library_path(library_path), start(start), end(end), aslr_slide(0) {}
    250     SharedLibraryAddress(const std::string& library_path, uintptr_t start,
    251                          uintptr_t end, intptr_t aslr_slide)
    252         : library_path(library_path),
    253           start(start),
    254           end(end),
    255           aslr_slide(aslr_slide) {}
    256 
    257     std::string library_path;
    258     uintptr_t start;
    259     uintptr_t end;
    260     intptr_t aslr_slide;
    261   };
    262 
    263   static std::vector<SharedLibraryAddress> GetSharedLibraryAddresses();
    264 
    265   // Support for the profiler.  Notifies the external profiling
    266   // process that a code moving garbage collection starts.  Can do
    267   // nothing, in which case the code objects must not move (e.g., by
    268   // using --never-compact) if accurate profiling is desired.
    269   static void SignalCodeMovingGC();
    270 
    271   // Support runtime detection of whether the hard float option of the
    272   // EABI is used.
    273   static bool ArmUsingHardFloat();
    274 
    275   // Returns the activation frame alignment constraint or zero if
    276   // the platform doesn't care. Guaranteed to be a power of two.
    277   static int ActivationFrameAlignment();
    278 
    279   static int GetCurrentProcessId();
    280 
    281   static int GetCurrentThreadId();
    282 
    283  private:
    284   static const int msPerSecond = 1000;
    285 
    286 #if V8_OS_POSIX
    287   static const char* GetGCFakeMMapFile();
    288 #endif
    289 
    290   DISALLOW_IMPLICIT_CONSTRUCTORS(OS);
    291 };
    292 
    293 
    294 // Represents and controls an area of reserved memory.
    295 // Control of the reserved memory can be assigned to another VirtualMemory
    296 // object by assignment or copy-contructing. This removes the reserved memory
    297 // from the original object.
    298 class V8_BASE_EXPORT VirtualMemory {
    299  public:
    300   // Empty VirtualMemory object, controlling no reserved memory.
    301   VirtualMemory();
    302 
    303   // Reserves virtual memory with size.
    304   explicit VirtualMemory(size_t size);
    305 
    306   // Reserves virtual memory containing an area of the given size that
    307   // is aligned per alignment. This may not be at the position returned
    308   // by address().
    309   VirtualMemory(size_t size, size_t alignment);
    310 
    311   // Construct a virtual memory by assigning it some already mapped address
    312   // and size.
    313   VirtualMemory(void* address, size_t size) : address_(address), size_(size) {}
    314 
    315   // Releases the reserved memory, if any, controlled by this VirtualMemory
    316   // object.
    317   ~VirtualMemory();
    318 
    319   // Returns whether the memory has been reserved.
    320   bool IsReserved();
    321 
    322   // Initialize or resets an embedded VirtualMemory object.
    323   void Reset();
    324 
    325   // Returns the start address of the reserved memory.
    326   // If the memory was reserved with an alignment, this address is not
    327   // necessarily aligned. The user might need to round it up to a multiple of
    328   // the alignment to get the start of the aligned block.
    329   void* address() {
    330     DCHECK(IsReserved());
    331     return address_;
    332   }
    333 
    334   // Returns the size of the reserved memory. The returned value is only
    335   // meaningful when IsReserved() returns true.
    336   // If the memory was reserved with an alignment, this size may be larger
    337   // than the requested size.
    338   size_t size() { return size_; }
    339 
    340   // Commits real memory. Returns whether the operation succeeded.
    341   bool Commit(void* address, size_t size, bool is_executable);
    342 
    343   // Uncommit real memory.  Returns whether the operation succeeded.
    344   bool Uncommit(void* address, size_t size);
    345 
    346   // Creates a single guard page at the given address.
    347   bool Guard(void* address);
    348 
    349   // Releases the memory after |free_start|.
    350   void ReleasePartial(void* free_start) {
    351     DCHECK(IsReserved());
    352     // Notice: Order is important here. The VirtualMemory object might live
    353     // inside the allocated region.
    354     size_t size = size_ - (reinterpret_cast<size_t>(free_start) -
    355                            reinterpret_cast<size_t>(address_));
    356     CHECK(InVM(free_start, size));
    357     DCHECK_LT(address_, free_start);
    358     DCHECK_LT(free_start, reinterpret_cast<void*>(
    359                               reinterpret_cast<size_t>(address_) + size_));
    360     bool result = ReleasePartialRegion(address_, size_, free_start, size);
    361     USE(result);
    362     DCHECK(result);
    363     size_ -= size;
    364   }
    365 
    366   void Release() {
    367     DCHECK(IsReserved());
    368     // Notice: Order is important here. The VirtualMemory object might live
    369     // inside the allocated region.
    370     void* address = address_;
    371     size_t size = size_;
    372     CHECK(InVM(address, size));
    373     Reset();
    374     bool result = ReleaseRegion(address, size);
    375     USE(result);
    376     DCHECK(result);
    377   }
    378 
    379   // Assign control of the reserved region to a different VirtualMemory object.
    380   // The old object is no longer functional (IsReserved() returns false).
    381   void TakeControl(VirtualMemory* from) {
    382     DCHECK(!IsReserved());
    383     address_ = from->address_;
    384     size_ = from->size_;
    385     from->Reset();
    386   }
    387 
    388   static void* ReserveRegion(size_t size);
    389 
    390   static bool CommitRegion(void* base, size_t size, bool is_executable);
    391 
    392   static bool UncommitRegion(void* base, size_t size);
    393 
    394   // Must be called with a base pointer that has been returned by ReserveRegion
    395   // and the same size it was reserved with.
    396   static bool ReleaseRegion(void* base, size_t size);
    397 
    398   // Must be called with a base pointer that has been returned by ReserveRegion
    399   // and the same size it was reserved with.
    400   // [free_start, free_start + free_size] is the memory that will be released.
    401   static bool ReleasePartialRegion(void* base, size_t size, void* free_start,
    402                                    size_t free_size);
    403 
    404   // Returns true if OS performs lazy commits, i.e. the memory allocation call
    405   // defers actual physical memory allocation till the first memory access.
    406   // Otherwise returns false.
    407   static bool HasLazyCommits();
    408 
    409  private:
    410   bool InVM(void* address, size_t size) {
    411     return (reinterpret_cast<uintptr_t>(address_) <=
    412             reinterpret_cast<uintptr_t>(address)) &&
    413            ((reinterpret_cast<uintptr_t>(address_) + size_) >=
    414             (reinterpret_cast<uintptr_t>(address) + size));
    415   }
    416 
    417   void* address_;  // Start address of the virtual memory.
    418   size_t size_;  // Size of the virtual memory.
    419 };
    420 
    421 
    422 // ----------------------------------------------------------------------------
    423 // Thread
    424 //
    425 // Thread objects are used for creating and running threads. When the start()
    426 // method is called the new thread starts running the run() method in the new
    427 // thread. The Thread object should not be deallocated before the thread has
    428 // terminated.
    429 
    430 class V8_BASE_EXPORT Thread {
    431  public:
    432   // Opaque data type for thread-local storage keys.
    433   typedef int32_t LocalStorageKey;
    434 
    435   class Options {
    436    public:
    437     Options() : name_("v8:<unknown>"), stack_size_(0) {}
    438     explicit Options(const char* name, int stack_size = 0)
    439         : name_(name), stack_size_(stack_size) {}
    440 
    441     const char* name() const { return name_; }
    442     int stack_size() const { return stack_size_; }
    443 
    444    private:
    445     const char* name_;
    446     int stack_size_;
    447   };
    448 
    449   // Create new thread.
    450   explicit Thread(const Options& options);
    451   virtual ~Thread();
    452 
    453   // Start new thread by calling the Run() method on the new thread.
    454   void Start();
    455 
    456   // Start new thread and wait until Run() method is called on the new thread.
    457   void StartSynchronously() {
    458     start_semaphore_ = new Semaphore(0);
    459     Start();
    460     start_semaphore_->Wait();
    461     delete start_semaphore_;
    462     start_semaphore_ = NULL;
    463   }
    464 
    465   // Wait until thread terminates.
    466   void Join();
    467 
    468   inline const char* name() const {
    469     return name_;
    470   }
    471 
    472   // Abstract method for run handler.
    473   virtual void Run() = 0;
    474 
    475   // Thread-local storage.
    476   static LocalStorageKey CreateThreadLocalKey();
    477   static void DeleteThreadLocalKey(LocalStorageKey key);
    478   static void* GetThreadLocal(LocalStorageKey key);
    479   static int GetThreadLocalInt(LocalStorageKey key) {
    480     return static_cast<int>(reinterpret_cast<intptr_t>(GetThreadLocal(key)));
    481   }
    482   static void SetThreadLocal(LocalStorageKey key, void* value);
    483   static void SetThreadLocalInt(LocalStorageKey key, int value) {
    484     SetThreadLocal(key, reinterpret_cast<void*>(static_cast<intptr_t>(value)));
    485   }
    486   static bool HasThreadLocal(LocalStorageKey key) {
    487     return GetThreadLocal(key) != NULL;
    488   }
    489 
    490 #ifdef V8_FAST_TLS_SUPPORTED
    491   static inline void* GetExistingThreadLocal(LocalStorageKey key) {
    492     void* result = reinterpret_cast<void*>(
    493         InternalGetExistingThreadLocal(static_cast<intptr_t>(key)));
    494     DCHECK(result == GetThreadLocal(key));
    495     return result;
    496   }
    497 #else
    498   static inline void* GetExistingThreadLocal(LocalStorageKey key) {
    499     return GetThreadLocal(key);
    500   }
    501 #endif
    502 
    503   // The thread name length is limited to 16 based on Linux's implementation of
    504   // prctl().
    505   static const int kMaxThreadNameLength = 16;
    506 
    507   class PlatformData;
    508   PlatformData* data() { return data_; }
    509 
    510   void NotifyStartedAndRun() {
    511     if (start_semaphore_) start_semaphore_->Signal();
    512     Run();
    513   }
    514 
    515  private:
    516   void set_name(const char* name);
    517 
    518   PlatformData* data_;
    519 
    520   char name_[kMaxThreadNameLength];
    521   int stack_size_;
    522   Semaphore* start_semaphore_;
    523 
    524   DISALLOW_COPY_AND_ASSIGN(Thread);
    525 };
    526 
    527 }  // namespace base
    528 }  // namespace v8
    529 
    530 #endif  // V8_BASE_PLATFORM_PLATFORM_H_
    531