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 : namespace base {
40 :
41 : // ----------------------------------------------------------------------------
42 : // Fast TLS support
43 :
44 : #ifndef V8_NO_FAST_TLS
45 :
46 : #if V8_CC_MSVC && V8_HOST_ARCH_IA32
47 :
48 : #define V8_FAST_TLS_SUPPORTED 1
49 :
50 : INLINE(intptr_t InternalGetExistingThreadLocal(intptr_t index));
51 :
52 : inline intptr_t InternalGetExistingThreadLocal(intptr_t index) {
53 : const intptr_t kTibInlineTlsOffset = 0xE10;
54 : const intptr_t kTibExtraTlsOffset = 0xF94;
55 : const intptr_t kMaxInlineSlots = 64;
56 : const intptr_t kMaxSlots = kMaxInlineSlots + 1024;
57 : const intptr_t kPointerSize = sizeof(void*);
58 : DCHECK(0 <= index && index < kMaxSlots);
59 : USE(kMaxSlots);
60 : if (index < kMaxInlineSlots) {
61 : return static_cast<intptr_t>(__readfsdword(kTibInlineTlsOffset +
62 : kPointerSize * index));
63 : }
64 : intptr_t extra = static_cast<intptr_t>(__readfsdword(kTibExtraTlsOffset));
65 : DCHECK_NE(extra, 0);
66 : return *reinterpret_cast<intptr_t*>(extra +
67 : kPointerSize * (index - kMaxInlineSlots));
68 : }
69 :
70 : #elif defined(__APPLE__) && (V8_HOST_ARCH_IA32 || V8_HOST_ARCH_X64)
71 :
72 : #define V8_FAST_TLS_SUPPORTED 1
73 :
74 : extern V8_BASE_EXPORT intptr_t kMacTlsBaseOffset;
75 :
76 : INLINE(intptr_t InternalGetExistingThreadLocal(intptr_t index));
77 :
78 : inline intptr_t InternalGetExistingThreadLocal(intptr_t index) {
79 : intptr_t result;
80 : #if V8_HOST_ARCH_IA32
81 : asm("movl %%gs:(%1,%2,4), %0;"
82 : :"=r"(result) // Output must be a writable register.
83 : :"r"(kMacTlsBaseOffset), "r"(index));
84 : #else
85 : asm("movq %%gs:(%1,%2,8), %0;"
86 : :"=r"(result)
87 : :"r"(kMacTlsBaseOffset), "r"(index));
88 : #endif
89 : return result;
90 : }
91 :
92 : #endif
93 :
94 : #endif // V8_NO_FAST_TLS
95 :
96 :
97 : class TimezoneCache;
98 :
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 : // - random_seed: Used for the GetRandomMmapAddress() if non-zero.
111 : // - hard_abort: If true, OS::Abort() will crash instead of aborting.
112 : // - gc_fake_mmap: Name of the file for fake gc mmap used in ll_prof.
113 : static void Initialize(int64_t random_seed, bool hard_abort,
114 : const char* const gc_fake_mmap);
115 :
116 : // Returns the accumulated user time for thread. This routine
117 : // can be used for profiling. The implementation should
118 : // strive for high-precision timer resolution, preferable
119 : // micro-second resolution.
120 : static int GetUserTime(uint32_t* secs, uint32_t* usecs);
121 :
122 : // Returns current time as the number of milliseconds since
123 : // 00:00:00 UTC, January 1, 1970.
124 : static double TimeCurrentMillis();
125 :
126 : static TimezoneCache* CreateTimezoneCache();
127 :
128 : // Returns last OS error.
129 : static int GetLastError();
130 :
131 : static FILE* FOpen(const char* path, const char* mode);
132 : static bool Remove(const char* path);
133 :
134 : static char DirectorySeparator();
135 : static bool isDirectorySeparator(const char ch);
136 :
137 : // Opens a temporary file, the file is auto removed on close.
138 : static FILE* OpenTemporaryFile();
139 :
140 : // Log file open mode is platform-dependent due to line ends issues.
141 : static const char* const LogFileOpenMode;
142 :
143 : // Print output to console. This is mostly used for debugging output.
144 : // On platforms that has standard terminal output, the output
145 : // should go to stdout.
146 : static PRINTF_FORMAT(1, 2) void Print(const char* format, ...);
147 : static PRINTF_FORMAT(1, 0) void VPrint(const char* format, va_list args);
148 :
149 : // Print output to a file. This is mostly used for debugging output.
150 : static PRINTF_FORMAT(2, 3) void FPrint(FILE* out, const char* format, ...);
151 : static PRINTF_FORMAT(2, 0) void VFPrint(FILE* out, const char* format,
152 : va_list args);
153 :
154 : // Print error output to console. This is mostly used for error message
155 : // output. On platforms that has standard terminal output, the output
156 : // should go to stderr.
157 : static PRINTF_FORMAT(1, 2) void PrintError(const char* format, ...);
158 : static PRINTF_FORMAT(1, 0) void VPrintError(const char* format, va_list args);
159 :
160 : // Memory access permissions. Only the modes currently used by V8 are listed
161 : // here even though most systems support additional modes.
162 : enum class MemoryPermission { kNoAccess, kReadWrite, kReadWriteExecute };
163 :
164 : // Allocate/Free memory used by JS heap. Permissions are set according to the
165 : // is_* flags. Returns the address of allocated memory, or nullptr if failed.
166 : static void* Allocate(const size_t requested, size_t* allocated,
167 : MemoryPermission access, void* hint = nullptr);
168 : // Allocate/Free memory used by JS heap. Pages are readable/writable, but
169 : // they are not guaranteed to be executable unless 'executable' is true.
170 : // Returns the address of allocated memory, or nullptr if failed.
171 : static void* Allocate(const size_t requested, size_t* allocated,
172 : bool is_executable, void* hint = nullptr);
173 : static void Free(void* address, const size_t size);
174 :
175 : // Allocates a region of memory that is inaccessible. On Windows this reserves
176 : // but does not commit the memory. On POSIX systems it allocates memory as
177 : // PROT_NONE, which also prevents it from being committed.
178 : static void* AllocateGuarded(const size_t requested);
179 :
180 : // This is the granularity at which the SetReadAndExecutable(...) call can
181 : // set page permissions.
182 : static intptr_t CommitPageSize();
183 :
184 : // Mark a region of memory executable and readable but not writable.
185 : static void SetReadAndExecutable(void* address, const size_t size);
186 :
187 : // Assign memory as a guard page so that access will cause an exception.
188 : static void Guard(void* address, const size_t size);
189 :
190 : // Make a region of memory non-executable but readable and writable.
191 : static void SetReadAndWritable(void* address, const size_t size, bool commit);
192 :
193 : // Generate a random address to be used for hinting mmap().
194 : static void* GetRandomMmapAddr();
195 :
196 : // Get the Alignment guaranteed by Allocate().
197 : static size_t AllocateAlignment();
198 :
199 : static void* ReserveRegion(size_t size, void* hint);
200 :
201 : static void* ReserveAlignedRegion(size_t size, size_t alignment, void* hint,
202 : size_t* allocated);
203 :
204 : static bool CommitRegion(void* address, size_t size, bool is_executable);
205 :
206 : static bool UncommitRegion(void* address, size_t size);
207 :
208 : static bool ReleaseRegion(void* address, size_t size);
209 :
210 : // Release part of a reserved address range.
211 : static bool ReleasePartialRegion(void* address, size_t size);
212 :
213 : static bool HasLazyCommits();
214 :
215 : // Sleep for a specified time interval.
216 : static void Sleep(TimeDelta interval);
217 :
218 : // Abort the current process.
219 : [[noreturn]] static void Abort();
220 :
221 : // Debug break.
222 : static void DebugBreak();
223 :
224 : // Walk the stack.
225 : static const int kStackWalkError = -1;
226 : static const int kStackWalkMaxNameLen = 256;
227 : static const int kStackWalkMaxTextLen = 256;
228 : struct StackFrame {
229 : void* address;
230 : char text[kStackWalkMaxTextLen];
231 : };
232 :
233 0 : class V8_BASE_EXPORT MemoryMappedFile {
234 : public:
235 0 : virtual ~MemoryMappedFile() {}
236 : virtual void* memory() const = 0;
237 : virtual size_t size() const = 0;
238 :
239 : static MemoryMappedFile* open(const char* name);
240 : static MemoryMappedFile* create(const char* name, size_t size,
241 : void* initial);
242 : };
243 :
244 : // Safe formatting print. Ensures that str is always null-terminated.
245 : // Returns the number of chars written, or -1 if output was truncated.
246 : static PRINTF_FORMAT(3, 4) int SNPrintF(char* str, int length,
247 : const char* format, ...);
248 : static PRINTF_FORMAT(3, 0) int VSNPrintF(char* str, int length,
249 : const char* format, va_list args);
250 :
251 : static char* StrChr(char* str, int c);
252 : static void StrNCpy(char* dest, int length, const char* src, size_t n);
253 :
254 : // Support for the profiler. Can do nothing, in which case ticks
255 : // occurring in shared libraries will not be properly accounted for.
256 0 : struct SharedLibraryAddress {
257 : SharedLibraryAddress(const std::string& library_path, uintptr_t start,
258 : uintptr_t end)
259 0 : : library_path(library_path), start(start), end(end), aslr_slide(0) {}
260 : SharedLibraryAddress(const std::string& library_path, uintptr_t start,
261 : uintptr_t end, intptr_t aslr_slide)
262 : : library_path(library_path),
263 : start(start),
264 : end(end),
265 : aslr_slide(aslr_slide) {}
266 :
267 : std::string library_path;
268 : uintptr_t start;
269 : uintptr_t end;
270 : intptr_t aslr_slide;
271 : };
272 :
273 : static std::vector<SharedLibraryAddress> GetSharedLibraryAddresses();
274 :
275 : // Support for the profiler. Notifies the external profiling
276 : // process that a code moving garbage collection starts. Can do
277 : // nothing, in which case the code objects must not move (e.g., by
278 : // using --never-compact) if accurate profiling is desired.
279 : static void SignalCodeMovingGC();
280 :
281 : // Support runtime detection of whether the hard float option of the
282 : // EABI is used.
283 : static bool ArmUsingHardFloat();
284 :
285 : // Returns the activation frame alignment constraint or zero if
286 : // the platform doesn't care. Guaranteed to be a power of two.
287 : static int ActivationFrameAlignment();
288 :
289 : static int GetCurrentProcessId();
290 :
291 : static int GetCurrentThreadId();
292 :
293 : private:
294 : static const int msPerSecond = 1000;
295 :
296 : #if V8_OS_POSIX
297 : static const char* GetGCFakeMMapFile();
298 : #endif
299 :
300 : DISALLOW_IMPLICIT_CONSTRUCTORS(OS);
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 : typedef int32_t LocalStorageKey;
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 440607 : : 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 245 : void StartSynchronously() {
339 245 : start_semaphore_ = new Semaphore(0);
340 245 : Start();
341 245 : start_semaphore_->Wait();
342 245 : delete start_semaphore_;
343 245 : start_semaphore_ = nullptr;
344 245 : }
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 3700036 : 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 65147 : 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 668074 : static inline void* GetExistingThreadLocal(LocalStorageKey key) {
380 668202 : 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 386366 : void NotifyStartedAndRun() {
392 386366 : if (start_semaphore_) start_semaphore_->Signal();
393 386366 : Run();
394 381224 : }
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_
|