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
38namespace v8 {
39
40namespace 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
51V8_INLINE intptr_t InternalGetExistingThreadLocal(intptr_t index);
52
53inline 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 kSystemPointerSize = sizeof(void*);
59 DCHECK(0 <= index && index < kMaxSlots);
60 USE(kMaxSlots);
61 if (index < kMaxInlineSlots) {
62 return static_cast<intptr_t>(
63 __readfsdword(kTibInlineTlsOffset + kSystemPointerSize * index));
64 }
65 intptr_t extra = static_cast<intptr_t>(__readfsdword(kTibExtraTlsOffset));
66 DCHECK_NE(extra, 0);
67 return *reinterpret_cast<intptr_t*>(extra + kSystemPointerSize *
68 (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
75extern V8_BASE_EXPORT intptr_t kMacTlsBaseOffset;
76
77V8_INLINE intptr_t InternalGetExistingThreadLocal(intptr_t index);
78
79inline 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
97class PageAllocator;
98class 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
107class 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:
191 enum class FileMode { kReadOnly, kReadWrite };
192
193 virtual ~MemoryMappedFile() = default;
194 virtual void* memory() const = 0;
195 virtual size_t size() const = 0;
196
197 static MemoryMappedFile* open(const char* name,
198 FileMode mode = FileMode::kReadWrite);
199 static MemoryMappedFile* create(const char* name, size_t size,
200 void* initial);
201 };
202
203 // Safe formatting print. Ensures that str is always null-terminated.
204 // Returns the number of chars written, or -1 if output was truncated.
205 static PRINTF_FORMAT(3, 4) int SNPrintF(char* str, int length,
206 const char* format, ...);
207 static PRINTF_FORMAT(3, 0) int VSNPrintF(char* str, int length,
208 const char* format, va_list args);
209
210 static char* StrChr(char* str, int c);
211 static void StrNCpy(char* dest, int length, const char* src, size_t n);
212
213 // Support for the profiler. Can do nothing, in which case ticks
214 // occurring in shared libraries will not be properly accounted for.
215 struct SharedLibraryAddress {
216 SharedLibraryAddress(const std::string& library_path, uintptr_t start,
217 uintptr_t end)
218 : library_path(library_path), start(start), end(end), aslr_slide(0) {}
219 SharedLibraryAddress(const std::string& library_path, uintptr_t start,
220 uintptr_t end, intptr_t aslr_slide)
221 : library_path(library_path),
222 start(start),
223 end(end),
224 aslr_slide(aslr_slide) {}
225
226 std::string library_path;
227 uintptr_t start;
228 uintptr_t end;
229 intptr_t aslr_slide;
230 };
231
232 static std::vector<SharedLibraryAddress> GetSharedLibraryAddresses();
233
234 // Support for the profiler. Notifies the external profiling
235 // process that a code moving garbage collection starts. Can do
236 // nothing, in which case the code objects must not move (e.g., by
237 // using --never-compact) if accurate profiling is desired.
238 static void SignalCodeMovingGC();
239
240 // Support runtime detection of whether the hard float option of the
241 // EABI is used.
242 static bool ArmUsingHardFloat();
243
244 // Returns the activation frame alignment constraint or zero if
245 // the platform doesn't care. Guaranteed to be a power of two.
246 static int ActivationFrameAlignment();
247
248 static int GetCurrentProcessId();
249
250 static int GetCurrentThreadId();
251
252 static void ExitProcess(int exit_code);
253
254 private:
255 // These classes use the private memory management API below.
256 friend class MemoryMappedFile;
257 friend class PosixMemoryMappedFile;
258 friend class v8::base::PageAllocator;
259
260 static size_t AllocatePageSize();
261
262 static size_t CommitPageSize();
263
264 static void SetRandomMmapSeed(int64_t seed);
265
266 static void* GetRandomMmapAddr();
267
268 V8_WARN_UNUSED_RESULT static void* Allocate(void* address, size_t size,
269 size_t alignment,
270 MemoryPermission access);
271
272 V8_WARN_UNUSED_RESULT static bool Free(void* address, const size_t size);
273
274 V8_WARN_UNUSED_RESULT static bool Release(void* address, size_t size);
275
276 V8_WARN_UNUSED_RESULT static bool SetPermissions(void* address, size_t size,
277 MemoryPermission access);
278
279 V8_WARN_UNUSED_RESULT static bool DiscardSystemPages(void* address,
280 size_t size);
281
282 static const int msPerSecond = 1000;
283
284#if V8_OS_POSIX
285 static const char* GetGCFakeMMapFile();
286#endif
287
288 DISALLOW_IMPLICIT_CONSTRUCTORS(OS);
289};
290
291#if (defined(_WIN32) || defined(_WIN64))
292V8_BASE_EXPORT void EnsureConsoleOutputWin32();
293#endif // (defined(_WIN32) || defined(_WIN64))
294
295inline void EnsureConsoleOutput() {
296#if (defined(_WIN32) || defined(_WIN64))
297 // Windows requires extra calls to send assert output to the console
298 // rather than a dialog box.
299 EnsureConsoleOutputWin32();
300#endif // (defined(_WIN32) || defined(_WIN64))
301}
302
303// ----------------------------------------------------------------------------
304// Thread
305//
306// Thread objects are used for creating and running threads. When the start()
307// method is called the new thread starts running the run() method in the new
308// thread. The Thread object should not be deallocated before the thread has
309// terminated.
310
311class V8_BASE_EXPORT Thread {
312 public:
313 // Opaque data type for thread-local storage keys.
314 using LocalStorageKey = int32_t;
315
316 class Options {
317 public:
318 Options() : name_("v8:<unknown>"), stack_size_(0) {}
319 explicit Options(const char* name, int stack_size = 0)
320 : name_(name), stack_size_(stack_size) {}
321
322 const char* name() const { return name_; }
323 int stack_size() const { return stack_size_; }
324
325 private:
326 const char* name_;
327 int stack_size_;
328 };
329
330 // Create new thread.
331 explicit Thread(const Options& options);
332 virtual ~Thread();
333
334 // Start new thread by calling the Run() method on the new thread.
335 void Start();
336
337 // Start new thread and wait until Run() method is called on the new thread.
338 void StartSynchronously() {
339 start_semaphore_ = new Semaphore(0);
340 Start();
341 start_semaphore_->Wait();
342 delete start_semaphore_;
343 start_semaphore_ = nullptr;
344 }
345
346 // Wait until thread terminates.
347 void Join();
348
349 inline const char* name() const {
350 return name_;
351 }
352
353 // Abstract method for run handler.
354 virtual void Run() = 0;
355
356 // Thread-local storage.
357 static LocalStorageKey CreateThreadLocalKey();
358 static void DeleteThreadLocalKey(LocalStorageKey key);
359 static void* GetThreadLocal(LocalStorageKey key);
360 static int GetThreadLocalInt(LocalStorageKey key) {
361 return static_cast<int>(reinterpret_cast<intptr_t>(GetThreadLocal(key)));
362 }
363 static void SetThreadLocal(LocalStorageKey key, void* value);
364 static void SetThreadLocalInt(LocalStorageKey key, int value) {
365 SetThreadLocal(key, reinterpret_cast<void*>(static_cast<intptr_t>(value)));
366 }
367 static bool HasThreadLocal(LocalStorageKey key) {
368 return GetThreadLocal(key) != nullptr;
369 }
370
371#ifdef V8_FAST_TLS_SUPPORTED
372 static inline void* GetExistingThreadLocal(LocalStorageKey key) {
373 void* result = reinterpret_cast<void*>(
374 InternalGetExistingThreadLocal(static_cast<intptr_t>(key)));
375 DCHECK(result == GetThreadLocal(key));
376 return result;
377 }
378#else
379 static inline void* GetExistingThreadLocal(LocalStorageKey key) {
380 return GetThreadLocal(key);
381 }
382#endif
383
384 // The thread name length is limited to 16 based on Linux's implementation of
385 // prctl().
386 static const int kMaxThreadNameLength = 16;
387
388 class PlatformData;
389 PlatformData* data() { return data_; }
390
391 void NotifyStartedAndRun() {
392 if (start_semaphore_) start_semaphore_->Signal();
393 Run();
394 }
395
396 private:
397 void set_name(const char* name);
398
399 PlatformData* data_;
400
401 char name_[kMaxThreadNameLength];
402 int stack_size_;
403 Semaphore* start_semaphore_;
404
405 DISALLOW_COPY_AND_ASSIGN(Thread);
406};
407
408} // namespace base
409} // namespace v8
410
411#endif // V8_BASE_PLATFORM_PLATFORM_H_
412