1 // Copyright 2011 the V8 project authors. All rights reserved. 2 // Redistribution and use in source and binary forms, with or without 3 // modification, are permitted provided that the following conditions are 4 // met: 5 // 6 // * Redistributions of source code must retain the above copyright 7 // notice, this list of conditions and the following disclaimer. 8 // * Redistributions in binary form must reproduce the above 9 // copyright notice, this list of conditions and the following 10 // disclaimer in the documentation and/or other materials provided 11 // with the distribution. 12 // * Neither the name of Google Inc. nor the names of its 13 // contributors may be used to endorse or promote products derived 14 // from this software without specific prior written permission. 15 // 16 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 17 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 18 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 19 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 20 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 21 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 22 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 23 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 24 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 26 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 28 // This module contains the platform-specific code. This make the rest of the 29 // code less dependent on operating system, compilers and runtime libraries. 30 // This module does specifically not deal with differences between different 31 // processor architecture. 32 // The platform classes have the same definition for all platforms. The 33 // implementation for a particular platform is put in platform_<os>.cc. 34 // The build system then uses the implementation for the target platform. 35 // 36 // This design has been chosen because it is simple and fast. Alternatively, 37 // the platform dependent classes could have been implemented using abstract 38 // superclasses with virtual methods and having specializations for each 39 // platform. This design was rejected because it was more complicated and 40 // slower. It would require factory methods for selecting the right 41 // implementation and the overhead of virtual methods for performance 42 // sensitive like mutex locking/unlocking. 43 44 #ifndef V8_PLATFORM_H_ 45 #define V8_PLATFORM_H_ 46 47 #ifdef __sun 48 # ifndef signbit 49 int signbit(double x); 50 # endif 51 #endif 52 53 // GCC specific stuff 54 #ifdef __GNUC__ 55 56 // Needed for va_list on at least MinGW and Android. 57 #include <stdarg.h> 58 59 #define __GNUC_VERSION__ (__GNUC__ * 10000 + __GNUC_MINOR__ * 100) 60 61 #endif // __GNUC__ 62 63 64 // Windows specific stuff. 65 #ifdef WIN32 66 67 // Microsoft Visual C++ specific stuff. 68 #ifdef _MSC_VER 69 70 #include "win32-math.h" 71 72 int strncasecmp(const char* s1, const char* s2, int n); 73 74 #endif // _MSC_VER 75 76 // Random is missing on both Visual Studio and MinGW. 77 int random(); 78 79 #endif // WIN32 80 81 #include "atomicops.h" 82 #include "lazy-instance.h" 83 #include "platform-tls.h" 84 #include "utils.h" 85 #include "v8globals.h" 86 87 namespace v8 { 88 namespace internal { 89 90 // Use AtomicWord for a machine-sized pointer. It is assumed that 91 // reads and writes of naturally aligned values of this type are atomic. 92 typedef intptr_t AtomicWord; 93 94 class Semaphore; 95 class Mutex; 96 97 double ceiling(double x); 98 double modulo(double x, double y); 99 100 // Custom implementation of sin, cos, tan and log. 101 double fast_sin(double input); 102 double fast_cos(double input); 103 double fast_tan(double input); 104 double fast_log(double input); 105 double fast_sqrt(double input); 106 107 // Forward declarations. 108 class Socket; 109 110 // ---------------------------------------------------------------------------- 111 // OS 112 // 113 // This class has static methods for the different platform specific 114 // functions. Add methods here to cope with differences between the 115 // supported platforms. 116 117 class OS { 118 public: 119 // Initializes the platform OS support. Called once at VM startup. 120 static void SetUp(); 121 122 // Initializes the platform OS support that depend on CPU features. This is 123 // called after CPU initialization. 124 static void PostSetUp(); 125 126 // Returns the accumulated user time for thread. This routine 127 // can be used for profiling. The implementation should 128 // strive for high-precision timer resolution, preferable 129 // micro-second resolution. 130 static int GetUserTime(uint32_t* secs, uint32_t* usecs); 131 132 // Get a tick counter normalized to one tick per microsecond. 133 // Used for calculating time intervals. 134 static int64_t Ticks(); 135 136 // Returns current time as the number of milliseconds since 137 // 00:00:00 UTC, January 1, 1970. 138 static double TimeCurrentMillis(); 139 140 // Returns a string identifying the current time zone. The 141 // timestamp is used for determining if DST is in effect. 142 static const char* LocalTimezone(double time); 143 144 // Returns the local time offset in milliseconds east of UTC without 145 // taking daylight savings time into account. 146 static double LocalTimeOffset(); 147 148 // Returns the daylight savings offset for the given time. 149 static double DaylightSavingsOffset(double time); 150 151 // Returns last OS error. 152 static int GetLastError(); 153 154 static FILE* FOpen(const char* path, const char* mode); 155 static bool Remove(const char* path); 156 157 // Opens a temporary file, the file is auto removed on close. 158 static FILE* OpenTemporaryFile(); 159 160 // Log file open mode is platform-dependent due to line ends issues. 161 static const char* const LogFileOpenMode; 162 163 // Print output to console. This is mostly used for debugging output. 164 // On platforms that has standard terminal output, the output 165 // should go to stdout. 166 static void Print(const char* format, ...); 167 static void VPrint(const char* format, va_list args); 168 169 // Print output to a file. This is mostly used for debugging output. 170 static void FPrint(FILE* out, const char* format, ...); 171 static void VFPrint(FILE* out, const char* format, va_list args); 172 173 // Print error output to console. This is mostly used for error message 174 // output. On platforms that has standard terminal output, the output 175 // should go to stderr. 176 static void PrintError(const char* format, ...); 177 static void VPrintError(const char* format, va_list args); 178 179 // Allocate/Free memory used by JS heap. Pages are readable/writable, but 180 // they are not guaranteed to be executable unless 'executable' is true. 181 // Returns the address of allocated memory, or NULL if failed. 182 static void* Allocate(const size_t requested, 183 size_t* allocated, 184 bool is_executable); 185 static void Free(void* address, const size_t size); 186 187 // This is the granularity at which the ProtectCode(...) call can set page 188 // permissions. 189 static intptr_t CommitPageSize(); 190 191 // Mark code segments non-writable. 192 static void ProtectCode(void* address, const size_t size); 193 194 // Assign memory as a guard page so that access will cause an exception. 195 static void Guard(void* address, const size_t size); 196 197 // Generate a random address to be used for hinting mmap(). 198 static void* GetRandomMmapAddr(); 199 200 // Get the Alignment guaranteed by Allocate(). 201 static size_t AllocateAlignment(); 202 203 // Returns an indication of whether a pointer is in a space that 204 // has been allocated by Allocate(). This method may conservatively 205 // always return false, but giving more accurate information may 206 // improve the robustness of the stack dump code in the presence of 207 // heap corruption. 208 static bool IsOutsideAllocatedSpace(void* pointer); 209 210 // Sleep for a number of milliseconds. 211 static void Sleep(const int milliseconds); 212 213 // Abort the current process. 214 static void Abort(); 215 216 // Debug break. 217 static void DebugBreak(); 218 219 // Walk the stack. 220 static const int kStackWalkError = -1; 221 static const int kStackWalkMaxNameLen = 256; 222 static const int kStackWalkMaxTextLen = 256; 223 struct StackFrame { 224 void* address; 225 char text[kStackWalkMaxTextLen]; 226 }; 227 228 static int StackWalk(Vector<StackFrame> frames); 229 230 // Factory method for creating platform dependent Mutex. 231 // Please use delete to reclaim the storage for the returned Mutex. 232 static Mutex* CreateMutex(); 233 234 // Factory method for creating platform dependent Semaphore. 235 // Please use delete to reclaim the storage for the returned Semaphore. 236 static Semaphore* CreateSemaphore(int count); 237 238 // Factory method for creating platform dependent Socket. 239 // Please use delete to reclaim the storage for the returned Socket. 240 static Socket* CreateSocket(); 241 242 class MemoryMappedFile { 243 public: 244 static MemoryMappedFile* open(const char* name); 245 static MemoryMappedFile* create(const char* name, int size, void* initial); ~MemoryMappedFile()246 virtual ~MemoryMappedFile() { } 247 virtual void* memory() = 0; 248 virtual int size() = 0; 249 }; 250 251 // Safe formatting print. Ensures that str is always null-terminated. 252 // Returns the number of chars written, or -1 if output was truncated. 253 static int SNPrintF(Vector<char> str, const char* format, ...); 254 static int VSNPrintF(Vector<char> str, 255 const char* format, 256 va_list args); 257 258 static char* StrChr(char* str, int c); 259 static void StrNCpy(Vector<char> dest, const char* src, size_t n); 260 261 // Support for the profiler. Can do nothing, in which case ticks 262 // occuring in shared libraries will not be properly accounted for. 263 static void LogSharedLibraryAddresses(); 264 265 // Support for the profiler. Notifies the external profiling 266 // process that a code moving garbage collection starts. Can do 267 // nothing, in which case the code objects must not move (e.g., by 268 // using --never-compact) if accurate profiling is desired. 269 static void SignalCodeMovingGC(); 270 271 // The return value indicates the CPU features we are sure of because of the 272 // OS. For example MacOSX doesn't run on any x86 CPUs that don't have SSE2 273 // instructions. 274 // This is a little messy because the interpretation is subject to the cross 275 // of the CPU and the OS. The bits in the answer correspond to the bit 276 // positions indicated by the members of the CpuFeature enum from globals.h 277 static uint64_t CpuFeaturesImpliedByPlatform(); 278 279 // Maximum size of the virtual memory. 0 means there is no artificial 280 // limit. 281 static intptr_t MaxVirtualMemory(); 282 283 // Returns the double constant NAN 284 static double nan_value(); 285 286 // Support runtime detection of VFP3 on ARM CPUs. 287 static bool ArmCpuHasFeature(CpuFeature feature); 288 289 // Support runtime detection of whether the hard float option of the 290 // EABI is used. 291 static bool ArmUsingHardFloat(); 292 293 // Support runtime detection of FPU on MIPS CPUs. 294 static bool MipsCpuHasFeature(CpuFeature feature); 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 void ReleaseStore(volatile AtomicWord* ptr, AtomicWord value); 301 302 #if defined(V8_TARGET_ARCH_IA32) 303 // Copy memory area to disjoint memory area. 304 static void MemCopy(void* dest, const void* src, size_t size); 305 // Limit below which the extra overhead of the MemCopy function is likely 306 // to outweigh the benefits of faster copying. 307 static const int kMinComplexMemCopy = 64; 308 typedef void (*MemCopyFunction)(void* dest, const void* src, size_t size); 309 310 #else // V8_TARGET_ARCH_IA32 MemCopy(void * dest,const void * src,size_t size)311 static void MemCopy(void* dest, const void* src, size_t size) { 312 memcpy(dest, src, size); 313 } 314 static const int kMinComplexMemCopy = 256; 315 #endif // V8_TARGET_ARCH_IA32 316 317 private: 318 static const int msPerSecond = 1000; 319 320 DISALLOW_IMPLICIT_CONSTRUCTORS(OS); 321 }; 322 323 // Represents and controls an area of reserved memory. 324 // Control of the reserved memory can be assigned to another VirtualMemory 325 // object by assignment or copy-contructing. This removes the reserved memory 326 // from the original object. 327 class VirtualMemory { 328 public: 329 // Empty VirtualMemory object, controlling no reserved memory. 330 VirtualMemory(); 331 332 // Reserves virtual memory with size. 333 explicit VirtualMemory(size_t size); 334 335 // Reserves virtual memory containing an area of the given size that 336 // is aligned per alignment. This may not be at the position returned 337 // by address(). 338 VirtualMemory(size_t size, size_t alignment); 339 340 // Releases the reserved memory, if any, controlled by this VirtualMemory 341 // object. 342 ~VirtualMemory(); 343 344 // Returns whether the memory has been reserved. 345 bool IsReserved(); 346 347 // Initialize or resets an embedded VirtualMemory object. 348 void Reset(); 349 350 // Returns the start address of the reserved memory. 351 // If the memory was reserved with an alignment, this address is not 352 // necessarily aligned. The user might need to round it up to a multiple of 353 // the alignment to get the start of the aligned block. address()354 void* address() { 355 ASSERT(IsReserved()); 356 return address_; 357 } 358 359 // Returns the size of the reserved memory. The returned value is only 360 // meaningful when IsReserved() returns true. 361 // If the memory was reserved with an alignment, this size may be larger 362 // than the requested size. size()363 size_t size() { return size_; } 364 365 // Commits real memory. Returns whether the operation succeeded. 366 bool Commit(void* address, size_t size, bool is_executable); 367 368 // Uncommit real memory. Returns whether the operation succeeded. 369 bool Uncommit(void* address, size_t size); 370 371 // Creates a single guard page at the given address. 372 bool Guard(void* address); 373 Release()374 void Release() { 375 ASSERT(IsReserved()); 376 // Notice: Order is important here. The VirtualMemory object might live 377 // inside the allocated region. 378 void* address = address_; 379 size_t size = size_; 380 Reset(); 381 bool result = ReleaseRegion(address, size); 382 USE(result); 383 ASSERT(result); 384 } 385 386 // Assign control of the reserved region to a different VirtualMemory object. 387 // The old object is no longer functional (IsReserved() returns false). TakeControl(VirtualMemory * from)388 void TakeControl(VirtualMemory* from) { 389 ASSERT(!IsReserved()); 390 address_ = from->address_; 391 size_ = from->size_; 392 from->Reset(); 393 } 394 395 static void* ReserveRegion(size_t size); 396 397 static bool CommitRegion(void* base, size_t size, bool is_executable); 398 399 static bool UncommitRegion(void* base, size_t size); 400 401 // Must be called with a base pointer that has been returned by ReserveRegion 402 // and the same size it was reserved with. 403 static bool ReleaseRegion(void* base, size_t size); 404 405 private: 406 void* address_; // Start address of the virtual memory. 407 size_t size_; // Size of the virtual memory. 408 }; 409 410 411 // ---------------------------------------------------------------------------- 412 // Thread 413 // 414 // Thread objects are used for creating and running threads. When the start() 415 // method is called the new thread starts running the run() method in the new 416 // thread. The Thread object should not be deallocated before the thread has 417 // terminated. 418 419 class Thread { 420 public: 421 // Opaque data type for thread-local storage keys. 422 // LOCAL_STORAGE_KEY_MIN_VALUE and LOCAL_STORAGE_KEY_MAX_VALUE are specified 423 // to ensure that enumeration type has correct value range (see Issue 830 for 424 // more details). 425 enum LocalStorageKey { 426 LOCAL_STORAGE_KEY_MIN_VALUE = kMinInt, 427 LOCAL_STORAGE_KEY_MAX_VALUE = kMaxInt 428 }; 429 430 class Options { 431 public: Options()432 Options() : name_("v8:<unknown>"), stack_size_(0) {} 433 Options(const char* name, int stack_size = 0) name_(name)434 : name_(name), stack_size_(stack_size) {} 435 name()436 const char* name() const { return name_; } stack_size()437 int stack_size() const { return stack_size_; } 438 439 private: 440 const char* name_; 441 int stack_size_; 442 }; 443 444 // Create new thread. 445 explicit Thread(const Options& options); 446 virtual ~Thread(); 447 448 // Start new thread by calling the Run() method in the new thread. 449 void Start(); 450 451 // Wait until thread terminates. 452 void Join(); 453 name()454 inline const char* name() const { 455 return name_; 456 } 457 458 // Abstract method for run handler. 459 virtual void Run() = 0; 460 461 // Thread-local storage. 462 static LocalStorageKey CreateThreadLocalKey(); 463 static void DeleteThreadLocalKey(LocalStorageKey key); 464 static void* GetThreadLocal(LocalStorageKey key); GetThreadLocalInt(LocalStorageKey key)465 static int GetThreadLocalInt(LocalStorageKey key) { 466 return static_cast<int>(reinterpret_cast<intptr_t>(GetThreadLocal(key))); 467 } 468 static void SetThreadLocal(LocalStorageKey key, void* value); SetThreadLocalInt(LocalStorageKey key,int value)469 static void SetThreadLocalInt(LocalStorageKey key, int value) { 470 SetThreadLocal(key, reinterpret_cast<void*>(static_cast<intptr_t>(value))); 471 } HasThreadLocal(LocalStorageKey key)472 static bool HasThreadLocal(LocalStorageKey key) { 473 return GetThreadLocal(key) != NULL; 474 } 475 476 #ifdef V8_FAST_TLS_SUPPORTED GetExistingThreadLocal(LocalStorageKey key)477 static inline void* GetExistingThreadLocal(LocalStorageKey key) { 478 void* result = reinterpret_cast<void*>( 479 InternalGetExistingThreadLocal(static_cast<intptr_t>(key))); 480 ASSERT(result == GetThreadLocal(key)); 481 return result; 482 } 483 #else GetExistingThreadLocal(LocalStorageKey key)484 static inline void* GetExistingThreadLocal(LocalStorageKey key) { 485 return GetThreadLocal(key); 486 } 487 #endif 488 489 // A hint to the scheduler to let another thread run. 490 static void YieldCPU(); 491 492 493 // The thread name length is limited to 16 based on Linux's implementation of 494 // prctl(). 495 static const int kMaxThreadNameLength = 16; 496 497 class PlatformData; data()498 PlatformData* data() { return data_; } 499 500 private: 501 void set_name(const char* name); 502 503 PlatformData* data_; 504 505 char name_[kMaxThreadNameLength]; 506 int stack_size_; 507 508 DISALLOW_COPY_AND_ASSIGN(Thread); 509 }; 510 511 512 // ---------------------------------------------------------------------------- 513 // Mutex 514 // 515 // Mutexes are used for serializing access to non-reentrant sections of code. 516 // The implementations of mutex should allow for nested/recursive locking. 517 518 class Mutex { 519 public: ~Mutex()520 virtual ~Mutex() {} 521 522 // Locks the given mutex. If the mutex is currently unlocked, it becomes 523 // locked and owned by the calling thread, and immediately. If the mutex 524 // is already locked by another thread, suspends the calling thread until 525 // the mutex is unlocked. 526 virtual int Lock() = 0; 527 528 // Unlocks the given mutex. The mutex is assumed to be locked and owned by 529 // the calling thread on entrance. 530 virtual int Unlock() = 0; 531 532 // Tries to lock the given mutex. Returns whether the mutex was 533 // successfully locked. 534 virtual bool TryLock() = 0; 535 }; 536 537 struct CreateMutexTrait { CreateCreateMutexTrait538 static Mutex* Create() { 539 return OS::CreateMutex(); 540 } 541 }; 542 543 // POD Mutex initialized lazily (i.e. the first time Pointer() is called). 544 // Usage: 545 // static LazyMutex my_mutex = LAZY_MUTEX_INITIALIZER; 546 // 547 // void my_function() { 548 // ScopedLock my_lock(my_mutex.Pointer()); 549 // // Do something. 550 // } 551 // 552 typedef LazyDynamicInstance< 553 Mutex, CreateMutexTrait, ThreadSafeInitOnceTrait>::type LazyMutex; 554 555 #define LAZY_MUTEX_INITIALIZER LAZY_DYNAMIC_INSTANCE_INITIALIZER 556 557 // ---------------------------------------------------------------------------- 558 // ScopedLock 559 // 560 // Stack-allocated ScopedLocks provide block-scoped locking and 561 // unlocking of a mutex. 562 class ScopedLock { 563 public: ScopedLock(Mutex * mutex)564 explicit ScopedLock(Mutex* mutex): mutex_(mutex) { 565 ASSERT(mutex_ != NULL); 566 mutex_->Lock(); 567 } ~ScopedLock()568 ~ScopedLock() { 569 mutex_->Unlock(); 570 } 571 572 private: 573 Mutex* mutex_; 574 DISALLOW_COPY_AND_ASSIGN(ScopedLock); 575 }; 576 577 578 // ---------------------------------------------------------------------------- 579 // Semaphore 580 // 581 // A semaphore object is a synchronization object that maintains a count. The 582 // count is decremented each time a thread completes a wait for the semaphore 583 // object and incremented each time a thread signals the semaphore. When the 584 // count reaches zero, threads waiting for the semaphore blocks until the 585 // count becomes non-zero. 586 587 class Semaphore { 588 public: ~Semaphore()589 virtual ~Semaphore() {} 590 591 // Suspends the calling thread until the semaphore counter is non zero 592 // and then decrements the semaphore counter. 593 virtual void Wait() = 0; 594 595 // Suspends the calling thread until the counter is non zero or the timeout 596 // time has passed. If timeout happens the return value is false and the 597 // counter is unchanged. Otherwise the semaphore counter is decremented and 598 // true is returned. The timeout value is specified in microseconds. 599 virtual bool Wait(int timeout) = 0; 600 601 // Increments the semaphore counter. 602 virtual void Signal() = 0; 603 }; 604 605 template <int InitialValue> 606 struct CreateSemaphoreTrait { CreateCreateSemaphoreTrait607 static Semaphore* Create() { 608 return OS::CreateSemaphore(InitialValue); 609 } 610 }; 611 612 // POD Semaphore initialized lazily (i.e. the first time Pointer() is called). 613 // Usage: 614 // // The following semaphore starts at 0. 615 // static LazySemaphore<0>::type my_semaphore = LAZY_SEMAPHORE_INITIALIZER; 616 // 617 // void my_function() { 618 // // Do something with my_semaphore.Pointer(). 619 // } 620 // 621 template <int InitialValue> 622 struct LazySemaphore { 623 typedef typename LazyDynamicInstance< 624 Semaphore, CreateSemaphoreTrait<InitialValue>, 625 ThreadSafeInitOnceTrait>::type type; 626 }; 627 628 #define LAZY_SEMAPHORE_INITIALIZER LAZY_DYNAMIC_INSTANCE_INITIALIZER 629 630 631 // ---------------------------------------------------------------------------- 632 // Socket 633 // 634 635 class Socket { 636 public: ~Socket()637 virtual ~Socket() {} 638 639 // Server initialization. 640 virtual bool Bind(const int port) = 0; 641 virtual bool Listen(int backlog) const = 0; 642 virtual Socket* Accept() const = 0; 643 644 // Client initialization. 645 virtual bool Connect(const char* host, const char* port) = 0; 646 647 // Shutdown socket for both read and write. This causes blocking Send and 648 // Receive calls to exit. After Shutdown the Socket object cannot be used for 649 // any communication. 650 virtual bool Shutdown() = 0; 651 652 // Data Transimission 653 virtual int Send(const char* data, int len) const = 0; 654 virtual int Receive(char* data, int len) const = 0; 655 656 // Set the value of the SO_REUSEADDR socket option. 657 virtual bool SetReuseAddress(bool reuse_address) = 0; 658 659 virtual bool IsValid() const = 0; 660 661 static bool SetUp(); 662 static int LastError(); 663 static uint16_t HToN(uint16_t value); 664 static uint16_t NToH(uint16_t value); 665 static uint32_t HToN(uint32_t value); 666 static uint32_t NToH(uint32_t value); 667 }; 668 669 670 // ---------------------------------------------------------------------------- 671 // Sampler 672 // 673 // A sampler periodically samples the state of the VM and optionally 674 // (if used for profiling) the program counter and stack pointer for 675 // the thread that created it. 676 677 // TickSample captures the information collected for each sample. 678 class TickSample { 679 public: TickSample()680 TickSample() 681 : state(OTHER), 682 pc(NULL), 683 sp(NULL), 684 fp(NULL), 685 tos(NULL), 686 frames_count(0), 687 has_external_callback(false) {} 688 StateTag state; // The state of the VM. 689 Address pc; // Instruction pointer. 690 Address sp; // Stack pointer. 691 Address fp; // Frame pointer. 692 union { 693 Address tos; // Top stack value (*sp). 694 Address external_callback; 695 }; 696 static const int kMaxFramesCount = 64; 697 Address stack[kMaxFramesCount]; // Call stack. 698 int frames_count : 8; // Number of captured frames. 699 bool has_external_callback : 1; 700 }; 701 702 class Sampler { 703 public: 704 // Initialize sampler. 705 Sampler(Isolate* isolate, int interval); 706 virtual ~Sampler(); 707 interval()708 int interval() const { return interval_; } 709 710 // Performs stack sampling. SampleStack(TickSample * sample)711 void SampleStack(TickSample* sample) { 712 DoSampleStack(sample); 713 IncSamplesTaken(); 714 } 715 716 // This method is called for each sampling period with the current 717 // program counter. 718 virtual void Tick(TickSample* sample) = 0; 719 720 // Start and stop sampler. 721 void Start(); 722 void Stop(); 723 724 // Is the sampler used for profiling? IsProfiling()725 bool IsProfiling() const { return NoBarrier_Load(&profiling_) > 0; } IncreaseProfilingDepth()726 void IncreaseProfilingDepth() { NoBarrier_AtomicIncrement(&profiling_, 1); } DecreaseProfilingDepth()727 void DecreaseProfilingDepth() { NoBarrier_AtomicIncrement(&profiling_, -1); } 728 729 // Whether the sampler is running (that is, consumes resources). IsActive()730 bool IsActive() const { return NoBarrier_Load(&active_); } 731 isolate()732 Isolate* isolate() { return isolate_; } 733 734 // Used in tests to make sure that stack sampling is performed. samples_taken()735 int samples_taken() const { return samples_taken_; } ResetSamplesTaken()736 void ResetSamplesTaken() { samples_taken_ = 0; } 737 738 class PlatformData; data()739 PlatformData* data() { return data_; } 740 platform_data()741 PlatformData* platform_data() { return data_; } 742 743 protected: 744 virtual void DoSampleStack(TickSample* sample) = 0; 745 746 private: SetActive(bool value)747 void SetActive(bool value) { NoBarrier_Store(&active_, value); } IncSamplesTaken()748 void IncSamplesTaken() { if (++samples_taken_ < 0) samples_taken_ = 0; } 749 750 Isolate* isolate_; 751 const int interval_; 752 Atomic32 profiling_; 753 Atomic32 active_; 754 PlatformData* data_; // Platform specific data. 755 int samples_taken_; // Counts stack samples taken. 756 DISALLOW_IMPLICIT_CONSTRUCTORS(Sampler); 757 }; 758 759 760 } } // namespace v8::internal 761 762 #endif // V8_PLATFORM_H_ 763