platform.h 15.3 KB
Newer Older
1
// Copyright 2012 the V8 project authors. All rights reserved.
2 3
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
4 5 6 7 8 9 10 11 12

// This module contains the platform-specific code. This make the rest of the
// code less dependent on operating system, compilers and runtime libraries.
// This module does specifically not deal with differences between different
// processor architecture.
// The platform classes have the same definition for all platforms. The
// implementation for a particular platform is put in platform_<os>.cc.
// The build system then uses the implementation for the target platform.
//
13
// This design has been chosen because it is simple and fast. Alternatively,
14 15 16 17 18 19 20
// the platform dependent classes could have been implemented using abstract
// superclasses with virtual methods and having specializations for each
// platform. This design was rejected because it was more complicated and
// slower. It would require factory methods for selecting the right
// implementation and the overhead of virtual methods for performance
// sensitive like mutex locking/unlocking.

21 22
#ifndef V8_BASE_PLATFORM_PLATFORM_H_
#define V8_BASE_PLATFORM_PLATFORM_H_
23

24
#include <cstdarg>
25 26
#include <string>
#include <vector>
27

28
#include "src/base/build_config.h"
29 30
#include "src/base/platform/mutex.h"
#include "src/base/platform/semaphore.h"
31

32
#if V8_OS_QNX
33
#include "src/base/qnx-math.h"
34 35
#endif

36
namespace v8 {
37
namespace base {
38

39 40 41 42 43
// ----------------------------------------------------------------------------
// Fast TLS support

#ifndef V8_NO_FAST_TLS

44
#if V8_CC_MSVC && V8_HOST_ARCH_IA32
45 46 47 48 49 50 51 52 53 54

#define V8_FAST_TLS_SUPPORTED 1

INLINE(intptr_t InternalGetExistingThreadLocal(intptr_t index));

inline intptr_t InternalGetExistingThreadLocal(intptr_t index) {
  const intptr_t kTibInlineTlsOffset = 0xE10;
  const intptr_t kTibExtraTlsOffset = 0xF94;
  const intptr_t kMaxInlineSlots = 64;
  const intptr_t kMaxSlots = kMaxInlineSlots + 1024;
55
  const intptr_t kPointerSize = sizeof(void*);
56
  DCHECK(0 <= index && index < kMaxSlots);
57 58 59 60 61
  if (index < kMaxInlineSlots) {
    return static_cast<intptr_t>(__readfsdword(kTibInlineTlsOffset +
                                               kPointerSize * index));
  }
  intptr_t extra = static_cast<intptr_t>(__readfsdword(kTibExtraTlsOffset));
62
  DCHECK(extra != 0);
63 64 65 66
  return *reinterpret_cast<intptr_t*>(extra +
                                      kPointerSize * (index - kMaxInlineSlots));
}

67
#elif defined(__APPLE__) && (V8_HOST_ARCH_IA32 || V8_HOST_ARCH_X64)
68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93

#define V8_FAST_TLS_SUPPORTED 1

extern intptr_t kMacTlsBaseOffset;

INLINE(intptr_t InternalGetExistingThreadLocal(intptr_t index));

inline intptr_t InternalGetExistingThreadLocal(intptr_t index) {
  intptr_t result;
#if V8_HOST_ARCH_IA32
  asm("movl %%gs:(%1,%2,4), %0;"
      :"=r"(result)  // Output must be a writable register.
      :"r"(kMacTlsBaseOffset), "r"(index));
#else
  asm("movq %%gs:(%1,%2,8), %0;"
      :"=r"(result)
      :"r"(kMacTlsBaseOffset), "r"(index));
#endif
  return result;
}

#endif

#endif  // V8_NO_FAST_TLS


94 95 96
class TimezoneCache;


97 98 99 100 101 102 103 104 105
// ----------------------------------------------------------------------------
// OS
//
// This class has static methods for the different platform specific
// functions. Add methods here to cope with differences between the
// supported platforms.

class OS {
 public:
106 107 108 109 110 111 112 113
  // Initialize the OS class.
  // - random_seed: Used for the GetRandomMmapAddress() if non-zero.
  // - hard_abort: If true, OS::Abort() will crash instead of aborting.
  // - gc_fake_mmap: Name of the file for fake gc mmap used in ll_prof.
  static void Initialize(int64_t random_seed,
                         bool hard_abort,
                         const char* const gc_fake_mmap);

114 115 116 117 118 119 120 121 122 123
  // Returns the accumulated user time for thread. This routine
  // can be used for profiling. The implementation should
  // strive for high-precision timer resolution, preferable
  // micro-second resolution.
  static int GetUserTime(uint32_t* secs,  uint32_t* usecs);

  // Returns current time as the number of milliseconds since
  // 00:00:00 UTC, January 1, 1970.
  static double TimeCurrentMillis();

124 125 126 127
  static TimezoneCache* CreateTimezoneCache();
  static void DisposeTimezoneCache(TimezoneCache* cache);
  static void ClearTimezoneCache(TimezoneCache* cache);

128 129
  // Returns a string identifying the current time zone. The
  // timestamp is used for determining if DST is in effect.
130
  static const char* LocalTimezone(double time, TimezoneCache* cache);
131 132 133

  // Returns the local time offset in milliseconds east of UTC without
  // taking daylight savings time into account.
134
  static double LocalTimeOffset(TimezoneCache* cache);
135 136

  // Returns the daylight savings offset for the given time.
137
  static double DaylightSavingsOffset(double time, TimezoneCache* cache);
138

139 140 141
  // Returns last OS error.
  static int GetLastError();

142
  static FILE* FOpen(const char* path, const char* mode);
143
  static bool Remove(const char* path);
144

sejunho's avatar
sejunho committed
145 146
  static bool isDirectorySeparator(const char ch);

147 148 149
  // Opens a temporary file, the file is auto removed on close.
  static FILE* OpenTemporaryFile();

150
  // Log file open mode is platform-dependent due to line ends issues.
151
  static const char* const LogFileOpenMode;
152

153 154 155 156 157 158
  // Print output to console. This is mostly used for debugging output.
  // On platforms that has standard terminal output, the output
  // should go to stdout.
  static void Print(const char* format, ...);
  static void VPrint(const char* format, va_list args);

159 160 161 162
  // Print output to a file. This is mostly used for debugging output.
  static void FPrint(FILE* out, const char* format, ...);
  static void VFPrint(FILE* out, const char* format, va_list args);

163 164 165 166 167 168
  // Print error output to console. This is mostly used for error message
  // output. On platforms that has standard terminal output, the output
  // should go to stderr.
  static void PrintError(const char* format, ...);
  static void VPrintError(const char* format, va_list args);

169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192
  // Allocate/Free memory used by JS heap. Pages are readable/writable, but
  // they are not guaranteed to be executable unless 'executable' is true.
  // Returns the address of allocated memory, or NULL if failed.
  static void* Allocate(const size_t requested,
                        size_t* allocated,
                        bool is_executable);
  static void Free(void* address, const size_t size);

  // This is the granularity at which the ProtectCode(...) call can set page
  // permissions.
  static intptr_t CommitPageSize();

  // Mark code segments non-writable.
  static void ProtectCode(void* address, const size_t size);

  // Assign memory as a guard page so that access will cause an exception.
  static void Guard(void* address, const size_t size);

  // Generate a random address to be used for hinting mmap().
  static void* GetRandomMmapAddr();

  // Get the Alignment guaranteed by Allocate().
  static size_t AllocateAlignment();

193 194
  // Sleep for a specified time interval.
  static void Sleep(TimeDelta interval);
195 196 197 198

  // Abort the current process.
  static void Abort();

199 200 201
  // Debug break.
  static void DebugBreak();

202 203 204 205 206 207 208 209 210 211 212
  // Walk the stack.
  static const int kStackWalkError = -1;
  static const int kStackWalkMaxNameLen = 256;
  static const int kStackWalkMaxTextLen = 256;
  struct StackFrame {
    void* address;
    char text[kStackWalkMaxTextLen];
  };

  class MemoryMappedFile {
   public:
213 214 215 216
    virtual ~MemoryMappedFile() {}
    virtual void* memory() const = 0;
    virtual size_t size() const = 0;

217
    static MemoryMappedFile* open(const char* name);
218 219
    static MemoryMappedFile* create(const char* name, size_t size,
                                    void* initial);
220 221
  };

222 223
  // Safe formatting print. Ensures that str is always null-terminated.
  // Returns the number of chars written, or -1 if output was truncated.
224 225 226
  static int SNPrintF(char* str, int length, const char* format, ...);
  static int VSNPrintF(char* str,
                       int length,
227 228 229
                       const char* format,
                       va_list args);

230
  static char* StrChr(char* str, int c);
231
  static void StrNCpy(char* dest, int length, const char* src, size_t n);
232

233 234
  // Support for the profiler.  Can do nothing, in which case ticks
  // occuring in shared libraries will not be properly accounted for.
235 236 237 238 239 240 241 242 243 244 245
  struct SharedLibraryAddress {
    SharedLibraryAddress(
        const std::string& library_path, uintptr_t start, uintptr_t end)
        : library_path(library_path), start(start), end(end) {}

    std::string library_path;
    uintptr_t start;
    uintptr_t end;
  };

  static std::vector<SharedLibraryAddress> GetSharedLibraryAddresses();
246

247 248 249 250 251 252
  // Support for the profiler.  Notifies the external profiling
  // process that a code moving garbage collection starts.  Can do
  // nothing, in which case the code objects must not move (e.g., by
  // using --never-compact) if accurate profiling is desired.
  static void SignalCodeMovingGC();

253 254 255 256
  // Support runtime detection of whether the hard float option of the
  // EABI is used.
  static bool ArmUsingHardFloat();

257 258 259 260
  // Returns the activation frame alignment constraint or zero if
  // the platform doesn't care. Guaranteed to be a power of two.
  static int ActivationFrameAlignment();

261 262
  static int GetCurrentProcessId();

263 264
  static int GetCurrentThreadId();

265 266
 private:
  static const int msPerSecond = 1000;
267

268 269 270 271
#if V8_OS_POSIX
  static const char* GetGCFakeMMapFile();
#endif

272
  DISALLOW_IMPLICIT_CONSTRUCTORS(OS);
273 274
};

275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306
// Represents and controls an area of reserved memory.
// Control of the reserved memory can be assigned to another VirtualMemory
// object by assignment or copy-contructing. This removes the reserved memory
// from the original object.
class VirtualMemory {
 public:
  // Empty VirtualMemory object, controlling no reserved memory.
  VirtualMemory();

  // Reserves virtual memory with size.
  explicit VirtualMemory(size_t size);

  // Reserves virtual memory containing an area of the given size that
  // is aligned per alignment. This may not be at the position returned
  // by address().
  VirtualMemory(size_t size, size_t alignment);

  // Releases the reserved memory, if any, controlled by this VirtualMemory
  // object.
  ~VirtualMemory();

  // Returns whether the memory has been reserved.
  bool IsReserved();

  // Initialize or resets an embedded VirtualMemory object.
  void Reset();

  // Returns the start address of the reserved memory.
  // If the memory was reserved with an alignment, this address is not
  // necessarily aligned. The user might need to round it up to a multiple of
  // the alignment to get the start of the aligned block.
  void* address() {
307
    DCHECK(IsReserved());
308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326
    return address_;
  }

  // Returns the size of the reserved memory. The returned value is only
  // meaningful when IsReserved() returns true.
  // If the memory was reserved with an alignment, this size may be larger
  // than the requested size.
  size_t size() { return size_; }

  // Commits real memory. Returns whether the operation succeeded.
  bool Commit(void* address, size_t size, bool is_executable);

  // Uncommit real memory.  Returns whether the operation succeeded.
  bool Uncommit(void* address, size_t size);

  // Creates a single guard page at the given address.
  bool Guard(void* address);

  void Release() {
327
    DCHECK(IsReserved());
328 329 330 331 332 333 334
    // Notice: Order is important here. The VirtualMemory object might live
    // inside the allocated region.
    void* address = address_;
    size_t size = size_;
    Reset();
    bool result = ReleaseRegion(address, size);
    USE(result);
335
    DCHECK(result);
336 337 338 339 340
  }

  // Assign control of the reserved region to a different VirtualMemory object.
  // The old object is no longer functional (IsReserved() returns false).
  void TakeControl(VirtualMemory* from) {
341
    DCHECK(!IsReserved());
342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367
    address_ = from->address_;
    size_ = from->size_;
    from->Reset();
  }

  static void* ReserveRegion(size_t size);

  static bool CommitRegion(void* base, size_t size, bool is_executable);

  static bool UncommitRegion(void* base, size_t size);

  // Must be called with a base pointer that has been returned by ReserveRegion
  // and the same size it was reserved with.
  static bool ReleaseRegion(void* base, size_t size);

  // Returns true if OS performs lazy commits, i.e. the memory allocation call
  // defers actual physical memory allocation till the first memory access.
  // Otherwise returns false.
  static bool HasLazyCommits();

 private:
  void* address_;  // Start address of the virtual memory.
  size_t size_;  // Size of the virtual memory.
};


368 369 370 371 372 373 374 375
// ----------------------------------------------------------------------------
// Thread
//
// Thread objects are used for creating and running threads. When the start()
// method is called the new thread starts running the run() method in the new
// thread. The Thread object should not be deallocated before the thread has
// terminated.

376
class Thread {
377 378
 public:
  // Opaque data type for thread-local storage keys.
379
  typedef int32_t LocalStorageKey;
380

381 382 383
  class Options {
   public:
    Options() : name_("v8:<unknown>"), stack_size_(0) {}
384
    explicit Options(const char* name, int stack_size = 0)
385 386 387 388
        : name_(name), stack_size_(stack_size) {}

    const char* name() const { return name_; }
    int stack_size() const { return stack_size_; }
389

390 391 392
   private:
    const char* name_;
    int stack_size_;
393 394
  };

395 396
  // Create new thread.
  explicit Thread(const Options& options);
397 398
  virtual ~Thread();

399
  // Start new thread by calling the Run() method on the new thread.
400 401
  void Start();

402 403
  // Start new thread and wait until Run() method is called on the new thread.
  void StartSynchronously() {
404
    start_semaphore_ = new Semaphore(0);
405 406 407 408 409 410
    Start();
    start_semaphore_->Wait();
    delete start_semaphore_;
    start_semaphore_ = NULL;
  }

411 412 413
  // Wait until thread terminates.
  void Join();

414 415 416 417
  inline const char* name() const {
    return name_;
  }

418 419 420 421 422 423 424
  // Abstract method for run handler.
  virtual void Run() = 0;

  // Thread-local storage.
  static LocalStorageKey CreateThreadLocalKey();
  static void DeleteThreadLocalKey(LocalStorageKey key);
  static void* GetThreadLocal(LocalStorageKey key);
425 426 427
  static int GetThreadLocalInt(LocalStorageKey key) {
    return static_cast<int>(reinterpret_cast<intptr_t>(GetThreadLocal(key)));
  }
428
  static void SetThreadLocal(LocalStorageKey key, void* value);
429 430 431 432 433 434
  static void SetThreadLocalInt(LocalStorageKey key, int value) {
    SetThreadLocal(key, reinterpret_cast<void*>(static_cast<intptr_t>(value)));
  }
  static bool HasThreadLocal(LocalStorageKey key) {
    return GetThreadLocal(key) != NULL;
  }
435

vitalyr@chromium.org's avatar
vitalyr@chromium.org committed
436 437 438 439
#ifdef V8_FAST_TLS_SUPPORTED
  static inline void* GetExistingThreadLocal(LocalStorageKey key) {
    void* result = reinterpret_cast<void*>(
        InternalGetExistingThreadLocal(static_cast<intptr_t>(key)));
440
    DCHECK(result == GetThreadLocal(key));
vitalyr@chromium.org's avatar
vitalyr@chromium.org committed
441 442 443 444 445 446 447 448
    return result;
  }
#else
  static inline void* GetExistingThreadLocal(LocalStorageKey key) {
    return GetThreadLocal(key);
  }
#endif

449 450 451
  // The thread name length is limited to 16 based on Linux's implementation of
  // prctl().
  static const int kMaxThreadNameLength = 16;
452 453 454 455

  class PlatformData;
  PlatformData* data() { return data_; }

456 457 458 459 460
  void NotifyStartedAndRun() {
    if (start_semaphore_) start_semaphore_->Signal();
    Run();
  }

461
 private:
462
  void set_name(const char* name);
463

464
  PlatformData* data_;
465

466
  char name_[kMaxThreadNameLength];
467
  int stack_size_;
468
  Semaphore* start_semaphore_;
469

470
  DISALLOW_COPY_AND_ASSIGN(Thread);
471 472
};

473
} }  // namespace v8::base
474

475
#endif  // V8_BASE_PLATFORM_PLATFORM_H_