blob: ec48d6305e3de2ea4b51f0571a1c7a83bb0ae619 [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;
verwaest@chromium.org33e09c82012-10-10 17:07:22 +0000151 case SUDIV:
152 search_string = "idiva";
153 break;
lrn@chromium.orgfa943b72010-11-03 08:14:36 +0000154 default:
155 UNREACHABLE();
156 }
157
ager@chromium.org5f0c45f2010-12-17 08:51:21 +0000158 if (CPUInfoContainsString(search_string)) {
159 return true;
160 }
161
162 if (feature == VFP3) {
163 // Some old kernels will report vfp not vfpv3. Here we make a last attempt
164 // to detect vfpv3 by checking for vfp *and* neon, since neon is only
165 // available on architectures with vfpv3.
166 // Checking neon on its own is not enough as it is possible to have neon
167 // without vfp.
168 if (CPUInfoContainsString("vfp") && CPUInfoContainsString("neon")) {
lrn@chromium.orgfa943b72010-11-03 08:14:36 +0000169 return true;
170 }
171 }
172
173 return false;
174}
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +0000175
176
rossberg@chromium.org89e18f52012-10-22 13:09:53 +0000177CpuImplementer OS::GetCpuImplementer() {
178 static bool use_cached_value = false;
179 static CpuImplementer cached_value = UNKNOWN_IMPLEMENTER;
180 if (use_cached_value) {
181 return cached_value;
182 }
183 if (CPUInfoContainsString("CPU implementer\t: 0x41")) {
184 cached_value = ARM_IMPLEMENTER;
185 } else if (CPUInfoContainsString("CPU implementer\t: 0x51")) {
186 cached_value = QUALCOMM_IMPLEMENTER;
187 } else {
188 cached_value = UNKNOWN_IMPLEMENTER;
189 }
190 use_cached_value = true;
191 return cached_value;
192}
193
194
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +0000195bool OS::ArmUsingHardFloat() {
yangguo@chromium.orgc74d6742012-06-29 15:15:45 +0000196 // GCC versions 4.6 and above define __ARM_PCS or __ARM_PCS_VFP to specify
197 // the Floating Point ABI used (PCS stands for Procedure Call Standard).
198 // We use these as well as a couple of other defines to statically determine
199 // what FP ABI used.
200 // GCC versions 4.4 and below don't support hard-fp.
201 // GCC versions 4.5 may support hard-fp without defining __ARM_PCS or
202 // __ARM_PCS_VFP.
203
204#define GCC_VERSION (__GNUC__ * 10000 \
205 + __GNUC_MINOR__ * 100 \
206 + __GNUC_PATCHLEVEL__)
207#if GCC_VERSION >= 40600
208#if defined(__ARM_PCS_VFP)
209 return true;
210#else
211 return false;
212#endif
213
214#elif GCC_VERSION < 40500
215 return false;
216
217#else
218#if defined(__ARM_PCS_VFP)
219 return true;
220#elif defined(__ARM_PCS) || defined(__SOFTFP) || !defined(__VFP_FP__)
221 return false;
222#else
223#error "Your version of GCC does not report the FP ABI compiled for." \
224 "Please report it on this issue" \
225 "http://code.google.com/p/v8/issues/detail?id=2140"
226
227#endif
228#endif
229#undef GCC_VERSION
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +0000230}
yangguo@chromium.orgc74d6742012-06-29 15:15:45 +0000231
ager@chromium.orgc4c92722009-11-18 14:12:51 +0000232#endif // def __arm__
233
234
lrn@chromium.org7516f052011-03-30 08:52:27 +0000235#ifdef __mips__
236bool OS::MipsCpuHasFeature(CpuFeature feature) {
237 const char* search_string = NULL;
238 const char* file_name = "/proc/cpuinfo";
239 // Simple detection of FPU at runtime for Linux.
240 // It is based on /proc/cpuinfo, which reveals hardware configuration
241 // to user-space applications. According to MIPS (early 2010), no similar
242 // facility is universally available on the MIPS architectures,
243 // so it's up to individual OSes to provide such.
244 //
245 // This is written as a straight shot one pass parser
246 // and not using STL string and ifstream because,
247 // on Linux, it's reading from a (non-mmap-able)
248 // character special device.
249
250 switch (feature) {
251 case FPU:
252 search_string = "FPU";
253 break;
254 default:
255 UNREACHABLE();
256 }
257
258 FILE* f = NULL;
259 const char* what = search_string;
260
261 if (NULL == (f = fopen(file_name, "r")))
262 return false;
263
264 int k;
265 while (EOF != (k = fgetc(f))) {
266 if (k == *what) {
267 ++what;
268 while ((*what != '\0') && (*what == fgetc(f))) {
269 ++what;
270 }
271 if (*what == '\0') {
272 fclose(f);
273 return true;
274 } else {
275 what = search_string;
276 }
277 }
278 }
279 fclose(f);
280
281 // Did not find string in the proc file.
282 return false;
283}
284#endif // def __mips__
285
286
ager@chromium.org236ad962008-09-25 09:45:57 +0000287int OS::ActivationFrameAlignment() {
ager@chromium.orge2902be2009-06-08 12:21:35 +0000288#ifdef V8_TARGET_ARCH_ARM
kasperl@chromium.orgb3284ad2009-05-18 06:12:45 +0000289 // On EABI ARM targets this is required for fp correctness in the
290 // runtime system.
ager@chromium.org3a6061e2009-03-12 14:24:36 +0000291 return 8;
ager@chromium.org5c838252010-02-19 08:53:10 +0000292#elif V8_TARGET_ARCH_MIPS
293 return 8;
294#endif
ricow@chromium.orgc9c80822010-04-21 08:22:37 +0000295 // With gcc 4.4 the tree vectorization optimizer can generate code
ager@chromium.orge2902be2009-06-08 12:21:35 +0000296 // that requires 16 byte alignment such as movdqa on x86.
297 return 16;
ager@chromium.org236ad962008-09-25 09:45:57 +0000298}
299
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000300
kmillikin@chromium.org9155e252010-05-26 13:27:57 +0000301void OS::ReleaseStore(volatile AtomicWord* ptr, AtomicWord value) {
lrn@chromium.org7516f052011-03-30 08:52:27 +0000302#if (defined(V8_TARGET_ARCH_ARM) && defined(__arm__)) || \
303 (defined(V8_TARGET_ARCH_MIPS) && defined(__mips__))
304 // Only use on ARM or MIPS hardware.
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000305 MemoryBarrier();
kmillikin@chromium.org9155e252010-05-26 13:27:57 +0000306#else
307 __asm__ __volatile__("" : : : "memory");
308 // An x86 store acts as a release barrier.
309#endif
310 *ptr = value;
311}
312
313
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000314const char* OS::LocalTimezone(double time) {
315 if (isnan(time)) return "";
316 time_t tv = static_cast<time_t>(floor(time/msPerSecond));
317 struct tm* t = localtime(&tv);
318 if (NULL == t) return "";
319 return t->tm_zone;
320}
321
322
323double OS::LocalTimeOffset() {
324 time_t tv = time(NULL);
325 struct tm* t = localtime(&tv);
326 // tm_gmtoff includes any daylight savings offset, so subtract it.
327 return static_cast<double>(t->tm_gmtoff * msPerSecond -
328 (t->tm_isdst > 0 ? 3600 * msPerSecond : 0));
329}
330
331
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000332// We keep the lowest and highest addresses mapped as a quick way of
333// determining that pointers are outside the heap (used mostly in assertions
ulan@chromium.org2efb9002012-01-19 15:36:35 +0000334// and verification). The estimate is conservative, i.e., not all addresses in
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000335// 'allocated' space are actually allocated to our heap. The range is
336// [lowest, highest), inclusive on the low and and exclusive on the high end.
337static void* lowest_ever_allocated = reinterpret_cast<void*>(-1);
338static void* highest_ever_allocated = reinterpret_cast<void*>(0);
339
340
341static void UpdateAllocatedSpaceLimits(void* address, int size) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000342 ASSERT(limit_mutex != NULL);
343 ScopedLock lock(limit_mutex);
344
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000345 lowest_ever_allocated = Min(lowest_ever_allocated, address);
346 highest_ever_allocated =
347 Max(highest_ever_allocated,
348 reinterpret_cast<void*>(reinterpret_cast<char*>(address) + size));
349}
350
351
352bool OS::IsOutsideAllocatedSpace(void* address) {
353 return address < lowest_ever_allocated || address >= highest_ever_allocated;
354}
355
356
357size_t OS::AllocateAlignment() {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000358 return sysconf(_SC_PAGESIZE);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000359}
360
361
kasper.lund7276f142008-07-30 08:49:36 +0000362void* OS::Allocate(const size_t requested,
363 size_t* allocated,
kasperl@chromium.orgf5aa8372009-03-24 14:47:14 +0000364 bool is_executable) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000365 const size_t msize = RoundUp(requested, AllocateAlignment());
kasperl@chromium.orgf5aa8372009-03-24 14:47:14 +0000366 int prot = PROT_READ | PROT_WRITE | (is_executable ? PROT_EXEC : 0);
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +0000367 void* addr = OS::GetRandomMmapAddr();
ricow@chromium.org9fa09672011-07-25 11:05:35 +0000368 void* mbase = mmap(addr, msize, prot, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000369 if (mbase == MAP_FAILED) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000370 LOG(i::Isolate::Current(),
371 StringEvent("OS::Allocate", "mmap failed"));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000372 return NULL;
373 }
374 *allocated = msize;
375 UpdateAllocatedSpaceLimits(mbase, msize);
376 return mbase;
377}
378
379
kasperl@chromium.orgf5aa8372009-03-24 14:47:14 +0000380void OS::Free(void* address, const size_t size) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000381 // TODO(1240712): munmap has a return value which is ignored here.
ager@chromium.orga1645e22009-09-09 19:27:10 +0000382 int result = munmap(address, size);
383 USE(result);
384 ASSERT(result == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000385}
386
387
388void OS::Sleep(int milliseconds) {
389 unsigned int ms = static_cast<unsigned int>(milliseconds);
390 usleep(1000 * ms);
391}
392
393
394void OS::Abort() {
395 // Redirect to std abort to signal abnormal program termination.
rossberg@chromium.org2c067b12012-03-19 11:01:52 +0000396 if (FLAG_break_on_abort) {
397 DebugBreak();
398 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000399 abort();
400}
401
402
kasper.lund7276f142008-07-30 08:49:36 +0000403void OS::DebugBreak() {
ager@chromium.org5ec48922009-05-05 07:25:34 +0000404// TODO(lrn): Introduce processor define for runtime system (!= V8_ARCH_x,
405// which is the architecture of generated code).
ager@chromium.orgea4f62e2010-08-16 16:28:43 +0000406#if (defined(__arm__) || defined(__thumb__))
407# if defined(CAN_USE_ARMV5_INSTRUCTIONS)
kasper.lund7276f142008-07-30 08:49:36 +0000408 asm("bkpt 0");
ager@chromium.orgea4f62e2010-08-16 16:28:43 +0000409# endif
ager@chromium.org5c838252010-02-19 08:53:10 +0000410#elif defined(__mips__)
411 asm("break");
kasper.lund7276f142008-07-30 08:49:36 +0000412#else
413 asm("int $3");
414#endif
415}
416
417
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000418class PosixMemoryMappedFile : public OS::MemoryMappedFile {
419 public:
420 PosixMemoryMappedFile(FILE* file, void* memory, int size)
421 : file_(file), memory_(memory), size_(size) { }
422 virtual ~PosixMemoryMappedFile();
423 virtual void* memory() { return memory_; }
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +0000424 virtual int size() { return size_; }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000425 private:
426 FILE* file_;
427 void* memory_;
428 int size_;
429};
430
431
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +0000432OS::MemoryMappedFile* OS::MemoryMappedFile::open(const char* name) {
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +0000433 FILE* file = fopen(name, "r+");
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +0000434 if (file == NULL) return NULL;
435
436 fseek(file, 0, SEEK_END);
437 int size = ftell(file);
438
439 void* memory =
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +0000440 mmap(OS::GetRandomMmapAddr(),
441 size,
442 PROT_READ | PROT_WRITE,
443 MAP_SHARED,
444 fileno(file),
445 0);
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +0000446 return new PosixMemoryMappedFile(file, memory, size);
447}
448
449
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000450OS::MemoryMappedFile* OS::MemoryMappedFile::create(const char* name, int size,
451 void* initial) {
452 FILE* file = fopen(name, "w+");
453 if (file == NULL) return NULL;
ager@chromium.org9258b6b2008-09-11 09:11:10 +0000454 int result = fwrite(initial, size, 1, file);
455 if (result < 1) {
456 fclose(file);
457 return NULL;
458 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000459 void* memory =
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +0000460 mmap(OS::GetRandomMmapAddr(),
461 size,
462 PROT_READ | PROT_WRITE,
463 MAP_SHARED,
464 fileno(file),
465 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000466 return new PosixMemoryMappedFile(file, memory, size);
467}
468
469
470PosixMemoryMappedFile::~PosixMemoryMappedFile() {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000471 if (memory_) OS::Free(memory_, size_);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000472 fclose(file_);
473}
474
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000475
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000476void OS::LogSharedLibraryAddresses() {
sgjesse@chromium.orgb9d7da12009-08-05 08:38:10 +0000477 // This function assumes that the layout of the file is as follows:
478 // hex_start_addr-hex_end_addr rwxp <unused data> [binary_file_name]
479 // If we encounter an unexpected situation we abort scanning further entries.
ager@chromium.orgc4c92722009-11-18 14:12:51 +0000480 FILE* fp = fopen("/proc/self/maps", "r");
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000481 if (fp == NULL) return;
sgjesse@chromium.orgb9d7da12009-08-05 08:38:10 +0000482
483 // Allocate enough room to be able to store a full file name.
484 const int kLibNameLen = FILENAME_MAX + 1;
485 char* lib_name = reinterpret_cast<char*>(malloc(kLibNameLen));
486
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000487 i::Isolate* isolate = ISOLATE;
sgjesse@chromium.orgb9d7da12009-08-05 08:38:10 +0000488 // This loop will terminate once the scanning hits an EOF.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000489 while (true) {
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000490 uintptr_t start, end;
491 char attr_r, attr_w, attr_x, attr_p;
sgjesse@chromium.orgb9d7da12009-08-05 08:38:10 +0000492 // Parse the addresses and permission bits at the beginning of the line.
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000493 if (fscanf(fp, "%" V8PRIxPTR "-%" V8PRIxPTR, &start, &end) != 2) break;
494 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 +0000495
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000496 int c;
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000497 if (attr_r == 'r' && attr_w != 'w' && attr_x == 'x') {
498 // Found a read-only executable entry. Skip characters until we reach
sgjesse@chromium.orgb9d7da12009-08-05 08:38:10 +0000499 // the beginning of the filename or the end of the line.
500 do {
501 c = getc(fp);
502 } while ((c != EOF) && (c != '\n') && (c != '/'));
503 if (c == EOF) break; // EOF: Was unexpected, just exit.
504
505 // Process the filename if found.
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000506 if (c == '/') {
sgjesse@chromium.orgb9d7da12009-08-05 08:38:10 +0000507 ungetc(c, fp); // Push the '/' back into the stream to be read below.
508
509 // Read to the end of the line. Exit if the read fails.
510 if (fgets(lib_name, kLibNameLen, fp) == NULL) break;
511
512 // Drop the newline character read by fgets. We do not need to check
513 // for a zero-length string because we know that we at least read the
514 // '/' character.
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000515 lib_name[strlen(lib_name) - 1] = '\0';
516 } else {
sgjesse@chromium.orgb9d7da12009-08-05 08:38:10 +0000517 // No library name found, just record the raw address range.
518 snprintf(lib_name, kLibNameLen,
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000519 "%08" V8PRIxPTR "-%08" V8PRIxPTR, start, end);
520 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000521 LOG(isolate, SharedLibraryEvent(lib_name, start, end));
sgjesse@chromium.orgb9d7da12009-08-05 08:38:10 +0000522 } else {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +0000523 // Entry not describing executable data. Skip to end of line to set up
sgjesse@chromium.orgb9d7da12009-08-05 08:38:10 +0000524 // reading the next entry.
525 do {
526 c = getc(fp);
527 } while ((c != EOF) && (c != '\n'));
528 if (c == EOF) break;
ager@chromium.org5aa501c2009-06-23 07:57:28 +0000529 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000530 }
sgjesse@chromium.orgb9d7da12009-08-05 08:38:10 +0000531 free(lib_name);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000532 fclose(fp);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000533}
534
535
whesse@chromium.org4a5224e2010-10-20 12:37:07 +0000536void OS::SignalCodeMovingGC() {
whesse@chromium.org4a5224e2010-10-20 12:37:07 +0000537 // Support for ll_prof.py.
538 //
539 // The Linux profiler built into the kernel logs all mmap's with
540 // PROT_EXEC so that analysis tools can properly attribute ticks. We
541 // do a mmap with a name known by ll_prof.py and immediately munmap
542 // it. This injects a GC marker into the stream of events generated
543 // by the kernel and allows us to synchronize V8 code log and the
544 // kernel log.
545 int size = sysconf(_SC_PAGESIZE);
mstarzinger@chromium.orgde886792012-09-11 13:22:37 +0000546 FILE* f = fopen(FLAG_gc_fake_mmap, "w+");
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +0000547 void* addr = mmap(OS::GetRandomMmapAddr(),
548 size,
549 PROT_READ | PROT_EXEC,
550 MAP_PRIVATE,
551 fileno(f),
552 0);
whesse@chromium.org4a5224e2010-10-20 12:37:07 +0000553 ASSERT(addr != MAP_FAILED);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000554 OS::Free(addr, size);
whesse@chromium.org4a5224e2010-10-20 12:37:07 +0000555 fclose(f);
whesse@chromium.org4a5224e2010-10-20 12:37:07 +0000556}
557
558
ager@chromium.org65dad4b2009-04-23 08:48:43 +0000559int OS::StackWalk(Vector<OS::StackFrame> frames) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000560 // backtrace is a glibc extension.
fschneider@chromium.org7d10be52012-04-10 12:30:14 +0000561#if defined(__GLIBC__) && !defined(__UCLIBC__)
ager@chromium.org65dad4b2009-04-23 08:48:43 +0000562 int frames_size = frames.length();
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +0000563 ScopedVector<void*> addresses(frames_size);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000564
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +0000565 int frames_count = backtrace(addresses.start(), frames_size);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000566
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +0000567 char** symbols = backtrace_symbols(addresses.start(), frames_count);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000568 if (symbols == NULL) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000569 return kStackWalkError;
570 }
571
572 for (int i = 0; i < frames_count; i++) {
573 frames[i].address = addresses[i];
574 // Format a text representation of the frame based on the information
575 // available.
kasperl@chromium.orgb9123622008-09-17 14:05:56 +0000576 SNPrintF(MutableCStrVector(frames[i].text, kStackWalkMaxTextLen),
577 "%s",
578 symbols[i]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000579 // Make sure line termination is in place.
580 frames[i].text[kStackWalkMaxTextLen - 1] = '\0';
581 }
582
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000583 free(symbols);
584
585 return frames_count;
fschneider@chromium.org7d10be52012-04-10 12:30:14 +0000586#else // defined(__GLIBC__) && !defined(__UCLIBC__)
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000587 return 0;
fschneider@chromium.org7d10be52012-04-10 12:30:14 +0000588#endif // defined(__GLIBC__) && !defined(__UCLIBC__)
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000589}
590
591
592// Constants used for mmap.
593static const int kMmapFd = -1;
594static const int kMmapFdOffset = 0;
595
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000596VirtualMemory::VirtualMemory() : address_(NULL), size_(0) { }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000597
ager@chromium.org9258b6b2008-09-11 09:11:10 +0000598VirtualMemory::VirtualMemory(size_t size) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000599 address_ = ReserveRegion(size);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000600 size_ = size;
601}
602
603
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000604VirtualMemory::VirtualMemory(size_t size, size_t alignment)
605 : address_(NULL), size_(0) {
606 ASSERT(IsAligned(alignment, static_cast<intptr_t>(OS::AllocateAlignment())));
607 size_t request_size = RoundUp(size + alignment,
608 static_cast<intptr_t>(OS::AllocateAlignment()));
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +0000609 void* reservation = mmap(OS::GetRandomMmapAddr(),
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000610 request_size,
611 PROT_NONE,
612 MAP_PRIVATE | MAP_ANONYMOUS | MAP_NORESERVE,
613 kMmapFd,
614 kMmapFdOffset);
615 if (reservation == MAP_FAILED) return;
616
617 Address base = static_cast<Address>(reservation);
618 Address aligned_base = RoundUp(base, alignment);
619 ASSERT_LE(base, aligned_base);
620
621 // Unmap extra memory reserved before and after the desired block.
622 if (aligned_base != base) {
623 size_t prefix_size = static_cast<size_t>(aligned_base - base);
624 OS::Free(base, prefix_size);
625 request_size -= prefix_size;
626 }
627
628 size_t aligned_size = RoundUp(size, OS::AllocateAlignment());
629 ASSERT_LE(aligned_size, request_size);
630
631 if (aligned_size != request_size) {
632 size_t suffix_size = request_size - aligned_size;
633 OS::Free(aligned_base + aligned_size, suffix_size);
634 request_size -= suffix_size;
635 }
636
637 ASSERT(aligned_size == request_size);
638
639 address_ = static_cast<void*>(aligned_base);
640 size_ = aligned_size;
641}
642
643
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000644VirtualMemory::~VirtualMemory() {
645 if (IsReserved()) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000646 bool result = ReleaseRegion(address(), size());
647 ASSERT(result);
648 USE(result);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000649 }
650}
651
652
653bool VirtualMemory::IsReserved() {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000654 return address_ != NULL;
655}
656
657
658void VirtualMemory::Reset() {
659 address_ = NULL;
660 size_ = 0;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000661}
662
663
kasperl@chromium.orgf5aa8372009-03-24 14:47:14 +0000664bool VirtualMemory::Commit(void* address, size_t size, bool is_executable) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000665 return CommitRegion(address, size, is_executable);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000666}
667
668
669bool VirtualMemory::Uncommit(void* address, size_t size) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000670 return UncommitRegion(address, size);
671}
672
673
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +0000674bool VirtualMemory::Guard(void* address) {
675 OS::Guard(address, OS::CommitPageSize());
676 return true;
677}
678
679
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000680void* VirtualMemory::ReserveRegion(size_t size) {
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +0000681 void* result = mmap(OS::GetRandomMmapAddr(),
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000682 size,
683 PROT_NONE,
684 MAP_PRIVATE | MAP_ANONYMOUS | MAP_NORESERVE,
685 kMmapFd,
686 kMmapFdOffset);
687
688 if (result == MAP_FAILED) return NULL;
689
690 return result;
691}
692
693
694bool VirtualMemory::CommitRegion(void* base, size_t size, bool is_executable) {
695 int prot = PROT_READ | PROT_WRITE | (is_executable ? PROT_EXEC : 0);
696 if (MAP_FAILED == mmap(base,
697 size,
698 prot,
699 MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED,
700 kMmapFd,
701 kMmapFdOffset)) {
702 return false;
703 }
704
705 UpdateAllocatedSpaceLimits(base, size);
706 return true;
707}
708
709
710bool VirtualMemory::UncommitRegion(void* base, size_t size) {
711 return mmap(base,
712 size,
713 PROT_NONE,
ager@chromium.orga1645e22009-09-09 19:27:10 +0000714 MAP_PRIVATE | MAP_ANONYMOUS | MAP_NORESERVE | MAP_FIXED,
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000715 kMmapFd,
716 kMmapFdOffset) != MAP_FAILED;
717}
718
719
720bool VirtualMemory::ReleaseRegion(void* base, size_t size) {
721 return munmap(base, size) == 0;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000722}
723
724
danno@chromium.org72204d52012-10-31 10:02:10 +0000725bool VirtualMemory::HasLazyCommits() {
726 return true;
727}
728
729
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +0000730class Thread::PlatformData : public Malloced {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000731 public:
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +0000732 PlatformData() : thread_(kNoThread) {}
ager@chromium.org41826e72009-03-30 13:30:57 +0000733
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000734 pthread_t thread_; // Thread handle for pthread.
735};
736
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000737Thread::Thread(const Options& options)
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +0000738 : data_(new PlatformData()),
yangguo@chromium.org659ceec2012-01-26 07:37:54 +0000739 stack_size_(options.stack_size()) {
740 set_name(options.name());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000741}
742
743
744Thread::~Thread() {
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +0000745 delete data_;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000746}
747
748
749static void* ThreadEntry(void* arg) {
750 Thread* thread = reinterpret_cast<Thread*>(arg);
751 // This is also initialized by the first argument to pthread_create() but we
752 // don't know which thread will run first (the original thread or the new
753 // one) so we initialize it here too.
danno@chromium.orgb6451162011-08-17 14:33:23 +0000754#ifdef PR_SET_NAME
karlklose@chromium.org8f806e82011-03-07 14:06:08 +0000755 prctl(PR_SET_NAME,
756 reinterpret_cast<unsigned long>(thread->name()), // NOLINT
757 0, 0, 0);
danno@chromium.orgb6451162011-08-17 14:33:23 +0000758#endif
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +0000759 thread->data()->thread_ = pthread_self();
760 ASSERT(thread->data()->thread_ != kNoThread);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000761 thread->Run();
762 return NULL;
763}
764
765
lrn@chromium.org5d00b602011-01-05 09:51:43 +0000766void Thread::set_name(const char* name) {
767 strncpy(name_, name, sizeof(name_));
768 name_[sizeof(name_) - 1] = '\0';
769}
770
771
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000772void Thread::Start() {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000773 pthread_attr_t* attr_ptr = NULL;
774 pthread_attr_t attr;
775 if (stack_size_ > 0) {
776 pthread_attr_init(&attr);
777 pthread_attr_setstacksize(&attr, static_cast<size_t>(stack_size_));
778 attr_ptr = &attr;
779 }
danno@chromium.orgc612e022011-11-10 11:38:15 +0000780 int result = pthread_create(&data_->thread_, attr_ptr, ThreadEntry, this);
781 CHECK_EQ(0, result);
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +0000782 ASSERT(data_->thread_ != kNoThread);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000783}
784
785
786void Thread::Join() {
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +0000787 pthread_join(data_->thread_, NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000788}
789
790
791Thread::LocalStorageKey Thread::CreateThreadLocalKey() {
792 pthread_key_t key;
793 int result = pthread_key_create(&key, NULL);
794 USE(result);
795 ASSERT(result == 0);
796 return static_cast<LocalStorageKey>(key);
797}
798
799
800void Thread::DeleteThreadLocalKey(LocalStorageKey key) {
801 pthread_key_t pthread_key = static_cast<pthread_key_t>(key);
802 int result = pthread_key_delete(pthread_key);
803 USE(result);
804 ASSERT(result == 0);
805}
806
807
808void* Thread::GetThreadLocal(LocalStorageKey key) {
809 pthread_key_t pthread_key = static_cast<pthread_key_t>(key);
810 return pthread_getspecific(pthread_key);
811}
812
813
814void Thread::SetThreadLocal(LocalStorageKey key, void* value) {
815 pthread_key_t pthread_key = static_cast<pthread_key_t>(key);
816 pthread_setspecific(pthread_key, value);
817}
818
819
820void Thread::YieldCPU() {
821 sched_yield();
822}
823
824
825class LinuxMutex : public Mutex {
826 public:
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000827 LinuxMutex() {
828 pthread_mutexattr_t attrs;
829 int result = pthread_mutexattr_init(&attrs);
830 ASSERT(result == 0);
831 result = pthread_mutexattr_settype(&attrs, PTHREAD_MUTEX_RECURSIVE);
832 ASSERT(result == 0);
833 result = pthread_mutex_init(&mutex_, &attrs);
834 ASSERT(result == 0);
rossberg@chromium.org717967f2011-07-20 13:44:42 +0000835 USE(result);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000836 }
837
838 virtual ~LinuxMutex() { pthread_mutex_destroy(&mutex_); }
839
840 virtual int Lock() {
841 int result = pthread_mutex_lock(&mutex_);
842 return result;
843 }
844
845 virtual int Unlock() {
846 int result = pthread_mutex_unlock(&mutex_);
847 return result;
848 }
849
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000850 virtual bool TryLock() {
851 int result = pthread_mutex_trylock(&mutex_);
852 // Return false if the lock is busy and locking failed.
853 if (result == EBUSY) {
854 return false;
855 }
856 ASSERT(result == 0); // Verify no other errors.
857 return true;
858 }
859
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000860 private:
861 pthread_mutex_t mutex_; // Pthread mutex for POSIX platforms.
862};
863
864
865Mutex* OS::CreateMutex() {
866 return new LinuxMutex();
867}
868
869
870class LinuxSemaphore : public Semaphore {
871 public:
872 explicit LinuxSemaphore(int count) { sem_init(&sem_, 0, count); }
873 virtual ~LinuxSemaphore() { sem_destroy(&sem_); }
874
kasper.lund7276f142008-07-30 08:49:36 +0000875 virtual void Wait();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000876 virtual bool Wait(int timeout);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000877 virtual void Signal() { sem_post(&sem_); }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000878 private:
879 sem_t sem_;
880};
881
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000882
kasper.lund7276f142008-07-30 08:49:36 +0000883void LinuxSemaphore::Wait() {
884 while (true) {
885 int result = sem_wait(&sem_);
886 if (result == 0) return; // Successfully got semaphore.
887 CHECK(result == -1 && errno == EINTR); // Signal caused spurious wakeup.
888 }
889}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000890
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000891
ager@chromium.org65dad4b2009-04-23 08:48:43 +0000892#ifndef TIMEVAL_TO_TIMESPEC
893#define TIMEVAL_TO_TIMESPEC(tv, ts) do { \
894 (ts)->tv_sec = (tv)->tv_sec; \
895 (ts)->tv_nsec = (tv)->tv_usec * 1000; \
896} while (false)
897#endif
898
899
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000900bool LinuxSemaphore::Wait(int timeout) {
901 const long kOneSecondMicros = 1000000; // NOLINT
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000902
903 // Split timeout into second and nanosecond parts.
ager@chromium.org65dad4b2009-04-23 08:48:43 +0000904 struct timeval delta;
905 delta.tv_usec = timeout % kOneSecondMicros;
906 delta.tv_sec = timeout / kOneSecondMicros;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000907
ager@chromium.org65dad4b2009-04-23 08:48:43 +0000908 struct timeval current_time;
909 // Get the current time.
910 if (gettimeofday(&current_time, NULL) == -1) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000911 return false;
912 }
913
ager@chromium.org65dad4b2009-04-23 08:48:43 +0000914 // Calculate time for end of timeout.
915 struct timeval end_time;
916 timeradd(&current_time, &delta, &end_time);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000917
ager@chromium.org65dad4b2009-04-23 08:48:43 +0000918 struct timespec ts;
919 TIMEVAL_TO_TIMESPEC(&end_time, &ts);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000920 // Wait for semaphore signalled or timeout.
921 while (true) {
922 int result = sem_timedwait(&sem_, &ts);
923 if (result == 0) return true; // Successfully got semaphore.
924 if (result > 0) {
925 // For glibc prior to 2.3.4 sem_timedwait returns the error instead of -1.
926 errno = result;
927 result = -1;
928 }
929 if (result == -1 && errno == ETIMEDOUT) return false; // Timeout.
930 CHECK(result == -1 && errno == EINTR); // Signal caused spurious wakeup.
931 }
932}
933
934
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000935Semaphore* OS::CreateSemaphore(int count) {
936 return new LinuxSemaphore(count);
937}
938
ager@chromium.org381abbb2009-02-25 13:23:22 +0000939
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +0000940#if defined(__ANDROID__) && !defined(__BIONIC_HAVE_UCONTEXT_T)
kasperl@chromium.orgacae3782009-04-11 09:17:08 +0000941
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +0000942// Not all versions of Android's C library provide ucontext_t.
943// Detect this and provide custom but compatible definitions. Note that these
944// follow the GLibc naming convention to access register values from
945// mcontext_t.
946//
947// See http://code.google.com/p/android/issues/detail?id=34784
948
949#if defined(__arm__)
950
kasperl@chromium.orgacae3782009-04-11 09:17:08 +0000951typedef struct sigcontext mcontext_t;
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +0000952
kasperl@chromium.orgacae3782009-04-11 09:17:08 +0000953typedef struct ucontext {
954 uint32_t uc_flags;
ager@chromium.orgc4c92722009-11-18 14:12:51 +0000955 struct ucontext* uc_link;
kasperl@chromium.orgacae3782009-04-11 09:17:08 +0000956 stack_t uc_stack;
957 mcontext_t uc_mcontext;
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +0000958 // Other fields are not used by V8, don't define them here.
kasperl@chromium.orgacae3782009-04-11 09:17:08 +0000959} ucontext_t;
kasperl@chromium.orgacae3782009-04-11 09:17:08 +0000960
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +0000961#elif defined(__mips__)
danno@chromium.orgfa458e42012-02-01 10:48:36 +0000962// MIPS version of sigcontext, for Android bionic.
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +0000963typedef struct {
danno@chromium.orgfa458e42012-02-01 10:48:36 +0000964 uint32_t regmask;
965 uint32_t status;
966 uint64_t pc;
967 uint64_t gregs[32];
968 uint64_t fpregs[32];
969 uint32_t acx;
970 uint32_t fpc_csr;
971 uint32_t fpc_eir;
972 uint32_t used_math;
973 uint32_t dsp;
974 uint64_t mdhi;
975 uint64_t mdlo;
976 uint32_t hi1;
977 uint32_t lo1;
978 uint32_t hi2;
979 uint32_t lo2;
980 uint32_t hi3;
981 uint32_t lo3;
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +0000982} mcontext_t;
983
danno@chromium.orgfa458e42012-02-01 10:48:36 +0000984typedef struct ucontext {
985 uint32_t uc_flags;
986 struct ucontext* uc_link;
987 stack_t uc_stack;
988 mcontext_t uc_mcontext;
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +0000989 // Other fields are not used by V8, don't define them here.
danno@chromium.orgfa458e42012-02-01 10:48:36 +0000990} ucontext_t;
991
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +0000992#elif defined(__i386__)
erik.corry@gmail.comed49e962012-04-17 11:57:53 +0000993// x86 version for Android.
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +0000994typedef struct {
yangguo@chromium.orgcb9affa2012-05-15 12:16:38 +0000995 uint32_t gregs[19];
996 void* fpregs;
997 uint32_t oldmask;
998 uint32_t cr2;
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +0000999} mcontext_t;
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00001000
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +00001001typedef uint32_t kernel_sigset_t[2]; // x86 kernel uses 64-bit signal masks
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00001002typedef struct ucontext {
yangguo@chromium.orgcb9affa2012-05-15 12:16:38 +00001003 uint32_t uc_flags;
1004 struct ucontext* uc_link;
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00001005 stack_t uc_stack;
1006 mcontext_t uc_mcontext;
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +00001007 // Other fields are not used by V8, don't define them here.
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00001008} ucontext_t;
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00001009enum { REG_EBP = 6, REG_ESP = 7, REG_EIP = 14 };
kasperl@chromium.orgacae3782009-04-11 09:17:08 +00001010#endif
1011
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +00001012#endif // __ANDROID__ && !defined(__BIONIC_HAVE_UCONTEXT_T)
kasperl@chromium.orgacae3782009-04-11 09:17:08 +00001013
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001014static int GetThreadID() {
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +00001015#if defined(__ANDROID__)
1016 // Android's C library provides gettid(2).
1017 return gettid();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001018#else
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +00001019 // Glibc doesn't provide a wrapper for gettid(2).
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001020 return syscall(SYS_gettid);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001021#endif
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001022}
1023
1024
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001025static void ProfilerSignalHandler(int signal, siginfo_t* info, void* context) {
1026 USE(info);
1027 if (signal != SIGPROF) return;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001028 Isolate* isolate = Isolate::UncheckedCurrent();
1029 if (isolate == NULL || !isolate->IsInitialized() || !isolate->IsInUse()) {
1030 // We require a fully initialized and entered isolate.
1031 return;
1032 }
vitalyr@chromium.org0ec56d62011-04-15 22:22:08 +00001033 if (v8::Locker::IsActive() &&
1034 !isolate->thread_manager()->IsLockedByCurrentThread()) {
1035 return;
1036 }
1037
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001038 Sampler* sampler = isolate->logger()->sampler();
1039 if (sampler == NULL || !sampler->IsActive()) return;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001040
rossberg@chromium.org89e18f52012-10-22 13:09:53 +00001041 TickSample sample_obj;
1042 TickSample* sample = CpuProfiler::TickSampleEvent(isolate);
1043 if (sample == NULL) sample = &sample_obj;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001044
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001045 // Extracting the sample from the context is extremely machine dependent.
1046 ucontext_t* ucontext = reinterpret_cast<ucontext_t*>(context);
1047 mcontext_t& mcontext = ucontext->uc_mcontext;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001048 sample->state = isolate->current_vm_state();
ager@chromium.org9085a012009-05-11 19:22:57 +00001049#if V8_HOST_ARCH_IA32
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001050 sample->pc = reinterpret_cast<Address>(mcontext.gregs[REG_EIP]);
1051 sample->sp = reinterpret_cast<Address>(mcontext.gregs[REG_ESP]);
1052 sample->fp = reinterpret_cast<Address>(mcontext.gregs[REG_EBP]);
ager@chromium.org9085a012009-05-11 19:22:57 +00001053#elif V8_HOST_ARCH_X64
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001054 sample->pc = reinterpret_cast<Address>(mcontext.gregs[REG_RIP]);
1055 sample->sp = reinterpret_cast<Address>(mcontext.gregs[REG_RSP]);
1056 sample->fp = reinterpret_cast<Address>(mcontext.gregs[REG_RBP]);
ager@chromium.org9085a012009-05-11 19:22:57 +00001057#elif V8_HOST_ARCH_ARM
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +00001058#if defined(__GLIBC__) && !defined(__UCLIBC__) && \
1059 (__GLIBC__ < 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ <= 3))
1060 // Old GLibc ARM versions used a gregs[] array to access the register
1061 // values from mcontext_t.
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001062 sample->pc = reinterpret_cast<Address>(mcontext.gregs[R15]);
1063 sample->sp = reinterpret_cast<Address>(mcontext.gregs[R13]);
1064 sample->fp = reinterpret_cast<Address>(mcontext.gregs[R11]);
kasperl@chromium.orgb3284ad2009-05-18 06:12:45 +00001065#else
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001066 sample->pc = reinterpret_cast<Address>(mcontext.arm_pc);
1067 sample->sp = reinterpret_cast<Address>(mcontext.arm_sp);
1068 sample->fp = reinterpret_cast<Address>(mcontext.arm_fp);
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +00001069#endif // defined(__GLIBC__) && !defined(__UCLIBC__) &&
1070 // (__GLIBC__ < 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ <= 3))
ager@chromium.org5c838252010-02-19 08:53:10 +00001071#elif V8_HOST_ARCH_MIPS
danno@chromium.orgc612e022011-11-10 11:38:15 +00001072 sample->pc = reinterpret_cast<Address>(mcontext.pc);
1073 sample->sp = reinterpret_cast<Address>(mcontext.gregs[29]);
1074 sample->fp = reinterpret_cast<Address>(mcontext.gregs[30]);
1075#endif // V8_HOST_ARCH_*
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001076 sampler->SampleStack(sample);
1077 sampler->Tick(sample);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001078}
1079
1080
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001081class Sampler::PlatformData : public Malloced {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001082 public:
rossberg@chromium.org89e18f52012-10-22 13:09:53 +00001083 PlatformData() : vm_tid_(GetThreadID()) {}
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001084
rossberg@chromium.org89e18f52012-10-22 13:09:53 +00001085 int vm_tid() const { return vm_tid_; }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001086
1087 private:
1088 const int vm_tid_;
1089};
1090
1091
1092class SignalSender : public Thread {
1093 public:
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001094 enum SleepInterval {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001095 HALF_INTERVAL,
1096 FULL_INTERVAL
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001097 };
1098
jkummerow@chromium.orgab7dad42012-02-07 12:07:34 +00001099 static const int kSignalSenderStackSize = 64 * KB;
yangguo@chromium.org659ceec2012-01-26 07:37:54 +00001100
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001101 explicit SignalSender(int interval)
yangguo@chromium.org659ceec2012-01-26 07:37:54 +00001102 : Thread(Thread::Options("SignalSender", kSignalSenderStackSize)),
rossberg@chromium.org89e18f52012-10-22 13:09:53 +00001103 vm_tgid_(getpid()),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001104 interval_(interval) {}
1105
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00001106 static void SetUp() { if (!mutex_) mutex_ = OS::CreateMutex(); }
1107 static void TearDown() { delete mutex_; }
fschneider@chromium.org7d10be52012-04-10 12:30:14 +00001108
rossberg@chromium.org89e18f52012-10-22 13:09:53 +00001109 static void InstallSignalHandler() {
1110 struct sigaction sa;
1111 sa.sa_sigaction = ProfilerSignalHandler;
1112 sigemptyset(&sa.sa_mask);
1113 sa.sa_flags = SA_RESTART | SA_SIGINFO;
1114 signal_handler_installed_ =
1115 (sigaction(SIGPROF, &sa, &old_signal_handler_) == 0);
1116 }
1117
1118 static void RestoreSignalHandler() {
1119 if (signal_handler_installed_) {
1120 sigaction(SIGPROF, &old_signal_handler_, 0);
1121 signal_handler_installed_ = false;
1122 }
1123 }
1124
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001125 static void AddActiveSampler(Sampler* sampler) {
fschneider@chromium.org7d10be52012-04-10 12:30:14 +00001126 ScopedLock lock(mutex_);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001127 SamplerRegistry::AddActiveSampler(sampler);
1128 if (instance_ == NULL) {
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +00001129 // Start a thread that will send SIGPROF signal to VM threads,
1130 // when CPU profiling will be enabled.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001131 instance_ = new SignalSender(sampler->interval());
1132 instance_->Start();
1133 } else {
1134 ASSERT(instance_->interval_ == sampler->interval());
1135 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001136 }
1137
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001138 static void RemoveActiveSampler(Sampler* sampler) {
fschneider@chromium.org7d10be52012-04-10 12:30:14 +00001139 ScopedLock lock(mutex_);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001140 SamplerRegistry::RemoveActiveSampler(sampler);
1141 if (SamplerRegistry::GetState() == SamplerRegistry::HAS_NO_SAMPLERS) {
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00001142 RuntimeProfiler::StopRuntimeProfilerThreadBeforeShutdown(instance_);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001143 delete instance_;
1144 instance_ = NULL;
rossberg@chromium.org89e18f52012-10-22 13:09:53 +00001145 RestoreSignalHandler();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001146 }
1147 }
1148
1149 // Implement Thread::Run().
1150 virtual void Run() {
1151 SamplerRegistry::State state;
1152 while ((state = SamplerRegistry::GetState()) !=
1153 SamplerRegistry::HAS_NO_SAMPLERS) {
rossberg@chromium.org89e18f52012-10-22 13:09:53 +00001154 bool cpu_profiling_enabled =
1155 (state == SamplerRegistry::HAS_CPU_PROFILING_SAMPLERS);
1156 bool runtime_profiler_enabled = RuntimeProfiler::IsEnabled();
1157 if (cpu_profiling_enabled && !signal_handler_installed_) {
1158 InstallSignalHandler();
1159 } else if (!cpu_profiling_enabled && signal_handler_installed_) {
1160 RestoreSignalHandler();
1161 }
1162 // When CPU profiling is enabled both JavaScript and C++ code is
1163 // profiled. We must not suspend.
1164 if (!cpu_profiling_enabled) {
1165 if (rate_limiter_.SuspendIfNecessary()) continue;
1166 }
1167 if (cpu_profiling_enabled && runtime_profiler_enabled) {
1168 if (!SamplerRegistry::IterateActiveSamplers(&DoCpuProfile, this)) {
1169 return;
1170 }
1171 Sleep(HALF_INTERVAL);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001172 if (!SamplerRegistry::IterateActiveSamplers(&DoRuntimeProfile, NULL)) {
1173 return;
1174 }
rossberg@chromium.org89e18f52012-10-22 13:09:53 +00001175 Sleep(HALF_INTERVAL);
1176 } else {
1177 if (cpu_profiling_enabled) {
1178 if (!SamplerRegistry::IterateActiveSamplers(&DoCpuProfile,
1179 this)) {
1180 return;
1181 }
1182 }
1183 if (runtime_profiler_enabled) {
1184 if (!SamplerRegistry::IterateActiveSamplers(&DoRuntimeProfile,
1185 NULL)) {
1186 return;
1187 }
1188 }
1189 Sleep(FULL_INTERVAL);
whesse@chromium.orgf0ac72d2010-11-08 12:47:26 +00001190 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00001191 }
1192 }
1193
rossberg@chromium.org89e18f52012-10-22 13:09:53 +00001194 static void DoCpuProfile(Sampler* sampler, void* raw_sender) {
1195 if (!sampler->IsProfiling()) return;
1196 SignalSender* sender = reinterpret_cast<SignalSender*>(raw_sender);
1197 sender->SendProfilingSignal(sampler->platform_data()->vm_tid());
1198 }
1199
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001200 static void DoRuntimeProfile(Sampler* sampler, void* ignored) {
1201 if (!sampler->isolate()->IsInitialized()) return;
1202 sampler->isolate()->runtime_profiler()->NotifyTick();
1203 }
1204
rossberg@chromium.org89e18f52012-10-22 13:09:53 +00001205 void SendProfilingSignal(int tid) {
1206 if (!signal_handler_installed_) return;
1207 // Glibc doesn't provide a wrapper for tgkill(2).
1208#if defined(ANDROID)
1209 syscall(__NR_tgkill, vm_tgid_, tid, SIGPROF);
1210#else
1211 syscall(SYS_tgkill, vm_tgid_, tid, SIGPROF);
1212#endif
1213 }
1214
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001215 void Sleep(SleepInterval full_or_half) {
1216 // Convert ms to us and subtract 100 us to compensate delays
1217 // occuring during signal delivery.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001218 useconds_t interval = interval_ * 1000 - 100;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001219 if (full_or_half == HALF_INTERVAL) interval /= 2;
ulan@chromium.org2efb9002012-01-19 15:36:35 +00001220#if defined(ANDROID)
1221 usleep(interval);
1222#else
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001223 int result = usleep(interval);
1224#ifdef DEBUG
1225 if (result != 0 && errno != EINTR) {
1226 fprintf(stderr,
1227 "SignalSender usleep error; interval = %u, errno = %d\n",
1228 interval,
1229 errno);
1230 ASSERT(result == 0 || errno == EINTR);
1231 }
ulan@chromium.org2efb9002012-01-19 15:36:35 +00001232#endif // DEBUG
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001233 USE(result);
ulan@chromium.org2efb9002012-01-19 15:36:35 +00001234#endif // ANDROID
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001235 }
1236
rossberg@chromium.org89e18f52012-10-22 13:09:53 +00001237 const int vm_tgid_;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001238 const int interval_;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001239 RuntimeProfilerRateLimiter rate_limiter_;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001240
1241 // Protects the process wide state below.
fschneider@chromium.org7d10be52012-04-10 12:30:14 +00001242 static Mutex* mutex_;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001243 static SignalSender* instance_;
rossberg@chromium.org89e18f52012-10-22 13:09:53 +00001244 static bool signal_handler_installed_;
1245 static struct sigaction old_signal_handler_;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001246
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00001247 private:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001248 DISALLOW_COPY_AND_ASSIGN(SignalSender);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001249};
1250
1251
fschneider@chromium.org7d10be52012-04-10 12:30:14 +00001252Mutex* SignalSender::mutex_ = NULL;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001253SignalSender* SignalSender::instance_ = NULL;
rossberg@chromium.org89e18f52012-10-22 13:09:53 +00001254struct sigaction SignalSender::old_signal_handler_;
1255bool SignalSender::signal_handler_installed_ = false;
lrn@chromium.org303ada72010-10-27 09:33:13 +00001256
1257
fschneider@chromium.org7d10be52012-04-10 12:30:14 +00001258void OS::SetUp() {
1259 // Seed the random number generator. We preserve microsecond resolution.
1260 uint64_t seed = Ticks() ^ (getpid() << 16);
1261 srandom(static_cast<unsigned int>(seed));
1262 limit_mutex = CreateMutex();
1263
1264#ifdef __arm__
1265 // When running on ARM hardware check that the EABI used by V8 and
1266 // by the C code is the same.
1267 bool hard_float = OS::ArmUsingHardFloat();
1268 if (hard_float) {
1269#if !USE_EABI_HARDFLOAT
1270 PrintF("ERROR: Binary compiled with -mfloat-abi=hard but without "
1271 "-DUSE_EABI_HARDFLOAT\n");
1272 exit(1);
1273#endif
1274 } else {
1275#if USE_EABI_HARDFLOAT
1276 PrintF("ERROR: Binary not compiled with -mfloat-abi=hard but with "
1277 "-DUSE_EABI_HARDFLOAT\n");
1278 exit(1);
1279#endif
1280 }
1281#endif
1282 SignalSender::SetUp();
1283}
1284
1285
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00001286void OS::TearDown() {
1287 SignalSender::TearDown();
1288 delete limit_mutex;
1289}
1290
1291
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001292Sampler::Sampler(Isolate* isolate, int interval)
1293 : isolate_(isolate),
1294 interval_(interval),
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001295 profiling_(false),
ager@chromium.orgbeb25712010-11-29 08:02:25 +00001296 active_(false),
1297 samples_taken_(0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001298 data_ = new PlatformData;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001299}
1300
1301
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001302Sampler::~Sampler() {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001303 ASSERT(!IsActive());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001304 delete data_;
1305}
1306
1307
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001308void Sampler::Start() {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001309 ASSERT(!IsActive());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001310 SetActive(true);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001311 SignalSender::AddActiveSampler(this);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001312}
1313
1314
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001315void Sampler::Stop() {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001316 ASSERT(IsActive());
1317 SignalSender::RemoveActiveSampler(this);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001318 SetActive(false);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001319}
1320
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001321
1322} } // namespace v8::internal