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