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 113774 : class V8_BASE_EXPORT MemoryMappedFile {
190 : public:
191 113774 : virtual ~MemoryMappedFile() = default;
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 0 : struct SharedLibraryAddress {
213 : SharedLibraryAddress(const std::string& library_path, uintptr_t start,
214 : uintptr_t end)
215 0 : : library_path(library_path), start(start), end(end), aslr_slide(0) {}
216 : 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 : V8_WARN_UNUSED_RESULT static bool DiscardSystemPages(void* address,
277 : size_t size);
278 :
279 : static const int msPerSecond = 1000;
280 :
281 : #if V8_OS_POSIX
282 : static const char* GetGCFakeMMapFile();
283 : #endif
284 :
285 : DISALLOW_IMPLICIT_CONSTRUCTORS(OS);
286 : };
287 :
288 : #if (defined(_WIN32) || defined(_WIN64))
289 : V8_BASE_EXPORT void EnsureConsoleOutputWin32();
290 : #endif // (defined(_WIN32) || defined(_WIN64))
291 :
292 : inline void EnsureConsoleOutput() {
293 : #if (defined(_WIN32) || defined(_WIN64))
294 : // Windows requires extra calls to send assert output to the console
295 : // rather than a dialog box.
296 : EnsureConsoleOutputWin32();
297 : #endif // (defined(_WIN32) || defined(_WIN64))
298 : }
299 :
300 : // ----------------------------------------------------------------------------
301 : // Thread
302 : //
303 : // Thread objects are used for creating and running threads. When the start()
304 : // method is called the new thread starts running the run() method in the new
305 : // thread. The Thread object should not be deallocated before the thread has
306 : // terminated.
307 :
308 : class V8_BASE_EXPORT Thread {
309 : public:
310 : // Opaque data type for thread-local storage keys.
311 : typedef int32_t LocalStorageKey;
312 :
313 : class Options {
314 : public:
315 : Options() : name_("v8:<unknown>"), stack_size_(0) {}
316 : explicit Options(const char* name, int stack_size = 0)
317 489639 : : name_(name), stack_size_(stack_size) {}
318 :
319 : const char* name() const { return name_; }
320 : int stack_size() const { return stack_size_; }
321 :
322 : private:
323 : const char* name_;
324 : int stack_size_;
325 : };
326 :
327 : // Create new thread.
328 : explicit Thread(const Options& options);
329 : virtual ~Thread();
330 :
331 : // Start new thread by calling the Run() method on the new thread.
332 : void Start();
333 :
334 : // Start new thread and wait until Run() method is called on the new thread.
335 728 : void StartSynchronously() {
336 728 : start_semaphore_ = new Semaphore(0);
337 728 : Start();
338 728 : start_semaphore_->Wait();
339 728 : delete start_semaphore_;
340 728 : start_semaphore_ = nullptr;
341 728 : }
342 :
343 : // Wait until thread terminates.
344 : void Join();
345 :
346 : inline const char* name() const {
347 : return name_;
348 : }
349 :
350 : // Abstract method for run handler.
351 : virtual void Run() = 0;
352 :
353 : // Thread-local storage.
354 : static LocalStorageKey CreateThreadLocalKey();
355 : static void DeleteThreadLocalKey(LocalStorageKey key);
356 : static void* GetThreadLocal(LocalStorageKey key);
357 : static int GetThreadLocalInt(LocalStorageKey key) {
358 648398 : return static_cast<int>(reinterpret_cast<intptr_t>(GetThreadLocal(key)));
359 : }
360 : static void SetThreadLocal(LocalStorageKey key, void* value);
361 : static void SetThreadLocalInt(LocalStorageKey key, int value) {
362 65796 : SetThreadLocal(key, reinterpret_cast<void*>(static_cast<intptr_t>(value)));
363 : }
364 : static bool HasThreadLocal(LocalStorageKey key) {
365 192 : return GetThreadLocal(key) != nullptr;
366 : }
367 :
368 : #ifdef V8_FAST_TLS_SUPPORTED
369 : static inline void* GetExistingThreadLocal(LocalStorageKey key) {
370 : void* result = reinterpret_cast<void*>(
371 : InternalGetExistingThreadLocal(static_cast<intptr_t>(key)));
372 : DCHECK(result == GetThreadLocal(key));
373 : return result;
374 : }
375 : #else
376 904764 : static inline void* GetExistingThreadLocal(LocalStorageKey key) {
377 904892 : return GetThreadLocal(key);
378 : }
379 : #endif
380 :
381 : // The thread name length is limited to 16 based on Linux's implementation of
382 : // prctl().
383 : static const int kMaxThreadNameLength = 16;
384 :
385 : class PlatformData;
386 : PlatformData* data() { return data_; }
387 :
388 443322 : void NotifyStartedAndRun() {
389 443322 : if (start_semaphore_) start_semaphore_->Signal();
390 443322 : Run();
391 422452 : }
392 :
393 : private:
394 : void set_name(const char* name);
395 :
396 : PlatformData* data_;
397 :
398 : char name_[kMaxThreadNameLength];
399 : int stack_size_;
400 : Semaphore* start_semaphore_;
401 :
402 : DISALLOW_COPY_AND_ASSIGN(Thread);
403 : };
404 :
405 : } // namespace base
406 : } // namespace v8
407 :
408 : #endif // V8_BASE_PLATFORM_PLATFORM_H_
|