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