The data contained in this repository can be downloaded to your computer using one of several clients.
Please see the documentation of your version control software client for more information.

Please select the desired protocol below to get the URL.

This URL has Read-Only access.

Statistics
| Branch: | Revision:

main_repo / deps / v8 / src / platform-linux.cc @ f230a1cf

History | View | Annotate | Download (13.3 KB)

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 Linux 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/prctl.h>
35
#include <sys/time.h>
36
#include <sys/resource.h>
37
#include <sys/syscall.h>
38
#include <sys/types.h>
39
#include <stdlib.h>
40

    
41
// Ubuntu Dapper requires memory pages to be marked as
42
// executable. Otherwise, OS raises an exception when executing code
43
// in that page.
44
#include <sys/types.h>  // mmap & munmap
45
#include <sys/mman.h>   // mmap & munmap
46
#include <sys/stat.h>   // open
47
#include <fcntl.h>      // open
48
#include <unistd.h>     // sysconf
49
#include <strings.h>    // index
50
#include <errno.h>
51
#include <stdarg.h>
52

    
53
// GLibc on ARM defines mcontext_t has a typedef for 'struct sigcontext'.
54
// Old versions of the C library <signal.h> didn't define the type.
55
#if defined(__ANDROID__) && !defined(__BIONIC_HAVE_UCONTEXT_T) && \
56
    defined(__arm__) && !defined(__BIONIC_HAVE_STRUCT_SIGCONTEXT)
57
#include <asm/sigcontext.h>
58
#endif
59

    
60
#undef MAP_TYPE
61

    
62
#include "v8.h"
63

    
64
#include "platform.h"
65
#include "v8threads.h"
66
#include "vm-state-inl.h"
67

    
68

    
69
namespace v8 {
70
namespace internal {
71

    
72

    
73
#ifdef __arm__
74

    
75
bool OS::ArmUsingHardFloat() {
76
  // GCC versions 4.6 and above define __ARM_PCS or __ARM_PCS_VFP to specify
77
  // the Floating Point ABI used (PCS stands for Procedure Call Standard).
78
  // We use these as well as a couple of other defines to statically determine
79
  // what FP ABI used.
80
  // GCC versions 4.4 and below don't support hard-fp.
81
  // GCC versions 4.5 may support hard-fp without defining __ARM_PCS or
82
  // __ARM_PCS_VFP.
83

    
84
#define GCC_VERSION (__GNUC__ * 10000                                          \
85
                     + __GNUC_MINOR__ * 100                                    \
86
                     + __GNUC_PATCHLEVEL__)
87
#if GCC_VERSION >= 40600
88
#if defined(__ARM_PCS_VFP)
89
  return true;
90
#else
91
  return false;
92
#endif
93

    
94
#elif GCC_VERSION < 40500
95
  return false;
96

    
97
#else
98
#if defined(__ARM_PCS_VFP)
99
  return true;
100
#elif defined(__ARM_PCS) || defined(__SOFTFP__) || defined(__SOFTFP) || \
101
      !defined(__VFP_FP__)
102
  return false;
103
#else
104
#error "Your version of GCC does not report the FP ABI compiled for."          \
105
       "Please report it on this issue"                                        \
106
       "http://code.google.com/p/v8/issues/detail?id=2140"
107

    
108
#endif
109
#endif
110
#undef GCC_VERSION
111
}
112

    
113
#endif  // def __arm__
114

    
115

    
116
const char* OS::LocalTimezone(double time) {
117
  if (std::isnan(time)) return "";
118
  time_t tv = static_cast<time_t>(floor(time/msPerSecond));
119
  struct tm* t = localtime(&tv);
120
  if (NULL == t) return "";
121
  return t->tm_zone;
122
}
123

    
124

    
125
double OS::LocalTimeOffset() {
126
  time_t tv = time(NULL);
127
  struct tm* t = localtime(&tv);
128
  // tm_gmtoff includes any daylight savings offset, so subtract it.
129
  return static_cast<double>(t->tm_gmtoff * msPerSecond -
130
                             (t->tm_isdst > 0 ? 3600 * msPerSecond : 0));
131
}
132

    
133

    
134
void* OS::Allocate(const size_t requested,
135
                   size_t* allocated,
136
                   bool is_executable) {
137
  const size_t msize = RoundUp(requested, AllocateAlignment());
138
  int prot = PROT_READ | PROT_WRITE | (is_executable ? PROT_EXEC : 0);
139
  void* addr = OS::GetRandomMmapAddr();
140
  void* mbase = mmap(addr, msize, prot, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
141
  if (mbase == MAP_FAILED) {
142
    LOG(i::Isolate::Current(),
143
        StringEvent("OS::Allocate", "mmap failed"));
144
    return NULL;
145
  }
146
  *allocated = msize;
147
  return mbase;
148
}
149

    
150

    
151
class PosixMemoryMappedFile : public OS::MemoryMappedFile {
152
 public:
153
  PosixMemoryMappedFile(FILE* file, void* memory, int size)
154
    : file_(file), memory_(memory), size_(size) { }
155
  virtual ~PosixMemoryMappedFile();
156
  virtual void* memory() { return memory_; }
157
  virtual int size() { return size_; }
158
 private:
159
  FILE* file_;
160
  void* memory_;
161
  int size_;
162
};
163

    
164

    
165
OS::MemoryMappedFile* OS::MemoryMappedFile::open(const char* name) {
166
  FILE* file = fopen(name, "r+");
167
  if (file == NULL) return NULL;
168

    
169
  fseek(file, 0, SEEK_END);
170
  int size = ftell(file);
171

    
172
  void* memory =
173
      mmap(OS::GetRandomMmapAddr(),
174
           size,
175
           PROT_READ | PROT_WRITE,
176
           MAP_SHARED,
177
           fileno(file),
178
           0);
179
  return new PosixMemoryMappedFile(file, memory, size);
180
}
181

    
182

    
183
OS::MemoryMappedFile* OS::MemoryMappedFile::create(const char* name, int size,
184
    void* initial) {
185
  FILE* file = fopen(name, "w+");
186
  if (file == NULL) return NULL;
187
  int result = fwrite(initial, size, 1, file);
188
  if (result < 1) {
189
    fclose(file);
190
    return NULL;
191
  }
192
  void* memory =
193
      mmap(OS::GetRandomMmapAddr(),
194
           size,
195
           PROT_READ | PROT_WRITE,
196
           MAP_SHARED,
197
           fileno(file),
198
           0);
199
  return new PosixMemoryMappedFile(file, memory, size);
200
}
201

    
202

    
203
PosixMemoryMappedFile::~PosixMemoryMappedFile() {
204
  if (memory_) OS::Free(memory_, size_);
205
  fclose(file_);
206
}
207

    
208

    
209
void OS::LogSharedLibraryAddresses(Isolate* isolate) {
210
  // This function assumes that the layout of the file is as follows:
211
  // hex_start_addr-hex_end_addr rwxp <unused data> [binary_file_name]
212
  // If we encounter an unexpected situation we abort scanning further entries.
213
  FILE* fp = fopen("/proc/self/maps", "r");
214
  if (fp == NULL) return;
215

    
216
  // Allocate enough room to be able to store a full file name.
217
  const int kLibNameLen = FILENAME_MAX + 1;
218
  char* lib_name = reinterpret_cast<char*>(malloc(kLibNameLen));
219

    
220
  // This loop will terminate once the scanning hits an EOF.
221
  while (true) {
222
    uintptr_t start, end;
223
    char attr_r, attr_w, attr_x, attr_p;
224
    // Parse the addresses and permission bits at the beginning of the line.
225
    if (fscanf(fp, "%" V8PRIxPTR "-%" V8PRIxPTR, &start, &end) != 2) break;
226
    if (fscanf(fp, " %c%c%c%c", &attr_r, &attr_w, &attr_x, &attr_p) != 4) break;
227

    
228
    int c;
229
    if (attr_r == 'r' && attr_w != 'w' && attr_x == 'x') {
230
      // Found a read-only executable entry. Skip characters until we reach
231
      // the beginning of the filename or the end of the line.
232
      do {
233
        c = getc(fp);
234
      } while ((c != EOF) && (c != '\n') && (c != '/') && (c != '['));
235
      if (c == EOF) break;  // EOF: Was unexpected, just exit.
236

    
237
      // Process the filename if found.
238
      if ((c == '/') || (c == '[')) {
239
        // Push the '/' or '[' back into the stream to be read below.
240
        ungetc(c, fp);
241

    
242
        // Read to the end of the line. Exit if the read fails.
243
        if (fgets(lib_name, kLibNameLen, fp) == NULL) break;
244

    
245
        // Drop the newline character read by fgets. We do not need to check
246
        // for a zero-length string because we know that we at least read the
247
        // '/' or '[' character.
248
        lib_name[strlen(lib_name) - 1] = '\0';
249
      } else {
250
        // No library name found, just record the raw address range.
251
        snprintf(lib_name, kLibNameLen,
252
                 "%08" V8PRIxPTR "-%08" V8PRIxPTR, start, end);
253
      }
254
      LOG(isolate, SharedLibraryEvent(lib_name, start, end));
255
    } else {
256
      // Entry not describing executable data. Skip to end of line to set up
257
      // reading the next entry.
258
      do {
259
        c = getc(fp);
260
      } while ((c != EOF) && (c != '\n'));
261
      if (c == EOF) break;
262
    }
263
  }
264
  free(lib_name);
265
  fclose(fp);
266
}
267

    
268

    
269
void OS::SignalCodeMovingGC() {
270
  // Support for ll_prof.py.
271
  //
272
  // The Linux profiler built into the kernel logs all mmap's with
273
  // PROT_EXEC so that analysis tools can properly attribute ticks. We
274
  // do a mmap with a name known by ll_prof.py and immediately munmap
275
  // it. This injects a GC marker into the stream of events generated
276
  // by the kernel and allows us to synchronize V8 code log and the
277
  // kernel log.
278
  int size = sysconf(_SC_PAGESIZE);
279
  FILE* f = fopen(FLAG_gc_fake_mmap, "w+");
280
  if (f == NULL) {
281
    OS::PrintError("Failed to open %s\n", FLAG_gc_fake_mmap);
282
    OS::Abort();
283
  }
284
  void* addr = mmap(OS::GetRandomMmapAddr(),
285
                    size,
286
#if defined(__native_client__)
287
                    // The Native Client port of V8 uses an interpreter,
288
                    // so code pages don't need PROT_EXEC.
289
                    PROT_READ,
290
#else
291
                    PROT_READ | PROT_EXEC,
292
#endif
293
                    MAP_PRIVATE,
294
                    fileno(f),
295
                    0);
296
  ASSERT(addr != MAP_FAILED);
297
  OS::Free(addr, size);
298
  fclose(f);
299
}
300

    
301

    
302
// Constants used for mmap.
303
static const int kMmapFd = -1;
304
static const int kMmapFdOffset = 0;
305

    
306

    
307
VirtualMemory::VirtualMemory() : address_(NULL), size_(0) { }
308

    
309

    
310
VirtualMemory::VirtualMemory(size_t size)
311
    : address_(ReserveRegion(size)), size_(size) { }
312

    
313

    
314
VirtualMemory::VirtualMemory(size_t size, size_t alignment)
315
    : address_(NULL), size_(0) {
316
  ASSERT(IsAligned(alignment, static_cast<intptr_t>(OS::AllocateAlignment())));
317
  size_t request_size = RoundUp(size + alignment,
318
                                static_cast<intptr_t>(OS::AllocateAlignment()));
319
  void* reservation = mmap(OS::GetRandomMmapAddr(),
320
                           request_size,
321
                           PROT_NONE,
322
                           MAP_PRIVATE | MAP_ANONYMOUS | MAP_NORESERVE,
323
                           kMmapFd,
324
                           kMmapFdOffset);
325
  if (reservation == MAP_FAILED) return;
326

    
327
  Address base = static_cast<Address>(reservation);
328
  Address aligned_base = RoundUp(base, alignment);
329
  ASSERT_LE(base, aligned_base);
330

    
331
  // Unmap extra memory reserved before and after the desired block.
332
  if (aligned_base != base) {
333
    size_t prefix_size = static_cast<size_t>(aligned_base - base);
334
    OS::Free(base, prefix_size);
335
    request_size -= prefix_size;
336
  }
337

    
338
  size_t aligned_size = RoundUp(size, OS::AllocateAlignment());
339
  ASSERT_LE(aligned_size, request_size);
340

    
341
  if (aligned_size != request_size) {
342
    size_t suffix_size = request_size - aligned_size;
343
    OS::Free(aligned_base + aligned_size, suffix_size);
344
    request_size -= suffix_size;
345
  }
346

    
347
  ASSERT(aligned_size == request_size);
348

    
349
  address_ = static_cast<void*>(aligned_base);
350
  size_ = aligned_size;
351
}
352

    
353

    
354
VirtualMemory::~VirtualMemory() {
355
  if (IsReserved()) {
356
    bool result = ReleaseRegion(address(), size());
357
    ASSERT(result);
358
    USE(result);
359
  }
360
}
361

    
362

    
363
bool VirtualMemory::IsReserved() {
364
  return address_ != NULL;
365
}
366

    
367

    
368
void VirtualMemory::Reset() {
369
  address_ = NULL;
370
  size_ = 0;
371
}
372

    
373

    
374
bool VirtualMemory::Commit(void* address, size_t size, bool is_executable) {
375
  return CommitRegion(address, size, is_executable);
376
}
377

    
378

    
379
bool VirtualMemory::Uncommit(void* address, size_t size) {
380
  return UncommitRegion(address, size);
381
}
382

    
383

    
384
bool VirtualMemory::Guard(void* address) {
385
  OS::Guard(address, OS::CommitPageSize());
386
  return true;
387
}
388

    
389

    
390
void* VirtualMemory::ReserveRegion(size_t size) {
391
  void* result = mmap(OS::GetRandomMmapAddr(),
392
                      size,
393
                      PROT_NONE,
394
                      MAP_PRIVATE | MAP_ANONYMOUS | MAP_NORESERVE,
395
                      kMmapFd,
396
                      kMmapFdOffset);
397

    
398
  if (result == MAP_FAILED) return NULL;
399

    
400
  return result;
401
}
402

    
403

    
404
bool VirtualMemory::CommitRegion(void* base, size_t size, bool is_executable) {
405
#if defined(__native_client__)
406
  // The Native Client port of V8 uses an interpreter,
407
  // so code pages don't need PROT_EXEC.
408
  int prot = PROT_READ | PROT_WRITE;
409
#else
410
  int prot = PROT_READ | PROT_WRITE | (is_executable ? PROT_EXEC : 0);
411
#endif
412
  if (MAP_FAILED == mmap(base,
413
                         size,
414
                         prot,
415
                         MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED,
416
                         kMmapFd,
417
                         kMmapFdOffset)) {
418
    return false;
419
  }
420

    
421
  return true;
422
}
423

    
424

    
425
bool VirtualMemory::UncommitRegion(void* base, size_t size) {
426
  return mmap(base,
427
              size,
428
              PROT_NONE,
429
              MAP_PRIVATE | MAP_ANONYMOUS | MAP_NORESERVE | MAP_FIXED,
430
              kMmapFd,
431
              kMmapFdOffset) != MAP_FAILED;
432
}
433

    
434

    
435
bool VirtualMemory::ReleaseRegion(void* base, size_t size) {
436
  return munmap(base, size) == 0;
437
}
438

    
439

    
440
bool VirtualMemory::HasLazyCommits() {
441
  return true;
442
}
443

    
444
} }  // namespace v8::internal