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