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