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 :
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 :
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 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 :
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 116216 : class V8_BASE_EXPORT MemoryMappedFile {
190 : public:
191 : enum class FileMode { kReadOnly, kReadWrite };
192 :
193 116216 : 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 0 : struct SharedLibraryAddress {
216 : SharedLibraryAddress(const std::string& library_path, uintptr_t start,
217 : uintptr_t end)
218 0 : : 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))
292 : V8_BASE_EXPORT void EnsureConsoleOutputWin32();
293 : #endif // (defined(_WIN32) || defined(_WIN64))
294 :
295 : inline 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 :
311 : class 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 501179 : : 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 783 : void StartSynchronously() {
339 783 : start_semaphore_ = new Semaphore(0);
340 783 : Start();
341 783 : start_semaphore_->Wait();
342 783 : delete start_semaphore_;
343 783 : start_semaphore_ = nullptr;
344 783 : }
345 :
346 : // Wait until thread terminates.
347 : void Join();
348 :
349 : inline const char* name() const {
350 453807 : 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 685686 : 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 67266 : SetThreadLocal(key, reinterpret_cast<void*>(static_cast<intptr_t>(value)));
366 : }
367 : static bool HasThreadLocal(LocalStorageKey key) {
368 192 : 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 921216 : 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 453158 : void NotifyStartedAndRun() {
392 453158 : if (start_semaphore_) start_semaphore_->Signal();
393 453158 : Run();
394 432535 : }
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_
|