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#define V8_INFINITY INFINITY
48
49// Windows specific stuff.
50#ifdef WIN32
51
52// Microsoft Visual C++ specific stuff.
53#ifdef _MSC_VER
54
55enum {
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
66namespace v8 {
67namespace internal {
68int isfinite(double x);
69} }
70int isnan(double x);
71int isinf(double x);
72int isless(double x, double y);
73int isgreater(double x, double y);
74int fpclassify(double x);
75int signbit(double x);
76
77int 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.
82int random();
83
84#endif  // WIN32
85
86
87#ifdef __sun
88# ifndef signbit
89int signbit(double x);
90# endif
91#endif
92
93
94// GCC specific stuff
95#ifdef __GNUC__
96
97// Needed for va_list on at least MinGW and Android.
98#include <stdarg.h>
99
100#define __GNUC_VERSION__ (__GNUC__ * 10000 + __GNUC_MINOR__ * 100)
101
102// Unfortunately, the INFINITY macro cannot be used with the '-pedantic'
103// warning flag and certain versions of GCC due to a bug:
104// http://gcc.gnu.org/bugzilla/show_bug.cgi?id=11931
105// For now, we use the more involved template-based version from <limits>, but
106// only when compiling with GCC versions affected by the bug (2.96.x - 4.0.x)
107// __GNUC_PREREQ is not defined in GCC for Mac OS X, so we define our own macro
108#if __GNUC_VERSION__ >= 29600 && __GNUC_VERSION__ < 40100
109#include <limits>
110#undef V8_INFINITY
111#define V8_INFINITY std::numeric_limits<double>::infinity()
112#endif
113
114#endif  // __GNUC__
115
116#include "atomicops.h"
117#include "platform-tls.h"
118#include "utils.h"
119#include "v8globals.h"
120
121namespace v8 {
122namespace internal {
123
124// Use AtomicWord for a machine-sized pointer. It is assumed that
125// reads and writes of naturally aligned values of this type are atomic.
126typedef intptr_t AtomicWord;
127
128class Semaphore;
129class Mutex;
130
131double ceiling(double x);
132double modulo(double x, double y);
133
134// Forward declarations.
135class Socket;
136
137// ----------------------------------------------------------------------------
138// OS
139//
140// This class has static methods for the different platform specific
141// functions. Add methods here to cope with differences between the
142// supported platforms.
143
144class OS {
145 public:
146  // Initializes the platform OS support. Called once at VM startup.
147  static void Setup();
148
149  // Returns the accumulated user time for thread. This routine
150  // can be used for profiling. The implementation should
151  // strive for high-precision timer resolution, preferable
152  // micro-second resolution.
153  static int GetUserTime(uint32_t* secs,  uint32_t* usecs);
154
155  // Get a tick counter normalized to one tick per microsecond.
156  // Used for calculating time intervals.
157  static int64_t Ticks();
158
159  // Returns current time as the number of milliseconds since
160  // 00:00:00 UTC, January 1, 1970.
161  static double TimeCurrentMillis();
162
163  // Returns a string identifying the current time zone. The
164  // timestamp is used for determining if DST is in effect.
165  static const char* LocalTimezone(double time);
166
167  // Returns the local time offset in milliseconds east of UTC without
168  // taking daylight savings time into account.
169  static double LocalTimeOffset();
170
171  // Returns the daylight savings offset for the given time.
172  static double DaylightSavingsOffset(double time);
173
174  // Returns last OS error.
175  static int GetLastError();
176
177  static FILE* FOpen(const char* path, const char* mode);
178  static bool Remove(const char* path);
179
180  // Log file open mode is platform-dependent due to line ends issues.
181  static const char* const LogFileOpenMode;
182
183  // Print output to console. This is mostly used for debugging output.
184  // On platforms that has standard terminal output, the output
185  // should go to stdout.
186  static void Print(const char* format, ...);
187  static void VPrint(const char* format, va_list args);
188
189  // Print output to a file. This is mostly used for debugging output.
190  static void FPrint(FILE* out, const char* format, ...);
191  static void VFPrint(FILE* out, const char* format, va_list args);
192
193  // Print error output to console. This is mostly used for error message
194  // output. On platforms that has standard terminal output, the output
195  // should go to stderr.
196  static void PrintError(const char* format, ...);
197  static void VPrintError(const char* format, va_list args);
198
199  // Allocate/Free memory used by JS heap. Pages are readable/writable, but
200  // they are not guaranteed to be executable unless 'executable' is true.
201  // Returns the address of allocated memory, or NULL if failed.
202  static void* Allocate(const size_t requested,
203                        size_t* allocated,
204                        bool is_executable);
205  static void Free(void* address, const size_t size);
206  // Get the Alignment guaranteed by Allocate().
207  static size_t AllocateAlignment();
208
209#ifdef ENABLE_HEAP_PROTECTION
210  // Protect/unprotect a block of memory by marking it read-only/writable.
211  static void Protect(void* address, size_t size);
212  static void Unprotect(void* address, size_t size, bool is_executable);
213#endif
214
215  // Returns an indication of whether a pointer is in a space that
216  // has been allocated by Allocate().  This method may conservatively
217  // always return false, but giving more accurate information may
218  // improve the robustness of the stack dump code in the presence of
219  // heap corruption.
220  static bool IsOutsideAllocatedSpace(void* pointer);
221
222  // Sleep for a number of milliseconds.
223  static void Sleep(const int milliseconds);
224
225  // Abort the current process.
226  static void Abort();
227
228  // Debug break.
229  static void DebugBreak();
230
231  // Walk the stack.
232  static const int kStackWalkError = -1;
233  static const int kStackWalkMaxNameLen = 256;
234  static const int kStackWalkMaxTextLen = 256;
235  struct StackFrame {
236    void* address;
237    char text[kStackWalkMaxTextLen];
238  };
239
240  static int StackWalk(Vector<StackFrame> frames);
241
242  // Factory method for creating platform dependent Mutex.
243  // Please use delete to reclaim the storage for the returned Mutex.
244  static Mutex* CreateMutex();
245
246  // Factory method for creating platform dependent Semaphore.
247  // Please use delete to reclaim the storage for the returned Semaphore.
248  static Semaphore* CreateSemaphore(int count);
249
250  // Factory method for creating platform dependent Socket.
251  // Please use delete to reclaim the storage for the returned Socket.
252  static Socket* CreateSocket();
253
254  class MemoryMappedFile {
255   public:
256    static MemoryMappedFile* open(const char* name);
257    static MemoryMappedFile* create(const char* name, int size, void* initial);
258    virtual ~MemoryMappedFile() { }
259    virtual void* memory() = 0;
260    virtual int size() = 0;
261  };
262
263  // Safe formatting print. Ensures that str is always null-terminated.
264  // Returns the number of chars written, or -1 if output was truncated.
265  static int SNPrintF(Vector<char> str, const char* format, ...);
266  static int VSNPrintF(Vector<char> str,
267                       const char* format,
268                       va_list args);
269
270  static char* StrChr(char* str, int c);
271  static void StrNCpy(Vector<char> dest, const char* src, size_t n);
272
273  // Support for the profiler.  Can do nothing, in which case ticks
274  // occuring in shared libraries will not be properly accounted for.
275  static void LogSharedLibraryAddresses();
276
277  // Support for the profiler.  Notifies the external profiling
278  // process that a code moving garbage collection starts.  Can do
279  // nothing, in which case the code objects must not move (e.g., by
280  // using --never-compact) if accurate profiling is desired.
281  static void SignalCodeMovingGC();
282
283  // The return value indicates the CPU features we are sure of because of the
284  // OS.  For example MacOSX doesn't run on any x86 CPUs that don't have SSE2
285  // instructions.
286  // This is a little messy because the interpretation is subject to the cross
287  // of the CPU and the OS.  The bits in the answer correspond to the bit
288  // positions indicated by the members of the CpuFeature enum from globals.h
289  static uint64_t CpuFeaturesImpliedByPlatform();
290
291  // Returns the double constant NAN
292  static double nan_value();
293
294  // Support runtime detection of VFP3 on ARM CPUs.
295  static bool ArmCpuHasFeature(CpuFeature feature);
296
297  // Support runtime detection of FPU on MIPS CPUs.
298  static bool MipsCpuHasFeature(CpuFeature feature);
299
300  // Returns the activation frame alignment constraint or zero if
301  // the platform doesn't care. Guaranteed to be a power of two.
302  static int ActivationFrameAlignment();
303
304  static void ReleaseStore(volatile AtomicWord* ptr, AtomicWord value);
305
306#if defined(V8_TARGET_ARCH_IA32)
307  // Copy memory area to disjoint memory area.
308  static void MemCopy(void* dest, const void* src, size_t size);
309  // Limit below which the extra overhead of the MemCopy function is likely
310  // to outweigh the benefits of faster copying.
311  static const int kMinComplexMemCopy = 64;
312  typedef void (*MemCopyFunction)(void* dest, const void* src, size_t size);
313
314#else  // V8_TARGET_ARCH_IA32
315  static void MemCopy(void* dest, const void* src, size_t size) {
316    memcpy(dest, src, size);
317  }
318  static const int kMinComplexMemCopy = 256;
319#endif  // V8_TARGET_ARCH_IA32
320
321 private:
322  static const int msPerSecond = 1000;
323
324  DISALLOW_IMPLICIT_CONSTRUCTORS(OS);
325};
326
327
328class VirtualMemory {
329 public:
330  // Reserves virtual memory with size.
331  explicit VirtualMemory(size_t size);
332  ~VirtualMemory();
333
334  // Returns whether the memory has been reserved.
335  bool IsReserved();
336
337  // Returns the start address of the reserved memory.
338  void* address() {
339    ASSERT(IsReserved());
340    return address_;
341  }
342
343  // Returns the size of the reserved memory.
344  size_t size() { return size_; }
345
346  // Commits real memory. Returns whether the operation succeeded.
347  bool Commit(void* address, size_t size, bool is_executable);
348
349  // Uncommit real memory.  Returns whether the operation succeeded.
350  bool Uncommit(void* address, size_t size);
351
352 private:
353  void* address_;  // Start address of the virtual memory.
354  size_t size_;  // Size of the virtual memory.
355};
356
357// ----------------------------------------------------------------------------
358// Thread
359//
360// Thread objects are used for creating and running threads. When the start()
361// method is called the new thread starts running the run() method in the new
362// thread. The Thread object should not be deallocated before the thread has
363// terminated.
364
365class Thread {
366 public:
367  // Opaque data type for thread-local storage keys.
368  // LOCAL_STORAGE_KEY_MIN_VALUE and LOCAL_STORAGE_KEY_MAX_VALUE are specified
369  // to ensure that enumeration type has correct value range (see Issue 830 for
370  // more details).
371  enum LocalStorageKey {
372    LOCAL_STORAGE_KEY_MIN_VALUE = kMinInt,
373    LOCAL_STORAGE_KEY_MAX_VALUE = kMaxInt
374  };
375
376  struct Options {
377    Options() : name("v8:<unknown>"), stack_size(0) {}
378
379    const char* name;
380    int stack_size;
381  };
382
383  // Create new thread (with a value for storing in the TLS isolate field).
384  Thread(Isolate* isolate, const Options& options);
385  Thread(Isolate* isolate, const char* name);
386  virtual ~Thread();
387
388  // Start new thread by calling the Run() method in the new thread.
389  void Start();
390
391  // Wait until thread terminates.
392  void Join();
393
394  inline const char* name() const {
395    return name_;
396  }
397
398  // Abstract method for run handler.
399  virtual void Run() = 0;
400
401  // Thread-local storage.
402  static LocalStorageKey CreateThreadLocalKey();
403  static void DeleteThreadLocalKey(LocalStorageKey key);
404  static void* GetThreadLocal(LocalStorageKey key);
405  static int GetThreadLocalInt(LocalStorageKey key) {
406    return static_cast<int>(reinterpret_cast<intptr_t>(GetThreadLocal(key)));
407  }
408  static void SetThreadLocal(LocalStorageKey key, void* value);
409  static void SetThreadLocalInt(LocalStorageKey key, int value) {
410    SetThreadLocal(key, reinterpret_cast<void*>(static_cast<intptr_t>(value)));
411  }
412  static bool HasThreadLocal(LocalStorageKey key) {
413    return GetThreadLocal(key) != NULL;
414  }
415
416#ifdef V8_FAST_TLS_SUPPORTED
417  static inline void* GetExistingThreadLocal(LocalStorageKey key) {
418    void* result = reinterpret_cast<void*>(
419        InternalGetExistingThreadLocal(static_cast<intptr_t>(key)));
420    ASSERT(result == GetThreadLocal(key));
421    return result;
422  }
423#else
424  static inline void* GetExistingThreadLocal(LocalStorageKey key) {
425    return GetThreadLocal(key);
426  }
427#endif
428
429  // A hint to the scheduler to let another thread run.
430  static void YieldCPU();
431
432  Isolate* isolate() const { return isolate_; }
433
434  // The thread name length is limited to 16 based on Linux's implementation of
435  // prctl().
436  static const int kMaxThreadNameLength = 16;
437
438  class PlatformData;
439  PlatformData* data() { return data_; }
440
441 private:
442  void set_name(const char *name);
443
444  PlatformData* data_;
445
446  Isolate* isolate_;
447  char name_[kMaxThreadNameLength];
448  int stack_size_;
449
450  DISALLOW_COPY_AND_ASSIGN(Thread);
451};
452
453
454// ----------------------------------------------------------------------------
455// Mutex
456//
457// Mutexes are used for serializing access to non-reentrant sections of code.
458// The implementations of mutex should allow for nested/recursive locking.
459
460class Mutex {
461 public:
462  virtual ~Mutex() {}
463
464  // Locks the given mutex. If the mutex is currently unlocked, it becomes
465  // locked and owned by the calling thread, and immediately. If the mutex
466  // is already locked by another thread, suspends the calling thread until
467  // the mutex is unlocked.
468  virtual int Lock() = 0;
469
470  // Unlocks the given mutex. The mutex is assumed to be locked and owned by
471  // the calling thread on entrance.
472  virtual int Unlock() = 0;
473
474  // Tries to lock the given mutex. Returns whether the mutex was
475  // successfully locked.
476  virtual bool TryLock() = 0;
477};
478
479
480// ----------------------------------------------------------------------------
481// ScopedLock
482//
483// Stack-allocated ScopedLocks provide block-scoped locking and
484// unlocking of a mutex.
485class ScopedLock {
486 public:
487  explicit ScopedLock(Mutex* mutex): mutex_(mutex) {
488    ASSERT(mutex_ != NULL);
489    mutex_->Lock();
490  }
491  ~ScopedLock() {
492    mutex_->Unlock();
493  }
494
495 private:
496  Mutex* mutex_;
497  DISALLOW_COPY_AND_ASSIGN(ScopedLock);
498};
499
500
501// ----------------------------------------------------------------------------
502// Semaphore
503//
504// A semaphore object is a synchronization object that maintains a count. The
505// count is decremented each time a thread completes a wait for the semaphore
506// object and incremented each time a thread signals the semaphore. When the
507// count reaches zero,  threads waiting for the semaphore blocks until the
508// count becomes non-zero.
509
510class Semaphore {
511 public:
512  virtual ~Semaphore() {}
513
514  // Suspends the calling thread until the semaphore counter is non zero
515  // and then decrements the semaphore counter.
516  virtual void Wait() = 0;
517
518  // Suspends the calling thread until the counter is non zero or the timeout
519  // time has passsed. If timeout happens the return value is false and the
520  // counter is unchanged. Otherwise the semaphore counter is decremented and
521  // true is returned. The timeout value is specified in microseconds.
522  virtual bool Wait(int timeout) = 0;
523
524  // Increments the semaphore counter.
525  virtual void Signal() = 0;
526};
527
528
529// ----------------------------------------------------------------------------
530// Socket
531//
532
533class Socket {
534 public:
535  virtual ~Socket() {}
536
537  // Server initialization.
538  virtual bool Bind(const int port) = 0;
539  virtual bool Listen(int backlog) const = 0;
540  virtual Socket* Accept() const = 0;
541
542  // Client initialization.
543  virtual bool Connect(const char* host, const char* port) = 0;
544
545  // Shutdown socket for both read and write. This causes blocking Send and
546  // Receive calls to exit. After Shutdown the Socket object cannot be used for
547  // any communication.
548  virtual bool Shutdown() = 0;
549
550  // Data Transimission
551  virtual int Send(const char* data, int len) const = 0;
552  virtual int Receive(char* data, int len) const = 0;
553
554  // Set the value of the SO_REUSEADDR socket option.
555  virtual bool SetReuseAddress(bool reuse_address) = 0;
556
557  virtual bool IsValid() const = 0;
558
559  static bool Setup();
560  static int LastError();
561  static uint16_t HToN(uint16_t value);
562  static uint16_t NToH(uint16_t value);
563  static uint32_t HToN(uint32_t value);
564  static uint32_t NToH(uint32_t value);
565};
566
567
568// ----------------------------------------------------------------------------
569// Sampler
570//
571// A sampler periodically samples the state of the VM and optionally
572// (if used for profiling) the program counter and stack pointer for
573// the thread that created it.
574
575// TickSample captures the information collected for each sample.
576class TickSample {
577 public:
578  TickSample()
579      : state(OTHER),
580        pc(NULL),
581        sp(NULL),
582        fp(NULL),
583        tos(NULL),
584        frames_count(0),
585        has_external_callback(false) {}
586  StateTag state;  // The state of the VM.
587  Address pc;      // Instruction pointer.
588  Address sp;      // Stack pointer.
589  Address fp;      // Frame pointer.
590  union {
591    Address tos;   // Top stack value (*sp).
592    Address external_callback;
593  };
594  static const int kMaxFramesCount = 64;
595  Address stack[kMaxFramesCount];  // Call stack.
596  int frames_count : 8;  // Number of captured frames.
597  bool has_external_callback : 1;
598};
599
600#ifdef ENABLE_LOGGING_AND_PROFILING
601class Sampler {
602 public:
603  // Initialize sampler.
604  Sampler(Isolate* isolate, int interval);
605  virtual ~Sampler();
606
607  int interval() const { return interval_; }
608
609  // Performs stack sampling.
610  void SampleStack(TickSample* sample) {
611    DoSampleStack(sample);
612    IncSamplesTaken();
613  }
614
615  // This method is called for each sampling period with the current
616  // program counter.
617  virtual void Tick(TickSample* sample) = 0;
618
619  // Start and stop sampler.
620  void Start();
621  void Stop();
622
623  // Is the sampler used for profiling?
624  bool IsProfiling() const { return NoBarrier_Load(&profiling_) > 0; }
625  void IncreaseProfilingDepth() { NoBarrier_AtomicIncrement(&profiling_, 1); }
626  void DecreaseProfilingDepth() { NoBarrier_AtomicIncrement(&profiling_, -1); }
627
628  // Whether the sampler is running (that is, consumes resources).
629  bool IsActive() const { return NoBarrier_Load(&active_); }
630
631  Isolate* isolate() { return isolate_; }
632
633  // Used in tests to make sure that stack sampling is performed.
634  int samples_taken() const { return samples_taken_; }
635  void ResetSamplesTaken() { samples_taken_ = 0; }
636
637  class PlatformData;
638  PlatformData* data() { return data_; }
639
640  PlatformData* platform_data() { return data_; }
641
642 protected:
643  virtual void DoSampleStack(TickSample* sample) = 0;
644
645 private:
646  void SetActive(bool value) { NoBarrier_Store(&active_, value); }
647  void IncSamplesTaken() { if (++samples_taken_ < 0) samples_taken_ = 0; }
648
649  Isolate* isolate_;
650  const int interval_;
651  Atomic32 profiling_;
652  Atomic32 active_;
653  PlatformData* data_;  // Platform specific data.
654  int samples_taken_;  // Counts stack samples taken.
655  DISALLOW_IMPLICIT_CONSTRUCTORS(Sampler);
656};
657
658
659#endif  // ENABLE_LOGGING_AND_PROFILING
660
661} }  // namespace v8::internal
662
663#endif  // V8_PLATFORM_H_
664