1 // Copyright 2012 the V8 project authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 // This module contains the platform-specific code. This make the rest of the
6 // code less dependent on operating system, compilers and runtime libraries.
7 // This module does specifically not deal with differences between different
8 // processor architecture.
9 // The platform classes have the same definition for all platforms. The
10 // implementation for a particular platform is put in platform_<os>.cc.
11 // 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 // the platform dependent classes could have been implemented using abstract
15 // superclasses with virtual methods and having specializations for each
16 // platform. This design was rejected because it was more complicated and
17 // slower. It would require factory methods for selecting the right
18 // implementation and the overhead of virtual methods for performance
19 // sensitive like mutex locking/unlocking.
21 #ifndef V8_BASE_PLATFORM_PLATFORM_H_
22 #define V8_BASE_PLATFORM_PLATFORM_H_
28 #include "src/base/build_config.h"
29 #include "src/base/platform/mutex.h"
30 #include "src/base/platform/semaphore.h"
33 #include "src/base/qnx-math.h"
39 // ----------------------------------------------------------------------------
42 #ifndef V8_NO_FAST_TLS
44 #if V8_CC_MSVC && V8_HOST_ARCH_IA32
46 #define V8_FAST_TLS_SUPPORTED 1
48 INLINE(intptr_t InternalGetExistingThreadLocal(intptr_t index));
50 inline intptr_t InternalGetExistingThreadLocal(intptr_t index) {
51 const intptr_t kTibInlineTlsOffset = 0xE10;
52 const intptr_t kTibExtraTlsOffset = 0xF94;
53 const intptr_t kMaxInlineSlots = 64;
54 const intptr_t kMaxSlots = kMaxInlineSlots + 1024;
55 const intptr_t kPointerSize = sizeof(void*);
56 DCHECK(0 <= index && index < kMaxSlots);
57 if (index < kMaxInlineSlots) {
58 return static_cast<intptr_t>(__readfsdword(kTibInlineTlsOffset +
59 kPointerSize * index));
61 intptr_t extra = static_cast<intptr_t>(__readfsdword(kTibExtraTlsOffset));
63 return *reinterpret_cast<intptr_t*>(extra +
64 kPointerSize * (index - kMaxInlineSlots));
67 #elif defined(__APPLE__) && (V8_HOST_ARCH_IA32 || V8_HOST_ARCH_X64)
69 #define V8_FAST_TLS_SUPPORTED 1
71 extern intptr_t kMacTlsBaseOffset;
73 INLINE(intptr_t InternalGetExistingThreadLocal(intptr_t index));
75 inline intptr_t InternalGetExistingThreadLocal(intptr_t index) {
78 asm("movl %%gs:(%1,%2,4), %0;"
79 :"=r"(result) // Output must be a writable register.
80 :"r"(kMacTlsBaseOffset), "r"(index));
82 asm("movq %%gs:(%1,%2,8), %0;"
84 :"r"(kMacTlsBaseOffset), "r"(index));
91 #endif // V8_NO_FAST_TLS
97 // ----------------------------------------------------------------------------
100 // This class has static methods for the different platform specific
101 // functions. Add methods here to cope with differences between the
102 // supported platforms.
106 // Initialize the OS class.
107 // - random_seed: Used for the GetRandomMmapAddress() if non-zero.
108 // - hard_abort: If true, OS::Abort() will crash instead of aborting.
109 // - gc_fake_mmap: Name of the file for fake gc mmap used in ll_prof.
110 static void Initialize(int64_t random_seed,
112 const char* const gc_fake_mmap);
114 // Returns the accumulated user time for thread. This routine
115 // can be used for profiling. The implementation should
116 // strive for high-precision timer resolution, preferable
117 // micro-second resolution.
118 static int GetUserTime(uint32_t* secs, uint32_t* usecs);
120 // Returns current time as the number of milliseconds since
121 // 00:00:00 UTC, January 1, 1970.
122 static double TimeCurrentMillis();
124 static TimezoneCache* CreateTimezoneCache();
125 static void DisposeTimezoneCache(TimezoneCache* cache);
126 static void ClearTimezoneCache(TimezoneCache* cache);
128 // Returns a string identifying the current time zone. The
129 // timestamp is used for determining if DST is in effect.
130 static const char* LocalTimezone(double time, TimezoneCache* cache);
132 // Returns the local time offset in milliseconds east of UTC without
133 // taking daylight savings time into account.
134 static double LocalTimeOffset(TimezoneCache* cache);
136 // Returns the daylight savings offset for the given time.
137 static double DaylightSavingsOffset(double time, TimezoneCache* cache);
139 // Returns last OS error.
140 static int GetLastError();
142 static FILE* FOpen(const char* path, const char* mode);
143 static bool Remove(const char* path);
145 static bool isDirectorySeparator(const char ch);
147 // Opens a temporary file, the file is auto removed on close.
148 static FILE* OpenTemporaryFile();
150 // Log file open mode is platform-dependent due to line ends issues.
151 static const char* const LogFileOpenMode;
153 // Print output to console. This is mostly used for debugging output.
154 // On platforms that has standard terminal output, the output
155 // should go to stdout.
156 static void Print(const char* format, ...);
157 static void VPrint(const char* format, va_list args);
159 // Print output to a file. This is mostly used for debugging output.
160 static void FPrint(FILE* out, const char* format, ...);
161 static void VFPrint(FILE* out, const char* format, va_list args);
163 // Print error output to console. This is mostly used for error message
164 // output. On platforms that has standard terminal output, the output
165 // should go to stderr.
166 static void PrintError(const char* format, ...);
167 static void VPrintError(const char* format, va_list args);
169 // Allocate/Free memory used by JS heap. Pages are readable/writable, but
170 // they are not guaranteed to be executable unless 'executable' is true.
171 // Returns the address of allocated memory, or NULL if failed.
172 static void* Allocate(const size_t requested,
175 static void Free(void* address, const size_t size);
177 // This is the granularity at which the ProtectCode(...) call can set page
179 static intptr_t CommitPageSize();
181 // Mark code segments non-writable.
182 static void ProtectCode(void* address, const size_t size);
184 // Assign memory as a guard page so that access will cause an exception.
185 static void Guard(void* address, const size_t size);
187 // Generate a random address to be used for hinting mmap().
188 static void* GetRandomMmapAddr();
190 // Get the Alignment guaranteed by Allocate().
191 static size_t AllocateAlignment();
193 // Sleep for a specified time interval.
194 static void Sleep(TimeDelta interval);
196 // Abort the current process.
200 static void DebugBreak();
203 static const int kStackWalkError = -1;
204 static const int kStackWalkMaxNameLen = 256;
205 static const int kStackWalkMaxTextLen = 256;
208 char text[kStackWalkMaxTextLen];
211 class MemoryMappedFile {
213 virtual ~MemoryMappedFile() {}
214 virtual void* memory() const = 0;
215 virtual size_t size() const = 0;
217 static MemoryMappedFile* open(const char* name);
218 static MemoryMappedFile* create(const char* name, size_t size,
222 // Safe formatting print. Ensures that str is always null-terminated.
223 // Returns the number of chars written, or -1 if output was truncated.
224 static int SNPrintF(char* str, int length, const char* format, ...);
225 static int VSNPrintF(char* str,
230 static char* StrChr(char* str, int c);
231 static void StrNCpy(char* dest, int length, const char* src, size_t n);
233 // Support for the profiler. Can do nothing, in which case ticks
234 // occuring in shared libraries will not be properly accounted for.
235 struct SharedLibraryAddress {
236 SharedLibraryAddress(
237 const std::string& library_path, uintptr_t start, uintptr_t end)
238 : library_path(library_path), start(start), end(end) {}
240 std::string library_path;
245 static std::vector<SharedLibraryAddress> GetSharedLibraryAddresses();
247 // Support for the profiler. Notifies the external profiling
248 // process that a code moving garbage collection starts. Can do
249 // nothing, in which case the code objects must not move (e.g., by
250 // using --never-compact) if accurate profiling is desired.
251 static void SignalCodeMovingGC();
253 // Support runtime detection of whether the hard float option of the
255 static bool ArmUsingHardFloat();
257 // Returns the activation frame alignment constraint or zero if
258 // the platform doesn't care. Guaranteed to be a power of two.
259 static int ActivationFrameAlignment();
261 static int GetCurrentProcessId();
263 static int GetCurrentThreadId();
266 static const int msPerSecond = 1000;
269 static const char* GetGCFakeMMapFile();
272 DISALLOW_IMPLICIT_CONSTRUCTORS(OS);
276 // Represents and controls an area of reserved memory.
277 // Control of the reserved memory can be assigned to another VirtualMemory
278 // object by assignment or copy-contructing. This removes the reserved memory
279 // from the original object.
280 class VirtualMemory {
282 // Empty VirtualMemory object, controlling no reserved memory.
285 // Reserves virtual memory with size.
286 explicit VirtualMemory(size_t size);
288 // Reserves virtual memory containing an area of the given size that
289 // is aligned per alignment. This may not be at the position returned
291 VirtualMemory(size_t size, size_t alignment);
293 // Releases the reserved memory, if any, controlled by this VirtualMemory
297 // Returns whether the memory has been reserved.
300 // Initialize or resets an embedded VirtualMemory object.
303 // Returns the start address of the reserved memory.
304 // If the memory was reserved with an alignment, this address is not
305 // necessarily aligned. The user might need to round it up to a multiple of
306 // the alignment to get the start of the aligned block.
308 DCHECK(IsReserved());
312 // Returns the size of the reserved memory. The returned value is only
313 // meaningful when IsReserved() returns true.
314 // If the memory was reserved with an alignment, this size may be larger
315 // than the requested size.
316 size_t size() { return size_; }
318 // Commits real memory. Returns whether the operation succeeded.
319 bool Commit(void* address, size_t size, bool is_executable);
321 // Uncommit real memory. Returns whether the operation succeeded.
322 bool Uncommit(void* address, size_t size);
324 // Creates a single guard page at the given address.
325 bool Guard(void* address);
328 DCHECK(IsReserved());
329 // Notice: Order is important here. The VirtualMemory object might live
330 // inside the allocated region.
331 void* address = address_;
333 CHECK(InVM(address, size));
335 bool result = ReleaseRegion(address, size);
340 // Assign control of the reserved region to a different VirtualMemory object.
341 // The old object is no longer functional (IsReserved() returns false).
342 void TakeControl(VirtualMemory* from) {
343 DCHECK(!IsReserved());
344 address_ = from->address_;
349 static void* ReserveRegion(size_t size);
351 static bool CommitRegion(void* base, size_t size, bool is_executable);
353 static bool UncommitRegion(void* base, size_t size);
355 // Must be called with a base pointer that has been returned by ReserveRegion
356 // and the same size it was reserved with.
357 static bool ReleaseRegion(void* base, size_t size);
359 // Returns true if OS performs lazy commits, i.e. the memory allocation call
360 // defers actual physical memory allocation till the first memory access.
361 // Otherwise returns false.
362 static bool HasLazyCommits();
365 bool InVM(void* address, size_t size) {
366 return (reinterpret_cast<uintptr_t>(address_) <=
367 reinterpret_cast<uintptr_t>(address)) &&
368 ((reinterpret_cast<uintptr_t>(address_) + size_) >=
369 (reinterpret_cast<uintptr_t>(address) + size));
372 void* address_; // Start address of the virtual memory.
373 size_t size_; // Size of the virtual memory.
377 // ----------------------------------------------------------------------------
380 // Thread objects are used for creating and running threads. When the start()
381 // method is called the new thread starts running the run() method in the new
382 // thread. The Thread object should not be deallocated before the thread has
387 // Opaque data type for thread-local storage keys.
388 typedef int32_t LocalStorageKey;
392 Options() : name_("v8:<unknown>"), stack_size_(0) {}
393 explicit Options(const char* name, int stack_size = 0)
394 : name_(name), stack_size_(stack_size) {}
396 const char* name() const { return name_; }
397 int stack_size() const { return stack_size_; }
404 // Create new thread.
405 explicit Thread(const Options& options);
408 // Start new thread by calling the Run() method on the new thread.
411 // Start new thread and wait until Run() method is called on the new thread.
412 void StartSynchronously() {
413 start_semaphore_ = new Semaphore(0);
415 start_semaphore_->Wait();
416 delete start_semaphore_;
417 start_semaphore_ = NULL;
420 // Wait until thread terminates.
423 inline const char* name() const {
427 // Abstract method for run handler.
428 virtual void Run() = 0;
430 // Thread-local storage.
431 static LocalStorageKey CreateThreadLocalKey();
432 static void DeleteThreadLocalKey(LocalStorageKey key);
433 static void* GetThreadLocal(LocalStorageKey key);
434 static int GetThreadLocalInt(LocalStorageKey key) {
435 return static_cast<int>(reinterpret_cast<intptr_t>(GetThreadLocal(key)));
437 static void SetThreadLocal(LocalStorageKey key, void* value);
438 static void SetThreadLocalInt(LocalStorageKey key, int value) {
439 SetThreadLocal(key, reinterpret_cast<void*>(static_cast<intptr_t>(value)));
441 static bool HasThreadLocal(LocalStorageKey key) {
442 return GetThreadLocal(key) != NULL;
445 #ifdef V8_FAST_TLS_SUPPORTED
446 static inline void* GetExistingThreadLocal(LocalStorageKey key) {
447 void* result = reinterpret_cast<void*>(
448 InternalGetExistingThreadLocal(static_cast<intptr_t>(key)));
449 DCHECK(result == GetThreadLocal(key));
453 static inline void* GetExistingThreadLocal(LocalStorageKey key) {
454 return GetThreadLocal(key);
458 // The thread name length is limited to 16 based on Linux's implementation of
460 static const int kMaxThreadNameLength = 16;
463 PlatformData* data() { return data_; }
465 void NotifyStartedAndRun() {
466 if (start_semaphore_) start_semaphore_->Signal();
471 void set_name(const char* name);
475 char name_[kMaxThreadNameLength];
477 Semaphore* start_semaphore_;
479 DISALLOW_COPY_AND_ASSIGN(Thread);
485 #endif // V8_BASE_PLATFORM_PLATFORM_H_