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/platform/mutex.h" 30 #include "src/base/platform/semaphore.h" 31 32 #if V8_OS_QNX 33 #include "src/base/qnx-math.h" 34 #endif 35 36 namespace v8 { 37 namespace base { 38 39 // ---------------------------------------------------------------------------- 40 // Fast TLS support 41 42 #ifndef V8_NO_FAST_TLS 43 44 #if V8_CC_MSVC && V8_HOST_ARCH_IA32 45 46 #define V8_FAST_TLS_SUPPORTED 1 47 48 INLINE(intptr_t InternalGetExistingThreadLocal(intptr_t index)); 49 50 inline intptr_t InternalGetExistingThreadLocal(intptr_t index) { 51 const intptr_t kTibInlineTlsOffset = 0xE10; 52 const intptr_t kTibExtraTlsOffset = 0xF94; 53 const intptr_t kMaxInlineSlots = 64; 54 const intptr_t kMaxSlots = kMaxInlineSlots + 1024; 55 const intptr_t kPointerSize = sizeof(void*); 56 DCHECK(0 <= index && index < kMaxSlots); 57 if (index < kMaxInlineSlots) { 58 return static_cast<intptr_t>(__readfsdword(kTibInlineTlsOffset + 59 kPointerSize * index)); 60 } 61 intptr_t extra = static_cast<intptr_t>(__readfsdword(kTibExtraTlsOffset)); 62 DCHECK(extra != 0); 63 return *reinterpret_cast<intptr_t*>(extra + 64 kPointerSize * (index - kMaxInlineSlots)); 65 } 66 67 #elif defined(__APPLE__) && (V8_HOST_ARCH_IA32 || V8_HOST_ARCH_X64) 68 69 #define V8_FAST_TLS_SUPPORTED 1 70 71 extern intptr_t kMacTlsBaseOffset; 72 73 INLINE(intptr_t InternalGetExistingThreadLocal(intptr_t index)); 74 75 inline intptr_t InternalGetExistingThreadLocal(intptr_t index) { 76 intptr_t result; 77 #if V8_HOST_ARCH_IA32 78 asm("movl %%gs:(%1,%2,4), %0;" 79 :"=r"(result) // Output must be a writable register. 80 :"r"(kMacTlsBaseOffset), "r"(index)); 81 #else 82 asm("movq %%gs:(%1,%2,8), %0;" 83 :"=r"(result) 84 :"r"(kMacTlsBaseOffset), "r"(index)); 85 #endif 86 return result; 87 } 88 89 #endif 90 91 #endif // V8_NO_FAST_TLS 92 93 94 class TimezoneCache; 95 96 97 // ---------------------------------------------------------------------------- 98 // OS 99 // 100 // This class has static methods for the different platform specific 101 // functions. Add methods here to cope with differences between the 102 // supported platforms. 103 104 class OS { 105 public: 106 // Initialize the OS class. 107 // - random_seed: Used for the GetRandomMmapAddress() if non-zero. 108 // - hard_abort: If true, OS::Abort() will crash instead of aborting. 109 // - gc_fake_mmap: Name of the file for fake gc mmap used in ll_prof. 110 static void Initialize(int64_t random_seed, 111 bool hard_abort, 112 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 static void DisposeTimezoneCache(TimezoneCache* cache); 126 static void ClearTimezoneCache(TimezoneCache* cache); 127 128 // Returns a string identifying the current time zone. The 129 // timestamp is used for determining if DST is in effect. 130 static const char* LocalTimezone(double time, TimezoneCache* cache); 131 132 // Returns the local time offset in milliseconds east of UTC without 133 // taking daylight savings time into account. 134 static double LocalTimeOffset(TimezoneCache* cache); 135 136 // Returns the daylight savings offset for the given time. 137 static double DaylightSavingsOffset(double time, TimezoneCache* cache); 138 139 // Returns last OS error. 140 static int GetLastError(); 141 142 static FILE* FOpen(const char* path, const char* mode); 143 static bool Remove(const char* path); 144 145 static bool isDirectorySeparator(const char ch); 146 147 // Opens a temporary file, the file is auto removed on close. 148 static FILE* OpenTemporaryFile(); 149 150 // Log file open mode is platform-dependent due to line ends issues. 151 static const char* const LogFileOpenMode; 152 153 // Print output to console. This is mostly used for debugging output. 154 // On platforms that has standard terminal output, the output 155 // should go to stdout. 156 static void Print(const char* format, ...); 157 static void VPrint(const char* format, va_list args); 158 159 // Print output to a file. This is mostly used for debugging output. 160 static void FPrint(FILE* out, const char* format, ...); 161 static void VFPrint(FILE* out, const char* format, va_list args); 162 163 // Print error output to console. This is mostly used for error message 164 // output. On platforms that has standard terminal output, the output 165 // should go to stderr. 166 static void PrintError(const char* format, ...); 167 static void VPrintError(const char* format, va_list args); 168 169 // Allocate/Free memory used by JS heap. Pages are readable/writable, but 170 // they are not guaranteed to be executable unless 'executable' is true. 171 // Returns the address of allocated memory, or NULL if failed. 172 static void* Allocate(const size_t requested, 173 size_t* allocated, 174 bool is_executable); 175 static void Free(void* address, const size_t size); 176 177 // This is the granularity at which the ProtectCode(...) call can set page 178 // permissions. 179 static intptr_t CommitPageSize(); 180 181 // Mark code segments non-writable. 182 static void ProtectCode(void* address, const size_t size); 183 184 // Assign memory as a guard page so that access will cause an exception. 185 static void Guard(void* address, const size_t size); 186 187 // Generate a random address to be used for hinting mmap(). 188 static void* GetRandomMmapAddr(); 189 190 // Get the Alignment guaranteed by Allocate(). 191 static size_t AllocateAlignment(); 192 193 // Sleep for a specified time interval. 194 static void Sleep(TimeDelta interval); 195 196 // Abort the current process. 197 V8_NORETURN static void Abort(); 198 199 // Debug break. 200 static void DebugBreak(); 201 202 // Walk the stack. 203 static const int kStackWalkError = -1; 204 static const int kStackWalkMaxNameLen = 256; 205 static const int kStackWalkMaxTextLen = 256; 206 struct StackFrame { 207 void* address; 208 char text[kStackWalkMaxTextLen]; 209 }; 210 211 class MemoryMappedFile { 212 public: 213 virtual ~MemoryMappedFile() {} 214 virtual void* memory() const = 0; 215 virtual size_t size() const = 0; 216 217 static MemoryMappedFile* open(const char* name); 218 static MemoryMappedFile* create(const char* name, size_t size, 219 void* initial); 220 }; 221 222 // Safe formatting print. Ensures that str is always null-terminated. 223 // Returns the number of chars written, or -1 if output was truncated. 224 static int SNPrintF(char* str, int length, const char* format, ...); 225 static int VSNPrintF(char* str, 226 int length, 227 const char* format, 228 va_list args); 229 230 static char* StrChr(char* str, int c); 231 static void StrNCpy(char* dest, int length, const char* src, size_t n); 232 233 // Support for the profiler. Can do nothing, in which case ticks 234 // occuring in shared libraries will not be properly accounted for. 235 struct SharedLibraryAddress { 236 SharedLibraryAddress( 237 const std::string& library_path, uintptr_t start, uintptr_t end) 238 : library_path(library_path), start(start), end(end) {} 239 240 std::string library_path; 241 uintptr_t start; 242 uintptr_t end; 243 }; 244 245 static std::vector<SharedLibraryAddress> GetSharedLibraryAddresses(); 246 247 // Support for the profiler. Notifies the external profiling 248 // process that a code moving garbage collection starts. Can do 249 // nothing, in which case the code objects must not move (e.g., by 250 // using --never-compact) if accurate profiling is desired. 251 static void SignalCodeMovingGC(); 252 253 // Support runtime detection of whether the hard float option of the 254 // EABI is used. 255 static bool ArmUsingHardFloat(); 256 257 // Returns the activation frame alignment constraint or zero if 258 // the platform doesn't care. Guaranteed to be a power of two. 259 static int ActivationFrameAlignment(); 260 261 static int GetCurrentProcessId(); 262 263 static int GetCurrentThreadId(); 264 265 private: 266 static const int msPerSecond = 1000; 267 268 #if V8_OS_POSIX 269 static const char* GetGCFakeMMapFile(); 270 #endif 271 272 DISALLOW_IMPLICIT_CONSTRUCTORS(OS); 273 }; 274 275 276 // Represents and controls an area of reserved memory. 277 // Control of the reserved memory can be assigned to another VirtualMemory 278 // object by assignment or copy-contructing. This removes the reserved memory 279 // from the original object. 280 class VirtualMemory { 281 public: 282 // Empty VirtualMemory object, controlling no reserved memory. 283 VirtualMemory(); 284 285 // Reserves virtual memory with size. 286 explicit VirtualMemory(size_t size); 287 288 // Reserves virtual memory containing an area of the given size that 289 // is aligned per alignment. This may not be at the position returned 290 // by address(). 291 VirtualMemory(size_t size, size_t alignment); 292 293 // Releases the reserved memory, if any, controlled by this VirtualMemory 294 // object. 295 ~VirtualMemory(); 296 297 // Returns whether the memory has been reserved. 298 bool IsReserved(); 299 300 // Initialize or resets an embedded VirtualMemory object. 301 void Reset(); 302 303 // Returns the start address of the reserved memory. 304 // If the memory was reserved with an alignment, this address is not 305 // necessarily aligned. The user might need to round it up to a multiple of 306 // the alignment to get the start of the aligned block. 307 void* address() { 308 DCHECK(IsReserved()); 309 return address_; 310 } 311 312 // Returns the size of the reserved memory. The returned value is only 313 // meaningful when IsReserved() returns true. 314 // If the memory was reserved with an alignment, this size may be larger 315 // than the requested size. 316 size_t size() { return size_; } 317 318 // Commits real memory. Returns whether the operation succeeded. 319 bool Commit(void* address, size_t size, bool is_executable); 320 321 // Uncommit real memory. Returns whether the operation succeeded. 322 bool Uncommit(void* address, size_t size); 323 324 // Creates a single guard page at the given address. 325 bool Guard(void* address); 326 327 void Release() { 328 DCHECK(IsReserved()); 329 // Notice: Order is important here. The VirtualMemory object might live 330 // inside the allocated region. 331 void* address = address_; 332 size_t size = size_; 333 CHECK(InVM(address, size)); 334 Reset(); 335 bool result = ReleaseRegion(address, size); 336 USE(result); 337 DCHECK(result); 338 } 339 340 // Assign control of the reserved region to a different VirtualMemory object. 341 // The old object is no longer functional (IsReserved() returns false). 342 void TakeControl(VirtualMemory* from) { 343 DCHECK(!IsReserved()); 344 address_ = from->address_; 345 size_ = from->size_; 346 from->Reset(); 347 } 348 349 static void* ReserveRegion(size_t size); 350 351 static bool CommitRegion(void* base, size_t size, bool is_executable); 352 353 static bool UncommitRegion(void* base, size_t size); 354 355 // Must be called with a base pointer that has been returned by ReserveRegion 356 // and the same size it was reserved with. 357 static bool ReleaseRegion(void* base, size_t size); 358 359 // Returns true if OS performs lazy commits, i.e. the memory allocation call 360 // defers actual physical memory allocation till the first memory access. 361 // Otherwise returns false. 362 static bool HasLazyCommits(); 363 364 private: 365 bool InVM(void* address, size_t size) { 366 return (reinterpret_cast<uintptr_t>(address_) <= 367 reinterpret_cast<uintptr_t>(address)) && 368 ((reinterpret_cast<uintptr_t>(address_) + size_) >= 369 (reinterpret_cast<uintptr_t>(address) + size)); 370 } 371 372 void* address_; // Start address of the virtual memory. 373 size_t size_; // Size of the virtual memory. 374 }; 375 376 377 // ---------------------------------------------------------------------------- 378 // Thread 379 // 380 // Thread objects are used for creating and running threads. When the start() 381 // method is called the new thread starts running the run() method in the new 382 // thread. The Thread object should not be deallocated before the thread has 383 // terminated. 384 385 class Thread { 386 public: 387 // Opaque data type for thread-local storage keys. 388 typedef int32_t LocalStorageKey; 389 390 class Options { 391 public: 392 Options() : name_("v8:<unknown>"), stack_size_(0) {} 393 explicit Options(const char* name, int stack_size = 0) 394 : name_(name), stack_size_(stack_size) {} 395 396 const char* name() const { return name_; } 397 int stack_size() const { return stack_size_; } 398 399 private: 400 const char* name_; 401 int stack_size_; 402 }; 403 404 // Create new thread. 405 explicit Thread(const Options& options); 406 virtual ~Thread(); 407 408 // Start new thread by calling the Run() method on the new thread. 409 void Start(); 410 411 // Start new thread and wait until Run() method is called on the new thread. 412 void StartSynchronously() { 413 start_semaphore_ = new Semaphore(0); 414 Start(); 415 start_semaphore_->Wait(); 416 delete start_semaphore_; 417 start_semaphore_ = NULL; 418 } 419 420 // Wait until thread terminates. 421 void Join(); 422 423 inline const char* name() const { 424 return name_; 425 } 426 427 // Abstract method for run handler. 428 virtual void Run() = 0; 429 430 // Thread-local storage. 431 static LocalStorageKey CreateThreadLocalKey(); 432 static void DeleteThreadLocalKey(LocalStorageKey key); 433 static void* GetThreadLocal(LocalStorageKey key); 434 static int GetThreadLocalInt(LocalStorageKey key) { 435 return static_cast<int>(reinterpret_cast<intptr_t>(GetThreadLocal(key))); 436 } 437 static void SetThreadLocal(LocalStorageKey key, void* value); 438 static void SetThreadLocalInt(LocalStorageKey key, int value) { 439 SetThreadLocal(key, reinterpret_cast<void*>(static_cast<intptr_t>(value))); 440 } 441 static bool HasThreadLocal(LocalStorageKey key) { 442 return GetThreadLocal(key) != NULL; 443 } 444 445 #ifdef V8_FAST_TLS_SUPPORTED 446 static inline void* GetExistingThreadLocal(LocalStorageKey key) { 447 void* result = reinterpret_cast<void*>( 448 InternalGetExistingThreadLocal(static_cast<intptr_t>(key))); 449 DCHECK(result == GetThreadLocal(key)); 450 return result; 451 } 452 #else 453 static inline void* GetExistingThreadLocal(LocalStorageKey key) { 454 return GetThreadLocal(key); 455 } 456 #endif 457 458 // The thread name length is limited to 16 based on Linux's implementation of 459 // prctl(). 460 static const int kMaxThreadNameLength = 16; 461 462 class PlatformData; 463 PlatformData* data() { return data_; } 464 465 void NotifyStartedAndRun() { 466 if (start_semaphore_) start_semaphore_->Signal(); 467 Run(); 468 } 469 470 private: 471 void set_name(const char* name); 472 473 PlatformData* data_; 474 475 char name_[kMaxThreadNameLength]; 476 int stack_size_; 477 Semaphore* start_semaphore_; 478 479 DISALLOW_COPY_AND_ASSIGN(Thread); 480 }; 481 482 } // namespace base 483 } // namespace v8 484 485 #endif // V8_BASE_PLATFORM_PLATFORM_H_ 486