blob: a0590cbecb89ed78507ac8c81c3099a32868c11e [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
54#include "platform.h"
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +000055#include "v8threads.h"
kasperl@chromium.orga5551262010-12-07 12:49:48 +000056#include "vm-state-inl.h"
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000057
58
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +000059// It seems there is a bug in some Solaris distributions (experienced in
60// SunOS 5.10 Generic_141445-09) which make it difficult or impossible to
61// access signbit() despite the availability of other C99 math functions.
62#ifndef signbit
ulan@chromium.org77ca49a2013-04-22 09:43:56 +000063namespace std {
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +000064// Test sign - usually defined in math.h
65int signbit(double x) {
66 // We need to take care of the special case of both positive and negative
67 // versions of zero.
68 if (x == 0) {
69 return fpclass(x) & FP_NZERO;
70 } else {
71 // This won't detect negative NaN but that should be okay since we don't
72 // assume that behavior.
73 return x < 0;
74 }
75}
ulan@chromium.org77ca49a2013-04-22 09:43:56 +000076} // namespace std
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +000077#endif // signbit
78
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000079namespace v8 {
80namespace internal {
81
82
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000083const char* OS::LocalTimezone(double time) {
ulan@chromium.org77ca49a2013-04-22 09:43:56 +000084 if (std::isnan(time)) return "";
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000085 time_t tv = static_cast<time_t>(floor(time/msPerSecond));
86 struct tm* t = localtime(&tv);
87 if (NULL == t) return "";
88 return tzname[0]; // The location of the timezone string on Solaris.
89}
90
91
92double OS::LocalTimeOffset() {
danno@chromium.org72204d52012-10-31 10:02:10 +000093 tzset();
94 return -static_cast<double>(timezone * msPerSecond);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000095}
96
97
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000098void* OS::Allocate(const size_t requested,
99 size_t* allocated,
100 bool is_executable) {
101 const size_t msize = RoundUp(requested, getpagesize());
102 int prot = PROT_READ | PROT_WRITE | (is_executable ? PROT_EXEC : 0);
103 void* mbase = mmap(NULL, msize, prot, MAP_PRIVATE | MAP_ANON, -1, 0);
104
105 if (mbase == MAP_FAILED) {
hpayer@chromium.orgc5d49712013-09-11 08:25:48 +0000106 LOG(Isolate::Current(), StringEvent("OS::Allocate", "mmap failed"));
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000107 return NULL;
108 }
109 *allocated = msize;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000110 return mbase;
111}
112
113
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000114class PosixMemoryMappedFile : public OS::MemoryMappedFile {
115 public:
116 PosixMemoryMappedFile(FILE* file, void* memory, int size)
117 : file_(file), memory_(memory), size_(size) { }
118 virtual ~PosixMemoryMappedFile();
119 virtual void* memory() { return memory_; }
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +0000120 virtual int size() { return size_; }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000121 private:
122 FILE* file_;
123 void* memory_;
124 int size_;
125};
126
127
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +0000128OS::MemoryMappedFile* OS::MemoryMappedFile::open(const char* name) {
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +0000129 FILE* file = fopen(name, "r+");
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +0000130 if (file == NULL) return NULL;
131
132 fseek(file, 0, SEEK_END);
133 int size = ftell(file);
134
135 void* memory =
136 mmap(0, size, PROT_READ | PROT_WRITE, MAP_SHARED, fileno(file), 0);
137 return new PosixMemoryMappedFile(file, memory, size);
138}
139
140
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000141OS::MemoryMappedFile* OS::MemoryMappedFile::create(const char* name, int size,
142 void* initial) {
143 FILE* file = fopen(name, "w+");
144 if (file == NULL) return NULL;
145 int result = fwrite(initial, size, 1, file);
146 if (result < 1) {
147 fclose(file);
148 return NULL;
149 }
150 void* memory =
151 mmap(0, size, PROT_READ | PROT_WRITE, MAP_SHARED, fileno(file), 0);
152 return new PosixMemoryMappedFile(file, memory, size);
153}
154
155
156PosixMemoryMappedFile::~PosixMemoryMappedFile() {
157 if (memory_) munmap(memory_, size_);
158 fclose(file_);
159}
160
161
dslomov@chromium.orge97852d2013-09-12 09:02:59 +0000162void OS::LogSharedLibraryAddresses(Isolate* isolate) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000163}
164
165
whesse@chromium.org4a5224e2010-10-20 12:37:07 +0000166void OS::SignalCodeMovingGC() {
167}
168
169
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000170struct StackWalker {
171 Vector<OS::StackFrame>& frames;
172 int index;
173};
174
175
176static int StackWalkCallback(uintptr_t pc, int signo, void* data) {
177 struct StackWalker* walker = static_cast<struct StackWalker*>(data);
178 Dl_info info;
179
180 int i = walker->index;
181
182 walker->frames[i].address = reinterpret_cast<void*>(pc);
183
184 // Make sure line termination is in place.
185 walker->frames[i].text[OS::kStackWalkMaxTextLen - 1] = '\0';
186
187 Vector<char> text = MutableCStrVector(walker->frames[i].text,
188 OS::kStackWalkMaxTextLen);
189
190 if (dladdr(reinterpret_cast<void*>(pc), &info) == 0) {
191 OS::SNPrintF(text, "[0x%p]", pc);
192 } else if ((info.dli_fname != NULL && info.dli_sname != NULL)) {
193 // We have symbol info.
194 OS::SNPrintF(text, "%s'%s+0x%x", info.dli_fname, info.dli_sname, pc);
195 } else {
196 // No local symbol info.
197 OS::SNPrintF(text,
198 "%s'0x%p [0x%p]",
199 info.dli_fname,
200 pc - reinterpret_cast<uintptr_t>(info.dli_fbase),
201 pc);
202 }
203 walker->index++;
204 return 0;
205}
206
207
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000208// Constants used for mmap.
209static const int kMmapFd = -1;
210static const int kMmapFdOffset = 0;
211
212
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +0000213VirtualMemory::VirtualMemory() : address_(NULL), size_(0) { }
214
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000215
216VirtualMemory::VirtualMemory(size_t size)
217 : address_(ReserveRegion(size)), size_(size) { }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000218
219
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +0000220VirtualMemory::VirtualMemory(size_t size, size_t alignment)
221 : address_(NULL), size_(0) {
222 ASSERT(IsAligned(alignment, static_cast<intptr_t>(OS::AllocateAlignment())));
223 size_t request_size = RoundUp(size + alignment,
224 static_cast<intptr_t>(OS::AllocateAlignment()));
225 void* reservation = mmap(OS::GetRandomMmapAddr(),
226 request_size,
227 PROT_NONE,
228 MAP_PRIVATE | MAP_ANONYMOUS | MAP_NORESERVE,
229 kMmapFd,
230 kMmapFdOffset);
231 if (reservation == MAP_FAILED) return;
232
233 Address base = static_cast<Address>(reservation);
234 Address aligned_base = RoundUp(base, alignment);
235 ASSERT_LE(base, aligned_base);
236
237 // Unmap extra memory reserved before and after the desired block.
238 if (aligned_base != base) {
239 size_t prefix_size = static_cast<size_t>(aligned_base - base);
240 OS::Free(base, prefix_size);
241 request_size -= prefix_size;
242 }
243
244 size_t aligned_size = RoundUp(size, OS::AllocateAlignment());
245 ASSERT_LE(aligned_size, request_size);
246
247 if (aligned_size != request_size) {
248 size_t suffix_size = request_size - aligned_size;
249 OS::Free(aligned_base + aligned_size, suffix_size);
250 request_size -= suffix_size;
251 }
252
253 ASSERT(aligned_size == request_size);
254
255 address_ = static_cast<void*>(aligned_base);
256 size_ = aligned_size;
257}
258
259
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000260VirtualMemory::~VirtualMemory() {
261 if (IsReserved()) {
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +0000262 bool result = ReleaseRegion(address(), size());
263 ASSERT(result);
264 USE(result);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000265 }
266}
267
268
269bool VirtualMemory::IsReserved() {
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +0000270 return address_ != NULL;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000271}
272
273
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +0000274void VirtualMemory::Reset() {
275 address_ = NULL;
276 size_ = 0;
277}
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000278
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +0000279
280bool VirtualMemory::Commit(void* address, size_t size, bool is_executable) {
281 return CommitRegion(address, size, is_executable);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000282}
283
284
285bool VirtualMemory::Uncommit(void* address, size_t size) {
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +0000286 return UncommitRegion(address, size);
287}
288
289
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +0000290bool VirtualMemory::Guard(void* address) {
291 OS::Guard(address, OS::CommitPageSize());
292 return true;
293}
294
295
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +0000296void* VirtualMemory::ReserveRegion(size_t size) {
297 void* result = mmap(OS::GetRandomMmapAddr(),
298 size,
299 PROT_NONE,
300 MAP_PRIVATE | MAP_ANONYMOUS | MAP_NORESERVE,
301 kMmapFd,
302 kMmapFdOffset);
303
304 if (result == MAP_FAILED) return NULL;
305
306 return result;
307}
308
309
310bool VirtualMemory::CommitRegion(void* base, size_t size, bool is_executable) {
311 int prot = PROT_READ | PROT_WRITE | (is_executable ? PROT_EXEC : 0);
312 if (MAP_FAILED == mmap(base,
313 size,
314 prot,
315 MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED,
316 kMmapFd,
317 kMmapFdOffset)) {
318 return false;
319 }
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +0000320 return true;
321}
322
323
324bool VirtualMemory::UncommitRegion(void* base, size_t size) {
325 return mmap(base,
326 size,
327 PROT_NONE,
328 MAP_PRIVATE | MAP_ANONYMOUS | MAP_NORESERVE | MAP_FIXED,
329 kMmapFd,
330 kMmapFdOffset) != MAP_FAILED;
331}
332
333
334bool VirtualMemory::ReleaseRegion(void* base, size_t size) {
335 return munmap(base, size) == 0;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000336}
337
338
danno@chromium.org72204d52012-10-31 10:02:10 +0000339bool VirtualMemory::HasLazyCommits() {
340 // TODO(alph): implement for the platform.
341 return false;
342}
343
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000344} } // namespace v8::internal