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