00001 // Copyright 2006-2008 the V8 project authors. All rights reserved. 00002 // Redistribution and use in source and binary forms, with or without 00003 // modification, are permitted provided that the following conditions are 00004 // met: 00005 // 00006 // * Redistributions of source code must retain the above copyright 00007 // notice, this list of conditions and the following disclaimer. 00008 // * Redistributions in binary form must reproduce the above 00009 // copyright notice, this list of conditions and the following 00010 // disclaimer in the documentation and/or other materials provided 00011 // with the distribution. 00012 // * Neither the name of Google Inc. nor the names of its 00013 // contributors may be used to endorse or promote products derived 00014 // from this software without specific prior written permission. 00015 // 00016 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 00017 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 00018 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 00019 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 00020 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 00021 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 00022 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 00023 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 00024 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 00025 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 00026 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 00027 00028 // This module contains the platform-specific code. This make the rest of the 00029 // code less dependent on operating system, compilers and runtime libraries. 00030 // This module does specifically not deal with differences between different 00031 // processor architecture. 00032 // The platform classes have the same definition for all platforms. The 00033 // implementation for a particular platform is put in platform_<os>.cc. 00034 // The build system then uses the implementation for the target platform. 00035 // 00036 // This design has been choosen because it is simple and fast. Alternatively, 00037 // the platform dependent classes could have been implemented using abstract 00038 // superclasses with virtual methods and having specializations for each 00039 // platform. This design was rejected because it was more complicated and 00040 // slower. It would require factory methods for selecting the right 00041 // implementation and the overhead of virtual methods for performance 00042 // sensitive like mutex locking/unlocking. 00043 00044 #ifndef V8_PLATFORM_H_ 00045 #define V8_PLATFORM_H_ 00046 00047 #ifdef WIN32 00048 00049 enum { 00050 FP_NAN, 00051 FP_INFINITE, 00052 FP_ZERO, 00053 FP_SUBNORMAL, 00054 FP_NORMAL 00055 }; 00056 00057 #define INFINITY HUGE_VAL 00058 00059 namespace v8 { namespace internal { 00060 int isfinite(double x); 00061 } } 00062 int isnan(double x); 00063 int isinf(double x); 00064 int isless(double x, double y); 00065 int isgreater(double x, double y); 00066 int fpclassify(double x); 00067 int signbit(double x); 00068 00069 int random(); 00070 00071 int strncasecmp(const char* s1, const char* s2, int n); 00072 00073 #else 00074 00075 // Unfortunately, the INFINITY macro cannot be used with the '-pedantic' 00076 // warning flag and certain versions of GCC due to a bug: 00077 // http://gcc.gnu.org/bugzilla/show_bug.cgi?id=11931 00078 // For now, we use the more involved template-based version from <limits>, but 00079 // only when compiling with GCC versions affected by the bug (2.96.x - 4.0.x) 00080 // __GNUC_PREREQ is not defined in GCC for Mac OS X, so we define our own macro 00081 #if defined(__GNUC__) 00082 #define __GNUC_VERSION__ (__GNUC__ * 10000 + __GNUC_MINOR__ * 100) 00083 #endif 00084 00085 #if __GNUC_VERSION__ >= 29600 && __GNUC_VERSION__ < 40100 00086 #include <limits> 00087 #undef INFINITY 00088 #define INFINITY std::numeric_limits<double>::infinity() 00089 #endif 00090 00091 #endif // WIN32 00092 00093 namespace v8 { namespace internal { 00094 00095 double ceiling(double x); 00096 00097 // ---------------------------------------------------------------------------- 00098 // OS 00099 // 00100 // This class has static methods for the different platform specific 00101 // functions. Add methods here to cope with differences between the 00102 // supported platforms. 00103 00104 class OS { 00105 public: 00106 // Initializes the platform OS support. Called once at VM startup. 00107 static void Setup(); 00108 00109 // Returns the accumulated user time for thread. This routine 00110 // can be used for profiling. The implementation should 00111 // strive for high-precision timer resolution, preferable 00112 // micro-second resolution. 00113 static int GetUserTime(uint32_t* secs, uint32_t* usecs); 00114 00115 // Get a tick counter normalized to one tick per microsecond. 00116 // Used for calculating time intervals. 00117 static int64_t Ticks(); 00118 00119 // Returns current time as the number of milliseconds since 00120 // 00:00:00 UTC, January 1, 1970. 00121 static double TimeCurrentMillis(); 00122 00123 // Returns a string identifying the current time zone. The 00124 // timestamp is used for determining if DST is in effect. 00125 static char* LocalTimezone(double time); 00126 00127 // Returns the local time offset in milliseconds east of UTC without 00128 // taking daylight savings time into account. 00129 static double LocalTimeOffset(); 00130 00131 // Returns the daylight savings offset for the given time. 00132 static double DaylightSavingsOffset(double time); 00133 00134 static FILE* FOpen(const char* path, const char* mode); 00135 00136 // Print output to console. This is mostly used for debugging output. 00137 // On platforms that has standard terminal output, the output 00138 // should go to stdout. 00139 static void Print(const char* format, ...); 00140 static void VPrint(const char* format, va_list args); 00141 00142 // Print error output to console. This is mostly used for error message 00143 // output. On platforms that has standard terminal output, the output 00144 // should go to stderr. 00145 static void PrintError(const char* format, ...); 00146 static void VPrintError(const char* format, va_list args); 00147 00148 // Allocate/Free memory used by JS heap. Pages are readable/writeable, but 00149 // they are not guaranteed to be executable unless 'executable' is true. 00150 // Returns the address of allocated memory, or NULL if failed. 00151 static void* Allocate(const size_t requested, 00152 size_t* allocated, 00153 bool executable); 00154 static void Free(void* buf, const size_t length); 00155 // Get the Alignment guaranteed by Allocate(). 00156 static size_t AllocateAlignment(); 00157 00158 // Returns an indication of whether a pointer is in a space that 00159 // has been allocated by Allocate(). This method may conservatively 00160 // always return false, but giving more accurate information may 00161 // improve the robustness of the stack dump code in the presence of 00162 // heap corruption. 00163 static bool IsOutsideAllocatedSpace(void* pointer); 00164 00165 // Sleep for a number of miliseconds. 00166 static void Sleep(const int miliseconds); 00167 00168 // Abort the current process. 00169 static void Abort(); 00170 00171 // Debug break. 00172 static void DebugBreak(); 00173 00174 // Walk the stack. 00175 static const int kStackWalkError = -1; 00176 static const int kStackWalkMaxNameLen = 256; 00177 static const int kStackWalkMaxTextLen = 256; 00178 struct StackFrame { 00179 void* address; 00180 char text[kStackWalkMaxTextLen]; 00181 }; 00182 00183 static int StackWalk(StackFrame* frames, int frames_size); 00184 00185 // Factory method for creating platform dependent Mutex. 00186 // Please use delete to reclaim the storage for the returned Mutex. 00187 static Mutex* CreateMutex(); 00188 00189 // Factory method for creating platform dependent Semaphore. 00190 // Please use delete to reclaim the storage for the returned Semaphore. 00191 static Semaphore* CreateSemaphore(int count); 00192 00193 class MemoryMappedFile { 00194 public: 00195 static MemoryMappedFile* create(const char* name, int size, void* initial); 00196 virtual ~MemoryMappedFile() { } 00197 virtual void* memory() = 0; 00198 }; 00199 00200 // Safe formatting print. Ensures that str is always null-terminated. 00201 // Returns the number of chars written, or -1 if output was truncated. 00202 static int SNPrintF(Vector<char> str, const char* format, ...); 00203 static int VSNPrintF(Vector<char> str, 00204 const char* format, 00205 va_list args); 00206 00207 static void StrNCpy(Vector<char> dest, const char* src, size_t n); 00208 static void WcsCpy(Vector<wchar_t> dest, const wchar_t* src); 00209 static char* StrDup(const char* str); 00210 00211 // Support for profiler. Can do nothing, in which case ticks 00212 // occuring in shared libraries will not be properly accounted 00213 // for. 00214 static void LogSharedLibraryAddresses(); 00215 00216 // Returns the double constant NAN 00217 static double nan_value(); 00218 00219 // Returns the activation frame alignment constraint or zero if 00220 // the platform doesn't care. Guaranteed to be a power of two. 00221 static int ActivationFrameAlignment(); 00222 00223 private: 00224 static const int msPerSecond = 1000; 00225 00226 DISALLOW_IMPLICIT_CONSTRUCTORS(OS); 00227 }; 00228 00229 00230 class VirtualMemory { 00231 public: 00232 // Reserves virtual memory with size. 00233 explicit VirtualMemory(size_t size); 00234 ~VirtualMemory(); 00235 00236 // Returns whether the memory has been reserved. 00237 bool IsReserved(); 00238 00239 // Returns the start address of the reserved memory. 00240 void* address() { 00241 ASSERT(IsReserved()); 00242 return address_; 00243 }; 00244 00245 // Returns the size of the reserved memory. 00246 size_t size() { return size_; } 00247 00248 // Commits real memory. Returns whether the operation succeeded. 00249 bool Commit(void* address, size_t size, bool executable); 00250 00251 // Uncommit real memory. Returns whether the operation succeeded. 00252 bool Uncommit(void* address, size_t size); 00253 00254 private: 00255 void* address_; // Start address of the virtual memory. 00256 size_t size_; // Size of the virtual memory. 00257 }; 00258 00259 00260 // ---------------------------------------------------------------------------- 00261 // ThreadHandle 00262 // 00263 // A ThreadHandle represents a thread identifier for a thread. The ThreadHandle 00264 // does not own the underlying os handle. Thread handles can be used for 00265 // refering to threads and testing equality. 00266 00267 class ThreadHandle { 00268 public: 00269 enum Kind { SELF, INVALID }; 00270 explicit ThreadHandle(Kind kind); 00271 00272 // Destructor. 00273 ~ThreadHandle(); 00274 00275 // Test for thread running. 00276 bool IsSelf() const; 00277 00278 // Test for valid thread handle. 00279 bool IsValid() const; 00280 00281 // Get platform-specific data. 00282 class PlatformData; 00283 PlatformData* thread_handle_data() { return data_; } 00284 00285 // Initialize the handle to kind 00286 void Initialize(Kind kind); 00287 00288 private: 00289 PlatformData* data_; // Captures platform dependent data. 00290 }; 00291 00292 00293 // ---------------------------------------------------------------------------- 00294 // Thread 00295 // 00296 // Thread objects are used for creating and running threads. When the start() 00297 // method is called the new thread starts running the run() method in the new 00298 // thread. The Thread object should not be deallocated before the thread has 00299 // terminated. 00300 00301 class Thread: public ThreadHandle { 00302 public: 00303 // Opaque data type for thread-local storage keys. 00304 enum LocalStorageKey {}; 00305 00306 // Create new thread. 00307 Thread(); 00308 virtual ~Thread(); 00309 00310 // Start new thread by calling the Run() method in the new thread. 00311 void Start(); 00312 00313 // Wait until thread terminates. 00314 void Join(); 00315 00316 // Abstract method for run handler. 00317 virtual void Run() = 0; 00318 00319 // Thread-local storage. 00320 static LocalStorageKey CreateThreadLocalKey(); 00321 static void DeleteThreadLocalKey(LocalStorageKey key); 00322 static void* GetThreadLocal(LocalStorageKey key); 00323 static void SetThreadLocal(LocalStorageKey key, void* value); 00324 00325 // A hint to the scheduler to let another thread run. 00326 static void YieldCPU(); 00327 00328 private: 00329 class PlatformData; 00330 PlatformData* data_; 00331 DISALLOW_COPY_AND_ASSIGN(Thread); 00332 }; 00333 00334 00335 // ---------------------------------------------------------------------------- 00336 // Mutex 00337 // 00338 // Mutexes are used for serializing access to non-reentrant sections of code. 00339 // The implementations of mutex should allow for nested/recursive locking. 00340 00341 class Mutex { 00342 public: 00343 virtual ~Mutex() {} 00344 00345 // Locks the given mutex. If the mutex is currently unlocked, it becomes 00346 // locked and owned by the calling thread, and immediately. If the mutex 00347 // is already locked by another thread, suspends the calling thread until 00348 // the mutex is unlocked. 00349 virtual int Lock() = 0; 00350 00351 // Unlocks the given mutex. The mutex is assumed to be locked and owned by 00352 // the calling thread on entrance. 00353 virtual int Unlock() = 0; 00354 }; 00355 00356 00357 // ---------------------------------------------------------------------------- 00358 // ScopedLock 00359 // 00360 // Stack-allocated ScopedLocks provide block-scoped locking and unlocking 00361 // of a mutex. 00362 class ScopedLock { 00363 public: 00364 explicit ScopedLock(Mutex* mutex): mutex_(mutex) { 00365 mutex_->Lock(); 00366 } 00367 ~ScopedLock() { 00368 mutex_->Unlock(); 00369 } 00370 00371 private: 00372 Mutex* mutex_; 00373 DISALLOW_COPY_AND_ASSIGN(ScopedLock); 00374 }; 00375 00376 00377 // ---------------------------------------------------------------------------- 00378 // Semaphore 00379 // 00380 // A semaphore object is a synchronization object that maintains a count. The 00381 // count is decremented each time a thread completes a wait for the semaphore 00382 // object and incremented each time a thread signals the semaphore. When the 00383 // count reaches zero, threads waiting for the semaphore blocks until the 00384 // count becomes non-zero. 00385 00386 class Semaphore { 00387 public: 00388 virtual ~Semaphore() {} 00389 00390 // Suspends the calling thread until the counter is non zero 00391 // and then decrements the semaphore counter. 00392 virtual void Wait() = 0; 00393 00394 // Increments the semaphore counter. 00395 virtual void Signal() = 0; 00396 }; 00397 00398 00399 #ifdef ENABLE_LOGGING_AND_PROFILING 00400 // ---------------------------------------------------------------------------- 00401 // Sampler 00402 // 00403 // A sampler periodically samples the state of the VM and optionally 00404 // (if used for profiling) the program counter and stack pointer for 00405 // the thread that created it. 00406 00407 // TickSample captures the information collected for each sample. 00408 class TickSample { 00409 public: 00410 TickSample() : pc(0), sp(0), state(OTHER) {} 00411 unsigned int pc; // Instruction pointer. 00412 unsigned int sp; // Stack pointer. 00413 StateTag state; // The state of the VM. 00414 }; 00415 00416 class Sampler { 00417 public: 00418 // Initialize sampler. 00419 explicit Sampler(int interval, bool profiling); 00420 virtual ~Sampler(); 00421 00422 // This method is called for each sampling period with the current 00423 // program counter. 00424 virtual void Tick(TickSample* sample) = 0; 00425 00426 // Start and stop sampler. 00427 void Start(); 00428 void Stop(); 00429 00430 // Is the sampler used for profiling. 00431 inline bool IsProfiling() { return profiling_; } 00432 00433 class PlatformData; 00434 protected: 00435 inline bool IsActive() { return active_; } 00436 00437 private: 00438 int interval_; 00439 bool profiling_; 00440 bool active_; 00441 PlatformData* data_; // Platform specific data. 00442 DISALLOW_IMPLICIT_CONSTRUCTORS(Sampler); 00443 }; 00444 00445 #endif // ENABLE_LOGGING_AND_PROFILING 00446 00447 } } // namespace v8::internal 00448 00449 #endif // V8_PLATFORM_H_