blob: 606d10236eb5f6a498eda7034b609edd56974d7a [file] [log] [blame]
ulan@chromium.org2efb9002012-01-19 15:36:35 +00001// Copyright 2012 the V8 project authors. All rights reserved.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002// Redistribution and use in source and binary forms, with or without
3// modification, are permitted provided that the following conditions are
4// met:
5//
6// * Redistributions of source code must retain the above copyright
7// notice, this list of conditions and the following disclaimer.
8// * Redistributions in binary form must reproduce the above
9// copyright notice, this list of conditions and the following
10// disclaimer in the documentation and/or other materials provided
11// with the distribution.
12// * Neither the name of Google Inc. nor the names of its
13// contributors may be used to endorse or promote products derived
14// from this software without specific prior written permission.
15//
16// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000028// Platform specific code for Linux goes here. For the POSIX comaptible parts
29// the implementation is in platform-posix.cc.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000030
31#include <pthread.h>
32#include <semaphore.h>
33#include <signal.h>
lrn@chromium.org5d00b602011-01-05 09:51:43 +000034#include <sys/prctl.h>
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000035#include <sys/time.h>
36#include <sys/resource.h>
lrn@chromium.org303ada72010-10-27 09:33:13 +000037#include <sys/syscall.h>
ager@chromium.org381abbb2009-02-25 13:23:22 +000038#include <sys/types.h>
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000039#include <stdlib.h>
40
41// Ubuntu Dapper requires memory pages to be marked as
42// executable. Otherwise, OS raises an exception when executing code
43// in that page.
44#include <sys/types.h> // mmap & munmap
ager@chromium.org236ad962008-09-25 09:45:57 +000045#include <sys/mman.h> // mmap & munmap
46#include <sys/stat.h> // open
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000047#include <fcntl.h> // open
48#include <unistd.h> // sysconf
fschneider@chromium.org7d10be52012-04-10 12:30:14 +000049#if defined(__GLIBC__) && !defined(__UCLIBC__)
ager@chromium.org236ad962008-09-25 09:45:57 +000050#include <execinfo.h> // backtrace, backtrace_symbols
fschneider@chromium.org7d10be52012-04-10 12:30:14 +000051#endif // defined(__GLIBC__) && !defined(__UCLIBC__)
ager@chromium.org236ad962008-09-25 09:45:57 +000052#include <strings.h> // index
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000053#include <errno.h>
54#include <stdarg.h>
55
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +000056// GLibc on ARM defines mcontext_t has a typedef for 'struct sigcontext'.
57// Old versions of the C library <signal.h> didn't define the type.
58#if defined(__ANDROID__) && !defined(__BIONIC_HAVE_UCONTEXT_T) && \
59 defined(__arm__) && !defined(__BIONIC_HAVE_STRUCT_SIGCONTEXT)
60#include <asm/sigcontext.h>
61#endif
62
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000063#undef MAP_TYPE
64
65#include "v8.h"
66
danno@chromium.org8c0a43f2012-04-03 08:37:53 +000067#include "platform-posix.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000068#include "platform.h"
ager@chromium.orga1645e22009-09-09 19:27:10 +000069#include "v8threads.h"
kasperl@chromium.orga5551262010-12-07 12:49:48 +000070#include "vm-state-inl.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000071
72
kasperl@chromium.org71affb52009-05-26 05:44:31 +000073namespace v8 {
74namespace internal {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000075
76// 0 is never a valid thread id on Linux since tids and pids share a
77// name space and pid 0 is reserved (see man 2 kill).
78static const pthread_t kNoThread = (pthread_t) 0;
79
80
81double ceiling(double x) {
82 return ceil(x);
83}
84
85
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000086static Mutex* limit_mutex = NULL;
87
88
danno@chromium.org8c0a43f2012-04-03 08:37:53 +000089void OS::PostSetUp() {
fschneider@chromium.org7d10be52012-04-10 12:30:14 +000090 POSIXPostSetUp();
danno@chromium.org8c0a43f2012-04-03 08:37:53 +000091}
92
93
ager@chromium.orgc4c92722009-11-18 14:12:51 +000094uint64_t OS::CpuFeaturesImpliedByPlatform() {
ager@chromium.orgc4c92722009-11-18 14:12:51 +000095 return 0; // Linux runs on anything.
ager@chromium.orgc4c92722009-11-18 14:12:51 +000096}
97
98
ager@chromium.orgc4c92722009-11-18 14:12:51 +000099#ifdef __arm__
lrn@chromium.orgfa943b72010-11-03 08:14:36 +0000100static bool CPUInfoContainsString(const char * search_string) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +0000101 const char* file_name = "/proc/cpuinfo";
ager@chromium.orgc4c92722009-11-18 14:12:51 +0000102 // This is written as a straight shot one pass parser
103 // and not using STL string and ifstream because,
104 // on Linux, it's reading from a (non-mmap-able)
105 // character special device.
ager@chromium.orgc4c92722009-11-18 14:12:51 +0000106 FILE* f = NULL;
107 const char* what = search_string;
108
109 if (NULL == (f = fopen(file_name, "r")))
110 return false;
111
112 int k;
113 while (EOF != (k = fgetc(f))) {
114 if (k == *what) {
115 ++what;
116 while ((*what != '\0') && (*what == fgetc(f))) {
117 ++what;
118 }
119 if (*what == '\0') {
120 fclose(f);
121 return true;
122 } else {
123 what = search_string;
124 }
125 }
126 }
127 fclose(f);
128
129 // Did not find string in the proc file.
130 return false;
131}
lrn@chromium.orgfa943b72010-11-03 08:14:36 +0000132
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +0000133
lrn@chromium.orgfa943b72010-11-03 08:14:36 +0000134bool OS::ArmCpuHasFeature(CpuFeature feature) {
ager@chromium.org5f0c45f2010-12-17 08:51:21 +0000135 const char* search_string = NULL;
lrn@chromium.orgfa943b72010-11-03 08:14:36 +0000136 // Simple detection of VFP at runtime for Linux.
137 // It is based on /proc/cpuinfo, which reveals hardware configuration
138 // to user-space applications. According to ARM (mid 2009), no similar
139 // facility is universally available on the ARM architectures,
140 // so it's up to individual OSes to provide such.
141 switch (feature) {
verwaest@chromium.orgb6d052d2012-07-27 08:03:27 +0000142 case VFP2:
143 search_string = "vfp";
144 break;
lrn@chromium.orgfa943b72010-11-03 08:14:36 +0000145 case VFP3:
ager@chromium.org5f0c45f2010-12-17 08:51:21 +0000146 search_string = "vfpv3";
lrn@chromium.orgfa943b72010-11-03 08:14:36 +0000147 break;
148 case ARMv7:
ager@chromium.org5f0c45f2010-12-17 08:51:21 +0000149 search_string = "ARMv7";
lrn@chromium.orgfa943b72010-11-03 08:14:36 +0000150 break;
151 default:
152 UNREACHABLE();
153 }
154
ager@chromium.org5f0c45f2010-12-17 08:51:21 +0000155 if (CPUInfoContainsString(search_string)) {
156 return true;
157 }
158
159 if (feature == VFP3) {
160 // Some old kernels will report vfp not vfpv3. Here we make a last attempt
161 // to detect vfpv3 by checking for vfp *and* neon, since neon is only
162 // available on architectures with vfpv3.
163 // Checking neon on its own is not enough as it is possible to have neon
164 // without vfp.
165 if (CPUInfoContainsString("vfp") && CPUInfoContainsString("neon")) {
lrn@chromium.orgfa943b72010-11-03 08:14:36 +0000166 return true;
167 }
168 }
169
170 return false;
171}
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +0000172
173
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +0000174bool OS::ArmUsingHardFloat() {
yangguo@chromium.orgc74d6742012-06-29 15:15:45 +0000175 // GCC versions 4.6 and above define __ARM_PCS or __ARM_PCS_VFP to specify
176 // the Floating Point ABI used (PCS stands for Procedure Call Standard).
177 // We use these as well as a couple of other defines to statically determine
178 // what FP ABI used.
179 // GCC versions 4.4 and below don't support hard-fp.
180 // GCC versions 4.5 may support hard-fp without defining __ARM_PCS or
181 // __ARM_PCS_VFP.
182
183#define GCC_VERSION (__GNUC__ * 10000 \
184 + __GNUC_MINOR__ * 100 \
185 + __GNUC_PATCHLEVEL__)
186#if GCC_VERSION >= 40600
187#if defined(__ARM_PCS_VFP)
188 return true;
189#else
190 return false;
191#endif
192
193#elif GCC_VERSION < 40500
194 return false;
195
196#else
197#if defined(__ARM_PCS_VFP)
198 return true;
199#elif defined(__ARM_PCS) || defined(__SOFTFP) || !defined(__VFP_FP__)
200 return false;
201#else
202#error "Your version of GCC does not report the FP ABI compiled for." \
203 "Please report it on this issue" \
204 "http://code.google.com/p/v8/issues/detail?id=2140"
205
206#endif
207#endif
208#undef GCC_VERSION
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +0000209}
yangguo@chromium.orgc74d6742012-06-29 15:15:45 +0000210
ager@chromium.orgc4c92722009-11-18 14:12:51 +0000211#endif // def __arm__
212
213
lrn@chromium.org7516f052011-03-30 08:52:27 +0000214#ifdef __mips__
215bool OS::MipsCpuHasFeature(CpuFeature feature) {
216 const char* search_string = NULL;
217 const char* file_name = "/proc/cpuinfo";
218 // Simple detection of FPU at runtime for Linux.
219 // It is based on /proc/cpuinfo, which reveals hardware configuration
220 // to user-space applications. According to MIPS (early 2010), no similar
221 // facility is universally available on the MIPS architectures,
222 // so it's up to individual OSes to provide such.
223 //
224 // This is written as a straight shot one pass parser
225 // and not using STL string and ifstream because,
226 // on Linux, it's reading from a (non-mmap-able)
227 // character special device.
228
229 switch (feature) {
230 case FPU:
231 search_string = "FPU";
232 break;
233 default:
234 UNREACHABLE();
235 }
236
237 FILE* f = NULL;
238 const char* what = search_string;
239
240 if (NULL == (f = fopen(file_name, "r")))
241 return false;
242
243 int k;
244 while (EOF != (k = fgetc(f))) {
245 if (k == *what) {
246 ++what;
247 while ((*what != '\0') && (*what == fgetc(f))) {
248 ++what;
249 }
250 if (*what == '\0') {
251 fclose(f);
252 return true;
253 } else {
254 what = search_string;
255 }
256 }
257 }
258 fclose(f);
259
260 // Did not find string in the proc file.
261 return false;
262}
263#endif // def __mips__
264
265
ager@chromium.org236ad962008-09-25 09:45:57 +0000266int OS::ActivationFrameAlignment() {
ager@chromium.orge2902be2009-06-08 12:21:35 +0000267#ifdef V8_TARGET_ARCH_ARM
kasperl@chromium.orgb3284ad2009-05-18 06:12:45 +0000268 // On EABI ARM targets this is required for fp correctness in the
269 // runtime system.
ager@chromium.org3a6061e2009-03-12 14:24:36 +0000270 return 8;
ager@chromium.org5c838252010-02-19 08:53:10 +0000271#elif V8_TARGET_ARCH_MIPS
272 return 8;
273#endif
ricow@chromium.orgc9c80822010-04-21 08:22:37 +0000274 // With gcc 4.4 the tree vectorization optimizer can generate code
ager@chromium.orge2902be2009-06-08 12:21:35 +0000275 // that requires 16 byte alignment such as movdqa on x86.
276 return 16;
ager@chromium.org236ad962008-09-25 09:45:57 +0000277}
278
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000279
kmillikin@chromium.org9155e252010-05-26 13:27:57 +0000280void OS::ReleaseStore(volatile AtomicWord* ptr, AtomicWord value) {
lrn@chromium.org7516f052011-03-30 08:52:27 +0000281#if (defined(V8_TARGET_ARCH_ARM) && defined(__arm__)) || \
282 (defined(V8_TARGET_ARCH_MIPS) && defined(__mips__))
283 // Only use on ARM or MIPS hardware.
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000284 MemoryBarrier();
kmillikin@chromium.org9155e252010-05-26 13:27:57 +0000285#else
286 __asm__ __volatile__("" : : : "memory");
287 // An x86 store acts as a release barrier.
288#endif
289 *ptr = value;
290}
291
292
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000293const char* OS::LocalTimezone(double time) {
294 if (isnan(time)) return "";
295 time_t tv = static_cast<time_t>(floor(time/msPerSecond));
296 struct tm* t = localtime(&tv);
297 if (NULL == t) return "";
298 return t->tm_zone;
299}
300
301
302double OS::LocalTimeOffset() {
303 time_t tv = time(NULL);
304 struct tm* t = localtime(&tv);
305 // tm_gmtoff includes any daylight savings offset, so subtract it.
306 return static_cast<double>(t->tm_gmtoff * msPerSecond -
307 (t->tm_isdst > 0 ? 3600 * msPerSecond : 0));
308}
309
310
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000311// We keep the lowest and highest addresses mapped as a quick way of
312// determining that pointers are outside the heap (used mostly in assertions
ulan@chromium.org2efb9002012-01-19 15:36:35 +0000313// and verification). The estimate is conservative, i.e., not all addresses in
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000314// 'allocated' space are actually allocated to our heap. The range is
315// [lowest, highest), inclusive on the low and and exclusive on the high end.
316static void* lowest_ever_allocated = reinterpret_cast<void*>(-1);
317static void* highest_ever_allocated = reinterpret_cast<void*>(0);
318
319
320static void UpdateAllocatedSpaceLimits(void* address, int size) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000321 ASSERT(limit_mutex != NULL);
322 ScopedLock lock(limit_mutex);
323
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000324 lowest_ever_allocated = Min(lowest_ever_allocated, address);
325 highest_ever_allocated =
326 Max(highest_ever_allocated,
327 reinterpret_cast<void*>(reinterpret_cast<char*>(address) + size));
328}
329
330
331bool OS::IsOutsideAllocatedSpace(void* address) {
332 return address < lowest_ever_allocated || address >= highest_ever_allocated;
333}
334
335
336size_t OS::AllocateAlignment() {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000337 return sysconf(_SC_PAGESIZE);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000338}
339
340
kasper.lund7276f142008-07-30 08:49:36 +0000341void* OS::Allocate(const size_t requested,
342 size_t* allocated,
kasperl@chromium.orgf5aa8372009-03-24 14:47:14 +0000343 bool is_executable) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000344 const size_t msize = RoundUp(requested, AllocateAlignment());
kasperl@chromium.orgf5aa8372009-03-24 14:47:14 +0000345 int prot = PROT_READ | PROT_WRITE | (is_executable ? PROT_EXEC : 0);
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +0000346 void* addr = OS::GetRandomMmapAddr();
ricow@chromium.org9fa09672011-07-25 11:05:35 +0000347 void* mbase = mmap(addr, msize, prot, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000348 if (mbase == MAP_FAILED) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000349 LOG(i::Isolate::Current(),
350 StringEvent("OS::Allocate", "mmap failed"));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000351 return NULL;
352 }
353 *allocated = msize;
354 UpdateAllocatedSpaceLimits(mbase, msize);
355 return mbase;
356}
357
358
kasperl@chromium.orgf5aa8372009-03-24 14:47:14 +0000359void OS::Free(void* address, const size_t size) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000360 // TODO(1240712): munmap has a return value which is ignored here.
ager@chromium.orga1645e22009-09-09 19:27:10 +0000361 int result = munmap(address, size);
362 USE(result);
363 ASSERT(result == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000364}
365
366
367void OS::Sleep(int milliseconds) {
368 unsigned int ms = static_cast<unsigned int>(milliseconds);
369 usleep(1000 * ms);
370}
371
372
373void OS::Abort() {
374 // Redirect to std abort to signal abnormal program termination.
rossberg@chromium.org2c067b12012-03-19 11:01:52 +0000375 if (FLAG_break_on_abort) {
376 DebugBreak();
377 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000378 abort();
379}
380
381
kasper.lund7276f142008-07-30 08:49:36 +0000382void OS::DebugBreak() {
ager@chromium.org5ec48922009-05-05 07:25:34 +0000383// TODO(lrn): Introduce processor define for runtime system (!= V8_ARCH_x,
384// which is the architecture of generated code).
ager@chromium.orgea4f62e2010-08-16 16:28:43 +0000385#if (defined(__arm__) || defined(__thumb__))
386# if defined(CAN_USE_ARMV5_INSTRUCTIONS)
kasper.lund7276f142008-07-30 08:49:36 +0000387 asm("bkpt 0");
ager@chromium.orgea4f62e2010-08-16 16:28:43 +0000388# endif
ager@chromium.org5c838252010-02-19 08:53:10 +0000389#elif defined(__mips__)
390 asm("break");
kasper.lund7276f142008-07-30 08:49:36 +0000391#else
392 asm("int $3");
393#endif
394}
395
396
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000397class PosixMemoryMappedFile : public OS::MemoryMappedFile {
398 public:
399 PosixMemoryMappedFile(FILE* file, void* memory, int size)
400 : file_(file), memory_(memory), size_(size) { }
401 virtual ~PosixMemoryMappedFile();
402 virtual void* memory() { return memory_; }
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +0000403 virtual int size() { return size_; }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000404 private:
405 FILE* file_;
406 void* memory_;
407 int size_;
408};
409
410
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +0000411OS::MemoryMappedFile* OS::MemoryMappedFile::open(const char* name) {
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +0000412 FILE* file = fopen(name, "r+");
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +0000413 if (file == NULL) return NULL;
414
415 fseek(file, 0, SEEK_END);
416 int size = ftell(file);
417
418 void* memory =
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +0000419 mmap(OS::GetRandomMmapAddr(),
420 size,
421 PROT_READ | PROT_WRITE,
422 MAP_SHARED,
423 fileno(file),
424 0);
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +0000425 return new PosixMemoryMappedFile(file, memory, size);
426}
427
428
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000429OS::MemoryMappedFile* OS::MemoryMappedFile::create(const char* name, int size,
430 void* initial) {
431 FILE* file = fopen(name, "w+");
432 if (file == NULL) return NULL;
ager@chromium.org9258b6b2008-09-11 09:11:10 +0000433 int result = fwrite(initial, size, 1, file);
434 if (result < 1) {
435 fclose(file);
436 return NULL;
437 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000438 void* memory =
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +0000439 mmap(OS::GetRandomMmapAddr(),
440 size,
441 PROT_READ | PROT_WRITE,
442 MAP_SHARED,
443 fileno(file),
444 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000445 return new PosixMemoryMappedFile(file, memory, size);
446}
447
448
449PosixMemoryMappedFile::~PosixMemoryMappedFile() {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000450 if (memory_) OS::Free(memory_, size_);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000451 fclose(file_);
452}
453
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000454
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000455void OS::LogSharedLibraryAddresses() {
sgjesse@chromium.orgb9d7da12009-08-05 08:38:10 +0000456 // This function assumes that the layout of the file is as follows:
457 // hex_start_addr-hex_end_addr rwxp <unused data> [binary_file_name]
458 // If we encounter an unexpected situation we abort scanning further entries.
ager@chromium.orgc4c92722009-11-18 14:12:51 +0000459 FILE* fp = fopen("/proc/self/maps", "r");
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000460 if (fp == NULL) return;
sgjesse@chromium.orgb9d7da12009-08-05 08:38:10 +0000461
462 // Allocate enough room to be able to store a full file name.
463 const int kLibNameLen = FILENAME_MAX + 1;
464 char* lib_name = reinterpret_cast<char*>(malloc(kLibNameLen));
465
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000466 i::Isolate* isolate = ISOLATE;
sgjesse@chromium.orgb9d7da12009-08-05 08:38:10 +0000467 // This loop will terminate once the scanning hits an EOF.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000468 while (true) {
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000469 uintptr_t start, end;
470 char attr_r, attr_w, attr_x, attr_p;
sgjesse@chromium.orgb9d7da12009-08-05 08:38:10 +0000471 // Parse the addresses and permission bits at the beginning of the line.
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000472 if (fscanf(fp, "%" V8PRIxPTR "-%" V8PRIxPTR, &start, &end) != 2) break;
473 if (fscanf(fp, " %c%c%c%c", &attr_r, &attr_w, &attr_x, &attr_p) != 4) break;
sgjesse@chromium.orgb9d7da12009-08-05 08:38:10 +0000474
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000475 int c;
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000476 if (attr_r == 'r' && attr_w != 'w' && attr_x == 'x') {
477 // Found a read-only executable entry. Skip characters until we reach
sgjesse@chromium.orgb9d7da12009-08-05 08:38:10 +0000478 // the beginning of the filename or the end of the line.
479 do {
480 c = getc(fp);
481 } while ((c != EOF) && (c != '\n') && (c != '/'));
482 if (c == EOF) break; // EOF: Was unexpected, just exit.
483
484 // Process the filename if found.
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000485 if (c == '/') {
sgjesse@chromium.orgb9d7da12009-08-05 08:38:10 +0000486 ungetc(c, fp); // Push the '/' back into the stream to be read below.
487
488 // Read to the end of the line. Exit if the read fails.
489 if (fgets(lib_name, kLibNameLen, fp) == NULL) break;
490
491 // Drop the newline character read by fgets. We do not need to check
492 // for a zero-length string because we know that we at least read the
493 // '/' character.
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000494 lib_name[strlen(lib_name) - 1] = '\0';
495 } else {
sgjesse@chromium.orgb9d7da12009-08-05 08:38:10 +0000496 // No library name found, just record the raw address range.
497 snprintf(lib_name, kLibNameLen,
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000498 "%08" V8PRIxPTR "-%08" V8PRIxPTR, start, end);
499 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000500 LOG(isolate, SharedLibraryEvent(lib_name, start, end));
sgjesse@chromium.orgb9d7da12009-08-05 08:38:10 +0000501 } else {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +0000502 // Entry not describing executable data. Skip to end of line to set up
sgjesse@chromium.orgb9d7da12009-08-05 08:38:10 +0000503 // reading the next entry.
504 do {
505 c = getc(fp);
506 } while ((c != EOF) && (c != '\n'));
507 if (c == EOF) break;
ager@chromium.org5aa501c2009-06-23 07:57:28 +0000508 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000509 }
sgjesse@chromium.orgb9d7da12009-08-05 08:38:10 +0000510 free(lib_name);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000511 fclose(fp);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000512}
513
514
whesse@chromium.org4a5224e2010-10-20 12:37:07 +0000515void OS::SignalCodeMovingGC() {
whesse@chromium.org4a5224e2010-10-20 12:37:07 +0000516 // Support for ll_prof.py.
517 //
518 // The Linux profiler built into the kernel logs all mmap's with
519 // PROT_EXEC so that analysis tools can properly attribute ticks. We
520 // do a mmap with a name known by ll_prof.py and immediately munmap
521 // it. This injects a GC marker into the stream of events generated
522 // by the kernel and allows us to synchronize V8 code log and the
523 // kernel log.
524 int size = sysconf(_SC_PAGESIZE);
mstarzinger@chromium.orgde886792012-09-11 13:22:37 +0000525 FILE* f = fopen(FLAG_gc_fake_mmap, "w+");
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +0000526 void* addr = mmap(OS::GetRandomMmapAddr(),
527 size,
528 PROT_READ | PROT_EXEC,
529 MAP_PRIVATE,
530 fileno(f),
531 0);
whesse@chromium.org4a5224e2010-10-20 12:37:07 +0000532 ASSERT(addr != MAP_FAILED);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000533 OS::Free(addr, size);
whesse@chromium.org4a5224e2010-10-20 12:37:07 +0000534 fclose(f);
whesse@chromium.org4a5224e2010-10-20 12:37:07 +0000535}
536
537
ager@chromium.org65dad4b2009-04-23 08:48:43 +0000538int OS::StackWalk(Vector<OS::StackFrame> frames) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000539 // backtrace is a glibc extension.
fschneider@chromium.org7d10be52012-04-10 12:30:14 +0000540#if defined(__GLIBC__) && !defined(__UCLIBC__)
ager@chromium.org65dad4b2009-04-23 08:48:43 +0000541 int frames_size = frames.length();
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +0000542 ScopedVector<void*> addresses(frames_size);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000543
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +0000544 int frames_count = backtrace(addresses.start(), frames_size);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000545
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +0000546 char** symbols = backtrace_symbols(addresses.start(), frames_count);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000547 if (symbols == NULL) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000548 return kStackWalkError;
549 }
550
551 for (int i = 0; i < frames_count; i++) {
552 frames[i].address = addresses[i];
553 // Format a text representation of the frame based on the information
554 // available.
kasperl@chromium.orgb9123622008-09-17 14:05:56 +0000555 SNPrintF(MutableCStrVector(frames[i].text, kStackWalkMaxTextLen),
556 "%s",
557 symbols[i]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000558 // Make sure line termination is in place.
559 frames[i].text[kStackWalkMaxTextLen - 1] = '\0';
560 }
561
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000562 free(symbols);
563
564 return frames_count;
fschneider@chromium.org7d10be52012-04-10 12:30:14 +0000565#else // defined(__GLIBC__) && !defined(__UCLIBC__)
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000566 return 0;
fschneider@chromium.org7d10be52012-04-10 12:30:14 +0000567#endif // defined(__GLIBC__) && !defined(__UCLIBC__)
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000568}
569
570
571// Constants used for mmap.
572static const int kMmapFd = -1;
573static const int kMmapFdOffset = 0;
574
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000575VirtualMemory::VirtualMemory() : address_(NULL), size_(0) { }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000576
ager@chromium.org9258b6b2008-09-11 09:11:10 +0000577VirtualMemory::VirtualMemory(size_t size) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000578 address_ = ReserveRegion(size);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000579 size_ = size;
580}
581
582
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000583VirtualMemory::VirtualMemory(size_t size, size_t alignment)
584 : address_(NULL), size_(0) {
585 ASSERT(IsAligned(alignment, static_cast<intptr_t>(OS::AllocateAlignment())));
586 size_t request_size = RoundUp(size + alignment,
587 static_cast<intptr_t>(OS::AllocateAlignment()));
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +0000588 void* reservation = mmap(OS::GetRandomMmapAddr(),
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000589 request_size,
590 PROT_NONE,
591 MAP_PRIVATE | MAP_ANONYMOUS | MAP_NORESERVE,
592 kMmapFd,
593 kMmapFdOffset);
594 if (reservation == MAP_FAILED) return;
595
596 Address base = static_cast<Address>(reservation);
597 Address aligned_base = RoundUp(base, alignment);
598 ASSERT_LE(base, aligned_base);
599
600 // Unmap extra memory reserved before and after the desired block.
601 if (aligned_base != base) {
602 size_t prefix_size = static_cast<size_t>(aligned_base - base);
603 OS::Free(base, prefix_size);
604 request_size -= prefix_size;
605 }
606
607 size_t aligned_size = RoundUp(size, OS::AllocateAlignment());
608 ASSERT_LE(aligned_size, request_size);
609
610 if (aligned_size != request_size) {
611 size_t suffix_size = request_size - aligned_size;
612 OS::Free(aligned_base + aligned_size, suffix_size);
613 request_size -= suffix_size;
614 }
615
616 ASSERT(aligned_size == request_size);
617
618 address_ = static_cast<void*>(aligned_base);
619 size_ = aligned_size;
620}
621
622
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000623VirtualMemory::~VirtualMemory() {
624 if (IsReserved()) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000625 bool result = ReleaseRegion(address(), size());
626 ASSERT(result);
627 USE(result);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000628 }
629}
630
631
632bool VirtualMemory::IsReserved() {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000633 return address_ != NULL;
634}
635
636
637void VirtualMemory::Reset() {
638 address_ = NULL;
639 size_ = 0;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000640}
641
642
kasperl@chromium.orgf5aa8372009-03-24 14:47:14 +0000643bool VirtualMemory::Commit(void* address, size_t size, bool is_executable) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000644 return CommitRegion(address, size, is_executable);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000645}
646
647
648bool VirtualMemory::Uncommit(void* address, size_t size) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000649 return UncommitRegion(address, size);
650}
651
652
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +0000653bool VirtualMemory::Guard(void* address) {
654 OS::Guard(address, OS::CommitPageSize());
655 return true;
656}
657
658
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000659void* VirtualMemory::ReserveRegion(size_t size) {
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +0000660 void* result = mmap(OS::GetRandomMmapAddr(),
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000661 size,
662 PROT_NONE,
663 MAP_PRIVATE | MAP_ANONYMOUS | MAP_NORESERVE,
664 kMmapFd,
665 kMmapFdOffset);
666
667 if (result == MAP_FAILED) return NULL;
668
669 return result;
670}
671
672
673bool VirtualMemory::CommitRegion(void* base, size_t size, bool is_executable) {
674 int prot = PROT_READ | PROT_WRITE | (is_executable ? PROT_EXEC : 0);
675 if (MAP_FAILED == mmap(base,
676 size,
677 prot,
678 MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED,
679 kMmapFd,
680 kMmapFdOffset)) {
681 return false;
682 }
683
684 UpdateAllocatedSpaceLimits(base, size);
685 return true;
686}
687
688
689bool VirtualMemory::UncommitRegion(void* base, size_t size) {
690 return mmap(base,
691 size,
692 PROT_NONE,
ager@chromium.orga1645e22009-09-09 19:27:10 +0000693 MAP_PRIVATE | MAP_ANONYMOUS | MAP_NORESERVE | MAP_FIXED,
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000694 kMmapFd,
695 kMmapFdOffset) != MAP_FAILED;
696}
697
698
699bool VirtualMemory::ReleaseRegion(void* base, size_t size) {
700 return munmap(base, size) == 0;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000701}
702
703
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +0000704class Thread::PlatformData : public Malloced {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000705 public:
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +0000706 PlatformData() : thread_(kNoThread) {}
ager@chromium.org41826e72009-03-30 13:30:57 +0000707
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000708 pthread_t thread_; // Thread handle for pthread.
709};
710
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000711Thread::Thread(const Options& options)
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +0000712 : data_(new PlatformData()),
yangguo@chromium.org659ceec2012-01-26 07:37:54 +0000713 stack_size_(options.stack_size()) {
714 set_name(options.name());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000715}
716
717
718Thread::~Thread() {
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +0000719 delete data_;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000720}
721
722
723static void* ThreadEntry(void* arg) {
724 Thread* thread = reinterpret_cast<Thread*>(arg);
725 // This is also initialized by the first argument to pthread_create() but we
726 // don't know which thread will run first (the original thread or the new
727 // one) so we initialize it here too.
danno@chromium.orgb6451162011-08-17 14:33:23 +0000728#ifdef PR_SET_NAME
karlklose@chromium.org8f806e82011-03-07 14:06:08 +0000729 prctl(PR_SET_NAME,
730 reinterpret_cast<unsigned long>(thread->name()), // NOLINT
731 0, 0, 0);
danno@chromium.orgb6451162011-08-17 14:33:23 +0000732#endif
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +0000733 thread->data()->thread_ = pthread_self();
734 ASSERT(thread->data()->thread_ != kNoThread);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000735 thread->Run();
736 return NULL;
737}
738
739
lrn@chromium.org5d00b602011-01-05 09:51:43 +0000740void Thread::set_name(const char* name) {
741 strncpy(name_, name, sizeof(name_));
742 name_[sizeof(name_) - 1] = '\0';
743}
744
745
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000746void Thread::Start() {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000747 pthread_attr_t* attr_ptr = NULL;
748 pthread_attr_t attr;
749 if (stack_size_ > 0) {
750 pthread_attr_init(&attr);
751 pthread_attr_setstacksize(&attr, static_cast<size_t>(stack_size_));
752 attr_ptr = &attr;
753 }
danno@chromium.orgc612e022011-11-10 11:38:15 +0000754 int result = pthread_create(&data_->thread_, attr_ptr, ThreadEntry, this);
755 CHECK_EQ(0, result);
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +0000756 ASSERT(data_->thread_ != kNoThread);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000757}
758
759
760void Thread::Join() {
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +0000761 pthread_join(data_->thread_, NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000762}
763
764
765Thread::LocalStorageKey Thread::CreateThreadLocalKey() {
766 pthread_key_t key;
767 int result = pthread_key_create(&key, NULL);
768 USE(result);
769 ASSERT(result == 0);
770 return static_cast<LocalStorageKey>(key);
771}
772
773
774void Thread::DeleteThreadLocalKey(LocalStorageKey key) {
775 pthread_key_t pthread_key = static_cast<pthread_key_t>(key);
776 int result = pthread_key_delete(pthread_key);
777 USE(result);
778 ASSERT(result == 0);
779}
780
781
782void* Thread::GetThreadLocal(LocalStorageKey key) {
783 pthread_key_t pthread_key = static_cast<pthread_key_t>(key);
784 return pthread_getspecific(pthread_key);
785}
786
787
788void Thread::SetThreadLocal(LocalStorageKey key, void* value) {
789 pthread_key_t pthread_key = static_cast<pthread_key_t>(key);
790 pthread_setspecific(pthread_key, value);
791}
792
793
794void Thread::YieldCPU() {
795 sched_yield();
796}
797
798
799class LinuxMutex : public Mutex {
800 public:
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000801 LinuxMutex() {
802 pthread_mutexattr_t attrs;
803 int result = pthread_mutexattr_init(&attrs);
804 ASSERT(result == 0);
805 result = pthread_mutexattr_settype(&attrs, PTHREAD_MUTEX_RECURSIVE);
806 ASSERT(result == 0);
807 result = pthread_mutex_init(&mutex_, &attrs);
808 ASSERT(result == 0);
rossberg@chromium.org717967f2011-07-20 13:44:42 +0000809 USE(result);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000810 }
811
812 virtual ~LinuxMutex() { pthread_mutex_destroy(&mutex_); }
813
814 virtual int Lock() {
815 int result = pthread_mutex_lock(&mutex_);
816 return result;
817 }
818
819 virtual int Unlock() {
820 int result = pthread_mutex_unlock(&mutex_);
821 return result;
822 }
823
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000824 virtual bool TryLock() {
825 int result = pthread_mutex_trylock(&mutex_);
826 // Return false if the lock is busy and locking failed.
827 if (result == EBUSY) {
828 return false;
829 }
830 ASSERT(result == 0); // Verify no other errors.
831 return true;
832 }
833
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000834 private:
835 pthread_mutex_t mutex_; // Pthread mutex for POSIX platforms.
836};
837
838
839Mutex* OS::CreateMutex() {
840 return new LinuxMutex();
841}
842
843
844class LinuxSemaphore : public Semaphore {
845 public:
846 explicit LinuxSemaphore(int count) { sem_init(&sem_, 0, count); }
847 virtual ~LinuxSemaphore() { sem_destroy(&sem_); }
848
kasper.lund7276f142008-07-30 08:49:36 +0000849 virtual void Wait();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000850 virtual bool Wait(int timeout);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000851 virtual void Signal() { sem_post(&sem_); }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000852 private:
853 sem_t sem_;
854};
855
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000856
kasper.lund7276f142008-07-30 08:49:36 +0000857void LinuxSemaphore::Wait() {
858 while (true) {
859 int result = sem_wait(&sem_);
860 if (result == 0) return; // Successfully got semaphore.
861 CHECK(result == -1 && errno == EINTR); // Signal caused spurious wakeup.
862 }
863}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000864
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000865
ager@chromium.org65dad4b2009-04-23 08:48:43 +0000866#ifndef TIMEVAL_TO_TIMESPEC
867#define TIMEVAL_TO_TIMESPEC(tv, ts) do { \
868 (ts)->tv_sec = (tv)->tv_sec; \
869 (ts)->tv_nsec = (tv)->tv_usec * 1000; \
870} while (false)
871#endif
872
873
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000874bool LinuxSemaphore::Wait(int timeout) {
875 const long kOneSecondMicros = 1000000; // NOLINT
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000876
877 // Split timeout into second and nanosecond parts.
ager@chromium.org65dad4b2009-04-23 08:48:43 +0000878 struct timeval delta;
879 delta.tv_usec = timeout % kOneSecondMicros;
880 delta.tv_sec = timeout / kOneSecondMicros;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000881
ager@chromium.org65dad4b2009-04-23 08:48:43 +0000882 struct timeval current_time;
883 // Get the current time.
884 if (gettimeofday(&current_time, NULL) == -1) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000885 return false;
886 }
887
ager@chromium.org65dad4b2009-04-23 08:48:43 +0000888 // Calculate time for end of timeout.
889 struct timeval end_time;
890 timeradd(&current_time, &delta, &end_time);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000891
ager@chromium.org65dad4b2009-04-23 08:48:43 +0000892 struct timespec ts;
893 TIMEVAL_TO_TIMESPEC(&end_time, &ts);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000894 // Wait for semaphore signalled or timeout.
895 while (true) {
896 int result = sem_timedwait(&sem_, &ts);
897 if (result == 0) return true; // Successfully got semaphore.
898 if (result > 0) {
899 // For glibc prior to 2.3.4 sem_timedwait returns the error instead of -1.
900 errno = result;
901 result = -1;
902 }
903 if (result == -1 && errno == ETIMEDOUT) return false; // Timeout.
904 CHECK(result == -1 && errno == EINTR); // Signal caused spurious wakeup.
905 }
906}
907
908
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000909Semaphore* OS::CreateSemaphore(int count) {
910 return new LinuxSemaphore(count);
911}
912
ager@chromium.org381abbb2009-02-25 13:23:22 +0000913
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +0000914#if defined(__ANDROID__) && !defined(__BIONIC_HAVE_UCONTEXT_T)
kasperl@chromium.orgacae3782009-04-11 09:17:08 +0000915
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +0000916// Not all versions of Android's C library provide ucontext_t.
917// Detect this and provide custom but compatible definitions. Note that these
918// follow the GLibc naming convention to access register values from
919// mcontext_t.
920//
921// See http://code.google.com/p/android/issues/detail?id=34784
922
923#if defined(__arm__)
924
kasperl@chromium.orgacae3782009-04-11 09:17:08 +0000925typedef struct sigcontext mcontext_t;
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +0000926
kasperl@chromium.orgacae3782009-04-11 09:17:08 +0000927typedef struct ucontext {
928 uint32_t uc_flags;
ager@chromium.orgc4c92722009-11-18 14:12:51 +0000929 struct ucontext* uc_link;
kasperl@chromium.orgacae3782009-04-11 09:17:08 +0000930 stack_t uc_stack;
931 mcontext_t uc_mcontext;
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +0000932 // Other fields are not used by V8, don't define them here.
kasperl@chromium.orgacae3782009-04-11 09:17:08 +0000933} ucontext_t;
kasperl@chromium.orgacae3782009-04-11 09:17:08 +0000934
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +0000935#elif defined(__mips__)
danno@chromium.orgfa458e42012-02-01 10:48:36 +0000936// MIPS version of sigcontext, for Android bionic.
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +0000937typedef struct {
danno@chromium.orgfa458e42012-02-01 10:48:36 +0000938 uint32_t regmask;
939 uint32_t status;
940 uint64_t pc;
941 uint64_t gregs[32];
942 uint64_t fpregs[32];
943 uint32_t acx;
944 uint32_t fpc_csr;
945 uint32_t fpc_eir;
946 uint32_t used_math;
947 uint32_t dsp;
948 uint64_t mdhi;
949 uint64_t mdlo;
950 uint32_t hi1;
951 uint32_t lo1;
952 uint32_t hi2;
953 uint32_t lo2;
954 uint32_t hi3;
955 uint32_t lo3;
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +0000956} mcontext_t;
957
danno@chromium.orgfa458e42012-02-01 10:48:36 +0000958typedef struct ucontext {
959 uint32_t uc_flags;
960 struct ucontext* uc_link;
961 stack_t uc_stack;
962 mcontext_t uc_mcontext;
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +0000963 // Other fields are not used by V8, don't define them here.
danno@chromium.orgfa458e42012-02-01 10:48:36 +0000964} ucontext_t;
965
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +0000966#elif defined(__i386__)
erik.corry@gmail.comed49e962012-04-17 11:57:53 +0000967// x86 version for Android.
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +0000968typedef struct {
yangguo@chromium.orgcb9affa2012-05-15 12:16:38 +0000969 uint32_t gregs[19];
970 void* fpregs;
971 uint32_t oldmask;
972 uint32_t cr2;
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +0000973} mcontext_t;
erik.corry@gmail.comed49e962012-04-17 11:57:53 +0000974
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +0000975typedef uint32_t kernel_sigset_t[2]; // x86 kernel uses 64-bit signal masks
erik.corry@gmail.comed49e962012-04-17 11:57:53 +0000976typedef struct ucontext {
yangguo@chromium.orgcb9affa2012-05-15 12:16:38 +0000977 uint32_t uc_flags;
978 struct ucontext* uc_link;
erik.corry@gmail.comed49e962012-04-17 11:57:53 +0000979 stack_t uc_stack;
980 mcontext_t uc_mcontext;
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +0000981 // Other fields are not used by V8, don't define them here.
erik.corry@gmail.comed49e962012-04-17 11:57:53 +0000982} ucontext_t;
erik.corry@gmail.comed49e962012-04-17 11:57:53 +0000983enum { REG_EBP = 6, REG_ESP = 7, REG_EIP = 14 };
kasperl@chromium.orgacae3782009-04-11 09:17:08 +0000984#endif
985
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +0000986#endif // __ANDROID__ && !defined(__BIONIC_HAVE_UCONTEXT_T)
kasperl@chromium.orgacae3782009-04-11 09:17:08 +0000987
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000988static int GetThreadID() {
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +0000989#if defined(__ANDROID__)
990 // Android's C library provides gettid(2).
991 return gettid();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000992#else
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +0000993 // Glibc doesn't provide a wrapper for gettid(2).
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000994 return syscall(SYS_gettid);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000995#endif
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000996}
997
998
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000999static void ProfilerSignalHandler(int signal, siginfo_t* info, void* context) {
1000 USE(info);
1001 if (signal != SIGPROF) return;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001002 Isolate* isolate = Isolate::UncheckedCurrent();
1003 if (isolate == NULL || !isolate->IsInitialized() || !isolate->IsInUse()) {
1004 // We require a fully initialized and entered isolate.
1005 return;
1006 }
vitalyr@chromium.org0ec56d62011-04-15 22:22:08 +00001007 if (v8::Locker::IsActive() &&
1008 !isolate->thread_manager()->IsLockedByCurrentThread()) {
1009 return;
1010 }
1011
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001012 Sampler* sampler = isolate->logger()->sampler();
1013 if (sampler == NULL || !sampler->IsActive()) return;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001014
lrn@chromium.org25156de2010-04-06 13:10:27 +00001015 TickSample sample_obj;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001016 TickSample* sample = CpuProfiler::TickSampleEvent(isolate);
ager@chromium.org357bf652010-04-12 11:30:10 +00001017 if (sample == NULL) sample = &sample_obj;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001018
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001019 // Extracting the sample from the context is extremely machine dependent.
1020 ucontext_t* ucontext = reinterpret_cast<ucontext_t*>(context);
1021 mcontext_t& mcontext = ucontext->uc_mcontext;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001022 sample->state = isolate->current_vm_state();
ager@chromium.org9085a012009-05-11 19:22:57 +00001023#if V8_HOST_ARCH_IA32
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001024 sample->pc = reinterpret_cast<Address>(mcontext.gregs[REG_EIP]);
1025 sample->sp = reinterpret_cast<Address>(mcontext.gregs[REG_ESP]);
1026 sample->fp = reinterpret_cast<Address>(mcontext.gregs[REG_EBP]);
ager@chromium.org9085a012009-05-11 19:22:57 +00001027#elif V8_HOST_ARCH_X64
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001028 sample->pc = reinterpret_cast<Address>(mcontext.gregs[REG_RIP]);
1029 sample->sp = reinterpret_cast<Address>(mcontext.gregs[REG_RSP]);
1030 sample->fp = reinterpret_cast<Address>(mcontext.gregs[REG_RBP]);
ager@chromium.org9085a012009-05-11 19:22:57 +00001031#elif V8_HOST_ARCH_ARM
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +00001032#if defined(__GLIBC__) && !defined(__UCLIBC__) && \
1033 (__GLIBC__ < 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ <= 3))
1034 // Old GLibc ARM versions used a gregs[] array to access the register
1035 // values from mcontext_t.
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001036 sample->pc = reinterpret_cast<Address>(mcontext.gregs[R15]);
1037 sample->sp = reinterpret_cast<Address>(mcontext.gregs[R13]);
1038 sample->fp = reinterpret_cast<Address>(mcontext.gregs[R11]);
kasperl@chromium.orgb3284ad2009-05-18 06:12:45 +00001039#else
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001040 sample->pc = reinterpret_cast<Address>(mcontext.arm_pc);
1041 sample->sp = reinterpret_cast<Address>(mcontext.arm_sp);
1042 sample->fp = reinterpret_cast<Address>(mcontext.arm_fp);
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +00001043#endif // defined(__GLIBC__) && !defined(__UCLIBC__) &&
1044 // (__GLIBC__ < 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ <= 3))
ager@chromium.org5c838252010-02-19 08:53:10 +00001045#elif V8_HOST_ARCH_MIPS
danno@chromium.orgc612e022011-11-10 11:38:15 +00001046 sample->pc = reinterpret_cast<Address>(mcontext.pc);
1047 sample->sp = reinterpret_cast<Address>(mcontext.gregs[29]);
1048 sample->fp = reinterpret_cast<Address>(mcontext.gregs[30]);
1049#endif // V8_HOST_ARCH_*
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001050 sampler->SampleStack(sample);
1051 sampler->Tick(sample);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001052}
1053
1054
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001055class Sampler::PlatformData : public Malloced {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001056 public:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001057 PlatformData() : vm_tid_(GetThreadID()) {}
1058
1059 int vm_tid() const { return vm_tid_; }
1060
1061 private:
1062 const int vm_tid_;
1063};
1064
1065
1066class SignalSender : public Thread {
1067 public:
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001068 enum SleepInterval {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001069 HALF_INTERVAL,
1070 FULL_INTERVAL
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001071 };
1072
jkummerow@chromium.orgab7dad42012-02-07 12:07:34 +00001073 static const int kSignalSenderStackSize = 64 * KB;
yangguo@chromium.org659ceec2012-01-26 07:37:54 +00001074
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001075 explicit SignalSender(int interval)
yangguo@chromium.org659ceec2012-01-26 07:37:54 +00001076 : Thread(Thread::Options("SignalSender", kSignalSenderStackSize)),
lrn@chromium.org303ada72010-10-27 09:33:13 +00001077 vm_tgid_(getpid()),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001078 interval_(interval) {}
1079
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00001080 static void SetUp() { if (!mutex_) mutex_ = OS::CreateMutex(); }
1081 static void TearDown() { delete mutex_; }
fschneider@chromium.org7d10be52012-04-10 12:30:14 +00001082
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +00001083 static void InstallSignalHandler() {
1084 struct sigaction sa;
1085 sa.sa_sigaction = ProfilerSignalHandler;
1086 sigemptyset(&sa.sa_mask);
1087 sa.sa_flags = SA_RESTART | SA_SIGINFO;
1088 signal_handler_installed_ =
1089 (sigaction(SIGPROF, &sa, &old_signal_handler_) == 0);
1090 }
1091
1092 static void RestoreSignalHandler() {
1093 if (signal_handler_installed_) {
1094 sigaction(SIGPROF, &old_signal_handler_, 0);
1095 signal_handler_installed_ = false;
1096 }
1097 }
1098
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001099 static void AddActiveSampler(Sampler* sampler) {
fschneider@chromium.org7d10be52012-04-10 12:30:14 +00001100 ScopedLock lock(mutex_);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001101 SamplerRegistry::AddActiveSampler(sampler);
1102 if (instance_ == NULL) {
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +00001103 // Start a thread that will send SIGPROF signal to VM threads,
1104 // when CPU profiling will be enabled.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001105 instance_ = new SignalSender(sampler->interval());
1106 instance_->Start();
1107 } else {
1108 ASSERT(instance_->interval_ == sampler->interval());
1109 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001110 }
1111
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001112 static void RemoveActiveSampler(Sampler* sampler) {
fschneider@chromium.org7d10be52012-04-10 12:30:14 +00001113 ScopedLock lock(mutex_);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001114 SamplerRegistry::RemoveActiveSampler(sampler);
1115 if (SamplerRegistry::GetState() == SamplerRegistry::HAS_NO_SAMPLERS) {
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00001116 RuntimeProfiler::StopRuntimeProfilerThreadBeforeShutdown(instance_);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001117 delete instance_;
1118 instance_ = NULL;
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +00001119 RestoreSignalHandler();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001120 }
1121 }
1122
1123 // Implement Thread::Run().
1124 virtual void Run() {
1125 SamplerRegistry::State state;
1126 while ((state = SamplerRegistry::GetState()) !=
1127 SamplerRegistry::HAS_NO_SAMPLERS) {
1128 bool cpu_profiling_enabled =
1129 (state == SamplerRegistry::HAS_CPU_PROFILING_SAMPLERS);
1130 bool runtime_profiler_enabled = RuntimeProfiler::IsEnabled();
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +00001131 if (cpu_profiling_enabled && !signal_handler_installed_) {
1132 InstallSignalHandler();
1133 } else if (!cpu_profiling_enabled && signal_handler_installed_) {
1134 RestoreSignalHandler();
1135 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001136 // When CPU profiling is enabled both JavaScript and C++ code is
1137 // profiled. We must not suspend.
1138 if (!cpu_profiling_enabled) {
1139 if (rate_limiter_.SuspendIfNecessary()) continue;
1140 }
1141 if (cpu_profiling_enabled && runtime_profiler_enabled) {
1142 if (!SamplerRegistry::IterateActiveSamplers(&DoCpuProfile, this)) {
1143 return;
1144 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001145 Sleep(HALF_INTERVAL);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001146 if (!SamplerRegistry::IterateActiveSamplers(&DoRuntimeProfile, NULL)) {
1147 return;
1148 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001149 Sleep(HALF_INTERVAL);
1150 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001151 if (cpu_profiling_enabled) {
1152 if (!SamplerRegistry::IterateActiveSamplers(&DoCpuProfile,
1153 this)) {
1154 return;
1155 }
1156 }
1157 if (runtime_profiler_enabled) {
1158 if (!SamplerRegistry::IterateActiveSamplers(&DoRuntimeProfile,
1159 NULL)) {
1160 return;
1161 }
1162 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001163 Sleep(FULL_INTERVAL);
whesse@chromium.orgf0ac72d2010-11-08 12:47:26 +00001164 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00001165 }
1166 }
1167
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001168 static void DoCpuProfile(Sampler* sampler, void* raw_sender) {
1169 if (!sampler->IsProfiling()) return;
1170 SignalSender* sender = reinterpret_cast<SignalSender*>(raw_sender);
1171 sender->SendProfilingSignal(sampler->platform_data()->vm_tid());
1172 }
1173
1174 static void DoRuntimeProfile(Sampler* sampler, void* ignored) {
1175 if (!sampler->isolate()->IsInitialized()) return;
1176 sampler->isolate()->runtime_profiler()->NotifyTick();
1177 }
1178
1179 void SendProfilingSignal(int tid) {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00001180 if (!signal_handler_installed_) return;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001181 // Glibc doesn't provide a wrapper for tgkill(2).
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001182#if defined(ANDROID)
1183 syscall(__NR_tgkill, vm_tgid_, tid, SIGPROF);
1184#else
1185 syscall(SYS_tgkill, vm_tgid_, tid, SIGPROF);
1186#endif
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001187 }
1188
1189 void Sleep(SleepInterval full_or_half) {
1190 // Convert ms to us and subtract 100 us to compensate delays
1191 // occuring during signal delivery.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001192 useconds_t interval = interval_ * 1000 - 100;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001193 if (full_or_half == HALF_INTERVAL) interval /= 2;
ulan@chromium.org2efb9002012-01-19 15:36:35 +00001194#if defined(ANDROID)
1195 usleep(interval);
1196#else
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001197 int result = usleep(interval);
1198#ifdef DEBUG
1199 if (result != 0 && errno != EINTR) {
1200 fprintf(stderr,
1201 "SignalSender usleep error; interval = %u, errno = %d\n",
1202 interval,
1203 errno);
1204 ASSERT(result == 0 || errno == EINTR);
1205 }
ulan@chromium.org2efb9002012-01-19 15:36:35 +00001206#endif // DEBUG
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001207 USE(result);
ulan@chromium.org2efb9002012-01-19 15:36:35 +00001208#endif // ANDROID
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001209 }
1210
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001211 const int vm_tgid_;
1212 const int interval_;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001213 RuntimeProfilerRateLimiter rate_limiter_;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001214
1215 // Protects the process wide state below.
fschneider@chromium.org7d10be52012-04-10 12:30:14 +00001216 static Mutex* mutex_;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001217 static SignalSender* instance_;
1218 static bool signal_handler_installed_;
1219 static struct sigaction old_signal_handler_;
1220
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00001221 private:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001222 DISALLOW_COPY_AND_ASSIGN(SignalSender);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001223};
1224
1225
fschneider@chromium.org7d10be52012-04-10 12:30:14 +00001226Mutex* SignalSender::mutex_ = NULL;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001227SignalSender* SignalSender::instance_ = NULL;
1228struct sigaction SignalSender::old_signal_handler_;
1229bool SignalSender::signal_handler_installed_ = false;
lrn@chromium.org303ada72010-10-27 09:33:13 +00001230
1231
fschneider@chromium.org7d10be52012-04-10 12:30:14 +00001232void OS::SetUp() {
1233 // Seed the random number generator. We preserve microsecond resolution.
1234 uint64_t seed = Ticks() ^ (getpid() << 16);
1235 srandom(static_cast<unsigned int>(seed));
1236 limit_mutex = CreateMutex();
1237
1238#ifdef __arm__
1239 // When running on ARM hardware check that the EABI used by V8 and
1240 // by the C code is the same.
1241 bool hard_float = OS::ArmUsingHardFloat();
1242 if (hard_float) {
1243#if !USE_EABI_HARDFLOAT
1244 PrintF("ERROR: Binary compiled with -mfloat-abi=hard but without "
1245 "-DUSE_EABI_HARDFLOAT\n");
1246 exit(1);
1247#endif
1248 } else {
1249#if USE_EABI_HARDFLOAT
1250 PrintF("ERROR: Binary not compiled with -mfloat-abi=hard but with "
1251 "-DUSE_EABI_HARDFLOAT\n");
1252 exit(1);
1253#endif
1254 }
1255#endif
1256 SignalSender::SetUp();
1257}
1258
1259
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00001260void OS::TearDown() {
1261 SignalSender::TearDown();
1262 delete limit_mutex;
1263}
1264
1265
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001266Sampler::Sampler(Isolate* isolate, int interval)
1267 : isolate_(isolate),
1268 interval_(interval),
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001269 profiling_(false),
ager@chromium.orgbeb25712010-11-29 08:02:25 +00001270 active_(false),
1271 samples_taken_(0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001272 data_ = new PlatformData;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001273}
1274
1275
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001276Sampler::~Sampler() {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001277 ASSERT(!IsActive());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001278 delete data_;
1279}
1280
1281
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001282void Sampler::Start() {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001283 ASSERT(!IsActive());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001284 SetActive(true);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001285 SignalSender::AddActiveSampler(this);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001286}
1287
1288
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001289void Sampler::Stop() {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001290 ASSERT(IsActive());
1291 SignalSender::RemoveActiveSampler(this);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001292 SetActive(false);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001293}
1294
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001295
1296} } // namespace v8::internal