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