1// Copyright 2012 the V8 project authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5// Platform-specific code for Solaris 10 goes here. For the POSIX-compatible
6// parts, the implementation is in platform-posix.cc.
7
8#ifdef __sparc
9# error "V8 does not support the SPARC CPU architecture."
10#endif
11
12#include <dlfcn.h>  // dladdr
13#include <errno.h>
14#include <ieeefp.h>  // finite()
15#include <pthread.h>
16#include <semaphore.h>
17#include <signal.h>  // sigemptyset(), etc
18#include <sys/mman.h>  // mmap()
19#include <sys/regset.h>
20#include <sys/stack.h>  // for stack alignment
21#include <sys/time.h>  // gettimeofday(), timeradd()
22#include <time.h>
23#include <ucontext.h>  // walkstack(), getcontext()
24#include <unistd.h>  // getpagesize(), usleep()
25
26#include <cmath>
27
28#undef MAP_TYPE
29
30#include "src/base/macros.h"
31#include "src/base/platform/platform.h"
32
33
34// It seems there is a bug in some Solaris distributions (experienced in
35// SunOS 5.10 Generic_141445-09) which make it difficult or impossible to
36// access signbit() despite the availability of other C99 math functions.
37#ifndef signbit
38namespace std {
39// Test sign - usually defined in math.h
40int signbit(double x) {
41  // We need to take care of the special case of both positive and negative
42  // versions of zero.
43  if (x == 0) {
44    return fpclass(x) & FP_NZERO;
45  } else {
46    // This won't detect negative NaN but that should be okay since we don't
47    // assume that behavior.
48    return x < 0;
49  }
50}
51}  // namespace std
52#endif  // signbit
53
54namespace v8 {
55namespace base {
56
57
58const char* OS::LocalTimezone(double time, TimezoneCache* cache) {
59  if (std::isnan(time)) return "";
60  time_t tv = static_cast<time_t>(std::floor(time/msPerSecond));
61  struct tm* t = localtime(&tv);
62  if (NULL == t) return "";
63  return tzname[0];  // The location of the timezone string on Solaris.
64}
65
66
67double OS::LocalTimeOffset(TimezoneCache* cache) {
68  tzset();
69  return -static_cast<double>(timezone * msPerSecond);
70}
71
72
73void* OS::Allocate(const size_t requested,
74                   size_t* allocated,
75                   bool is_executable) {
76  const size_t msize = RoundUp(requested, getpagesize());
77  int prot = PROT_READ | PROT_WRITE | (is_executable ? PROT_EXEC : 0);
78  void* mbase = mmap(NULL, msize, prot, MAP_PRIVATE | MAP_ANON, -1, 0);
79
80  if (mbase == MAP_FAILED) return NULL;
81  *allocated = msize;
82  return mbase;
83}
84
85
86class PosixMemoryMappedFile : public OS::MemoryMappedFile {
87 public:
88  PosixMemoryMappedFile(FILE* file, void* memory, int size)
89    : file_(file), memory_(memory), size_(size) { }
90  virtual ~PosixMemoryMappedFile();
91  virtual void* memory() { return memory_; }
92  virtual int size() { return size_; }
93 private:
94  FILE* file_;
95  void* memory_;
96  int size_;
97};
98
99
100OS::MemoryMappedFile* OS::MemoryMappedFile::open(const char* name) {
101  FILE* file = fopen(name, "r+");
102  if (file == NULL) return NULL;
103
104  fseek(file, 0, SEEK_END);
105  int size = ftell(file);
106
107  void* memory =
108      mmap(0, size, PROT_READ | PROT_WRITE, MAP_SHARED, fileno(file), 0);
109  return new PosixMemoryMappedFile(file, memory, size);
110}
111
112
113OS::MemoryMappedFile* OS::MemoryMappedFile::create(const char* name, int size,
114    void* initial) {
115  FILE* file = fopen(name, "w+");
116  if (file == NULL) return NULL;
117  int result = fwrite(initial, size, 1, file);
118  if (result < 1) {
119    fclose(file);
120    return NULL;
121  }
122  void* memory =
123      mmap(0, size, PROT_READ | PROT_WRITE, MAP_SHARED, fileno(file), 0);
124  return new PosixMemoryMappedFile(file, memory, size);
125}
126
127
128PosixMemoryMappedFile::~PosixMemoryMappedFile() {
129  if (memory_) munmap(memory_, size_);
130  fclose(file_);
131}
132
133
134std::vector<OS::SharedLibraryAddress> OS::GetSharedLibraryAddresses() {
135  return std::vector<SharedLibraryAddress>();
136}
137
138
139void OS::SignalCodeMovingGC() {
140}
141
142
143// Constants used for mmap.
144static const int kMmapFd = -1;
145static const int kMmapFdOffset = 0;
146
147
148VirtualMemory::VirtualMemory() : address_(NULL), size_(0) { }
149
150
151VirtualMemory::VirtualMemory(size_t size)
152    : address_(ReserveRegion(size)), size_(size) { }
153
154
155VirtualMemory::VirtualMemory(size_t size, size_t alignment)
156    : address_(NULL), size_(0) {
157  DCHECK((alignment % OS::AllocateAlignment()) == 0);
158  size_t request_size = RoundUp(size + alignment,
159                                static_cast<intptr_t>(OS::AllocateAlignment()));
160  void* reservation = mmap(OS::GetRandomMmapAddr(),
161                           request_size,
162                           PROT_NONE,
163                           MAP_PRIVATE | MAP_ANONYMOUS | MAP_NORESERVE,
164                           kMmapFd,
165                           kMmapFdOffset);
166  if (reservation == MAP_FAILED) return;
167
168  uint8_t* base = static_cast<uint8_t*>(reservation);
169  uint8_t* aligned_base = RoundUp(base, alignment);
170  DCHECK_LE(base, aligned_base);
171
172  // Unmap extra memory reserved before and after the desired block.
173  if (aligned_base != base) {
174    size_t prefix_size = static_cast<size_t>(aligned_base - base);
175    OS::Free(base, prefix_size);
176    request_size -= prefix_size;
177  }
178
179  size_t aligned_size = RoundUp(size, OS::AllocateAlignment());
180  DCHECK_LE(aligned_size, request_size);
181
182  if (aligned_size != request_size) {
183    size_t suffix_size = request_size - aligned_size;
184    OS::Free(aligned_base + aligned_size, suffix_size);
185    request_size -= suffix_size;
186  }
187
188  DCHECK(aligned_size == request_size);
189
190  address_ = static_cast<void*>(aligned_base);
191  size_ = aligned_size;
192}
193
194
195VirtualMemory::~VirtualMemory() {
196  if (IsReserved()) {
197    bool result = ReleaseRegion(address(), size());
198    DCHECK(result);
199    USE(result);
200  }
201}
202
203
204bool VirtualMemory::IsReserved() {
205  return address_ != NULL;
206}
207
208
209void VirtualMemory::Reset() {
210  address_ = NULL;
211  size_ = 0;
212}
213
214
215bool VirtualMemory::Commit(void* address, size_t size, bool is_executable) {
216  return CommitRegion(address, size, is_executable);
217}
218
219
220bool VirtualMemory::Uncommit(void* address, size_t size) {
221  return UncommitRegion(address, size);
222}
223
224
225bool VirtualMemory::Guard(void* address) {
226  OS::Guard(address, OS::CommitPageSize());
227  return true;
228}
229
230
231void* VirtualMemory::ReserveRegion(size_t size) {
232  void* result = mmap(OS::GetRandomMmapAddr(),
233                      size,
234                      PROT_NONE,
235                      MAP_PRIVATE | MAP_ANONYMOUS | MAP_NORESERVE,
236                      kMmapFd,
237                      kMmapFdOffset);
238
239  if (result == MAP_FAILED) return NULL;
240
241  return result;
242}
243
244
245bool VirtualMemory::CommitRegion(void* base, size_t size, bool is_executable) {
246  int prot = PROT_READ | PROT_WRITE | (is_executable ? PROT_EXEC : 0);
247  if (MAP_FAILED == mmap(base,
248                         size,
249                         prot,
250                         MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED,
251                         kMmapFd,
252                         kMmapFdOffset)) {
253    return false;
254  }
255  return true;
256}
257
258
259bool VirtualMemory::UncommitRegion(void* base, size_t size) {
260  return mmap(base,
261              size,
262              PROT_NONE,
263              MAP_PRIVATE | MAP_ANONYMOUS | MAP_NORESERVE | MAP_FIXED,
264              kMmapFd,
265              kMmapFdOffset) != MAP_FAILED;
266}
267
268
269bool VirtualMemory::ReleaseRegion(void* base, size_t size) {
270  return munmap(base, size) == 0;
271}
272
273
274bool VirtualMemory::HasLazyCommits() {
275  // TODO(alph): implement for the platform.
276  return false;
277}
278
279} }  // namespace v8::base
280