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