1 // Copyright 2006-2008 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 #define V8_INFINITY INFINITY 48 49 // Windows specific stuff. 50 #ifdef WIN32 51 52 // Microsoft Visual C++ specific stuff. 53 #ifdef _MSC_VER 54 55 enum { 56 FP_NAN, 57 FP_INFINITE, 58 FP_ZERO, 59 FP_SUBNORMAL, 60 FP_NORMAL 61 }; 62 63 #undef V8_INFINITY 64 #define V8_INFINITY HUGE_VAL 65 66 namespace v8 { 67 namespace internal { 68 int isfinite(double x); 69 } } 70 int isnan(double x); 71 int isinf(double x); 72 int isless(double x, double y); 73 int isgreater(double x, double y); 74 int fpclassify(double x); 75 int signbit(double x); 76 77 int strncasecmp(const char* s1, const char* s2, int n); 78 79 #endif // _MSC_VER 80 81 // Random is missing on both Visual Studio and MinGW. 82 int random(); 83 84 #endif // WIN32 85 86 // GCC specific stuff 87 #ifdef __GNUC__ 88 89 // Needed for va_list on at least MinGW and Android. 90 #include <stdarg.h> 91 92 #define __GNUC_VERSION__ (__GNUC__ * 10000 + __GNUC_MINOR__ * 100) 93 94 // Unfortunately, the INFINITY macro cannot be used with the '-pedantic' 95 // warning flag and certain versions of GCC due to a bug: 96 // http://gcc.gnu.org/bugzilla/show_bug.cgi?id=11931 97 // For now, we use the more involved template-based version from <limits>, but 98 // only when compiling with GCC versions affected by the bug (2.96.x - 4.0.x) 99 // __GNUC_PREREQ is not defined in GCC for Mac OS X, so we define our own macro 100 #if __GNUC_VERSION__ >= 29600 && __GNUC_VERSION__ < 40100 101 #include <limits> 102 #undef V8_INFINITY 103 #define V8_INFINITY std::numeric_limits<double>::infinity() 104 #endif 105 106 #endif // __GNUC__ 107 108 namespace v8 { 109 namespace internal { 110 111 class Semaphore; 112 113 double ceiling(double x); 114 115 // Forward declarations. 116 class Socket; 117 118 // ---------------------------------------------------------------------------- 119 // OS 120 // 121 // This class has static methods for the different platform specific 122 // functions. Add methods here to cope with differences between the 123 // supported platforms. 124 125 class OS { 126 public: 127 // Initializes the platform OS support. Called once at VM startup. 128 static void Setup(); 129 130 // Returns the accumulated user time for thread. This routine 131 // can be used for profiling. The implementation should 132 // strive for high-precision timer resolution, preferable 133 // micro-second resolution. 134 static int GetUserTime(uint32_t* secs, uint32_t* usecs); 135 136 // Get a tick counter normalized to one tick per microsecond. 137 // Used for calculating time intervals. 138 static int64_t Ticks(); 139 140 // Returns current time as the number of milliseconds since 141 // 00:00:00 UTC, January 1, 1970. 142 static double TimeCurrentMillis(); 143 144 // Returns a string identifying the current time zone. The 145 // timestamp is used for determining if DST is in effect. 146 static const char* LocalTimezone(double time); 147 148 // Returns the local time offset in milliseconds east of UTC without 149 // taking daylight savings time into account. 150 static double LocalTimeOffset(); 151 152 // Returns the daylight savings offset for the given time. 153 static double DaylightSavingsOffset(double time); 154 155 static FILE* FOpen(const char* path, const char* mode); 156 157 // Log file open mode is platform-dependent due to line ends issues. 158 static const char* LogFileOpenMode; 159 160 // Print output to console. This is mostly used for debugging output. 161 // On platforms that has standard terminal output, the output 162 // should go to stdout. 163 static void Print(const char* format, ...); 164 static void VPrint(const char* format, va_list args); 165 166 // Print error output to console. This is mostly used for error message 167 // output. On platforms that has standard terminal output, the output 168 // should go to stderr. 169 static void PrintError(const char* format, ...); 170 static void VPrintError(const char* format, va_list args); 171 172 // Allocate/Free memory used by JS heap. Pages are readable/writable, but 173 // they are not guaranteed to be executable unless 'executable' is true. 174 // Returns the address of allocated memory, or NULL if failed. 175 static void* Allocate(const size_t requested, 176 size_t* allocated, 177 bool is_executable); 178 static void Free(void* address, const size_t size); 179 // Get the Alignment guaranteed by Allocate(). 180 static size_t AllocateAlignment(); 181 182 #ifdef ENABLE_HEAP_PROTECTION 183 // Protect/unprotect a block of memory by marking it read-only/writable. 184 static void Protect(void* address, size_t size); 185 static void Unprotect(void* address, size_t size, bool is_executable); 186 #endif 187 188 // Returns an indication of whether a pointer is in a space that 189 // has been allocated by Allocate(). This method may conservatively 190 // always return false, but giving more accurate information may 191 // improve the robustness of the stack dump code in the presence of 192 // heap corruption. 193 static bool IsOutsideAllocatedSpace(void* pointer); 194 195 // Sleep for a number of milliseconds. 196 static void Sleep(const int milliseconds); 197 198 // Abort the current process. 199 static void Abort(); 200 201 // Debug break. 202 static void DebugBreak(); 203 204 // Walk the stack. 205 static const int kStackWalkError = -1; 206 static const int kStackWalkMaxNameLen = 256; 207 static const int kStackWalkMaxTextLen = 256; 208 struct StackFrame { 209 void* address; 210 char text[kStackWalkMaxTextLen]; 211 }; 212 213 static int StackWalk(Vector<StackFrame> frames); 214 215 // Factory method for creating platform dependent Mutex. 216 // Please use delete to reclaim the storage for the returned Mutex. 217 static Mutex* CreateMutex(); 218 219 // Factory method for creating platform dependent Semaphore. 220 // Please use delete to reclaim the storage for the returned Semaphore. 221 static Semaphore* CreateSemaphore(int count); 222 223 // Factory method for creating platform dependent Socket. 224 // Please use delete to reclaim the storage for the returned Socket. 225 static Socket* CreateSocket(); 226 227 class MemoryMappedFile { 228 public: 229 static MemoryMappedFile* create(const char* name, int size, void* initial); ~MemoryMappedFile()230 virtual ~MemoryMappedFile() { } 231 virtual void* memory() = 0; 232 }; 233 234 // Safe formatting print. Ensures that str is always null-terminated. 235 // Returns the number of chars written, or -1 if output was truncated. 236 static int SNPrintF(Vector<char> str, const char* format, ...); 237 static int VSNPrintF(Vector<char> str, 238 const char* format, 239 va_list args); 240 241 static char* StrChr(char* str, int c); 242 static void StrNCpy(Vector<char> dest, const char* src, size_t n); 243 244 // Support for profiler. Can do nothing, in which case ticks 245 // occuring in shared libraries will not be properly accounted 246 // for. 247 static void LogSharedLibraryAddresses(); 248 249 // Returns the double constant NAN 250 static double nan_value(); 251 252 // Returns the activation frame alignment constraint or zero if 253 // the platform doesn't care. Guaranteed to be a power of two. 254 static int ActivationFrameAlignment(); 255 256 private: 257 static const int msPerSecond = 1000; 258 259 DISALLOW_IMPLICIT_CONSTRUCTORS(OS); 260 }; 261 262 263 class VirtualMemory { 264 public: 265 // Reserves virtual memory with size. 266 explicit VirtualMemory(size_t size); 267 ~VirtualMemory(); 268 269 // Returns whether the memory has been reserved. 270 bool IsReserved(); 271 272 // Returns the start address of the reserved memory. address()273 void* address() { 274 ASSERT(IsReserved()); 275 return address_; 276 }; 277 278 // Returns the size of the reserved memory. size()279 size_t size() { return size_; } 280 281 // Commits real memory. Returns whether the operation succeeded. 282 bool Commit(void* address, size_t size, bool is_executable); 283 284 // Uncommit real memory. Returns whether the operation succeeded. 285 bool Uncommit(void* address, size_t size); 286 287 private: 288 void* address_; // Start address of the virtual memory. 289 size_t size_; // Size of the virtual memory. 290 }; 291 292 293 // ---------------------------------------------------------------------------- 294 // ThreadHandle 295 // 296 // A ThreadHandle represents a thread identifier for a thread. The ThreadHandle 297 // does not own the underlying os handle. Thread handles can be used for 298 // refering to threads and testing equality. 299 300 class ThreadHandle { 301 public: 302 enum Kind { SELF, INVALID }; 303 explicit ThreadHandle(Kind kind); 304 305 // Destructor. 306 ~ThreadHandle(); 307 308 // Test for thread running. 309 bool IsSelf() const; 310 311 // Test for valid thread handle. 312 bool IsValid() const; 313 314 // Get platform-specific data. 315 class PlatformData; thread_handle_data()316 PlatformData* thread_handle_data() { return data_; } 317 318 // Initialize the handle to kind 319 void Initialize(Kind kind); 320 321 private: 322 PlatformData* data_; // Captures platform dependent data. 323 }; 324 325 326 // ---------------------------------------------------------------------------- 327 // Thread 328 // 329 // Thread objects are used for creating and running threads. When the start() 330 // method is called the new thread starts running the run() method in the new 331 // thread. The Thread object should not be deallocated before the thread has 332 // terminated. 333 334 class Thread: public ThreadHandle { 335 public: 336 // Opaque data type for thread-local storage keys. 337 enum LocalStorageKey {}; 338 339 // Create new thread. 340 Thread(); 341 virtual ~Thread(); 342 343 // Start new thread by calling the Run() method in the new thread. 344 void Start(); 345 346 // Wait until thread terminates. 347 void Join(); 348 349 // Abstract method for run handler. 350 virtual void Run() = 0; 351 352 // Thread-local storage. 353 static LocalStorageKey CreateThreadLocalKey(); 354 static void DeleteThreadLocalKey(LocalStorageKey key); 355 static void* GetThreadLocal(LocalStorageKey key); GetThreadLocalInt(LocalStorageKey key)356 static int GetThreadLocalInt(LocalStorageKey key) { 357 return static_cast<int>(reinterpret_cast<intptr_t>(GetThreadLocal(key))); 358 } 359 static void SetThreadLocal(LocalStorageKey key, void* value); SetThreadLocalInt(LocalStorageKey key,int value)360 static void SetThreadLocalInt(LocalStorageKey key, int value) { 361 SetThreadLocal(key, reinterpret_cast<void*>(static_cast<intptr_t>(value))); 362 } HasThreadLocal(LocalStorageKey key)363 static bool HasThreadLocal(LocalStorageKey key) { 364 return GetThreadLocal(key) != NULL; 365 } 366 367 // A hint to the scheduler to let another thread run. 368 static void YieldCPU(); 369 370 private: 371 class PlatformData; 372 PlatformData* data_; 373 DISALLOW_COPY_AND_ASSIGN(Thread); 374 }; 375 376 377 // ---------------------------------------------------------------------------- 378 // Mutex 379 // 380 // Mutexes are used for serializing access to non-reentrant sections of code. 381 // The implementations of mutex should allow for nested/recursive locking. 382 383 class Mutex { 384 public: ~Mutex()385 virtual ~Mutex() {} 386 387 // Locks the given mutex. If the mutex is currently unlocked, it becomes 388 // locked and owned by the calling thread, and immediately. If the mutex 389 // is already locked by another thread, suspends the calling thread until 390 // the mutex is unlocked. 391 virtual int Lock() = 0; 392 393 // Unlocks the given mutex. The mutex is assumed to be locked and owned by 394 // the calling thread on entrance. 395 virtual int Unlock() = 0; 396 }; 397 398 399 // ---------------------------------------------------------------------------- 400 // ScopedLock 401 // 402 // Stack-allocated ScopedLocks provide block-scoped locking and unlocking 403 // of a mutex. 404 class ScopedLock { 405 public: ScopedLock(Mutex * mutex)406 explicit ScopedLock(Mutex* mutex): mutex_(mutex) { 407 mutex_->Lock(); 408 } ~ScopedLock()409 ~ScopedLock() { 410 mutex_->Unlock(); 411 } 412 413 private: 414 Mutex* mutex_; 415 DISALLOW_COPY_AND_ASSIGN(ScopedLock); 416 }; 417 418 419 // ---------------------------------------------------------------------------- 420 // Semaphore 421 // 422 // A semaphore object is a synchronization object that maintains a count. The 423 // count is decremented each time a thread completes a wait for the semaphore 424 // object and incremented each time a thread signals the semaphore. When the 425 // count reaches zero, threads waiting for the semaphore blocks until the 426 // count becomes non-zero. 427 428 class Semaphore { 429 public: ~Semaphore()430 virtual ~Semaphore() {} 431 432 // Suspends the calling thread until the semaphore counter is non zero 433 // and then decrements the semaphore counter. 434 virtual void Wait() = 0; 435 436 // Suspends the calling thread until the counter is non zero or the timeout 437 // time has passsed. If timeout happens the return value is false and the 438 // counter is unchanged. Otherwise the semaphore counter is decremented and 439 // true is returned. The timeout value is specified in microseconds. 440 virtual bool Wait(int timeout) = 0; 441 442 // Increments the semaphore counter. 443 virtual void Signal() = 0; 444 }; 445 446 447 // ---------------------------------------------------------------------------- 448 // Socket 449 // 450 451 class Socket { 452 public: ~Socket()453 virtual ~Socket() {} 454 455 // Server initialization. 456 virtual bool Bind(const int port) = 0; 457 virtual bool Listen(int backlog) const = 0; 458 virtual Socket* Accept() const = 0; 459 460 // Client initialization. 461 virtual bool Connect(const char* host, const char* port) = 0; 462 463 // Shutdown socket for both read and write. This causes blocking Send and 464 // Receive calls to exit. After Shutdown the Socket object cannot be used for 465 // any communication. 466 virtual bool Shutdown() = 0; 467 468 // Data Transimission 469 virtual int Send(const char* data, int len) const = 0; 470 virtual int Receive(char* data, int len) const = 0; 471 472 // Set the value of the SO_REUSEADDR socket option. 473 virtual bool SetReuseAddress(bool reuse_address) = 0; 474 475 virtual bool IsValid() const = 0; 476 477 static bool Setup(); 478 static int LastError(); 479 static uint16_t HToN(uint16_t value); 480 static uint16_t NToH(uint16_t value); 481 static uint32_t HToN(uint32_t value); 482 static uint32_t NToH(uint32_t value); 483 }; 484 485 486 #ifdef ENABLE_LOGGING_AND_PROFILING 487 // ---------------------------------------------------------------------------- 488 // Sampler 489 // 490 // A sampler periodically samples the state of the VM and optionally 491 // (if used for profiling) the program counter and stack pointer for 492 // the thread that created it. 493 494 // TickSample captures the information collected for each sample. 495 class TickSample { 496 public: TickSample()497 TickSample() : pc(0), sp(0), fp(0), state(OTHER), frames_count(0) {} 498 uintptr_t pc; // Instruction pointer. 499 uintptr_t sp; // Stack pointer. 500 uintptr_t fp; // Frame pointer. 501 StateTag state; // The state of the VM. 502 static const int kMaxFramesCount = 100; 503 EmbeddedVector<Address, kMaxFramesCount> stack; // Call stack. 504 int frames_count; // Number of captured frames. 505 }; 506 507 class Sampler { 508 public: 509 // Initialize sampler. 510 explicit Sampler(int interval, bool profiling); 511 virtual ~Sampler(); 512 513 // Performs stack sampling. 514 virtual void SampleStack(TickSample* sample) = 0; 515 516 // This method is called for each sampling period with the current 517 // program counter. 518 virtual void Tick(TickSample* sample) = 0; 519 520 // Start and stop sampler. 521 void Start(); 522 void Stop(); 523 524 // Is the sampler used for profiling. IsProfiling()525 inline bool IsProfiling() { return profiling_; } 526 527 // Whether the sampler is running (that is, consumes resources). IsActive()528 inline bool IsActive() { return active_; } 529 530 class PlatformData; 531 532 private: 533 const int interval_; 534 const bool profiling_; 535 bool active_; 536 PlatformData* data_; // Platform specific data. 537 DISALLOW_IMPLICIT_CONSTRUCTORS(Sampler); 538 }; 539 540 #endif // ENABLE_LOGGING_AND_PROFILING 541 542 } } // namespace v8::internal 543 544 #endif // V8_PLATFORM_H_ 545