blob: 9464fb11231dbcd59efed2846ff4d4894681f83f [file] [log] [blame]
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001// 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.
4
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.
12//
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.
20
21#ifndef V8_BASE_PLATFORM_PLATFORM_H_
22#define V8_BASE_PLATFORM_PLATFORM_H_
23
Emily Bernierd0a1eb72015-03-24 16:35:39 -040024#include <cstdarg>
Ben Murdochb8a8cc12014-11-26 15:28:44 +000025#include <string>
26#include <vector>
27
28#include "src/base/build_config.h"
Ben Murdochc5610432016-08-08 18:44:38 +010029#include "src/base/compiler-specific.h"
Ben Murdochb8a8cc12014-11-26 15:28:44 +000030#include "src/base/platform/mutex.h"
31#include "src/base/platform/semaphore.h"
32
Ben Murdochb8a8cc12014-11-26 15:28:44 +000033#if V8_OS_QNX
34#include "src/base/qnx-math.h"
35#endif
36
Ben Murdochb8a8cc12014-11-26 15:28:44 +000037namespace v8 {
38namespace base {
39
40// ----------------------------------------------------------------------------
41// Fast TLS support
42
43#ifndef V8_NO_FAST_TLS
44
Emily Bernierd0a1eb72015-03-24 16:35:39 -040045#if V8_CC_MSVC && V8_HOST_ARCH_IA32
Ben Murdochb8a8cc12014-11-26 15:28:44 +000046
47#define V8_FAST_TLS_SUPPORTED 1
48
49INLINE(intptr_t InternalGetExistingThreadLocal(intptr_t index));
50
51inline intptr_t InternalGetExistingThreadLocal(intptr_t index) {
52 const intptr_t kTibInlineTlsOffset = 0xE10;
53 const intptr_t kTibExtraTlsOffset = 0xF94;
54 const intptr_t kMaxInlineSlots = 64;
55 const intptr_t kMaxSlots = kMaxInlineSlots + 1024;
56 const intptr_t kPointerSize = sizeof(void*);
57 DCHECK(0 <= index && index < kMaxSlots);
58 if (index < kMaxInlineSlots) {
59 return static_cast<intptr_t>(__readfsdword(kTibInlineTlsOffset +
60 kPointerSize * index));
61 }
62 intptr_t extra = static_cast<intptr_t>(__readfsdword(kTibExtraTlsOffset));
63 DCHECK(extra != 0);
64 return *reinterpret_cast<intptr_t*>(extra +
65 kPointerSize * (index - kMaxInlineSlots));
66}
67
68#elif defined(__APPLE__) && (V8_HOST_ARCH_IA32 || V8_HOST_ARCH_X64)
69
70#define V8_FAST_TLS_SUPPORTED 1
71
72extern intptr_t kMacTlsBaseOffset;
73
74INLINE(intptr_t InternalGetExistingThreadLocal(intptr_t index));
75
76inline intptr_t InternalGetExistingThreadLocal(intptr_t index) {
77 intptr_t result;
78#if V8_HOST_ARCH_IA32
79 asm("movl %%gs:(%1,%2,4), %0;"
80 :"=r"(result) // Output must be a writable register.
81 :"r"(kMacTlsBaseOffset), "r"(index));
82#else
83 asm("movq %%gs:(%1,%2,8), %0;"
84 :"=r"(result)
85 :"r"(kMacTlsBaseOffset), "r"(index));
86#endif
87 return result;
88}
89
90#endif
91
92#endif // V8_NO_FAST_TLS
93
94
95class TimezoneCache;
96
97
98// ----------------------------------------------------------------------------
99// OS
100//
101// This class has static methods for the different platform specific
102// functions. Add methods here to cope with differences between the
103// supported platforms.
104
105class OS {
106 public:
107 // Initialize the OS class.
108 // - random_seed: Used for the GetRandomMmapAddress() if non-zero.
109 // - hard_abort: If true, OS::Abort() will crash instead of aborting.
110 // - gc_fake_mmap: Name of the file for fake gc mmap used in ll_prof.
111 static void Initialize(int64_t random_seed,
112 bool hard_abort,
113 const char* const gc_fake_mmap);
114
115 // Returns the accumulated user time for thread. This routine
116 // can be used for profiling. The implementation should
117 // strive for high-precision timer resolution, preferable
118 // micro-second resolution.
119 static int GetUserTime(uint32_t* secs, uint32_t* usecs);
120
121 // Returns current time as the number of milliseconds since
122 // 00:00:00 UTC, January 1, 1970.
123 static double TimeCurrentMillis();
124
125 static TimezoneCache* CreateTimezoneCache();
126 static void DisposeTimezoneCache(TimezoneCache* cache);
127 static void ClearTimezoneCache(TimezoneCache* cache);
128
129 // Returns a string identifying the current time zone. The
130 // timestamp is used for determining if DST is in effect.
131 static const char* LocalTimezone(double time, TimezoneCache* cache);
132
133 // Returns the local time offset in milliseconds east of UTC without
134 // taking daylight savings time into account.
135 static double LocalTimeOffset(TimezoneCache* cache);
136
137 // Returns the daylight savings offset for the given time.
138 static double DaylightSavingsOffset(double time, TimezoneCache* cache);
139
140 // Returns last OS error.
141 static int GetLastError();
142
143 static FILE* FOpen(const char* path, const char* mode);
144 static bool Remove(const char* path);
145
Ben Murdochda12d292016-06-02 14:46:10 +0100146 static char DirectorySeparator();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000147 static bool isDirectorySeparator(const char ch);
148
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000149 // Opens a temporary file, the file is auto removed on close.
150 static FILE* OpenTemporaryFile();
151
152 // Log file open mode is platform-dependent due to line ends issues.
153 static const char* const LogFileOpenMode;
154
155 // Print output to console. This is mostly used for debugging output.
156 // On platforms that has standard terminal output, the output
157 // should go to stdout.
Ben Murdochc5610432016-08-08 18:44:38 +0100158 static PRINTF_FORMAT(1, 2) void Print(const char* format, ...);
159 static PRINTF_FORMAT(1, 0) void VPrint(const char* format, va_list args);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000160
161 // Print output to a file. This is mostly used for debugging output.
Ben Murdochc5610432016-08-08 18:44:38 +0100162 static PRINTF_FORMAT(2, 3) void FPrint(FILE* out, const char* format, ...);
163 static PRINTF_FORMAT(2, 0) void VFPrint(FILE* out, const char* format,
164 va_list args);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000165
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.
Ben Murdochc5610432016-08-08 18:44:38 +0100169 static PRINTF_FORMAT(1, 2) void PrintError(const char* format, ...);
170 static PRINTF_FORMAT(1, 0) void VPrintError(const char* format, va_list args);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000171
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
180 // This is the granularity at which the ProtectCode(...) call can set page
181 // permissions.
182 static intptr_t CommitPageSize();
183
184 // Mark code segments non-writable.
185 static void ProtectCode(void* address, const size_t size);
186
187 // Assign memory as a guard page so that access will cause an exception.
188 static void Guard(void* address, const size_t size);
189
190 // Generate a random address to be used for hinting mmap().
191 static void* GetRandomMmapAddr();
192
193 // Get the Alignment guaranteed by Allocate().
194 static size_t AllocateAlignment();
195
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000196 // Sleep for a specified time interval.
197 static void Sleep(TimeDelta interval);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000198
199 // Abort the current process.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000200 V8_NORETURN static void Abort();
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000201
202 // Debug break.
203 static void DebugBreak();
204
205 // Walk the stack.
206 static const int kStackWalkError = -1;
207 static const int kStackWalkMaxNameLen = 256;
208 static const int kStackWalkMaxTextLen = 256;
209 struct StackFrame {
210 void* address;
211 char text[kStackWalkMaxTextLen];
212 };
213
214 class MemoryMappedFile {
215 public:
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000216 virtual ~MemoryMappedFile() {}
217 virtual void* memory() const = 0;
218 virtual size_t size() const = 0;
219
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000220 static MemoryMappedFile* open(const char* name);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000221 static MemoryMappedFile* create(const char* name, size_t size,
222 void* initial);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000223 };
224
225 // Safe formatting print. Ensures that str is always null-terminated.
226 // Returns the number of chars written, or -1 if output was truncated.
Ben Murdochc5610432016-08-08 18:44:38 +0100227 static PRINTF_FORMAT(3, 4) int SNPrintF(char* str, int length,
228 const char* format, ...);
229 static PRINTF_FORMAT(3, 0) int VSNPrintF(char* str, int length,
230 const char* format, va_list args);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000231
232 static char* StrChr(char* str, int c);
233 static void StrNCpy(char* dest, int length, const char* src, size_t n);
234
235 // Support for the profiler. Can do nothing, in which case ticks
236 // occuring in shared libraries will not be properly accounted for.
237 struct SharedLibraryAddress {
Ben Murdochc5610432016-08-08 18:44:38 +0100238 SharedLibraryAddress(const std::string& library_path, uintptr_t start,
239 uintptr_t end)
240 : library_path(library_path), start(start), end(end), aslr_slide(0) {}
241 SharedLibraryAddress(const std::string& library_path, uintptr_t start,
242 uintptr_t end, intptr_t aslr_slide)
243 : library_path(library_path),
244 start(start),
245 end(end),
246 aslr_slide(aslr_slide) {}
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000247
248 std::string library_path;
249 uintptr_t start;
250 uintptr_t end;
Ben Murdochc5610432016-08-08 18:44:38 +0100251 intptr_t aslr_slide;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000252 };
253
254 static std::vector<SharedLibraryAddress> GetSharedLibraryAddresses();
255
256 // Support for the profiler. Notifies the external profiling
257 // process that a code moving garbage collection starts. Can do
258 // nothing, in which case the code objects must not move (e.g., by
259 // using --never-compact) if accurate profiling is desired.
260 static void SignalCodeMovingGC();
261
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000262 // Support runtime detection of whether the hard float option of the
263 // EABI is used.
264 static bool ArmUsingHardFloat();
265
266 // Returns the activation frame alignment constraint or zero if
267 // the platform doesn't care. Guaranteed to be a power of two.
268 static int ActivationFrameAlignment();
269
270 static int GetCurrentProcessId();
271
272 static int GetCurrentThreadId();
273
274 private:
275 static const int msPerSecond = 1000;
276
277#if V8_OS_POSIX
278 static const char* GetGCFakeMMapFile();
279#endif
280
281 DISALLOW_IMPLICIT_CONSTRUCTORS(OS);
282};
283
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000284
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000285// Represents and controls an area of reserved memory.
286// Control of the reserved memory can be assigned to another VirtualMemory
287// object by assignment or copy-contructing. This removes the reserved memory
288// from the original object.
289class VirtualMemory {
290 public:
291 // Empty VirtualMemory object, controlling no reserved memory.
292 VirtualMemory();
293
294 // Reserves virtual memory with size.
295 explicit VirtualMemory(size_t size);
296
297 // Reserves virtual memory containing an area of the given size that
298 // is aligned per alignment. This may not be at the position returned
299 // by address().
300 VirtualMemory(size_t size, size_t alignment);
301
Ben Murdochda12d292016-06-02 14:46:10 +0100302 // Construct a virtual memory by assigning it some already mapped address
303 // and size.
304 VirtualMemory(void* address, size_t size) : address_(address), size_(size) {}
305
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000306 // Releases the reserved memory, if any, controlled by this VirtualMemory
307 // object.
308 ~VirtualMemory();
309
310 // Returns whether the memory has been reserved.
311 bool IsReserved();
312
313 // Initialize or resets an embedded VirtualMemory object.
314 void Reset();
315
316 // Returns the start address of the reserved memory.
317 // If the memory was reserved with an alignment, this address is not
318 // necessarily aligned. The user might need to round it up to a multiple of
319 // the alignment to get the start of the aligned block.
320 void* address() {
321 DCHECK(IsReserved());
322 return address_;
323 }
324
325 // Returns the size of the reserved memory. The returned value is only
326 // meaningful when IsReserved() returns true.
327 // If the memory was reserved with an alignment, this size may be larger
328 // than the requested size.
329 size_t size() { return size_; }
330
331 // Commits real memory. Returns whether the operation succeeded.
332 bool Commit(void* address, size_t size, bool is_executable);
333
334 // Uncommit real memory. Returns whether the operation succeeded.
335 bool Uncommit(void* address, size_t size);
336
337 // Creates a single guard page at the given address.
338 bool Guard(void* address);
339
340 void Release() {
341 DCHECK(IsReserved());
342 // Notice: Order is important here. The VirtualMemory object might live
343 // inside the allocated region.
344 void* address = address_;
345 size_t size = size_;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000346 CHECK(InVM(address, size));
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000347 Reset();
348 bool result = ReleaseRegion(address, size);
349 USE(result);
350 DCHECK(result);
351 }
352
353 // Assign control of the reserved region to a different VirtualMemory object.
354 // The old object is no longer functional (IsReserved() returns false).
355 void TakeControl(VirtualMemory* from) {
356 DCHECK(!IsReserved());
357 address_ = from->address_;
358 size_ = from->size_;
359 from->Reset();
360 }
361
362 static void* ReserveRegion(size_t size);
363
364 static bool CommitRegion(void* base, size_t size, bool is_executable);
365
366 static bool UncommitRegion(void* base, size_t size);
367
368 // Must be called with a base pointer that has been returned by ReserveRegion
369 // and the same size it was reserved with.
370 static bool ReleaseRegion(void* base, size_t size);
371
372 // Returns true if OS performs lazy commits, i.e. the memory allocation call
373 // defers actual physical memory allocation till the first memory access.
374 // Otherwise returns false.
375 static bool HasLazyCommits();
376
377 private:
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000378 bool InVM(void* address, size_t size) {
379 return (reinterpret_cast<uintptr_t>(address_) <=
380 reinterpret_cast<uintptr_t>(address)) &&
381 ((reinterpret_cast<uintptr_t>(address_) + size_) >=
382 (reinterpret_cast<uintptr_t>(address) + size));
383 }
384
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000385 void* address_; // Start address of the virtual memory.
386 size_t size_; // Size of the virtual memory.
387};
388
389
390// ----------------------------------------------------------------------------
391// Thread
392//
393// Thread objects are used for creating and running threads. When the start()
394// method is called the new thread starts running the run() method in the new
395// thread. The Thread object should not be deallocated before the thread has
396// terminated.
397
398class Thread {
399 public:
400 // Opaque data type for thread-local storage keys.
401 typedef int32_t LocalStorageKey;
402
403 class Options {
404 public:
405 Options() : name_("v8:<unknown>"), stack_size_(0) {}
406 explicit Options(const char* name, int stack_size = 0)
407 : name_(name), stack_size_(stack_size) {}
408
409 const char* name() const { return name_; }
410 int stack_size() const { return stack_size_; }
411
412 private:
413 const char* name_;
414 int stack_size_;
415 };
416
417 // Create new thread.
418 explicit Thread(const Options& options);
419 virtual ~Thread();
420
421 // Start new thread by calling the Run() method on the new thread.
422 void Start();
423
424 // Start new thread and wait until Run() method is called on the new thread.
425 void StartSynchronously() {
426 start_semaphore_ = new Semaphore(0);
427 Start();
428 start_semaphore_->Wait();
429 delete start_semaphore_;
430 start_semaphore_ = NULL;
431 }
432
433 // Wait until thread terminates.
434 void Join();
435
436 inline const char* name() const {
437 return name_;
438 }
439
440 // Abstract method for run handler.
441 virtual void Run() = 0;
442
443 // Thread-local storage.
444 static LocalStorageKey CreateThreadLocalKey();
445 static void DeleteThreadLocalKey(LocalStorageKey key);
446 static void* GetThreadLocal(LocalStorageKey key);
447 static int GetThreadLocalInt(LocalStorageKey key) {
448 return static_cast<int>(reinterpret_cast<intptr_t>(GetThreadLocal(key)));
449 }
450 static void SetThreadLocal(LocalStorageKey key, void* value);
451 static void SetThreadLocalInt(LocalStorageKey key, int value) {
452 SetThreadLocal(key, reinterpret_cast<void*>(static_cast<intptr_t>(value)));
453 }
454 static bool HasThreadLocal(LocalStorageKey key) {
455 return GetThreadLocal(key) != NULL;
456 }
457
458#ifdef V8_FAST_TLS_SUPPORTED
459 static inline void* GetExistingThreadLocal(LocalStorageKey key) {
460 void* result = reinterpret_cast<void*>(
461 InternalGetExistingThreadLocal(static_cast<intptr_t>(key)));
462 DCHECK(result == GetThreadLocal(key));
463 return result;
464 }
465#else
466 static inline void* GetExistingThreadLocal(LocalStorageKey key) {
467 return GetThreadLocal(key);
468 }
469#endif
470
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000471 // The thread name length is limited to 16 based on Linux's implementation of
472 // prctl().
473 static const int kMaxThreadNameLength = 16;
474
475 class PlatformData;
476 PlatformData* data() { return data_; }
477
478 void NotifyStartedAndRun() {
479 if (start_semaphore_) start_semaphore_->Signal();
480 Run();
481 }
482
483 private:
484 void set_name(const char* name);
485
486 PlatformData* data_;
487
488 char name_[kMaxThreadNameLength];
489 int stack_size_;
490 Semaphore* start_semaphore_;
491
492 DISALLOW_COPY_AND_ASSIGN(Thread);
493};
494
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000495} // namespace base
496} // namespace v8
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000497
498#endif // V8_BASE_PLATFORM_PLATFORM_H_