| OLD | NEW |
| (Empty) |
| 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 // 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 number of processors online. | |
| 288 static int NumberOfProcessorsOnline(); | |
| 289 | |
| 290 // The total amount of physical memory available on the current system. | |
| 291 static uint64_t TotalPhysicalMemory(); | |
| 292 | |
| 293 // Maximum size of the virtual memory. 0 means there is no artificial | |
| 294 // limit. | |
| 295 static intptr_t MaxVirtualMemory(); | |
| 296 | |
| 297 // Returns the double constant NAN | |
| 298 static double nan_value(); | |
| 299 | |
| 300 // Support runtime detection of whether the hard float option of the | |
| 301 // EABI is used. | |
| 302 static bool ArmUsingHardFloat(); | |
| 303 | |
| 304 // Returns the activation frame alignment constraint or zero if | |
| 305 // the platform doesn't care. Guaranteed to be a power of two. | |
| 306 static int ActivationFrameAlignment(); | |
| 307 | |
| 308 static int GetCurrentProcessId(); | |
| 309 | |
| 310 private: | |
| 311 static const int msPerSecond = 1000; | |
| 312 | |
| 313 #if V8_OS_POSIX | |
| 314 static const char* GetGCFakeMMapFile(); | |
| 315 #endif | |
| 316 | |
| 317 DISALLOW_IMPLICIT_CONSTRUCTORS(OS); | |
| 318 }; | |
| 319 | |
| 320 // Represents and controls an area of reserved memory. | |
| 321 // Control of the reserved memory can be assigned to another VirtualMemory | |
| 322 // object by assignment or copy-contructing. This removes the reserved memory | |
| 323 // from the original object. | |
| 324 class VirtualMemory { | |
| 325 public: | |
| 326 // Empty VirtualMemory object, controlling no reserved memory. | |
| 327 VirtualMemory(); | |
| 328 | |
| 329 // Reserves virtual memory with size. | |
| 330 explicit VirtualMemory(size_t size); | |
| 331 | |
| 332 // Reserves virtual memory containing an area of the given size that | |
| 333 // is aligned per alignment. This may not be at the position returned | |
| 334 // by address(). | |
| 335 VirtualMemory(size_t size, size_t alignment); | |
| 336 | |
| 337 // Releases the reserved memory, if any, controlled by this VirtualMemory | |
| 338 // object. | |
| 339 ~VirtualMemory(); | |
| 340 | |
| 341 // Returns whether the memory has been reserved. | |
| 342 bool IsReserved(); | |
| 343 | |
| 344 // Initialize or resets an embedded VirtualMemory object. | |
| 345 void Reset(); | |
| 346 | |
| 347 // Returns the start address of the reserved memory. | |
| 348 // If the memory was reserved with an alignment, this address is not | |
| 349 // necessarily aligned. The user might need to round it up to a multiple of | |
| 350 // the alignment to get the start of the aligned block. | |
| 351 void* address() { | |
| 352 ASSERT(IsReserved()); | |
| 353 return address_; | |
| 354 } | |
| 355 | |
| 356 // Returns the size of the reserved memory. The returned value is only | |
| 357 // meaningful when IsReserved() returns true. | |
| 358 // If the memory was reserved with an alignment, this size may be larger | |
| 359 // than the requested size. | |
| 360 size_t size() { return size_; } | |
| 361 | |
| 362 // Commits real memory. Returns whether the operation succeeded. | |
| 363 bool Commit(void* address, size_t size, bool is_executable); | |
| 364 | |
| 365 // Uncommit real memory. Returns whether the operation succeeded. | |
| 366 bool Uncommit(void* address, size_t size); | |
| 367 | |
| 368 // Creates a single guard page at the given address. | |
| 369 bool Guard(void* address); | |
| 370 | |
| 371 void Release() { | |
| 372 ASSERT(IsReserved()); | |
| 373 // Notice: Order is important here. The VirtualMemory object might live | |
| 374 // inside the allocated region. | |
| 375 void* address = address_; | |
| 376 size_t size = size_; | |
| 377 Reset(); | |
| 378 bool result = ReleaseRegion(address, size); | |
| 379 USE(result); | |
| 380 ASSERT(result); | |
| 381 } | |
| 382 | |
| 383 // Assign control of the reserved region to a different VirtualMemory object. | |
| 384 // The old object is no longer functional (IsReserved() returns false). | |
| 385 void TakeControl(VirtualMemory* from) { | |
| 386 ASSERT(!IsReserved()); | |
| 387 address_ = from->address_; | |
| 388 size_ = from->size_; | |
| 389 from->Reset(); | |
| 390 } | |
| 391 | |
| 392 static void* ReserveRegion(size_t size); | |
| 393 | |
| 394 static bool CommitRegion(void* base, size_t size, bool is_executable); | |
| 395 | |
| 396 static bool UncommitRegion(void* base, size_t size); | |
| 397 | |
| 398 // Must be called with a base pointer that has been returned by ReserveRegion | |
| 399 // and the same size it was reserved with. | |
| 400 static bool ReleaseRegion(void* base, size_t size); | |
| 401 | |
| 402 // Returns true if OS performs lazy commits, i.e. the memory allocation call | |
| 403 // defers actual physical memory allocation till the first memory access. | |
| 404 // Otherwise returns false. | |
| 405 static bool HasLazyCommits(); | |
| 406 | |
| 407 private: | |
| 408 void* address_; // Start address of the virtual memory. | |
| 409 size_t size_; // Size of the virtual memory. | |
| 410 }; | |
| 411 | |
| 412 | |
| 413 // ---------------------------------------------------------------------------- | |
| 414 // Thread | |
| 415 // | |
| 416 // Thread objects are used for creating and running threads. When the start() | |
| 417 // method is called the new thread starts running the run() method in the new | |
| 418 // thread. The Thread object should not be deallocated before the thread has | |
| 419 // terminated. | |
| 420 | |
| 421 class Thread { | |
| 422 public: | |
| 423 // Opaque data type for thread-local storage keys. | |
| 424 typedef int32_t LocalStorageKey; | |
| 425 | |
| 426 class Options { | |
| 427 public: | |
| 428 Options() : name_("v8:<unknown>"), stack_size_(0) {} | |
| 429 Options(const char* name, int stack_size = 0) | |
| 430 : name_(name), stack_size_(stack_size) {} | |
| 431 | |
| 432 const char* name() const { return name_; } | |
| 433 int stack_size() const { return stack_size_; } | |
| 434 | |
| 435 private: | |
| 436 const char* name_; | |
| 437 int stack_size_; | |
| 438 }; | |
| 439 | |
| 440 // Create new thread. | |
| 441 explicit Thread(const Options& options); | |
| 442 virtual ~Thread(); | |
| 443 | |
| 444 // Start new thread by calling the Run() method on the new thread. | |
| 445 void Start(); | |
| 446 | |
| 447 // Start new thread and wait until Run() method is called on the new thread. | |
| 448 void StartSynchronously() { | |
| 449 start_semaphore_ = new Semaphore(0); | |
| 450 Start(); | |
| 451 start_semaphore_->Wait(); | |
| 452 delete start_semaphore_; | |
| 453 start_semaphore_ = NULL; | |
| 454 } | |
| 455 | |
| 456 // Wait until thread terminates. | |
| 457 void Join(); | |
| 458 | |
| 459 inline const char* name() const { | |
| 460 return name_; | |
| 461 } | |
| 462 | |
| 463 // Abstract method for run handler. | |
| 464 virtual void Run() = 0; | |
| 465 | |
| 466 // Thread-local storage. | |
| 467 static LocalStorageKey CreateThreadLocalKey(); | |
| 468 static void DeleteThreadLocalKey(LocalStorageKey key); | |
| 469 static void* GetThreadLocal(LocalStorageKey key); | |
| 470 static int GetThreadLocalInt(LocalStorageKey key) { | |
| 471 return static_cast<int>(reinterpret_cast<intptr_t>(GetThreadLocal(key))); | |
| 472 } | |
| 473 static void SetThreadLocal(LocalStorageKey key, void* value); | |
| 474 static void SetThreadLocalInt(LocalStorageKey key, int value) { | |
| 475 SetThreadLocal(key, reinterpret_cast<void*>(static_cast<intptr_t>(value))); | |
| 476 } | |
| 477 static bool HasThreadLocal(LocalStorageKey key) { | |
| 478 return GetThreadLocal(key) != NULL; | |
| 479 } | |
| 480 | |
| 481 #ifdef V8_FAST_TLS_SUPPORTED | |
| 482 static inline void* GetExistingThreadLocal(LocalStorageKey key) { | |
| 483 void* result = reinterpret_cast<void*>( | |
| 484 InternalGetExistingThreadLocal(static_cast<intptr_t>(key))); | |
| 485 ASSERT(result == GetThreadLocal(key)); | |
| 486 return result; | |
| 487 } | |
| 488 #else | |
| 489 static inline void* GetExistingThreadLocal(LocalStorageKey key) { | |
| 490 return GetThreadLocal(key); | |
| 491 } | |
| 492 #endif | |
| 493 | |
| 494 // A hint to the scheduler to let another thread run. | |
| 495 static void YieldCPU(); | |
| 496 | |
| 497 | |
| 498 // The thread name length is limited to 16 based on Linux's implementation of | |
| 499 // prctl(). | |
| 500 static const int kMaxThreadNameLength = 16; | |
| 501 | |
| 502 class PlatformData; | |
| 503 PlatformData* data() { return data_; } | |
| 504 | |
| 505 void NotifyStartedAndRun() { | |
| 506 if (start_semaphore_) start_semaphore_->Signal(); | |
| 507 Run(); | |
| 508 } | |
| 509 | |
| 510 private: | |
| 511 void set_name(const char* name); | |
| 512 | |
| 513 PlatformData* data_; | |
| 514 | |
| 515 char name_[kMaxThreadNameLength]; | |
| 516 int stack_size_; | |
| 517 Semaphore* start_semaphore_; | |
| 518 | |
| 519 DISALLOW_COPY_AND_ASSIGN(Thread); | |
| 520 }; | |
| 521 | |
| 522 } } // namespace v8::internal | |
| 523 | |
| 524 #endif // V8_PLATFORM_H_ | |
| OLD | NEW |