blob: 512d995792731cb9e0a1333cd8ec856868f4cc03 [file] [log] [blame]
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00001// Copyright 2012 the V8 project authors. All rights reserved.
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +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
28// Platform specific code for Solaris 10 goes here. For the POSIX comaptible
29// parts the implementation is in platform-posix.cc.
30
31#ifdef __sparc
32# error "V8 does not support the SPARC CPU architecture."
33#endif
34
35#include <sys/stack.h> // for stack alignment
36#include <unistd.h> // getpagesize(), usleep()
37#include <sys/mman.h> // mmap()
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +000038#include <ucontext.h> // walkstack(), getcontext()
39#include <dlfcn.h> // dladdr
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000040#include <pthread.h>
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000041#include <semaphore.h>
42#include <time.h>
43#include <sys/time.h> // gettimeofday(), timeradd()
44#include <errno.h>
45#include <ieeefp.h> // finite()
46#include <signal.h> // sigemptyset(), etc
whesse@chromium.orgb08986c2011-03-14 16:13:42 +000047#include <sys/regset.h>
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000048
49
50#undef MAP_TYPE
51
52#include "v8.h"
53
danno@chromium.org8c0a43f2012-04-03 08:37:53 +000054#include "platform-posix.h"
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000055#include "platform.h"
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +000056#include "v8threads.h"
kasperl@chromium.orga5551262010-12-07 12:49:48 +000057#include "vm-state-inl.h"
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000058
59
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +000060// It seems there is a bug in some Solaris distributions (experienced in
61// SunOS 5.10 Generic_141445-09) which make it difficult or impossible to
62// access signbit() despite the availability of other C99 math functions.
63#ifndef signbit
ulan@chromium.org77ca49a2013-04-22 09:43:56 +000064namespace std {
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +000065// Test sign - usually defined in math.h
66int signbit(double x) {
67 // We need to take care of the special case of both positive and negative
68 // versions of zero.
69 if (x == 0) {
70 return fpclass(x) & FP_NZERO;
71 } else {
72 // This won't detect negative NaN but that should be okay since we don't
73 // assume that behavior.
74 return x < 0;
75 }
76}
ulan@chromium.org77ca49a2013-04-22 09:43:56 +000077} // namespace std
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +000078#endif // signbit
79
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000080namespace v8 {
81namespace internal {
82
83
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000084const char* OS::LocalTimezone(double time) {
ulan@chromium.org77ca49a2013-04-22 09:43:56 +000085 if (std::isnan(time)) return "";
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000086 time_t tv = static_cast<time_t>(floor(time/msPerSecond));
87 struct tm* t = localtime(&tv);
88 if (NULL == t) return "";
89 return tzname[0]; // The location of the timezone string on Solaris.
90}
91
92
93double OS::LocalTimeOffset() {
danno@chromium.org72204d52012-10-31 10:02:10 +000094 tzset();
95 return -static_cast<double>(timezone * msPerSecond);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000096}
97
98
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000099void* OS::Allocate(const size_t requested,
100 size_t* allocated,
101 bool is_executable) {
102 const size_t msize = RoundUp(requested, getpagesize());
103 int prot = PROT_READ | PROT_WRITE | (is_executable ? PROT_EXEC : 0);
104 void* mbase = mmap(NULL, msize, prot, MAP_PRIVATE | MAP_ANON, -1, 0);
105
106 if (mbase == MAP_FAILED) {
hpayer@chromium.orgc5d49712013-09-11 08:25:48 +0000107 LOG(Isolate::Current(), StringEvent("OS::Allocate", "mmap failed"));
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000108 return NULL;
109 }
110 *allocated = msize;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000111 return mbase;
112}
113
114
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +0000115void OS::DumpBacktrace() {
116 // Currently unsupported.
117}
118
119
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000120class PosixMemoryMappedFile : public OS::MemoryMappedFile {
121 public:
122 PosixMemoryMappedFile(FILE* file, void* memory, int size)
123 : file_(file), memory_(memory), size_(size) { }
124 virtual ~PosixMemoryMappedFile();
125 virtual void* memory() { return memory_; }
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +0000126 virtual int size() { return size_; }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000127 private:
128 FILE* file_;
129 void* memory_;
130 int size_;
131};
132
133
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +0000134OS::MemoryMappedFile* OS::MemoryMappedFile::open(const char* name) {
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +0000135 FILE* file = fopen(name, "r+");
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +0000136 if (file == NULL) return NULL;
137
138 fseek(file, 0, SEEK_END);
139 int size = ftell(file);
140
141 void* memory =
142 mmap(0, size, PROT_READ | PROT_WRITE, MAP_SHARED, fileno(file), 0);
143 return new PosixMemoryMappedFile(file, memory, size);
144}
145
146
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000147OS::MemoryMappedFile* OS::MemoryMappedFile::create(const char* name, int size,
148 void* initial) {
149 FILE* file = fopen(name, "w+");
150 if (file == NULL) return NULL;
151 int result = fwrite(initial, size, 1, file);
152 if (result < 1) {
153 fclose(file);
154 return NULL;
155 }
156 void* memory =
157 mmap(0, size, PROT_READ | PROT_WRITE, MAP_SHARED, fileno(file), 0);
158 return new PosixMemoryMappedFile(file, memory, size);
159}
160
161
162PosixMemoryMappedFile::~PosixMemoryMappedFile() {
163 if (memory_) munmap(memory_, size_);
164 fclose(file_);
165}
166
167
168void OS::LogSharedLibraryAddresses() {
169}
170
171
whesse@chromium.org4a5224e2010-10-20 12:37:07 +0000172void OS::SignalCodeMovingGC() {
173}
174
175
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000176struct StackWalker {
177 Vector<OS::StackFrame>& frames;
178 int index;
179};
180
181
182static int StackWalkCallback(uintptr_t pc, int signo, void* data) {
183 struct StackWalker* walker = static_cast<struct StackWalker*>(data);
184 Dl_info info;
185
186 int i = walker->index;
187
188 walker->frames[i].address = reinterpret_cast<void*>(pc);
189
190 // Make sure line termination is in place.
191 walker->frames[i].text[OS::kStackWalkMaxTextLen - 1] = '\0';
192
193 Vector<char> text = MutableCStrVector(walker->frames[i].text,
194 OS::kStackWalkMaxTextLen);
195
196 if (dladdr(reinterpret_cast<void*>(pc), &info) == 0) {
197 OS::SNPrintF(text, "[0x%p]", pc);
198 } else if ((info.dli_fname != NULL && info.dli_sname != NULL)) {
199 // We have symbol info.
200 OS::SNPrintF(text, "%s'%s+0x%x", info.dli_fname, info.dli_sname, pc);
201 } else {
202 // No local symbol info.
203 OS::SNPrintF(text,
204 "%s'0x%p [0x%p]",
205 info.dli_fname,
206 pc - reinterpret_cast<uintptr_t>(info.dli_fbase),
207 pc);
208 }
209 walker->index++;
210 return 0;
211}
212
213
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000214int OS::StackWalk(Vector<OS::StackFrame> frames) {
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000215 ucontext_t ctx;
216 struct StackWalker walker = { frames, 0 };
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000217
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000218 if (getcontext(&ctx) < 0) return kStackWalkError;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000219
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000220 if (!walkcontext(&ctx, StackWalkCallback, &walker)) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000221 return kStackWalkError;
222 }
223
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000224 return walker.index;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000225}
226
227
228// Constants used for mmap.
229static const int kMmapFd = -1;
230static const int kMmapFdOffset = 0;
231
232
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +0000233VirtualMemory::VirtualMemory() : address_(NULL), size_(0) { }
234
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000235
236VirtualMemory::VirtualMemory(size_t size)
237 : address_(ReserveRegion(size)), size_(size) { }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000238
239
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +0000240VirtualMemory::VirtualMemory(size_t size, size_t alignment)
241 : address_(NULL), size_(0) {
242 ASSERT(IsAligned(alignment, static_cast<intptr_t>(OS::AllocateAlignment())));
243 size_t request_size = RoundUp(size + alignment,
244 static_cast<intptr_t>(OS::AllocateAlignment()));
245 void* reservation = mmap(OS::GetRandomMmapAddr(),
246 request_size,
247 PROT_NONE,
248 MAP_PRIVATE | MAP_ANONYMOUS | MAP_NORESERVE,
249 kMmapFd,
250 kMmapFdOffset);
251 if (reservation == MAP_FAILED) return;
252
253 Address base = static_cast<Address>(reservation);
254 Address aligned_base = RoundUp(base, alignment);
255 ASSERT_LE(base, aligned_base);
256
257 // Unmap extra memory reserved before and after the desired block.
258 if (aligned_base != base) {
259 size_t prefix_size = static_cast<size_t>(aligned_base - base);
260 OS::Free(base, prefix_size);
261 request_size -= prefix_size;
262 }
263
264 size_t aligned_size = RoundUp(size, OS::AllocateAlignment());
265 ASSERT_LE(aligned_size, request_size);
266
267 if (aligned_size != request_size) {
268 size_t suffix_size = request_size - aligned_size;
269 OS::Free(aligned_base + aligned_size, suffix_size);
270 request_size -= suffix_size;
271 }
272
273 ASSERT(aligned_size == request_size);
274
275 address_ = static_cast<void*>(aligned_base);
276 size_ = aligned_size;
277}
278
279
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000280VirtualMemory::~VirtualMemory() {
281 if (IsReserved()) {
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +0000282 bool result = ReleaseRegion(address(), size());
283 ASSERT(result);
284 USE(result);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000285 }
286}
287
288
289bool VirtualMemory::IsReserved() {
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +0000290 return address_ != NULL;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000291}
292
293
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +0000294void VirtualMemory::Reset() {
295 address_ = NULL;
296 size_ = 0;
297}
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000298
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +0000299
300bool VirtualMemory::Commit(void* address, size_t size, bool is_executable) {
301 return CommitRegion(address, size, is_executable);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000302}
303
304
305bool VirtualMemory::Uncommit(void* address, size_t size) {
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +0000306 return UncommitRegion(address, size);
307}
308
309
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +0000310bool VirtualMemory::Guard(void* address) {
311 OS::Guard(address, OS::CommitPageSize());
312 return true;
313}
314
315
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +0000316void* VirtualMemory::ReserveRegion(size_t size) {
317 void* result = mmap(OS::GetRandomMmapAddr(),
318 size,
319 PROT_NONE,
320 MAP_PRIVATE | MAP_ANONYMOUS | MAP_NORESERVE,
321 kMmapFd,
322 kMmapFdOffset);
323
324 if (result == MAP_FAILED) return NULL;
325
326 return result;
327}
328
329
330bool VirtualMemory::CommitRegion(void* base, size_t size, bool is_executable) {
331 int prot = PROT_READ | PROT_WRITE | (is_executable ? PROT_EXEC : 0);
332 if (MAP_FAILED == mmap(base,
333 size,
334 prot,
335 MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED,
336 kMmapFd,
337 kMmapFdOffset)) {
338 return false;
339 }
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +0000340 return true;
341}
342
343
344bool VirtualMemory::UncommitRegion(void* base, size_t size) {
345 return mmap(base,
346 size,
347 PROT_NONE,
348 MAP_PRIVATE | MAP_ANONYMOUS | MAP_NORESERVE | MAP_FIXED,
349 kMmapFd,
350 kMmapFdOffset) != MAP_FAILED;
351}
352
353
354bool VirtualMemory::ReleaseRegion(void* base, size_t size) {
355 return munmap(base, size) == 0;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000356}
357
358
danno@chromium.org72204d52012-10-31 10:02:10 +0000359bool VirtualMemory::HasLazyCommits() {
360 // TODO(alph): implement for the platform.
361 return false;
362}
363
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000364} } // namespace v8::internal