blob: 885683398e24fa36930a3118d2a0c31c1902b770 [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
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +000041#if defined(__GLIBC__) && !defined(__UCLIBC__)
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +000042#include <execinfo.h>
43#include <cxxabi.h>
44#endif
45
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000046// Ubuntu Dapper requires memory pages to be marked as
47// executable. Otherwise, OS raises an exception when executing code
48// in that page.
49#include <sys/types.h> // mmap & munmap
ager@chromium.org236ad962008-09-25 09:45:57 +000050#include <sys/mman.h> // mmap & munmap
51#include <sys/stat.h> // open
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000052#include <fcntl.h> // open
53#include <unistd.h> // sysconf
ager@chromium.org236ad962008-09-25 09:45:57 +000054#include <strings.h> // index
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000055#include <errno.h>
56#include <stdarg.h>
57
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +000058// GLibc on ARM defines mcontext_t has a typedef for 'struct sigcontext'.
59// Old versions of the C library <signal.h> didn't define the type.
60#if defined(__ANDROID__) && !defined(__BIONIC_HAVE_UCONTEXT_T) && \
61 defined(__arm__) && !defined(__BIONIC_HAVE_STRUCT_SIGCONTEXT)
62#include <asm/sigcontext.h>
63#endif
64
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000065#undef MAP_TYPE
66
67#include "v8.h"
68
danno@chromium.org8c0a43f2012-04-03 08:37:53 +000069#include "platform-posix.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000070#include "platform.h"
ager@chromium.orga1645e22009-09-09 19:27:10 +000071#include "v8threads.h"
kasperl@chromium.orga5551262010-12-07 12:49:48 +000072#include "vm-state-inl.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000073
74
kasperl@chromium.org71affb52009-05-26 05:44:31 +000075namespace v8 {
76namespace internal {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000077
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000078
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000079static Mutex* limit_mutex = NULL;
80
81
ager@chromium.orgc4c92722009-11-18 14:12:51 +000082#ifdef __arm__
lrn@chromium.orgfa943b72010-11-03 08:14:36 +000083static bool CPUInfoContainsString(const char * search_string) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +000084 const char* file_name = "/proc/cpuinfo";
ager@chromium.orgc4c92722009-11-18 14:12:51 +000085 // This is written as a straight shot one pass parser
86 // and not using STL string and ifstream because,
87 // on Linux, it's reading from a (non-mmap-able)
88 // character special device.
ager@chromium.orgc4c92722009-11-18 14:12:51 +000089 FILE* f = NULL;
90 const char* what = search_string;
91
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +000092 if (NULL == (f = fopen(file_name, "r"))) {
93 OS::PrintError("Failed to open /proc/cpuinfo\n");
ager@chromium.orgc4c92722009-11-18 14:12:51 +000094 return false;
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +000095 }
ager@chromium.orgc4c92722009-11-18 14:12:51 +000096
97 int k;
98 while (EOF != (k = fgetc(f))) {
99 if (k == *what) {
100 ++what;
101 while ((*what != '\0') && (*what == fgetc(f))) {
102 ++what;
103 }
104 if (*what == '\0') {
105 fclose(f);
106 return true;
107 } else {
108 what = search_string;
109 }
110 }
111 }
112 fclose(f);
113
114 // Did not find string in the proc file.
115 return false;
116}
lrn@chromium.orgfa943b72010-11-03 08:14:36 +0000117
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +0000118
lrn@chromium.orgfa943b72010-11-03 08:14:36 +0000119bool OS::ArmCpuHasFeature(CpuFeature feature) {
ager@chromium.org5f0c45f2010-12-17 08:51:21 +0000120 const char* search_string = NULL;
lrn@chromium.orgfa943b72010-11-03 08:14:36 +0000121 // Simple detection of VFP at runtime for Linux.
122 // It is based on /proc/cpuinfo, which reveals hardware configuration
123 // to user-space applications. According to ARM (mid 2009), no similar
124 // facility is universally available on the ARM architectures,
125 // so it's up to individual OSes to provide such.
126 switch (feature) {
127 case VFP3:
ager@chromium.org5f0c45f2010-12-17 08:51:21 +0000128 search_string = "vfpv3";
lrn@chromium.orgfa943b72010-11-03 08:14:36 +0000129 break;
danno@chromium.org169691d2013-07-15 08:01:13 +0000130 case NEON:
131 search_string = "neon";
132 break;
lrn@chromium.orgfa943b72010-11-03 08:14:36 +0000133 case ARMv7:
ager@chromium.org5f0c45f2010-12-17 08:51:21 +0000134 search_string = "ARMv7";
lrn@chromium.orgfa943b72010-11-03 08:14:36 +0000135 break;
verwaest@chromium.org33e09c82012-10-10 17:07:22 +0000136 case SUDIV:
137 search_string = "idiva";
138 break;
yangguo@chromium.org003650e2013-01-24 16:31:08 +0000139 case VFP32DREGS:
140 // This case is handled specially below.
141 break;
lrn@chromium.orgfa943b72010-11-03 08:14:36 +0000142 default:
143 UNREACHABLE();
144 }
145
yangguo@chromium.org003650e2013-01-24 16:31:08 +0000146 if (feature == VFP32DREGS) {
147 return ArmCpuHasFeature(VFP3) && !CPUInfoContainsString("d16");
148 }
149
ager@chromium.org5f0c45f2010-12-17 08:51:21 +0000150 if (CPUInfoContainsString(search_string)) {
151 return true;
152 }
153
154 if (feature == VFP3) {
155 // Some old kernels will report vfp not vfpv3. Here we make a last attempt
156 // to detect vfpv3 by checking for vfp *and* neon, since neon is only
157 // available on architectures with vfpv3.
158 // Checking neon on its own is not enough as it is possible to have neon
159 // without vfp.
160 if (CPUInfoContainsString("vfp") && CPUInfoContainsString("neon")) {
lrn@chromium.orgfa943b72010-11-03 08:14:36 +0000161 return true;
162 }
163 }
164
165 return false;
166}
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +0000167
168
rossberg@chromium.org89e18f52012-10-22 13:09:53 +0000169CpuImplementer OS::GetCpuImplementer() {
170 static bool use_cached_value = false;
171 static CpuImplementer cached_value = UNKNOWN_IMPLEMENTER;
172 if (use_cached_value) {
173 return cached_value;
174 }
175 if (CPUInfoContainsString("CPU implementer\t: 0x41")) {
176 cached_value = ARM_IMPLEMENTER;
177 } else if (CPUInfoContainsString("CPU implementer\t: 0x51")) {
178 cached_value = QUALCOMM_IMPLEMENTER;
179 } else {
180 cached_value = UNKNOWN_IMPLEMENTER;
181 }
182 use_cached_value = true;
183 return cached_value;
184}
185
186
danno@chromium.org169691d2013-07-15 08:01:13 +0000187CpuPart OS::GetCpuPart(CpuImplementer implementer) {
188 static bool use_cached_value = false;
189 static CpuPart cached_value = CPU_UNKNOWN;
190 if (use_cached_value) {
191 return cached_value;
192 }
193 if (implementer == ARM_IMPLEMENTER) {
194 if (CPUInfoContainsString("CPU part\t: 0xc0f")) {
195 cached_value = CORTEX_A15;
196 } else if (CPUInfoContainsString("CPU part\t: 0xc0c")) {
197 cached_value = CORTEX_A12;
198 } else if (CPUInfoContainsString("CPU part\t: 0xc09")) {
199 cached_value = CORTEX_A9;
200 } else if (CPUInfoContainsString("CPU part\t: 0xc08")) {
201 cached_value = CORTEX_A8;
202 } else if (CPUInfoContainsString("CPU part\t: 0xc07")) {
203 cached_value = CORTEX_A7;
204 } else if (CPUInfoContainsString("CPU part\t: 0xc05")) {
205 cached_value = CORTEX_A5;
206 } else {
207 cached_value = CPU_UNKNOWN;
208 }
209 } else {
210 cached_value = CPU_UNKNOWN;
211 }
212 use_cached_value = true;
213 return cached_value;
214}
215
216
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +0000217bool OS::ArmUsingHardFloat() {
yangguo@chromium.orgc74d6742012-06-29 15:15:45 +0000218 // GCC versions 4.6 and above define __ARM_PCS or __ARM_PCS_VFP to specify
219 // the Floating Point ABI used (PCS stands for Procedure Call Standard).
220 // We use these as well as a couple of other defines to statically determine
221 // what FP ABI used.
222 // GCC versions 4.4 and below don't support hard-fp.
223 // GCC versions 4.5 may support hard-fp without defining __ARM_PCS or
224 // __ARM_PCS_VFP.
225
226#define GCC_VERSION (__GNUC__ * 10000 \
227 + __GNUC_MINOR__ * 100 \
228 + __GNUC_PATCHLEVEL__)
229#if GCC_VERSION >= 40600
230#if defined(__ARM_PCS_VFP)
231 return true;
232#else
233 return false;
234#endif
235
236#elif GCC_VERSION < 40500
237 return false;
238
239#else
240#if defined(__ARM_PCS_VFP)
241 return true;
danno@chromium.org59400602013-08-13 17:09:37 +0000242#elif defined(__ARM_PCS) || defined(__SOFTFP__) || defined(__SOFTFP) || \
243 !defined(__VFP_FP__)
yangguo@chromium.orgc74d6742012-06-29 15:15:45 +0000244 return false;
245#else
246#error "Your version of GCC does not report the FP ABI compiled for." \
247 "Please report it on this issue" \
248 "http://code.google.com/p/v8/issues/detail?id=2140"
249
250#endif
251#endif
252#undef GCC_VERSION
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +0000253}
yangguo@chromium.orgc74d6742012-06-29 15:15:45 +0000254
ager@chromium.orgc4c92722009-11-18 14:12:51 +0000255#endif // def __arm__
256
257
lrn@chromium.org7516f052011-03-30 08:52:27 +0000258#ifdef __mips__
259bool OS::MipsCpuHasFeature(CpuFeature feature) {
260 const char* search_string = NULL;
261 const char* file_name = "/proc/cpuinfo";
262 // Simple detection of FPU at runtime for Linux.
263 // It is based on /proc/cpuinfo, which reveals hardware configuration
264 // to user-space applications. According to MIPS (early 2010), no similar
265 // facility is universally available on the MIPS architectures,
266 // so it's up to individual OSes to provide such.
267 //
268 // This is written as a straight shot one pass parser
269 // and not using STL string and ifstream because,
270 // on Linux, it's reading from a (non-mmap-able)
271 // character special device.
272
273 switch (feature) {
274 case FPU:
275 search_string = "FPU";
276 break;
277 default:
278 UNREACHABLE();
279 }
280
281 FILE* f = NULL;
282 const char* what = search_string;
283
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000284 if (NULL == (f = fopen(file_name, "r"))) {
285 OS::PrintError("Failed to open /proc/cpuinfo\n");
lrn@chromium.org7516f052011-03-30 08:52:27 +0000286 return false;
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000287 }
lrn@chromium.org7516f052011-03-30 08:52:27 +0000288
289 int k;
290 while (EOF != (k = fgetc(f))) {
291 if (k == *what) {
292 ++what;
293 while ((*what != '\0') && (*what == fgetc(f))) {
294 ++what;
295 }
296 if (*what == '\0') {
297 fclose(f);
298 return true;
299 } else {
300 what = search_string;
301 }
302 }
303 }
304 fclose(f);
305
306 // Did not find string in the proc file.
307 return false;
308}
309#endif // def __mips__
310
311
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000312const char* OS::LocalTimezone(double time) {
ulan@chromium.org77ca49a2013-04-22 09:43:56 +0000313 if (std::isnan(time)) return "";
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000314 time_t tv = static_cast<time_t>(floor(time/msPerSecond));
315 struct tm* t = localtime(&tv);
316 if (NULL == t) return "";
317 return t->tm_zone;
318}
319
320
321double OS::LocalTimeOffset() {
322 time_t tv = time(NULL);
323 struct tm* t = localtime(&tv);
324 // tm_gmtoff includes any daylight savings offset, so subtract it.
325 return static_cast<double>(t->tm_gmtoff * msPerSecond -
326 (t->tm_isdst > 0 ? 3600 * msPerSecond : 0));
327}
328
329
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000330// We keep the lowest and highest addresses mapped as a quick way of
331// determining that pointers are outside the heap (used mostly in assertions
ulan@chromium.org2efb9002012-01-19 15:36:35 +0000332// and verification). The estimate is conservative, i.e., not all addresses in
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000333// 'allocated' space are actually allocated to our heap. The range is
334// [lowest, highest), inclusive on the low and and exclusive on the high end.
335static void* lowest_ever_allocated = reinterpret_cast<void*>(-1);
336static void* highest_ever_allocated = reinterpret_cast<void*>(0);
337
338
339static void UpdateAllocatedSpaceLimits(void* address, int size) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000340 ASSERT(limit_mutex != NULL);
341 ScopedLock lock(limit_mutex);
342
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000343 lowest_ever_allocated = Min(lowest_ever_allocated, address);
344 highest_ever_allocated =
345 Max(highest_ever_allocated,
346 reinterpret_cast<void*>(reinterpret_cast<char*>(address) + size));
347}
348
349
350bool OS::IsOutsideAllocatedSpace(void* address) {
351 return address < lowest_ever_allocated || address >= highest_ever_allocated;
352}
353
354
kasper.lund7276f142008-07-30 08:49:36 +0000355void* OS::Allocate(const size_t requested,
356 size_t* allocated,
kasperl@chromium.orgf5aa8372009-03-24 14:47:14 +0000357 bool is_executable) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000358 const size_t msize = RoundUp(requested, AllocateAlignment());
kasperl@chromium.orgf5aa8372009-03-24 14:47:14 +0000359 int prot = PROT_READ | PROT_WRITE | (is_executable ? PROT_EXEC : 0);
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +0000360 void* addr = OS::GetRandomMmapAddr();
ricow@chromium.org9fa09672011-07-25 11:05:35 +0000361 void* mbase = mmap(addr, msize, prot, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000362 if (mbase == MAP_FAILED) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000363 LOG(i::Isolate::Current(),
364 StringEvent("OS::Allocate", "mmap failed"));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000365 return NULL;
366 }
367 *allocated = msize;
368 UpdateAllocatedSpaceLimits(mbase, msize);
369 return mbase;
370}
371
372
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +0000373void OS::DumpBacktrace() {
danno@chromium.org169691d2013-07-15 08:01:13 +0000374 // backtrace is a glibc extension.
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000375#if defined(__GLIBC__) && !defined(__UCLIBC__)
danno@chromium.org169691d2013-07-15 08:01:13 +0000376 POSIXBacktraceHelper<backtrace, backtrace_symbols>::DumpBacktrace();
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +0000377#endif
378}
379
380
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000381class PosixMemoryMappedFile : public OS::MemoryMappedFile {
382 public:
383 PosixMemoryMappedFile(FILE* file, void* memory, int size)
384 : file_(file), memory_(memory), size_(size) { }
385 virtual ~PosixMemoryMappedFile();
386 virtual void* memory() { return memory_; }
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +0000387 virtual int size() { return size_; }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000388 private:
389 FILE* file_;
390 void* memory_;
391 int size_;
392};
393
394
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +0000395OS::MemoryMappedFile* OS::MemoryMappedFile::open(const char* name) {
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +0000396 FILE* file = fopen(name, "r+");
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +0000397 if (file == NULL) return NULL;
398
399 fseek(file, 0, SEEK_END);
400 int size = ftell(file);
401
402 void* memory =
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +0000403 mmap(OS::GetRandomMmapAddr(),
404 size,
405 PROT_READ | PROT_WRITE,
406 MAP_SHARED,
407 fileno(file),
408 0);
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +0000409 return new PosixMemoryMappedFile(file, memory, size);
410}
411
412
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000413OS::MemoryMappedFile* OS::MemoryMappedFile::create(const char* name, int size,
414 void* initial) {
415 FILE* file = fopen(name, "w+");
416 if (file == NULL) return NULL;
ager@chromium.org9258b6b2008-09-11 09:11:10 +0000417 int result = fwrite(initial, size, 1, file);
418 if (result < 1) {
419 fclose(file);
420 return NULL;
421 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000422 void* memory =
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +0000423 mmap(OS::GetRandomMmapAddr(),
424 size,
425 PROT_READ | PROT_WRITE,
426 MAP_SHARED,
427 fileno(file),
428 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000429 return new PosixMemoryMappedFile(file, memory, size);
430}
431
432
433PosixMemoryMappedFile::~PosixMemoryMappedFile() {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000434 if (memory_) OS::Free(memory_, size_);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000435 fclose(file_);
436}
437
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000438
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000439void OS::LogSharedLibraryAddresses() {
sgjesse@chromium.orgb9d7da12009-08-05 08:38:10 +0000440 // This function assumes that the layout of the file is as follows:
441 // hex_start_addr-hex_end_addr rwxp <unused data> [binary_file_name]
442 // If we encounter an unexpected situation we abort scanning further entries.
ager@chromium.orgc4c92722009-11-18 14:12:51 +0000443 FILE* fp = fopen("/proc/self/maps", "r");
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000444 if (fp == NULL) return;
sgjesse@chromium.orgb9d7da12009-08-05 08:38:10 +0000445
446 // Allocate enough room to be able to store a full file name.
447 const int kLibNameLen = FILENAME_MAX + 1;
448 char* lib_name = reinterpret_cast<char*>(malloc(kLibNameLen));
449
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000450 i::Isolate* isolate = ISOLATE;
sgjesse@chromium.orgb9d7da12009-08-05 08:38:10 +0000451 // This loop will terminate once the scanning hits an EOF.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000452 while (true) {
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000453 uintptr_t start, end;
454 char attr_r, attr_w, attr_x, attr_p;
sgjesse@chromium.orgb9d7da12009-08-05 08:38:10 +0000455 // Parse the addresses and permission bits at the beginning of the line.
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000456 if (fscanf(fp, "%" V8PRIxPTR "-%" V8PRIxPTR, &start, &end) != 2) break;
457 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 +0000458
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000459 int c;
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000460 if (attr_r == 'r' && attr_w != 'w' && attr_x == 'x') {
461 // Found a read-only executable entry. Skip characters until we reach
sgjesse@chromium.orgb9d7da12009-08-05 08:38:10 +0000462 // the beginning of the filename or the end of the line.
463 do {
464 c = getc(fp);
yangguo@chromium.org46a2a512013-01-18 16:29:40 +0000465 } while ((c != EOF) && (c != '\n') && (c != '/') && (c != '['));
sgjesse@chromium.orgb9d7da12009-08-05 08:38:10 +0000466 if (c == EOF) break; // EOF: Was unexpected, just exit.
467
468 // Process the filename if found.
yangguo@chromium.org46a2a512013-01-18 16:29:40 +0000469 if ((c == '/') || (c == '[')) {
470 // Push the '/' or '[' back into the stream to be read below.
471 ungetc(c, fp);
sgjesse@chromium.orgb9d7da12009-08-05 08:38:10 +0000472
473 // Read to the end of the line. Exit if the read fails.
474 if (fgets(lib_name, kLibNameLen, fp) == NULL) break;
475
476 // Drop the newline character read by fgets. We do not need to check
477 // for a zero-length string because we know that we at least read the
yangguo@chromium.org46a2a512013-01-18 16:29:40 +0000478 // '/' or '[' character.
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000479 lib_name[strlen(lib_name) - 1] = '\0';
480 } else {
sgjesse@chromium.orgb9d7da12009-08-05 08:38:10 +0000481 // No library name found, just record the raw address range.
482 snprintf(lib_name, kLibNameLen,
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000483 "%08" V8PRIxPTR "-%08" V8PRIxPTR, start, end);
484 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000485 LOG(isolate, SharedLibraryEvent(lib_name, start, end));
sgjesse@chromium.orgb9d7da12009-08-05 08:38:10 +0000486 } else {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +0000487 // Entry not describing executable data. Skip to end of line to set up
sgjesse@chromium.orgb9d7da12009-08-05 08:38:10 +0000488 // reading the next entry.
489 do {
490 c = getc(fp);
491 } while ((c != EOF) && (c != '\n'));
492 if (c == EOF) break;
ager@chromium.org5aa501c2009-06-23 07:57:28 +0000493 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000494 }
sgjesse@chromium.orgb9d7da12009-08-05 08:38:10 +0000495 free(lib_name);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000496 fclose(fp);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000497}
498
499
whesse@chromium.org4a5224e2010-10-20 12:37:07 +0000500void OS::SignalCodeMovingGC() {
whesse@chromium.org4a5224e2010-10-20 12:37:07 +0000501 // Support for ll_prof.py.
502 //
503 // The Linux profiler built into the kernel logs all mmap's with
504 // PROT_EXEC so that analysis tools can properly attribute ticks. We
505 // do a mmap with a name known by ll_prof.py and immediately munmap
506 // it. This injects a GC marker into the stream of events generated
507 // by the kernel and allows us to synchronize V8 code log and the
508 // kernel log.
509 int size = sysconf(_SC_PAGESIZE);
mstarzinger@chromium.orgde886792012-09-11 13:22:37 +0000510 FILE* f = fopen(FLAG_gc_fake_mmap, "w+");
rossberg@chromium.orgb99c7542013-05-31 11:40:45 +0000511 if (f == NULL) {
512 OS::PrintError("Failed to open %s\n", FLAG_gc_fake_mmap);
513 OS::Abort();
514 }
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +0000515 void* addr = mmap(OS::GetRandomMmapAddr(),
516 size,
jkummerow@chromium.orgba72ec82013-07-22 09:21:20 +0000517#if defined(__native_client__)
518 // The Native Client port of V8 uses an interpreter,
519 // so code pages don't need PROT_EXEC.
520 PROT_READ,
521#else
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +0000522 PROT_READ | PROT_EXEC,
jkummerow@chromium.orgba72ec82013-07-22 09:21:20 +0000523#endif
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +0000524 MAP_PRIVATE,
525 fileno(f),
526 0);
whesse@chromium.org4a5224e2010-10-20 12:37:07 +0000527 ASSERT(addr != MAP_FAILED);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000528 OS::Free(addr, size);
whesse@chromium.org4a5224e2010-10-20 12:37:07 +0000529 fclose(f);
whesse@chromium.org4a5224e2010-10-20 12:37:07 +0000530}
531
532
ager@chromium.org65dad4b2009-04-23 08:48:43 +0000533int OS::StackWalk(Vector<OS::StackFrame> frames) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000534 // backtrace is a glibc extension.
fschneider@chromium.org7d10be52012-04-10 12:30:14 +0000535#if defined(__GLIBC__) && !defined(__UCLIBC__)
danno@chromium.org169691d2013-07-15 08:01:13 +0000536 return POSIXBacktraceHelper<backtrace, backtrace_symbols>::StackWalk(frames);
537#else
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000538 return 0;
danno@chromium.org169691d2013-07-15 08:01:13 +0000539#endif
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000540}
541
542
543// Constants used for mmap.
544static const int kMmapFd = -1;
545static const int kMmapFdOffset = 0;
546
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000547
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000548VirtualMemory::VirtualMemory() : address_(NULL), size_(0) { }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000549
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000550
551VirtualMemory::VirtualMemory(size_t size)
552 : address_(ReserveRegion(size)), size_(size) { }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000553
554
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000555VirtualMemory::VirtualMemory(size_t size, size_t alignment)
556 : address_(NULL), size_(0) {
557 ASSERT(IsAligned(alignment, static_cast<intptr_t>(OS::AllocateAlignment())));
558 size_t request_size = RoundUp(size + alignment,
559 static_cast<intptr_t>(OS::AllocateAlignment()));
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +0000560 void* reservation = mmap(OS::GetRandomMmapAddr(),
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000561 request_size,
562 PROT_NONE,
563 MAP_PRIVATE | MAP_ANONYMOUS | MAP_NORESERVE,
564 kMmapFd,
565 kMmapFdOffset);
566 if (reservation == MAP_FAILED) return;
567
568 Address base = static_cast<Address>(reservation);
569 Address aligned_base = RoundUp(base, alignment);
570 ASSERT_LE(base, aligned_base);
571
572 // Unmap extra memory reserved before and after the desired block.
573 if (aligned_base != base) {
574 size_t prefix_size = static_cast<size_t>(aligned_base - base);
575 OS::Free(base, prefix_size);
576 request_size -= prefix_size;
577 }
578
579 size_t aligned_size = RoundUp(size, OS::AllocateAlignment());
580 ASSERT_LE(aligned_size, request_size);
581
582 if (aligned_size != request_size) {
583 size_t suffix_size = request_size - aligned_size;
584 OS::Free(aligned_base + aligned_size, suffix_size);
585 request_size -= suffix_size;
586 }
587
588 ASSERT(aligned_size == request_size);
589
590 address_ = static_cast<void*>(aligned_base);
591 size_ = aligned_size;
592}
593
594
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000595VirtualMemory::~VirtualMemory() {
596 if (IsReserved()) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000597 bool result = ReleaseRegion(address(), size());
598 ASSERT(result);
599 USE(result);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000600 }
601}
602
603
604bool VirtualMemory::IsReserved() {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000605 return address_ != NULL;
606}
607
608
609void VirtualMemory::Reset() {
610 address_ = NULL;
611 size_ = 0;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000612}
613
614
kasperl@chromium.orgf5aa8372009-03-24 14:47:14 +0000615bool VirtualMemory::Commit(void* address, size_t size, bool is_executable) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000616 return CommitRegion(address, size, is_executable);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000617}
618
619
620bool VirtualMemory::Uncommit(void* address, size_t size) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000621 return UncommitRegion(address, size);
622}
623
624
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +0000625bool VirtualMemory::Guard(void* address) {
626 OS::Guard(address, OS::CommitPageSize());
627 return true;
628}
629
630
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000631void* VirtualMemory::ReserveRegion(size_t size) {
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +0000632 void* result = mmap(OS::GetRandomMmapAddr(),
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000633 size,
634 PROT_NONE,
635 MAP_PRIVATE | MAP_ANONYMOUS | MAP_NORESERVE,
636 kMmapFd,
637 kMmapFdOffset);
638
639 if (result == MAP_FAILED) return NULL;
640
641 return result;
642}
643
644
645bool VirtualMemory::CommitRegion(void* base, size_t size, bool is_executable) {
jkummerow@chromium.orgba72ec82013-07-22 09:21:20 +0000646#if defined(__native_client__)
647 // The Native Client port of V8 uses an interpreter,
648 // so code pages don't need PROT_EXEC.
649 int prot = PROT_READ | PROT_WRITE;
650#else
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000651 int prot = PROT_READ | PROT_WRITE | (is_executable ? PROT_EXEC : 0);
jkummerow@chromium.orgba72ec82013-07-22 09:21:20 +0000652#endif
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000653 if (MAP_FAILED == mmap(base,
654 size,
655 prot,
656 MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED,
657 kMmapFd,
658 kMmapFdOffset)) {
659 return false;
660 }
661
662 UpdateAllocatedSpaceLimits(base, size);
663 return true;
664}
665
666
667bool VirtualMemory::UncommitRegion(void* base, size_t size) {
668 return mmap(base,
669 size,
670 PROT_NONE,
ager@chromium.orga1645e22009-09-09 19:27:10 +0000671 MAP_PRIVATE | MAP_ANONYMOUS | MAP_NORESERVE | MAP_FIXED,
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000672 kMmapFd,
673 kMmapFdOffset) != MAP_FAILED;
674}
675
676
677bool VirtualMemory::ReleaseRegion(void* base, size_t size) {
678 return munmap(base, size) == 0;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000679}
680
681
danno@chromium.org72204d52012-10-31 10:02:10 +0000682bool VirtualMemory::HasLazyCommits() {
683 return true;
684}
685
686
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000687class LinuxSemaphore : public Semaphore {
688 public:
689 explicit LinuxSemaphore(int count) { sem_init(&sem_, 0, count); }
690 virtual ~LinuxSemaphore() { sem_destroy(&sem_); }
691
kasper.lund7276f142008-07-30 08:49:36 +0000692 virtual void Wait();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000693 virtual bool Wait(int timeout);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000694 virtual void Signal() { sem_post(&sem_); }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000695 private:
696 sem_t sem_;
697};
698
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000699
kasper.lund7276f142008-07-30 08:49:36 +0000700void LinuxSemaphore::Wait() {
701 while (true) {
702 int result = sem_wait(&sem_);
703 if (result == 0) return; // Successfully got semaphore.
704 CHECK(result == -1 && errno == EINTR); // Signal caused spurious wakeup.
705 }
706}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000707
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000708
ager@chromium.org65dad4b2009-04-23 08:48:43 +0000709#ifndef TIMEVAL_TO_TIMESPEC
710#define TIMEVAL_TO_TIMESPEC(tv, ts) do { \
711 (ts)->tv_sec = (tv)->tv_sec; \
712 (ts)->tv_nsec = (tv)->tv_usec * 1000; \
713} while (false)
714#endif
715
716
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000717bool LinuxSemaphore::Wait(int timeout) {
718 const long kOneSecondMicros = 1000000; // NOLINT
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000719
720 // Split timeout into second and nanosecond parts.
ager@chromium.org65dad4b2009-04-23 08:48:43 +0000721 struct timeval delta;
722 delta.tv_usec = timeout % kOneSecondMicros;
723 delta.tv_sec = timeout / kOneSecondMicros;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000724
ager@chromium.org65dad4b2009-04-23 08:48:43 +0000725 struct timeval current_time;
726 // Get the current time.
727 if (gettimeofday(&current_time, NULL) == -1) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000728 return false;
729 }
730
ager@chromium.org65dad4b2009-04-23 08:48:43 +0000731 // Calculate time for end of timeout.
732 struct timeval end_time;
733 timeradd(&current_time, &delta, &end_time);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000734
ager@chromium.org65dad4b2009-04-23 08:48:43 +0000735 struct timespec ts;
736 TIMEVAL_TO_TIMESPEC(&end_time, &ts);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000737 // Wait for semaphore signalled or timeout.
738 while (true) {
739 int result = sem_timedwait(&sem_, &ts);
740 if (result == 0) return true; // Successfully got semaphore.
741 if (result > 0) {
742 // For glibc prior to 2.3.4 sem_timedwait returns the error instead of -1.
743 errno = result;
744 result = -1;
745 }
746 if (result == -1 && errno == ETIMEDOUT) return false; // Timeout.
747 CHECK(result == -1 && errno == EINTR); // Signal caused spurious wakeup.
748 }
749}
750
751
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000752Semaphore* OS::CreateSemaphore(int count) {
753 return new LinuxSemaphore(count);
754}
755
ager@chromium.org381abbb2009-02-25 13:23:22 +0000756
fschneider@chromium.org7d10be52012-04-10 12:30:14 +0000757void OS::SetUp() {
758 // Seed the random number generator. We preserve microsecond resolution.
759 uint64_t seed = Ticks() ^ (getpid() << 16);
760 srandom(static_cast<unsigned int>(seed));
761 limit_mutex = CreateMutex();
fschneider@chromium.org7d10be52012-04-10 12:30:14 +0000762}
763
764
erik.corry@gmail.comed49e962012-04-17 11:57:53 +0000765void OS::TearDown() {
erik.corry@gmail.comed49e962012-04-17 11:57:53 +0000766 delete limit_mutex;
767}
768
769
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000770} } // namespace v8::internal