allocation.cc 5.86 KB
Newer Older
1
// Copyright 2012 the V8 project authors. All rights reserved.
2 3
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
4

5
#include "src/allocation.h"
6 7

#include <stdlib.h>  // For free, malloc.
8
#include "src/base/bits.h"
9 10
#include "src/base/logging.h"
#include "src/base/platform/platform.h"
11
#include "src/utils.h"
12
#include "src/v8.h"
13

14 15 16 17
#if V8_LIBC_BIONIC
#include <malloc.h>  // NOLINT
#endif

18 19 20 21
#if defined(LEAK_SANITIZER)
#include <sanitizer/lsan_interface.h>
#endif

22 23
namespace v8 {
namespace internal {
24

25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42
namespace {

void* AlignedAllocInternal(size_t size, size_t alignment) {
  void* ptr;
#if V8_OS_WIN
  ptr = _aligned_malloc(size, alignment);
#elif V8_LIBC_BIONIC
  // posix_memalign is not exposed in some Android versions, so we fall back to
  // memalign. See http://code.google.com/p/android/issues/detail?id=35391.
  ptr = memalign(alignment, size);
#else
  if (posix_memalign(&ptr, alignment, size)) ptr = nullptr;
#endif
  return ptr;
}

}  // namespace

43 44
void* Malloced::New(size_t size) {
  void* result = malloc(size);
45 46 47 48 49 50
  if (result == nullptr) {
    V8::GetCurrentPlatform()->OnCriticalMemoryPressure();
    result = malloc(size);
    if (result == nullptr) {
      V8::FatalProcessOutOfMemory("Malloced operator new");
    }
51
  }
52 53 54 55 56 57 58 59 60 61
  return result;
}


void Malloced::Delete(void* p) {
  free(p);
}


char* StrDup(const char* str) {
62
  int length = StrLength(str);
63
  char* result = NewArray<char>(length + 1);
64
  MemCopy(result, str, length);
65 66 67 68 69
  result[length] = '\0';
  return result;
}


70 71
char* StrNDup(const char* str, int n) {
  int length = StrLength(str);
72 73
  if (n < length) length = n;
  char* result = NewArray<char>(length + 1);
74
  MemCopy(result, str, length);
75 76 77 78
  result[length] = '\0';
  return result;
}

79 80

void* AlignedAlloc(size_t size, size_t alignment) {
81
  DCHECK_LE(V8_ALIGNOF(void*), alignment);
82
  DCHECK(base::bits::IsPowerOfTwo(alignment));
83 84 85 86 87 88 89 90
  void* ptr = AlignedAllocInternal(size, alignment);
  if (ptr == nullptr) {
    V8::GetCurrentPlatform()->OnCriticalMemoryPressure();
    ptr = AlignedAllocInternal(size, alignment);
    if (ptr == nullptr) {
      V8::FatalProcessOutOfMemory("AlignedAlloc");
    }
  }
91 92 93 94 95 96 97 98 99 100 101 102 103 104 105
  return ptr;
}


void AlignedFree(void *ptr) {
#if V8_OS_WIN
  _aligned_free(ptr);
#elif V8_LIBC_BIONIC
  // Using free is not correct in general, but for V8_LIBC_BIONIC it is.
  free(ptr);
#else
  free(ptr);
#endif
}

106 107 108 109 110 111
byte* AllocateSystemPage(void* address, size_t* allocated) {
  size_t page_size = base::OS::AllocatePageSize();
  void* result = base::OS::Allocate(address, page_size, page_size,
                                    base::OS::MemoryPermission::kReadWrite);
  if (result != nullptr) *allocated = page_size;
  return static_cast<byte*>(result);
112 113
}

114 115 116
VirtualMemory::VirtualMemory() : address_(nullptr), size_(0) {}

VirtualMemory::VirtualMemory(size_t size, void* hint, size_t alignment)
117
    : address_(nullptr), size_(0) {
118 119 120 121 122 123
  size_t page_size = base::OS::AllocatePageSize();
  size_t alloc_size = RoundUp(size, page_size);
  address_ = base::OS::Allocate(hint, alloc_size, alignment,
                                base::OS::MemoryPermission::kNoAccess);
  if (address_ != nullptr) {
    size_ = alloc_size;
124
#if defined(LEAK_SANITIZER)
125
    __lsan_register_root_region(address_, size_);
126
#endif
127
  }
128 129 130 131
}

VirtualMemory::~VirtualMemory() {
  if (IsReserved()) {
132
    Free();
133 134 135 136 137 138 139 140
  }
}

void VirtualMemory::Reset() {
  address_ = nullptr;
  size_ = 0;
}

141 142
bool VirtualMemory::SetPermissions(void* address, size_t size,
                                   base::OS::MemoryPermission access) {
143
  CHECK(InVM(address, size));
144 145 146
  bool result = base::OS::SetPermissions(address, size, access);
  DCHECK(result);
  USE(result);
147
  return result;
148 149
}

150
size_t VirtualMemory::Release(void* free_start) {
151
  DCHECK(IsReserved());
152 153
  DCHECK(IsAddressAligned(static_cast<Address>(free_start),
                          base::OS::CommitPageSize()));
154 155
  // Notice: Order is important here. The VirtualMemory object might live
  // inside the allocated region.
156 157 158
  const size_t free_size = size_ - (reinterpret_cast<size_t>(free_start) -
                                    reinterpret_cast<size_t>(address_));
  CHECK(InVM(free_start, free_size));
159 160 161
  DCHECK_LT(address_, free_start);
  DCHECK_LT(free_start, reinterpret_cast<void*>(
                            reinterpret_cast<size_t>(address_) + size_));
162 163 164 165
#if defined(LEAK_SANITIZER)
  __lsan_unregister_root_region(address_, size_);
  __lsan_register_root_region(address_, size_ - free_size);
#endif
166
  CHECK(base::OS::Release(free_start, free_size));
167 168
  size_ -= free_size;
  return free_size;
169 170
}

171
void VirtualMemory::Free() {
172 173 174 175 176 177 178
  DCHECK(IsReserved());
  // Notice: Order is important here. The VirtualMemory object might live
  // inside the allocated region.
  void* address = address_;
  size_t size = size_;
  CHECK(InVM(address, size));
  Reset();
179 180 181
#if defined(LEAK_SANITIZER)
  __lsan_unregister_root_region(address, size);
#endif
182
  CHECK(base::OS::Free(address, size));
183 184 185 186 187 188 189 190 191 192 193
}

void VirtualMemory::TakeControl(VirtualMemory* from) {
  DCHECK(!IsReserved());
  address_ = from->address_;
  size_ = from->size_;
  from->Reset();
}

bool AllocVirtualMemory(size_t size, void* hint, VirtualMemory* result) {
  VirtualMemory first_try(size, hint);
194 195 196 197 198 199
  if (first_try.IsReserved()) {
    result->TakeControl(&first_try);
    return true;
  }

  V8::GetCurrentPlatform()->OnCriticalMemoryPressure();
200
  VirtualMemory second_try(size, hint);
201 202 203 204 205
  result->TakeControl(&second_try);
  return result->IsReserved();
}

bool AlignedAllocVirtualMemory(size_t size, size_t alignment, void* hint,
206
                               VirtualMemory* result) {
207
  VirtualMemory first_try(size, hint, alignment);
208 209 210 211 212 213
  if (first_try.IsReserved()) {
    result->TakeControl(&first_try);
    return true;
  }

  V8::GetCurrentPlatform()->OnCriticalMemoryPressure();
214
  VirtualMemory second_try(size, hint, alignment);
215 216 217 218
  result->TakeControl(&second_try);
  return result->IsReserved();
}

219 220
}  // namespace internal
}  // namespace v8