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
40 namespace base {
41
42 // ----------------------------------------------------------------------------
43 // Fast TLS support
44
45 #ifndef V8_NO_FAST_TLS
46
47 #if V8_CC_MSVC && V8_HOST_ARCH_IA32
48
49 #define V8_FAST_TLS_SUPPORTED 1
50
51 V8_INLINE intptr_t InternalGetExistingThreadLocal(intptr_t index);
52
InternalGetExistingThreadLocal(intptr_t index)53 inline intptr_t InternalGetExistingThreadLocal(intptr_t index) {
54 const intptr_t kTibInlineTlsOffset = 0xE10;
55 const intptr_t kTibExtraTlsOffset = 0xF94;
56 const intptr_t kMaxInlineSlots = 64;
57 const intptr_t kMaxSlots = kMaxInlineSlots + 1024;
58 const intptr_t kPointerSize = sizeof(void*);
59 DCHECK(0 <= index && index < kMaxSlots);
60 USE(kMaxSlots);
61 if (index < kMaxInlineSlots) {
62 return static_cast<intptr_t>(__readfsdword(kTibInlineTlsOffset +
63 kPointerSize * index));
64 }
65 intptr_t extra = static_cast<intptr_t>(__readfsdword(kTibExtraTlsOffset));
66 DCHECK_NE(extra, 0);
67 return *reinterpret_cast<intptr_t*>(extra +
68 kPointerSize * (index - kMaxInlineSlots));
69 }
70
71 #elif defined(__APPLE__) && (V8_HOST_ARCH_IA32 || V8_HOST_ARCH_X64)
72
73 #define V8_FAST_TLS_SUPPORTED 1
74
75 extern V8_BASE_EXPORT intptr_t kMacTlsBaseOffset;
76
77 V8_INLINE intptr_t InternalGetExistingThreadLocal(intptr_t index);
78
79 inline intptr_t InternalGetExistingThreadLocal(intptr_t index) {
80 intptr_t result;
81 #if V8_HOST_ARCH_IA32
82 asm("movl %%gs:(%1,%2,4), %0;"
83 :"=r"(result) // Output must be a writable register.
84 :"r"(kMacTlsBaseOffset), "r"(index));
85 #else
86 asm("movq %%gs:(%1,%2,8), %0;"
87 :"=r"(result)
88 :"r"(kMacTlsBaseOffset), "r"(index));
89 #endif
90 return result;
91 }
92
93 #endif
94
95 #endif // V8_NO_FAST_TLS
96
97 class PageAllocator;
98 class TimezoneCache;
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 // - 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(bool hard_abort, const char* const gc_fake_mmap);
113
114 // Returns the accumulated user time for thread. This routine
115 // can be used for profiling. The implementation should
116 // strive for high-precision timer resolution, preferable
117 // micro-second resolution.
118 static int GetUserTime(uint32_t* secs, uint32_t* usecs);
119
120 // Returns current time as the number of milliseconds since
121 // 00:00:00 UTC, January 1, 1970.
122 static double TimeCurrentMillis();
123
124 static TimezoneCache* CreateTimezoneCache();
125
126 // Returns last OS error.
127 static int GetLastError();
128
129 static FILE* FOpen(const char* path, const char* mode);
130 static bool Remove(const char* path);
131
132 static char DirectorySeparator();
133 static bool isDirectorySeparator(const char ch);
134
135 // Opens a temporary file, the file is auto removed on close.
136 static FILE* OpenTemporaryFile();
137
138 // Log file open mode is platform-dependent due to line ends issues.
139 static const char* const LogFileOpenMode;
140
141 // Print output to console. This is mostly used for debugging output.
142 // On platforms that has standard terminal output, the output
143 // should go to stdout.
144 static PRINTF_FORMAT(1, 2) void Print(const char* format, ...);
145 static PRINTF_FORMAT(1, 0) void VPrint(const char* format, va_list args);
146
147 // Print output to a file. This is mostly used for debugging output.
148 static PRINTF_FORMAT(2, 3) void FPrint(FILE* out, const char* format, ...);
149 static PRINTF_FORMAT(2, 0) void VFPrint(FILE* out, const char* format,
150 va_list args);
151
152 // Print error output to console. This is mostly used for error message
153 // output. On platforms that has standard terminal output, the output
154 // should go to stderr.
155 static PRINTF_FORMAT(1, 2) void PrintError(const char* format, ...);
156 static PRINTF_FORMAT(1, 0) void VPrintError(const char* format, va_list args);
157
158 // Memory permissions. These should be kept in sync with the ones in
159 // v8::PageAllocator.
160 enum class MemoryPermission {
161 kNoAccess,
162 kRead,
163 kReadWrite,
164 // TODO(hpayer): Remove this flag. Memory should never be rwx.
165 kReadWriteExecute,
166 kReadExecute
167 };
168
169 static bool HasLazyCommits();
170
171 // Sleep for a specified time interval.
172 static void Sleep(TimeDelta interval);
173
174 // Abort the current process.
175 [[noreturn]] static void Abort();
176
177 // Debug break.
178 static void DebugBreak();
179
180 // Walk the stack.
181 static const int kStackWalkError = -1;
182 static const int kStackWalkMaxNameLen = 256;
183 static const int kStackWalkMaxTextLen = 256;
184 struct StackFrame {
185 void* address;
186 char text[kStackWalkMaxTextLen];
187 };
188
189 class V8_BASE_EXPORT MemoryMappedFile {
190 public:
~MemoryMappedFile()191 virtual ~MemoryMappedFile() {}
192 virtual void* memory() const = 0;
193 virtual size_t size() const = 0;
194
195 static MemoryMappedFile* open(const char* name);
196 static MemoryMappedFile* create(const char* name, size_t size,
197 void* initial);
198 };
199
200 // Safe formatting print. Ensures that str is always null-terminated.
201 // Returns the number of chars written, or -1 if output was truncated.
202 static PRINTF_FORMAT(3, 4) int SNPrintF(char* str, int length,
203 const char* format, ...);
204 static PRINTF_FORMAT(3, 0) int VSNPrintF(char* str, int length,
205 const char* format, va_list args);
206
207 static char* StrChr(char* str, int c);
208 static void StrNCpy(char* dest, int length, const char* src, size_t n);
209
210 // Support for the profiler. Can do nothing, in which case ticks
211 // occurring in shared libraries will not be properly accounted for.
212 struct SharedLibraryAddress {
SharedLibraryAddressSharedLibraryAddress213 SharedLibraryAddress(const std::string& library_path, uintptr_t start,
214 uintptr_t end)
215 : library_path(library_path), start(start), end(end), aslr_slide(0) {}
SharedLibraryAddressSharedLibraryAddress216 SharedLibraryAddress(const std::string& library_path, uintptr_t start,
217 uintptr_t end, intptr_t aslr_slide)
218 : library_path(library_path),
219 start(start),
220 end(end),
221 aslr_slide(aslr_slide) {}
222
223 std::string library_path;
224 uintptr_t start;
225 uintptr_t end;
226 intptr_t aslr_slide;
227 };
228
229 static std::vector<SharedLibraryAddress> GetSharedLibraryAddresses();
230
231 // Support for the profiler. Notifies the external profiling
232 // process that a code moving garbage collection starts. Can do
233 // nothing, in which case the code objects must not move (e.g., by
234 // using --never-compact) if accurate profiling is desired.
235 static void SignalCodeMovingGC();
236
237 // Support runtime detection of whether the hard float option of the
238 // EABI is used.
239 static bool ArmUsingHardFloat();
240
241 // Returns the activation frame alignment constraint or zero if
242 // the platform doesn't care. Guaranteed to be a power of two.
243 static int ActivationFrameAlignment();
244
245 static int GetCurrentProcessId();
246
247 static int GetCurrentThreadId();
248
249 static void ExitProcess(int exit_code);
250
251 private:
252 // These classes use the private memory management API below.
253 friend class MemoryMappedFile;
254 friend class PosixMemoryMappedFile;
255 friend class v8::base::PageAllocator;
256
257 static size_t AllocatePageSize();
258
259 static size_t CommitPageSize();
260
261 static void SetRandomMmapSeed(int64_t seed);
262
263 static void* GetRandomMmapAddr();
264
265 V8_WARN_UNUSED_RESULT static void* Allocate(void* address, size_t size,
266 size_t alignment,
267 MemoryPermission access);
268
269 V8_WARN_UNUSED_RESULT static bool Free(void* address, const size_t size);
270
271 V8_WARN_UNUSED_RESULT static bool Release(void* address, size_t size);
272
273 V8_WARN_UNUSED_RESULT static bool SetPermissions(void* address, size_t size,
274 MemoryPermission access);
275
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 #if (defined(_WIN32) || defined(_WIN64))
286 V8_BASE_EXPORT void EnsureConsoleOutputWin32();
287 #endif // (defined(_WIN32) || defined(_WIN64))
288
EnsureConsoleOutput()289 inline void EnsureConsoleOutput() {
290 #if (defined(_WIN32) || defined(_WIN64))
291 // Windows requires extra calls to send assert output to the console
292 // rather than a dialog box.
293 EnsureConsoleOutputWin32();
294 #endif // (defined(_WIN32) || defined(_WIN64))
295 }
296
297 // ----------------------------------------------------------------------------
298 // Thread
299 //
300 // Thread objects are used for creating and running threads. When the start()
301 // method is called the new thread starts running the run() method in the new
302 // thread. The Thread object should not be deallocated before the thread has
303 // terminated.
304
305 class V8_BASE_EXPORT Thread {
306 public:
307 // Opaque data type for thread-local storage keys.
308 typedef int32_t LocalStorageKey;
309
310 class Options {
311 public:
Options()312 Options() : name_("v8:<unknown>"), stack_size_(0) {}
313 explicit Options(const char* name, int stack_size = 0)
name_(name)314 : name_(name), stack_size_(stack_size) {}
315
name()316 const char* name() const { return name_; }
stack_size()317 int stack_size() const { return stack_size_; }
318
319 private:
320 const char* name_;
321 int stack_size_;
322 };
323
324 // Create new thread.
325 explicit Thread(const Options& options);
326 virtual ~Thread();
327
328 // Start new thread by calling the Run() method on the new thread.
329 void Start();
330
331 // Start new thread and wait until Run() method is called on the new thread.
StartSynchronously()332 void StartSynchronously() {
333 start_semaphore_ = new Semaphore(0);
334 Start();
335 start_semaphore_->Wait();
336 delete start_semaphore_;
337 start_semaphore_ = nullptr;
338 }
339
340 // Wait until thread terminates.
341 void Join();
342
name()343 inline const char* name() const {
344 return name_;
345 }
346
347 // Abstract method for run handler.
348 virtual void Run() = 0;
349
350 // Thread-local storage.
351 static LocalStorageKey CreateThreadLocalKey();
352 static void DeleteThreadLocalKey(LocalStorageKey key);
353 static void* GetThreadLocal(LocalStorageKey key);
GetThreadLocalInt(LocalStorageKey key)354 static int GetThreadLocalInt(LocalStorageKey key) {
355 return static_cast<int>(reinterpret_cast<intptr_t>(GetThreadLocal(key)));
356 }
357 static void SetThreadLocal(LocalStorageKey key, void* value);
SetThreadLocalInt(LocalStorageKey key,int value)358 static void SetThreadLocalInt(LocalStorageKey key, int value) {
359 SetThreadLocal(key, reinterpret_cast<void*>(static_cast<intptr_t>(value)));
360 }
HasThreadLocal(LocalStorageKey key)361 static bool HasThreadLocal(LocalStorageKey key) {
362 return GetThreadLocal(key) != nullptr;
363 }
364
365 #ifdef V8_FAST_TLS_SUPPORTED
GetExistingThreadLocal(LocalStorageKey key)366 static inline void* GetExistingThreadLocal(LocalStorageKey key) {
367 void* result = reinterpret_cast<void*>(
368 InternalGetExistingThreadLocal(static_cast<intptr_t>(key)));
369 DCHECK(result == GetThreadLocal(key));
370 return result;
371 }
372 #else
GetExistingThreadLocal(LocalStorageKey key)373 static inline void* GetExistingThreadLocal(LocalStorageKey key) {
374 return GetThreadLocal(key);
375 }
376 #endif
377
378 // The thread name length is limited to 16 based on Linux's implementation of
379 // prctl().
380 static const int kMaxThreadNameLength = 16;
381
382 class PlatformData;
data()383 PlatformData* data() { return data_; }
384
NotifyStartedAndRun()385 void NotifyStartedAndRun() {
386 if (start_semaphore_) start_semaphore_->Signal();
387 Run();
388 }
389
390 private:
391 void set_name(const char* name);
392
393 PlatformData* data_;
394
395 char name_[kMaxThreadNameLength];
396 int stack_size_;
397 Semaphore* start_semaphore_;
398
399 DISALLOW_COPY_AND_ASSIGN(Thread);
400 };
401
402 } // namespace base
403 } // namespace v8
404
405 #endif // V8_BASE_PLATFORM_PLATFORM_H_
406