Home | History | Annotate | Download | only in src
      1 // Copyright 2012 the V8 project authors. All rights reserved.
      2 // 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 FreeBSD goes here. For the POSIX comaptible parts
     29 // the implementation is in platform-posix.cc.
     30 
     31 #include <pthread.h>
     32 #include <semaphore.h>
     33 #include <signal.h>
     34 #include <sys/time.h>
     35 #include <sys/resource.h>
     36 #include <sys/types.h>
     37 #include <sys/ucontext.h>
     38 #include <stdlib.h>
     39 
     40 #include <sys/types.h>  // mmap & munmap
     41 #include <sys/mman.h>   // mmap & munmap
     42 #include <sys/stat.h>   // open
     43 #include <sys/fcntl.h>  // open
     44 #include <unistd.h>     // getpagesize
     45 // If you don't have execinfo.h then you need devel/libexecinfo from ports.
     46 #include <strings.h>    // index
     47 #include <errno.h>
     48 #include <stdarg.h>
     49 #include <limits.h>
     50 
     51 #undef MAP_TYPE
     52 
     53 #include "v8.h"
     54 #include "v8threads.h"
     55 
     56 #include "platform.h"
     57 #include "vm-state-inl.h"
     58 
     59 
     60 namespace v8 {
     61 namespace internal {
     62 
     63 
     64 const char* OS::LocalTimezone(double time) {
     65   if (std::isnan(time)) return "";
     66   time_t tv = static_cast<time_t>(floor(time/msPerSecond));
     67   struct tm* t = localtime(&tv);
     68   if (NULL == t) return "";
     69   return t->tm_zone;
     70 }
     71 
     72 
     73 double OS::LocalTimeOffset() {
     74   time_t tv = time(NULL);
     75   struct tm* t = localtime(&tv);
     76   // tm_gmtoff includes any daylight savings offset, so subtract it.
     77   return static_cast<double>(t->tm_gmtoff * msPerSecond -
     78                              (t->tm_isdst > 0 ? 3600 * msPerSecond : 0));
     79 }
     80 
     81 
     82 void* OS::Allocate(const size_t requested,
     83                    size_t* allocated,
     84                    bool executable) {
     85   const size_t msize = RoundUp(requested, getpagesize());
     86   int prot = PROT_READ | PROT_WRITE | (executable ? PROT_EXEC : 0);
     87   void* mbase = mmap(NULL, msize, prot, MAP_PRIVATE | MAP_ANON, -1, 0);
     88 
     89   if (mbase == MAP_FAILED) {
     90     LOG(Isolate::Current(), StringEvent("OS::Allocate", "mmap failed"));
     91     return NULL;
     92   }
     93   *allocated = msize;
     94   return mbase;
     95 }
     96 
     97 
     98 class PosixMemoryMappedFile : public OS::MemoryMappedFile {
     99  public:
    100   PosixMemoryMappedFile(FILE* file, void* memory, int size)
    101     : file_(file), memory_(memory), size_(size) { }
    102   virtual ~PosixMemoryMappedFile();
    103   virtual void* memory() { return memory_; }
    104   virtual int size() { return size_; }
    105  private:
    106   FILE* file_;
    107   void* memory_;
    108   int size_;
    109 };
    110 
    111 
    112 OS::MemoryMappedFile* OS::MemoryMappedFile::open(const char* name) {
    113   FILE* file = fopen(name, "r+");
    114   if (file == NULL) return NULL;
    115 
    116   fseek(file, 0, SEEK_END);
    117   int size = ftell(file);
    118 
    119   void* memory =
    120       mmap(0, size, PROT_READ | PROT_WRITE, MAP_SHARED, fileno(file), 0);
    121   return new PosixMemoryMappedFile(file, memory, size);
    122 }
    123 
    124 
    125 OS::MemoryMappedFile* OS::MemoryMappedFile::create(const char* name, int size,
    126     void* initial) {
    127   FILE* file = fopen(name, "w+");
    128   if (file == NULL) return NULL;
    129   int result = fwrite(initial, size, 1, file);
    130   if (result < 1) {
    131     fclose(file);
    132     return NULL;
    133   }
    134   void* memory =
    135       mmap(0, size, PROT_READ | PROT_WRITE, MAP_SHARED, fileno(file), 0);
    136   return new PosixMemoryMappedFile(file, memory, size);
    137 }
    138 
    139 
    140 PosixMemoryMappedFile::~PosixMemoryMappedFile() {
    141   if (memory_) munmap(memory_, size_);
    142   fclose(file_);
    143 }
    144 
    145 
    146 static unsigned StringToLong(char* buffer) {
    147   return static_cast<unsigned>(strtol(buffer, NULL, 16));  // NOLINT
    148 }
    149 
    150 
    151 void OS::LogSharedLibraryAddresses(Isolate* isolate) {
    152   static const int MAP_LENGTH = 1024;
    153   int fd = open("/proc/self/maps", O_RDONLY);
    154   if (fd < 0) return;
    155   while (true) {
    156     char addr_buffer[11];
    157     addr_buffer[0] = '0';
    158     addr_buffer[1] = 'x';
    159     addr_buffer[10] = 0;
    160     int result = read(fd, addr_buffer + 2, 8);
    161     if (result < 8) break;
    162     unsigned start = StringToLong(addr_buffer);
    163     result = read(fd, addr_buffer + 2, 1);
    164     if (result < 1) break;
    165     if (addr_buffer[2] != '-') break;
    166     result = read(fd, addr_buffer + 2, 8);
    167     if (result < 8) break;
    168     unsigned end = StringToLong(addr_buffer);
    169     char buffer[MAP_LENGTH];
    170     int bytes_read = -1;
    171     do {
    172       bytes_read++;
    173       if (bytes_read >= MAP_LENGTH - 1)
    174         break;
    175       result = read(fd, buffer + bytes_read, 1);
    176       if (result < 1) break;
    177     } while (buffer[bytes_read] != '\n');
    178     buffer[bytes_read] = 0;
    179     // Ignore mappings that are not executable.
    180     if (buffer[3] != 'x') continue;
    181     char* start_of_path = index(buffer, '/');
    182     // There may be no filename in this line.  Skip to next.
    183     if (start_of_path == NULL) continue;
    184     buffer[bytes_read] = 0;
    185     LOG(isolate, SharedLibraryEvent(start_of_path, start, end));
    186   }
    187   close(fd);
    188 }
    189 
    190 
    191 void OS::SignalCodeMovingGC() {
    192 }
    193 
    194 
    195 
    196 // Constants used for mmap.
    197 static const int kMmapFd = -1;
    198 static const int kMmapFdOffset = 0;
    199 
    200 
    201 VirtualMemory::VirtualMemory() : address_(NULL), size_(0) { }
    202 
    203 
    204 VirtualMemory::VirtualMemory(size_t size)
    205     : address_(ReserveRegion(size)), size_(size) { }
    206 
    207 
    208 VirtualMemory::VirtualMemory(size_t size, size_t alignment)
    209     : address_(NULL), size_(0) {
    210   ASSERT(IsAligned(alignment, static_cast<intptr_t>(OS::AllocateAlignment())));
    211   size_t request_size = RoundUp(size + alignment,
    212                                 static_cast<intptr_t>(OS::AllocateAlignment()));
    213   void* reservation = mmap(OS::GetRandomMmapAddr(),
    214                            request_size,
    215                            PROT_NONE,
    216                            MAP_PRIVATE | MAP_ANON | MAP_NORESERVE,
    217                            kMmapFd,
    218                            kMmapFdOffset);
    219   if (reservation == MAP_FAILED) return;
    220 
    221   Address base = static_cast<Address>(reservation);
    222   Address aligned_base = RoundUp(base, alignment);
    223   ASSERT_LE(base, aligned_base);
    224 
    225   // Unmap extra memory reserved before and after the desired block.
    226   if (aligned_base != base) {
    227     size_t prefix_size = static_cast<size_t>(aligned_base - base);
    228     OS::Free(base, prefix_size);
    229     request_size -= prefix_size;
    230   }
    231 
    232   size_t aligned_size = RoundUp(size, OS::AllocateAlignment());
    233   ASSERT_LE(aligned_size, request_size);
    234 
    235   if (aligned_size != request_size) {
    236     size_t suffix_size = request_size - aligned_size;
    237     OS::Free(aligned_base + aligned_size, suffix_size);
    238     request_size -= suffix_size;
    239   }
    240 
    241   ASSERT(aligned_size == request_size);
    242 
    243   address_ = static_cast<void*>(aligned_base);
    244   size_ = aligned_size;
    245 }
    246 
    247 
    248 VirtualMemory::~VirtualMemory() {
    249   if (IsReserved()) {
    250     bool result = ReleaseRegion(address(), size());
    251     ASSERT(result);
    252     USE(result);
    253   }
    254 }
    255 
    256 
    257 bool VirtualMemory::IsReserved() {
    258   return address_ != NULL;
    259 }
    260 
    261 
    262 void VirtualMemory::Reset() {
    263   address_ = NULL;
    264   size_ = 0;
    265 }
    266 
    267 
    268 bool VirtualMemory::Commit(void* address, size_t size, bool is_executable) {
    269   return CommitRegion(address, size, is_executable);
    270 }
    271 
    272 
    273 bool VirtualMemory::Uncommit(void* address, size_t size) {
    274   return UncommitRegion(address, size);
    275 }
    276 
    277 
    278 bool VirtualMemory::Guard(void* address) {
    279   OS::Guard(address, OS::CommitPageSize());
    280   return true;
    281 }
    282 
    283 
    284 void* VirtualMemory::ReserveRegion(size_t size) {
    285   void* result = mmap(OS::GetRandomMmapAddr(),
    286                       size,
    287                       PROT_NONE,
    288                       MAP_PRIVATE | MAP_ANON | MAP_NORESERVE,
    289                       kMmapFd,
    290                       kMmapFdOffset);
    291 
    292   if (result == MAP_FAILED) return NULL;
    293 
    294   return result;
    295 }
    296 
    297 
    298 bool VirtualMemory::CommitRegion(void* base, size_t size, bool is_executable) {
    299   int prot = PROT_READ | PROT_WRITE | (is_executable ? PROT_EXEC : 0);
    300   if (MAP_FAILED == mmap(base,
    301                          size,
    302                          prot,
    303                          MAP_PRIVATE | MAP_ANON | MAP_FIXED,
    304                          kMmapFd,
    305                          kMmapFdOffset)) {
    306     return false;
    307   }
    308   return true;
    309 }
    310 
    311 
    312 bool VirtualMemory::UncommitRegion(void* base, size_t size) {
    313   return mmap(base,
    314               size,
    315               PROT_NONE,
    316               MAP_PRIVATE | MAP_ANON | MAP_NORESERVE | MAP_FIXED,
    317               kMmapFd,
    318               kMmapFdOffset) != MAP_FAILED;
    319 }
    320 
    321 
    322 bool VirtualMemory::ReleaseRegion(void* base, size_t size) {
    323   return munmap(base, size) == 0;
    324 }
    325 
    326 
    327 bool VirtualMemory::HasLazyCommits() {
    328   // TODO(alph): implement for the platform.
    329   return false;
    330 }
    331 
    332 } }  // namespace v8::internal
    333