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