Home | History | Annotate | Download | only in src
      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 <sys/stack.h>  // for stack alignment
     13 #include <unistd.h>  // getpagesize(), usleep()
     14 #include <sys/mman.h>  // mmap()
     15 #include <ucontext.h>  // walkstack(), getcontext()
     16 #include <dlfcn.h>     // dladdr
     17 #include <pthread.h>
     18 #include <semaphore.h>
     19 #include <time.h>
     20 #include <sys/time.h>  // gettimeofday(), timeradd()
     21 #include <errno.h>
     22 #include <ieeefp.h>  // finite()
     23 #include <signal.h>  // sigemptyset(), etc
     24 #include <sys/regset.h>
     25 
     26 
     27 #undef MAP_TYPE
     28 
     29 #include "src/v8.h"
     30 
     31 #include "src/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
     38 namespace std {
     39 // Test sign - usually defined in math.h
     40 int 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 
     54 namespace v8 {
     55 namespace internal {
     56 
     57 
     58 const 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 
     67 double OS::LocalTimeOffset(TimezoneCache* cache) {
     68   tzset();
     69   return -static_cast<double>(timezone * msPerSecond);
     70 }
     71 
     72 
     73 void* 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 
     86 class 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 
    100 OS::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 
    113 OS::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 
    128 PosixMemoryMappedFile::~PosixMemoryMappedFile() {
    129   if (memory_) munmap(memory_, size_);
    130   fclose(file_);
    131 }
    132 
    133 
    134 std::vector<OS::SharedLibraryAddress> OS::GetSharedLibraryAddresses() {
    135   return std::vector<SharedLibraryAddress>();
    136 }
    137 
    138 
    139 void OS::SignalCodeMovingGC() {
    140 }
    141 
    142 
    143 // Constants used for mmap.
    144 static const int kMmapFd = -1;
    145 static const int kMmapFdOffset = 0;
    146 
    147 
    148 VirtualMemory::VirtualMemory() : address_(NULL), size_(0) { }
    149 
    150 
    151 VirtualMemory::VirtualMemory(size_t size)
    152     : address_(ReserveRegion(size)), size_(size) { }
    153 
    154 
    155 VirtualMemory::VirtualMemory(size_t size, size_t alignment)
    156     : address_(NULL), size_(0) {
    157   ASSERT(IsAligned(alignment, static_cast<intptr_t>(OS::AllocateAlignment())));
    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   Address base = static_cast<Address>(reservation);
    169   Address aligned_base = RoundUp(base, alignment);
    170   ASSERT_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   ASSERT_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   ASSERT(aligned_size == request_size);
    189 
    190   address_ = static_cast<void*>(aligned_base);
    191   size_ = aligned_size;
    192 }
    193 
    194 
    195 VirtualMemory::~VirtualMemory() {
    196   if (IsReserved()) {
    197     bool result = ReleaseRegion(address(), size());
    198     ASSERT(result);
    199     USE(result);
    200   }
    201 }
    202 
    203 
    204 bool VirtualMemory::IsReserved() {
    205   return address_ != NULL;
    206 }
    207 
    208 
    209 void VirtualMemory::Reset() {
    210   address_ = NULL;
    211   size_ = 0;
    212 }
    213 
    214 
    215 bool VirtualMemory::Commit(void* address, size_t size, bool is_executable) {
    216   return CommitRegion(address, size, is_executable);
    217 }
    218 
    219 
    220 bool VirtualMemory::Uncommit(void* address, size_t size) {
    221   return UncommitRegion(address, size);
    222 }
    223 
    224 
    225 bool VirtualMemory::Guard(void* address) {
    226   OS::Guard(address, OS::CommitPageSize());
    227   return true;
    228 }
    229 
    230 
    231 void* 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 
    245 bool 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 
    259 bool 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 
    269 bool VirtualMemory::ReleaseRegion(void* base, size_t size) {
    270   return munmap(base, size) == 0;
    271 }
    272 
    273 
    274 bool VirtualMemory::HasLazyCommits() {
    275   // TODO(alph): implement for the platform.
    276   return false;
    277 }
    278 
    279 } }  // namespace v8::internal
    280