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 
     40 namespace base {
     41 
     42 // ----------------------------------------------------------------------------
     43 // Fast TLS support
     44 
     45 #ifndef V8_NO_FAST_TLS
     46 
     47 #if V8_CC_MSVC && V8_HOST_ARCH_IA32
     48 
     49 #define V8_FAST_TLS_SUPPORTED 1
     50 
     51 V8_INLINE intptr_t InternalGetExistingThreadLocal(intptr_t index);
     52 
     53 inline intptr_t InternalGetExistingThreadLocal(intptr_t index) {
     54   const intptr_t kTibInlineTlsOffset = 0xE10;
     55   const intptr_t kTibExtraTlsOffset = 0xF94;
     56   const intptr_t kMaxInlineSlots = 64;
     57   const intptr_t kMaxSlots = kMaxInlineSlots + 1024;
     58   const intptr_t kPointerSize = sizeof(void*);
     59   DCHECK(0 <= index && index < kMaxSlots);
     60   USE(kMaxSlots);
     61   if (index < kMaxInlineSlots) {
     62     return static_cast<intptr_t>(__readfsdword(kTibInlineTlsOffset +
     63                                                kPointerSize * index));
     64   }
     65   intptr_t extra = static_cast<intptr_t>(__readfsdword(kTibExtraTlsOffset));
     66   DCHECK_NE(extra, 0);
     67   return *reinterpret_cast<intptr_t*>(extra +
     68                                       kPointerSize * (index - kMaxInlineSlots));
     69 }
     70 
     71 #elif defined(__APPLE__) && (V8_HOST_ARCH_IA32 || V8_HOST_ARCH_X64)
     72 
     73 #define V8_FAST_TLS_SUPPORTED 1
     74 
     75 extern V8_BASE_EXPORT intptr_t kMacTlsBaseOffset;
     76 
     77 V8_INLINE intptr_t InternalGetExistingThreadLocal(intptr_t index);
     78 
     79 inline intptr_t InternalGetExistingThreadLocal(intptr_t index) {
     80   intptr_t result;
     81 #if V8_HOST_ARCH_IA32
     82   asm("movl %%gs:(%1,%2,4), %0;"
     83       :"=r"(result)  // Output must be a writable register.
     84       :"r"(kMacTlsBaseOffset), "r"(index));
     85 #else
     86   asm("movq %%gs:(%1,%2,8), %0;"
     87       :"=r"(result)
     88       :"r"(kMacTlsBaseOffset), "r"(index));
     89 #endif
     90   return result;
     91 }
     92 
     93 #endif
     94 
     95 #endif  // V8_NO_FAST_TLS
     96 
     97 class PageAllocator;
     98 class TimezoneCache;
     99 
    100 // ----------------------------------------------------------------------------
    101 // OS
    102 //
    103 // This class has static methods for the different platform specific
    104 // functions. Add methods here to cope with differences between the
    105 // supported platforms.
    106 
    107 class V8_BASE_EXPORT OS {
    108  public:
    109   // Initialize the OS class.
    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(bool hard_abort, const char* const gc_fake_mmap);
    113 
    114   // Returns the accumulated user time for thread. This routine
    115   // can be used for profiling. The implementation should
    116   // strive for high-precision timer resolution, preferable
    117   // micro-second resolution.
    118   static int GetUserTime(uint32_t* secs,  uint32_t* usecs);
    119 
    120   // Returns current time as the number of milliseconds since
    121   // 00:00:00 UTC, January 1, 1970.
    122   static double TimeCurrentMillis();
    123 
    124   static TimezoneCache* CreateTimezoneCache();
    125 
    126   // Returns last OS error.
    127   static int GetLastError();
    128 
    129   static FILE* FOpen(const char* path, const char* mode);
    130   static bool Remove(const char* path);
    131 
    132   static char DirectorySeparator();
    133   static bool isDirectorySeparator(const char ch);
    134 
    135   // Opens a temporary file, the file is auto removed on close.
    136   static FILE* OpenTemporaryFile();
    137 
    138   // Log file open mode is platform-dependent due to line ends issues.
    139   static const char* const LogFileOpenMode;
    140 
    141   // Print output to console. This is mostly used for debugging output.
    142   // On platforms that has standard terminal output, the output
    143   // should go to stdout.
    144   static PRINTF_FORMAT(1, 2) void Print(const char* format, ...);
    145   static PRINTF_FORMAT(1, 0) void VPrint(const char* format, va_list args);
    146 
    147   // Print output to a file. This is mostly used for debugging output.
    148   static PRINTF_FORMAT(2, 3) void FPrint(FILE* out, const char* format, ...);
    149   static PRINTF_FORMAT(2, 0) void VFPrint(FILE* out, const char* format,
    150                                           va_list args);
    151 
    152   // Print error output to console. This is mostly used for error message
    153   // output. On platforms that has standard terminal output, the output
    154   // should go to stderr.
    155   static PRINTF_FORMAT(1, 2) void PrintError(const char* format, ...);
    156   static PRINTF_FORMAT(1, 0) void VPrintError(const char* format, va_list args);
    157 
    158   // Memory permissions. These should be kept in sync with the ones in
    159   // v8::PageAllocator.
    160   enum class MemoryPermission {
    161     kNoAccess,
    162     kRead,
    163     kReadWrite,
    164     // TODO(hpayer): Remove this flag. Memory should never be rwx.
    165     kReadWriteExecute,
    166     kReadExecute
    167   };
    168 
    169   static bool HasLazyCommits();
    170 
    171   // Sleep for a specified time interval.
    172   static void Sleep(TimeDelta interval);
    173 
    174   // Abort the current process.
    175   [[noreturn]] static void Abort();
    176 
    177   // Debug break.
    178   static void DebugBreak();
    179 
    180   // Walk the stack.
    181   static const int kStackWalkError = -1;
    182   static const int kStackWalkMaxNameLen = 256;
    183   static const int kStackWalkMaxTextLen = 256;
    184   struct StackFrame {
    185     void* address;
    186     char text[kStackWalkMaxTextLen];
    187   };
    188 
    189   class V8_BASE_EXPORT MemoryMappedFile {
    190    public:
    191     virtual ~MemoryMappedFile() {}
    192     virtual void* memory() const = 0;
    193     virtual size_t size() const = 0;
    194 
    195     static MemoryMappedFile* open(const char* name);
    196     static MemoryMappedFile* create(const char* name, size_t size,
    197                                     void* initial);
    198   };
    199 
    200   // Safe formatting print. Ensures that str is always null-terminated.
    201   // Returns the number of chars written, or -1 if output was truncated.
    202   static PRINTF_FORMAT(3, 4) int SNPrintF(char* str, int length,
    203                                           const char* format, ...);
    204   static PRINTF_FORMAT(3, 0) int VSNPrintF(char* str, int length,
    205                                            const char* format, va_list args);
    206 
    207   static char* StrChr(char* str, int c);
    208   static void StrNCpy(char* dest, int length, const char* src, size_t n);
    209 
    210   // Support for the profiler.  Can do nothing, in which case ticks
    211   // occurring in shared libraries will not be properly accounted for.
    212   struct SharedLibraryAddress {
    213     SharedLibraryAddress(const std::string& library_path, uintptr_t start,
    214                          uintptr_t end)
    215         : library_path(library_path), start(start), end(end), aslr_slide(0) {}
    216     SharedLibraryAddress(const std::string& library_path, uintptr_t start,
    217                          uintptr_t end, intptr_t aslr_slide)
    218         : library_path(library_path),
    219           start(start),
    220           end(end),
    221           aslr_slide(aslr_slide) {}
    222 
    223     std::string library_path;
    224     uintptr_t start;
    225     uintptr_t end;
    226     intptr_t aslr_slide;
    227   };
    228 
    229   static std::vector<SharedLibraryAddress> GetSharedLibraryAddresses();
    230 
    231   // Support for the profiler.  Notifies the external profiling
    232   // process that a code moving garbage collection starts.  Can do
    233   // nothing, in which case the code objects must not move (e.g., by
    234   // using --never-compact) if accurate profiling is desired.
    235   static void SignalCodeMovingGC();
    236 
    237   // Support runtime detection of whether the hard float option of the
    238   // EABI is used.
    239   static bool ArmUsingHardFloat();
    240 
    241   // Returns the activation frame alignment constraint or zero if
    242   // the platform doesn't care. Guaranteed to be a power of two.
    243   static int ActivationFrameAlignment();
    244 
    245   static int GetCurrentProcessId();
    246 
    247   static int GetCurrentThreadId();
    248 
    249   static void ExitProcess(int exit_code);
    250 
    251  private:
    252   // These classes use the private memory management API below.
    253   friend class MemoryMappedFile;
    254   friend class PosixMemoryMappedFile;
    255   friend class v8::base::PageAllocator;
    256 
    257   static size_t AllocatePageSize();
    258 
    259   static size_t CommitPageSize();
    260 
    261   static void SetRandomMmapSeed(int64_t seed);
    262 
    263   static void* GetRandomMmapAddr();
    264 
    265   V8_WARN_UNUSED_RESULT static void* Allocate(void* address, size_t size,
    266                                               size_t alignment,
    267                                               MemoryPermission access);
    268 
    269   V8_WARN_UNUSED_RESULT static bool Free(void* address, const size_t size);
    270 
    271   V8_WARN_UNUSED_RESULT static bool Release(void* address, size_t size);
    272 
    273   V8_WARN_UNUSED_RESULT static bool SetPermissions(void* address, size_t size,
    274                                                    MemoryPermission access);
    275 
    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 #if (defined(_WIN32) || defined(_WIN64))
    286 V8_BASE_EXPORT void EnsureConsoleOutputWin32();
    287 #endif  // (defined(_WIN32) || defined(_WIN64))
    288 
    289 inline void EnsureConsoleOutput() {
    290 #if (defined(_WIN32) || defined(_WIN64))
    291   // Windows requires extra calls to send assert output to the console
    292   // rather than a dialog box.
    293   EnsureConsoleOutputWin32();
    294 #endif  // (defined(_WIN32) || defined(_WIN64))
    295 }
    296 
    297 // ----------------------------------------------------------------------------
    298 // Thread
    299 //
    300 // Thread objects are used for creating and running threads. When the start()
    301 // method is called the new thread starts running the run() method in the new
    302 // thread. The Thread object should not be deallocated before the thread has
    303 // terminated.
    304 
    305 class V8_BASE_EXPORT Thread {
    306  public:
    307   // Opaque data type for thread-local storage keys.
    308   typedef int32_t LocalStorageKey;
    309 
    310   class Options {
    311    public:
    312     Options() : name_("v8:<unknown>"), stack_size_(0) {}
    313     explicit Options(const char* name, int stack_size = 0)
    314         : name_(name), stack_size_(stack_size) {}
    315 
    316     const char* name() const { return name_; }
    317     int stack_size() const { return stack_size_; }
    318 
    319    private:
    320     const char* name_;
    321     int stack_size_;
    322   };
    323 
    324   // Create new thread.
    325   explicit Thread(const Options& options);
    326   virtual ~Thread();
    327 
    328   // Start new thread by calling the Run() method on the new thread.
    329   void Start();
    330 
    331   // Start new thread and wait until Run() method is called on the new thread.
    332   void StartSynchronously() {
    333     start_semaphore_ = new Semaphore(0);
    334     Start();
    335     start_semaphore_->Wait();
    336     delete start_semaphore_;
    337     start_semaphore_ = nullptr;
    338   }
    339 
    340   // Wait until thread terminates.
    341   void Join();
    342 
    343   inline const char* name() const {
    344     return name_;
    345   }
    346 
    347   // Abstract method for run handler.
    348   virtual void Run() = 0;
    349 
    350   // Thread-local storage.
    351   static LocalStorageKey CreateThreadLocalKey();
    352   static void DeleteThreadLocalKey(LocalStorageKey key);
    353   static void* GetThreadLocal(LocalStorageKey key);
    354   static int GetThreadLocalInt(LocalStorageKey key) {
    355     return static_cast<int>(reinterpret_cast<intptr_t>(GetThreadLocal(key)));
    356   }
    357   static void SetThreadLocal(LocalStorageKey key, void* value);
    358   static void SetThreadLocalInt(LocalStorageKey key, int value) {
    359     SetThreadLocal(key, reinterpret_cast<void*>(static_cast<intptr_t>(value)));
    360   }
    361   static bool HasThreadLocal(LocalStorageKey key) {
    362     return GetThreadLocal(key) != nullptr;
    363   }
    364 
    365 #ifdef V8_FAST_TLS_SUPPORTED
    366   static inline void* GetExistingThreadLocal(LocalStorageKey key) {
    367     void* result = reinterpret_cast<void*>(
    368         InternalGetExistingThreadLocal(static_cast<intptr_t>(key)));
    369     DCHECK(result == GetThreadLocal(key));
    370     return result;
    371   }
    372 #else
    373   static inline void* GetExistingThreadLocal(LocalStorageKey key) {
    374     return GetThreadLocal(key);
    375   }
    376 #endif
    377 
    378   // The thread name length is limited to 16 based on Linux's implementation of
    379   // prctl().
    380   static const int kMaxThreadNameLength = 16;
    381 
    382   class PlatformData;
    383   PlatformData* data() { return data_; }
    384 
    385   void NotifyStartedAndRun() {
    386     if (start_semaphore_) start_semaphore_->Signal();
    387     Run();
    388   }
    389 
    390  private:
    391   void set_name(const char* name);
    392 
    393   PlatformData* data_;
    394 
    395   char name_[kMaxThreadNameLength];
    396   int stack_size_;
    397   Semaphore* start_semaphore_;
    398 
    399   DISALLOW_COPY_AND_ASSIGN(Thread);
    400 };
    401 
    402 }  // namespace base
    403 }  // namespace v8
    404 
    405 #endif  // V8_BASE_PLATFORM_PLATFORM_H_
    406