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