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)
lrint(double flt)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
InternalGetExistingThreadLocal(intptr_t index)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 // Returns the accumulated user time for thread. This routine
145 // can be used for profiling. The implementation should
146 // strive for high-precision timer resolution, preferable
147 // micro-second resolution.
148 static int GetUserTime(uint32_t* secs, uint32_t* usecs);
149
150 // Returns current time as the number of milliseconds since
151 // 00:00:00 UTC, January 1, 1970.
152 static double TimeCurrentMillis();
153
154 static TimezoneCache* CreateTimezoneCache();
155 static void DisposeTimezoneCache(TimezoneCache* cache);
156 static void ClearTimezoneCache(TimezoneCache* cache);
157
158 // Returns a string identifying the current time zone. The
159 // timestamp is used for determining if DST is in effect.
160 static const char* LocalTimezone(double time, TimezoneCache* cache);
161
162 // Returns the local time offset in milliseconds east of UTC without
163 // taking daylight savings time into account.
164 static double LocalTimeOffset(TimezoneCache* cache);
165
166 // Returns the daylight savings offset for the given time.
167 static double DaylightSavingsOffset(double time, TimezoneCache* cache);
168
169 // Returns last OS error.
170 static int GetLastError();
171
172 static FILE* FOpen(const char* path, const char* mode);
173 static bool Remove(const char* path);
174
175 // Opens a temporary file, the file is auto removed on close.
176 static FILE* OpenTemporaryFile();
177
178 // Log file open mode is platform-dependent due to line ends issues.
179 static const char* const LogFileOpenMode;
180
181 // Print output to console. This is mostly used for debugging output.
182 // On platforms that has standard terminal output, the output
183 // should go to stdout.
184 static void Print(const char* format, ...);
185 static void VPrint(const char* format, va_list args);
186
187 // Print output to a file. This is mostly used for debugging output.
188 static void FPrint(FILE* out, const char* format, ...);
189 static void VFPrint(FILE* out, const char* format, va_list args);
190
191 // Print error output to console. This is mostly used for error message
192 // output. On platforms that has standard terminal output, the output
193 // should go to stderr.
194 static void PrintError(const char* format, ...);
195 static void VPrintError(const char* format, va_list args);
196
197 // Allocate/Free memory used by JS heap. Pages are readable/writable, but
198 // they are not guaranteed to be executable unless 'executable' is true.
199 // Returns the address of allocated memory, or NULL if failed.
200 static void* Allocate(const size_t requested,
201 size_t* allocated,
202 bool is_executable);
203 static void Free(void* address, const size_t size);
204
205 // This is the granularity at which the ProtectCode(...) call can set page
206 // permissions.
207 static intptr_t CommitPageSize();
208
209 // Mark code segments non-writable.
210 static void ProtectCode(void* address, const size_t size);
211
212 // Assign memory as a guard page so that access will cause an exception.
213 static void Guard(void* address, const size_t size);
214
215 // Generate a random address to be used for hinting mmap().
216 static void* GetRandomMmapAddr();
217
218 // Get the Alignment guaranteed by Allocate().
219 static size_t AllocateAlignment();
220
221 // Sleep for a number of milliseconds.
222 static void Sleep(const int milliseconds);
223
224 // Abort the current process.
225 static void Abort();
226
227 // Debug break.
228 static void DebugBreak();
229
230 // Walk the stack.
231 static const int kStackWalkError = -1;
232 static const int kStackWalkMaxNameLen = 256;
233 static const int kStackWalkMaxTextLen = 256;
234 struct StackFrame {
235 void* address;
236 char text[kStackWalkMaxTextLen];
237 };
238
239 class MemoryMappedFile {
240 public:
241 static MemoryMappedFile* open(const char* name);
242 static MemoryMappedFile* create(const char* name, int size, void* initial);
~MemoryMappedFile()243 virtual ~MemoryMappedFile() { }
244 virtual void* memory() = 0;
245 virtual int size() = 0;
246 };
247
248 // Safe formatting print. Ensures that str is always null-terminated.
249 // Returns the number of chars written, or -1 if output was truncated.
250 static int SNPrintF(char* str, int length, const char* format, ...);
251 static int VSNPrintF(char* str,
252 int length,
253 const char* format,
254 va_list args);
255
256 static char* StrChr(char* str, int c);
257 static void StrNCpy(char* dest, int length, const char* src, size_t n);
258
259 // Support for the profiler. Can do nothing, in which case ticks
260 // occuring in shared libraries will not be properly accounted for.
261 struct SharedLibraryAddress {
SharedLibraryAddressSharedLibraryAddress262 SharedLibraryAddress(
263 const std::string& library_path, uintptr_t start, uintptr_t end)
264 : library_path(library_path), start(start), end(end) {}
265
266 std::string library_path;
267 uintptr_t start;
268 uintptr_t end;
269 };
270
271 static std::vector<SharedLibraryAddress> GetSharedLibraryAddresses();
272
273 // Support for the profiler. Notifies the external profiling
274 // process that a code moving garbage collection starts. Can do
275 // nothing, in which case the code objects must not move (e.g., by
276 // using --never-compact) if accurate profiling is desired.
277 static void SignalCodeMovingGC();
278
279 // Returns the number of processors online.
280 static int NumberOfProcessorsOnline();
281
282 // The total amount of physical memory available on the current system.
283 static uint64_t TotalPhysicalMemory();
284
285 // Maximum size of the virtual memory. 0 means there is no artificial
286 // limit.
287 static intptr_t MaxVirtualMemory();
288
289 // Returns the double constant NAN
290 static double nan_value();
291
292 // Support runtime detection of whether the hard float option of the
293 // EABI is used.
294 static bool ArmUsingHardFloat();
295
296 // Returns the activation frame alignment constraint or zero if
297 // the platform doesn't care. Guaranteed to be a power of two.
298 static int ActivationFrameAlignment();
299
300 static int GetCurrentProcessId();
301
302 private:
303 static const int msPerSecond = 1000;
304
305 DISALLOW_IMPLICIT_CONSTRUCTORS(OS);
306 };
307
308 // Represents and controls an area of reserved memory.
309 // Control of the reserved memory can be assigned to another VirtualMemory
310 // object by assignment or copy-contructing. This removes the reserved memory
311 // from the original object.
312 class VirtualMemory {
313 public:
314 // Empty VirtualMemory object, controlling no reserved memory.
315 VirtualMemory();
316
317 // Reserves virtual memory with size.
318 explicit VirtualMemory(size_t size);
319
320 // Reserves virtual memory containing an area of the given size that
321 // is aligned per alignment. This may not be at the position returned
322 // by address().
323 VirtualMemory(size_t size, size_t alignment);
324
325 // Releases the reserved memory, if any, controlled by this VirtualMemory
326 // object.
327 ~VirtualMemory();
328
329 // Returns whether the memory has been reserved.
330 bool IsReserved();
331
332 // Initialize or resets an embedded VirtualMemory object.
333 void Reset();
334
335 // Returns the start address of the reserved memory.
336 // If the memory was reserved with an alignment, this address is not
337 // necessarily aligned. The user might need to round it up to a multiple of
338 // the alignment to get the start of the aligned block.
address()339 void* address() {
340 ASSERT(IsReserved());
341 return address_;
342 }
343
344 // Returns the size of the reserved memory. The returned value is only
345 // meaningful when IsReserved() returns true.
346 // If the memory was reserved with an alignment, this size may be larger
347 // than the requested size.
size()348 size_t size() { return size_; }
349
350 // Commits real memory. Returns whether the operation succeeded.
351 bool Commit(void* address, size_t size, bool is_executable);
352
353 // Uncommit real memory. Returns whether the operation succeeded.
354 bool Uncommit(void* address, size_t size);
355
356 // Creates a single guard page at the given address.
357 bool Guard(void* address);
358
Release()359 void Release() {
360 ASSERT(IsReserved());
361 // Notice: Order is important here. The VirtualMemory object might live
362 // inside the allocated region.
363 void* address = address_;
364 size_t size = size_;
365 Reset();
366 bool result = ReleaseRegion(address, size);
367 USE(result);
368 ASSERT(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 ASSERT(!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 // Returns true if OS performs lazy commits, i.e. the memory allocation call
391 // defers actual physical memory allocation till the first memory access.
392 // Otherwise returns false.
393 static bool HasLazyCommits();
394
395 private:
396 void* address_; // Start address of the virtual memory.
397 size_t size_; // Size of the virtual memory.
398 };
399
400
401 // ----------------------------------------------------------------------------
402 // Thread
403 //
404 // Thread objects are used for creating and running threads. When the start()
405 // method is called the new thread starts running the run() method in the new
406 // thread. The Thread object should not be deallocated before the thread has
407 // terminated.
408
409 class Thread {
410 public:
411 // Opaque data type for thread-local storage keys.
412 typedef int32_t LocalStorageKey;
413
414 class Options {
415 public:
Options()416 Options() : name_("v8:<unknown>"), stack_size_(0) {}
417 Options(const char* name, int stack_size = 0)
name_(name)418 : name_(name), stack_size_(stack_size) {}
419
name()420 const char* name() const { return name_; }
stack_size()421 int stack_size() const { return stack_size_; }
422
423 private:
424 const char* name_;
425 int stack_size_;
426 };
427
428 // Create new thread.
429 explicit Thread(const Options& options);
430 virtual ~Thread();
431
432 // Start new thread by calling the Run() method on the new thread.
433 void Start();
434
435 // Start new thread and wait until Run() method is called on the new thread.
StartSynchronously()436 void StartSynchronously() {
437 start_semaphore_ = new Semaphore(0);
438 Start();
439 start_semaphore_->Wait();
440 delete start_semaphore_;
441 start_semaphore_ = NULL;
442 }
443
444 // Wait until thread terminates.
445 void Join();
446
name()447 inline const char* name() const {
448 return name_;
449 }
450
451 // Abstract method for run handler.
452 virtual void Run() = 0;
453
454 // Thread-local storage.
455 static LocalStorageKey CreateThreadLocalKey();
456 static void DeleteThreadLocalKey(LocalStorageKey key);
457 static void* GetThreadLocal(LocalStorageKey key);
GetThreadLocalInt(LocalStorageKey key)458 static int GetThreadLocalInt(LocalStorageKey key) {
459 return static_cast<int>(reinterpret_cast<intptr_t>(GetThreadLocal(key)));
460 }
461 static void SetThreadLocal(LocalStorageKey key, void* value);
SetThreadLocalInt(LocalStorageKey key,int value)462 static void SetThreadLocalInt(LocalStorageKey key, int value) {
463 SetThreadLocal(key, reinterpret_cast<void*>(static_cast<intptr_t>(value)));
464 }
HasThreadLocal(LocalStorageKey key)465 static bool HasThreadLocal(LocalStorageKey key) {
466 return GetThreadLocal(key) != NULL;
467 }
468
469 #ifdef V8_FAST_TLS_SUPPORTED
GetExistingThreadLocal(LocalStorageKey key)470 static inline void* GetExistingThreadLocal(LocalStorageKey key) {
471 void* result = reinterpret_cast<void*>(
472 InternalGetExistingThreadLocal(static_cast<intptr_t>(key)));
473 ASSERT(result == GetThreadLocal(key));
474 return result;
475 }
476 #else
GetExistingThreadLocal(LocalStorageKey key)477 static inline void* GetExistingThreadLocal(LocalStorageKey key) {
478 return GetThreadLocal(key);
479 }
480 #endif
481
482 // A hint to the scheduler to let another thread run.
483 static void YieldCPU();
484
485
486 // The thread name length is limited to 16 based on Linux's implementation of
487 // prctl().
488 static const int kMaxThreadNameLength = 16;
489
490 class PlatformData;
data()491 PlatformData* data() { return data_; }
492
NotifyStartedAndRun()493 void NotifyStartedAndRun() {
494 if (start_semaphore_) start_semaphore_->Signal();
495 Run();
496 }
497
498 private:
499 void set_name(const char* name);
500
501 PlatformData* data_;
502
503 char name_[kMaxThreadNameLength];
504 int stack_size_;
505 Semaphore* start_semaphore_;
506
507 DISALLOW_COPY_AND_ASSIGN(Thread);
508 };
509
510 } } // namespace v8::internal
511
512 #endif // V8_PLATFORM_H_
513