Upstream version 7.36.149.0
[platform/framework/web/crosswalk.git] / src / v8 / src / platform-qnx.cc
1 // Copyright 2013 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 QNX goes here. For the POSIX-compatible
6 // parts the implementation is in platform-posix.cc.
7
8 #include <pthread.h>
9 #include <semaphore.h>
10 #include <signal.h>
11 #include <sys/time.h>
12 #include <sys/resource.h>
13 #include <sys/types.h>
14 #include <stdlib.h>
15 #include <ucontext.h>
16 #include <backtrace.h>
17
18 // QNX requires memory pages to be marked as executable.
19 // Otherwise, the OS raises an exception when executing code in that page.
20 #include <sys/types.h>  // mmap & munmap
21 #include <sys/mman.h>   // mmap & munmap
22 #include <sys/stat.h>   // open
23 #include <fcntl.h>      // open
24 #include <unistd.h>     // sysconf
25 #include <strings.h>    // index
26 #include <errno.h>
27 #include <stdarg.h>
28 #include <sys/procfs.h>
29
30 #undef MAP_TYPE
31
32 #include "v8.h"
33
34 #include "platform.h"
35 #include "v8threads.h"
36
37
38 namespace v8 {
39 namespace internal {
40
41 // 0 is never a valid thread id on Qnx since tids and pids share a
42 // name space and pid 0 is reserved (see man 2 kill).
43 static const pthread_t kNoThread = (pthread_t) 0;
44
45
46 #ifdef __arm__
47
48 bool OS::ArmUsingHardFloat() {
49   // GCC versions 4.6 and above define __ARM_PCS or __ARM_PCS_VFP to specify
50   // the Floating Point ABI used (PCS stands for Procedure Call Standard).
51   // We use these as well as a couple of other defines to statically determine
52   // what FP ABI used.
53   // GCC versions 4.4 and below don't support hard-fp.
54   // GCC versions 4.5 may support hard-fp without defining __ARM_PCS or
55   // __ARM_PCS_VFP.
56
57 #define GCC_VERSION (__GNUC__ * 10000                                          \
58                      + __GNUC_MINOR__ * 100                                    \
59                      + __GNUC_PATCHLEVEL__)
60 #if GCC_VERSION >= 40600
61 #if defined(__ARM_PCS_VFP)
62   return true;
63 #else
64   return false;
65 #endif
66
67 #elif GCC_VERSION < 40500
68   return false;
69
70 #else
71 #if defined(__ARM_PCS_VFP)
72   return true;
73 #elif defined(__ARM_PCS) || defined(__SOFTFP__) || defined(__SOFTFP) || \
74       !defined(__VFP_FP__)
75   return false;
76 #else
77 #error "Your version of GCC does not report the FP ABI compiled for."          \
78        "Please report it on this issue"                                        \
79        "http://code.google.com/p/v8/issues/detail?id=2140"
80
81 #endif
82 #endif
83 #undef GCC_VERSION
84 }
85
86 #endif  // __arm__
87
88
89 const char* OS::LocalTimezone(double time, TimezoneCache* cache) {
90   if (std::isnan(time)) return "";
91   time_t tv = static_cast<time_t>(std::floor(time/msPerSecond));
92   struct tm* t = localtime(&tv);
93   if (NULL == t) return "";
94   return t->tm_zone;
95 }
96
97
98 double OS::LocalTimeOffset(TimezoneCache* cache) {
99   time_t tv = time(NULL);
100   struct tm* t = localtime(&tv);
101   // tm_gmtoff includes any daylight savings offset, so subtract it.
102   return static_cast<double>(t->tm_gmtoff * msPerSecond -
103                              (t->tm_isdst > 0 ? 3600 * msPerSecond : 0));
104 }
105
106
107 void* OS::Allocate(const size_t requested,
108                    size_t* allocated,
109                    bool is_executable) {
110   const size_t msize = RoundUp(requested, AllocateAlignment());
111   int prot = PROT_READ | PROT_WRITE | (is_executable ? PROT_EXEC : 0);
112   void* addr = OS::GetRandomMmapAddr();
113   void* mbase = mmap(addr, msize, prot, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
114   if (mbase == MAP_FAILED) {
115     LOG(i::Isolate::Current(),
116         StringEvent("OS::Allocate", "mmap failed"));
117     return NULL;
118   }
119   *allocated = msize;
120   return mbase;
121 }
122
123
124 class PosixMemoryMappedFile : public OS::MemoryMappedFile {
125  public:
126   PosixMemoryMappedFile(FILE* file, void* memory, int size)
127     : file_(file), memory_(memory), size_(size) { }
128   virtual ~PosixMemoryMappedFile();
129   virtual void* memory() { return memory_; }
130   virtual int size() { return size_; }
131  private:
132   FILE* file_;
133   void* memory_;
134   int size_;
135 };
136
137
138 OS::MemoryMappedFile* OS::MemoryMappedFile::open(const char* name) {
139   FILE* file = fopen(name, "r+");
140   if (file == NULL) return NULL;
141
142   fseek(file, 0, SEEK_END);
143   int size = ftell(file);
144
145   void* memory =
146       mmap(OS::GetRandomMmapAddr(),
147            size,
148            PROT_READ | PROT_WRITE,
149            MAP_SHARED,
150            fileno(file),
151            0);
152   return new PosixMemoryMappedFile(file, memory, size);
153 }
154
155
156 OS::MemoryMappedFile* OS::MemoryMappedFile::create(const char* name, int size,
157     void* initial) {
158   FILE* file = fopen(name, "w+");
159   if (file == NULL) return NULL;
160   int result = fwrite(initial, size, 1, file);
161   if (result < 1) {
162     fclose(file);
163     return NULL;
164   }
165   void* memory =
166       mmap(OS::GetRandomMmapAddr(),
167            size,
168            PROT_READ | PROT_WRITE,
169            MAP_SHARED,
170            fileno(file),
171            0);
172   return new PosixMemoryMappedFile(file, memory, size);
173 }
174
175
176 PosixMemoryMappedFile::~PosixMemoryMappedFile() {
177   if (memory_) OS::Free(memory_, size_);
178   fclose(file_);
179 }
180
181
182 void OS::LogSharedLibraryAddresses(Isolate* isolate) {
183   procfs_mapinfo *mapinfos = NULL, *mapinfo;
184   int proc_fd, num, i;
185
186   struct {
187     procfs_debuginfo info;
188     char buff[PATH_MAX];
189   } map;
190
191   char buf[PATH_MAX + 1];
192   snprintf(buf, PATH_MAX + 1, "/proc/%d/as", getpid());
193
194   if ((proc_fd = open(buf, O_RDONLY)) == -1) {
195     close(proc_fd);
196     return;
197   }
198
199   /* Get the number of map entries.  */
200   if (devctl(proc_fd, DCMD_PROC_MAPINFO, NULL, 0, &num) != EOK) {
201     close(proc_fd);
202     return;
203   }
204
205   mapinfos = reinterpret_cast<procfs_mapinfo *>(
206       malloc(num * sizeof(procfs_mapinfo)));
207   if (mapinfos == NULL) {
208     close(proc_fd);
209     return;
210   }
211
212   /* Fill the map entries.  */
213   if (devctl(proc_fd, DCMD_PROC_PAGEDATA,
214       mapinfos, num * sizeof(procfs_mapinfo), &num) != EOK) {
215     free(mapinfos);
216     close(proc_fd);
217     return;
218   }
219
220   for (i = 0; i < num; i++) {
221     mapinfo = mapinfos + i;
222     if (mapinfo->flags & MAP_ELF) {
223       map.info.vaddr = mapinfo->vaddr;
224       if (devctl(proc_fd, DCMD_PROC_MAPDEBUG, &map, sizeof(map), 0) != EOK) {
225         continue;
226       }
227       LOG(isolate, SharedLibraryEvent(map.info.path,
228                                       mapinfo->vaddr,
229                                       mapinfo->vaddr + mapinfo->size));
230     }
231   }
232   free(mapinfos);
233   close(proc_fd);
234 }
235
236
237 void OS::SignalCodeMovingGC() {
238 }
239
240
241 // Constants used for mmap.
242 static const int kMmapFd = -1;
243 static const int kMmapFdOffset = 0;
244
245
246 VirtualMemory::VirtualMemory() : address_(NULL), size_(0) { }
247
248
249 VirtualMemory::VirtualMemory(size_t size)
250     : address_(ReserveRegion(size)), size_(size) { }
251
252
253 VirtualMemory::VirtualMemory(size_t size, size_t alignment)
254     : address_(NULL), size_(0) {
255   ASSERT(IsAligned(alignment, static_cast<intptr_t>(OS::AllocateAlignment())));
256   size_t request_size = RoundUp(size + alignment,
257                                 static_cast<intptr_t>(OS::AllocateAlignment()));
258   void* reservation = mmap(OS::GetRandomMmapAddr(),
259                            request_size,
260                            PROT_NONE,
261                            MAP_PRIVATE | MAP_ANONYMOUS | MAP_LAZY,
262                            kMmapFd,
263                            kMmapFdOffset);
264   if (reservation == MAP_FAILED) return;
265
266   Address base = static_cast<Address>(reservation);
267   Address aligned_base = RoundUp(base, alignment);
268   ASSERT_LE(base, aligned_base);
269
270   // Unmap extra memory reserved before and after the desired block.
271   if (aligned_base != base) {
272     size_t prefix_size = static_cast<size_t>(aligned_base - base);
273     OS::Free(base, prefix_size);
274     request_size -= prefix_size;
275   }
276
277   size_t aligned_size = RoundUp(size, OS::AllocateAlignment());
278   ASSERT_LE(aligned_size, request_size);
279
280   if (aligned_size != request_size) {
281     size_t suffix_size = request_size - aligned_size;
282     OS::Free(aligned_base + aligned_size, suffix_size);
283     request_size -= suffix_size;
284   }
285
286   ASSERT(aligned_size == request_size);
287
288   address_ = static_cast<void*>(aligned_base);
289   size_ = aligned_size;
290 }
291
292
293 VirtualMemory::~VirtualMemory() {
294   if (IsReserved()) {
295     bool result = ReleaseRegion(address(), size());
296     ASSERT(result);
297     USE(result);
298   }
299 }
300
301
302 bool VirtualMemory::IsReserved() {
303   return address_ != NULL;
304 }
305
306
307 void VirtualMemory::Reset() {
308   address_ = NULL;
309   size_ = 0;
310 }
311
312
313 bool VirtualMemory::Commit(void* address, size_t size, bool is_executable) {
314   return CommitRegion(address, size, is_executable);
315 }
316
317
318 bool VirtualMemory::Uncommit(void* address, size_t size) {
319   return UncommitRegion(address, size);
320 }
321
322
323 bool VirtualMemory::Guard(void* address) {
324   OS::Guard(address, OS::CommitPageSize());
325   return true;
326 }
327
328
329 void* VirtualMemory::ReserveRegion(size_t size) {
330   void* result = mmap(OS::GetRandomMmapAddr(),
331                       size,
332                       PROT_NONE,
333                       MAP_PRIVATE | MAP_ANONYMOUS | MAP_LAZY,
334                       kMmapFd,
335                       kMmapFdOffset);
336
337   if (result == MAP_FAILED) return NULL;
338
339   return result;
340 }
341
342
343 bool VirtualMemory::CommitRegion(void* base, size_t size, bool is_executable) {
344   int prot = PROT_READ | PROT_WRITE | (is_executable ? PROT_EXEC : 0);
345   if (MAP_FAILED == mmap(base,
346                          size,
347                          prot,
348                          MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED,
349                          kMmapFd,
350                          kMmapFdOffset)) {
351     return false;
352   }
353
354   return true;
355 }
356
357
358 bool VirtualMemory::UncommitRegion(void* base, size_t size) {
359   return mmap(base,
360               size,
361               PROT_NONE,
362               MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED | MAP_LAZY,
363               kMmapFd,
364               kMmapFdOffset) != MAP_FAILED;
365 }
366
367
368 bool VirtualMemory::ReleaseRegion(void* base, size_t size) {
369   return munmap(base, size) == 0;
370 }
371
372
373 bool VirtualMemory::HasLazyCommits() {
374   return false;
375 }
376
377 } }  // namespace v8::internal