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