Commit 699144a2 authored by Bill Budge's avatar Bill Budge Committed by Commit Bot

[Memory] Add PageAllocator concept to v8::Platform.

- Adds abstract base class PageAllocator, defined in v8-platform.h. Adds
  GetPageAllocator method to v8::Platform.
- Implements a DefaultPageAllocator, implemented in terms of base::OS
  page allocation methods.

Bug: chromium:756050
Cq-Include-Trybots: master.tryserver.chromium.linux:linux_chromium_rel_ng
Change-Id: Iece0b261a07294a49c30ac25e848dc39cb1a32e2
Reviewed-on: https://chromium-review.googlesource.com/809778
Commit-Queue: Bill Budge <bbudge@chromium.org>
Reviewed-by: 's avatarHannes Payer <hpayer@chromium.org>
Cr-Commit-Position: refs/heads/master@{#50282}
parent efdbc429
......@@ -2525,6 +2525,8 @@ v8_component("v8_libbase") {
"src/base/once.cc",
"src/base/once.h",
"src/base/optional.h",
"src/base/page-allocator.cc",
"src/base/page-allocator.h",
"src/base/platform/condition-variable.cc",
"src/base/platform/condition-variable.h",
"src/base/platform/elapsed-timer.h",
......
......@@ -157,6 +157,74 @@ class TracingController {
virtual void RemoveTraceStateObserver(TraceStateObserver*) {}
};
/**
* A V8 page memory allocator.
*
* Can be implemented by an embedder to manage large host OS allocations.
*/
class PageAllocator {
public:
virtual ~PageAllocator() = default;
/**
* Gets the page granularity for AllocatePages and FreePages. Addresses and
* lengths for those calls should be multiples of AllocatePageSize().
*/
virtual size_t AllocatePageSize() = 0;
/**
* Gets the page granularity for SetPermissions and ReleasePages. Addresses
* and lengths for those calls should be multiples of CommitPageSize().
*/
virtual size_t CommitPageSize() = 0;
/**
* Sets the random seed so that GetRandomMmapAddr() will generate repeatable
* sequences of random mmap addresses.
*/
virtual void SetRandomMmapSeed(int64_t seed) = 0;
/**
* Returns a randomized address, suitable for memory allocation under ASLR.
* The address will be aligned to AllocatePageSize.
*/
virtual void* GetRandomMmapAddr() = 0;
/**
* Memory permissions.
*/
enum Permission {
kNoAccess,
kReadWrite,
// TODO(hpayer): Remove this flag. Memory should never be rwx.
kReadWriteExecute,
kReadExecute
};
/**
* Allocates memory in range with the given alignment and permission.
*/
virtual void* AllocatePages(void* address, size_t length, size_t alignment,
Permission permissions) = 0;
/**
* Frees memory in a range that was allocated by a call to AllocatePages.
*/
virtual bool FreePages(void* address, size_t length) = 0;
/**
* Releases memory in a range that was allocated by a call to AllocatePages.
*/
virtual bool ReleasePages(void* address, size_t length,
size_t new_length) = 0;
/**
* Sets permissions on pages in an allocated range.
*/
virtual bool SetPermissions(void* address, size_t length,
Permission permissions) = 0;
};
/**
* V8 Platform abstraction layer.
*
......@@ -177,6 +245,14 @@ class Platform {
virtual ~Platform() = default;
/**
* Allows the embedder to manage large memory allocations.
*/
virtual PageAllocator* GetPageAllocator() {
// TODO(bbudge) Make this abstract after all embedders implement this.
return nullptr;
}
/**
* Enables the embedder to respond in cases where V8 can't allocate large
* blocks of memory. V8 retries the failed allocation once after calling this
......@@ -184,7 +260,12 @@ class Platform {
* error.
* Embedder overrides of this function must NOT call back into V8.
*/
virtual void OnCriticalMemoryPressure() {}
virtual void OnCriticalMemoryPressure() {
// TODO(bbudge) Change this method by adding a failed_allocation_size
// parameter, and to return a bool. This will allow embedders to manage a
// reserve, rather than simply release it all on a failure.
// See crbug.com/634547.
}
/**
* Gets the number of threads that are used to execute background tasks. Is
......
......@@ -6,7 +6,9 @@
#include <stdlib.h> // For free, malloc.
#include "src/base/bits.h"
#include "src/base/lazy-instance.h"
#include "src/base/logging.h"
#include "src/base/page-allocator.h"
#include "src/base/platform/platform.h"
#include "src/utils.h"
#include "src/v8.h"
......@@ -38,6 +40,26 @@ void* AlignedAllocInternal(size_t size, size_t alignment) {
return ptr;
}
// TODO(bbudge) Simplify this once all embedders implement a page allocator.
struct InitializePageAllocator {
static void Construct(void* page_allocator_ptr_arg) {
auto page_allocator_ptr =
reinterpret_cast<v8::PageAllocator**>(page_allocator_ptr_arg);
v8::PageAllocator* page_allocator =
V8::GetCurrentPlatform()->GetPageAllocator();
if (page_allocator == nullptr) {
static v8::base::PageAllocator default_allocator;
page_allocator = &default_allocator;
}
*page_allocator_ptr = page_allocator;
}
};
static base::LazyInstance<v8::PageAllocator*, InitializePageAllocator>::type
page_allocator = LAZY_INSTANCE_INITIALIZER;
v8::PageAllocator* GetPageAllocator() { return page_allocator.Get(); }
} // namespace
void* Malloced::New(size_t size) {
......@@ -103,109 +125,59 @@ void AlignedFree(void *ptr) {
#endif
}
#define STATIC_ASSERT_ENUM(a, b) \
static_assert(static_cast<int>(a) == static_cast<int>(b), \
"mismatching enum: " #a)
STATIC_ASSERT_ENUM(MemoryPermission::kNoAccess,
base::OS::MemoryPermission::kNoAccess);
STATIC_ASSERT_ENUM(MemoryPermission::kReadWrite,
base::OS::MemoryPermission::kReadWrite);
STATIC_ASSERT_ENUM(MemoryPermission::kReadWriteExecute,
base::OS::MemoryPermission::kReadWriteExecute);
STATIC_ASSERT_ENUM(MemoryPermission::kReadExecute,
base::OS::MemoryPermission::kReadExecute);
#undef STATIC_ASSERT_ENUM
// Default Memory Manager.
// TODO(bbudge) Move this to libplatform.
class DefaultMemoryManager {
public:
static size_t AllocatePageSize() { return base::OS::AllocatePageSize(); }
static size_t CommitPageSize() { return base::OS::CommitPageSize(); }
static void SetRandomMmapSeed(int64_t seed) {
base::OS::SetRandomMmapSeed(seed);
}
static void* GetRandomMmapAddr() { return base::OS::GetRandomMmapAddr(); }
static void* AllocatePages(void* address, size_t size, size_t alignment,
MemoryPermission access) {
void* result =
base::OS::Allocate(address, size, alignment,
static_cast<base::OS::MemoryPermission>(access));
#if defined(LEAK_SANITIZER)
if (result != nullptr) {
__lsan_register_root_region(result, size);
}
#endif
return result;
}
static bool FreePages(void* address, const size_t size) {
bool result = base::OS::Free(address, size);
#if defined(LEAK_SANITIZER)
if (result) {
__lsan_unregister_root_region(address, size);
}
#endif
return result;
}
static bool ReleasePages(void* address, size_t size, size_t new_size) {
DCHECK_LT(new_size, size);
bool result = base::OS::Release(reinterpret_cast<byte*>(address) + new_size,
size - new_size);
#if defined(LEAK_SANITIZER)
if (result) {
__lsan_unregister_root_region(address, size);
__lsan_register_root_region(address, new_size);
}
#endif
return result;
}
size_t AllocatePageSize() { return GetPageAllocator()->AllocatePageSize(); }
static bool SetPermissions(void* address, size_t size,
MemoryPermission access) {
return base::OS::SetPermissions(
address, size, static_cast<base::OS::MemoryPermission>(access));
}
};
size_t AllocatePageSize() { return DefaultMemoryManager::AllocatePageSize(); }
size_t CommitPageSize() { return DefaultMemoryManager::CommitPageSize(); }
size_t CommitPageSize() { return GetPageAllocator()->CommitPageSize(); }
void SetRandomMmapSeed(int64_t seed) {
DefaultMemoryManager::SetRandomMmapSeed(seed);
GetPageAllocator()->SetRandomMmapSeed(seed);
}
void* GetRandomMmapAddr() { return DefaultMemoryManager::GetRandomMmapAddr(); }
void* GetRandomMmapAddr() { return GetPageAllocator()->GetRandomMmapAddr(); }
void* AllocatePages(void* address, size_t size, size_t alignment,
MemoryPermission access) {
return DefaultMemoryManager::AllocatePages(address, size, alignment, access);
PageAllocator::Permission access) {
void* result =
GetPageAllocator()->AllocatePages(address, size, alignment, access);
#if defined(LEAK_SANITIZER)
if (result != nullptr) {
__lsan_register_root_region(result, size);
}
#endif
return result;
}
bool FreePages(void* address, const size_t size) {
return DefaultMemoryManager::FreePages(address, size);
bool result = GetPageAllocator()->FreePages(address, size);
#if defined(LEAK_SANITIZER)
if (result) {
__lsan_unregister_root_region(address, size);
}
#endif
return result;
}
bool ReleasePages(void* address, size_t size, size_t new_size) {
return DefaultMemoryManager::ReleasePages(address, size, new_size);
DCHECK_LT(new_size, size);
bool result = GetPageAllocator()->ReleasePages(address, size, new_size);
#if defined(LEAK_SANITIZER)
if (result) {
__lsan_unregister_root_region(address, size);
__lsan_register_root_region(address, new_size);
}
#endif
return result;
}
bool SetPermissions(void* address, size_t size, MemoryPermission access) {
return DefaultMemoryManager::SetPermissions(address, size, access);
bool SetPermissions(void* address, size_t size,
PageAllocator::Permission access) {
return GetPageAllocator()->SetPermissions(address, size, access);
}
byte* AllocatePage(void* address, size_t* allocated) {
size_t page_size = AllocatePageSize();
void* result = AllocatePages(address, page_size, page_size,
MemoryPermission::kReadWrite);
void* result =
AllocatePages(address, page_size, page_size, PageAllocator::kReadWrite);
if (result != nullptr) *allocated = page_size;
return static_cast<byte*>(result);
}
......@@ -217,7 +189,7 @@ VirtualMemory::VirtualMemory(size_t size, void* hint, size_t alignment)
size_t page_size = AllocatePageSize();
size_t alloc_size = RoundUp(size, page_size);
address_ =
AllocatePages(hint, alloc_size, alignment, MemoryPermission::kNoAccess);
AllocatePages(hint, alloc_size, alignment, PageAllocator::kNoAccess);
if (address_ != nullptr) {
size_ = alloc_size;
}
......@@ -235,7 +207,7 @@ void VirtualMemory::Reset() {
}
bool VirtualMemory::SetPermissions(void* address, size_t size,
MemoryPermission access) {
PageAllocator::Permission access) {
CHECK(InVM(address, size));
bool result = v8::internal::SetPermissions(address, size, access);
DCHECK(result);
......
......@@ -76,15 +76,6 @@ class FreeStoreAllocationPolicy {
void* AlignedAlloc(size_t size, size_t alignment);
void AlignedFree(void *ptr);
// These must be in sync with the permissions in base/platform/platform.h.
enum class MemoryPermission {
kNoAccess,
kReadWrite,
// TODO(hpayer): Remove this flag. Memory should never be rwx.
kReadWriteExecute,
kReadExecute
};
// Gets the page granularity for AllocatePages and FreePages. Addresses returned
// by AllocatePages and AllocatePage are aligned to this size.
V8_EXPORT_PRIVATE size_t AllocatePageSize();
......@@ -92,7 +83,8 @@ V8_EXPORT_PRIVATE size_t AllocatePageSize();
// Gets the granularity at which the permissions and release calls can be made.
V8_EXPORT_PRIVATE size_t CommitPageSize();
// Sets the random seed for repeatable sequences of random mmap addresses.
// Sets the random seed so that GetRandomMmapAddr() will generate repeatable
// sequences of random mmap addresses.
V8_EXPORT_PRIVATE void SetRandomMmapSeed(int64_t seed);
// Generate a random address to be used for hinting allocation calls.
......@@ -105,7 +97,7 @@ V8_EXPORT_PRIVATE void* GetRandomMmapAddr();
V8_EXPORT_PRIVATE
V8_WARN_UNUSED_RESULT void* AllocatePages(void* address, size_t size,
size_t alignment,
MemoryPermission access);
PageAllocator::Permission access);
// Frees memory allocated by a call to AllocatePages. |address| and |size| must
// be multiples of AllocatePageSize(). Returns true on success, otherwise false.
......@@ -127,7 +119,7 @@ V8_WARN_UNUSED_RESULT bool ReleasePages(void* address, size_t size,
// false.
V8_EXPORT_PRIVATE
V8_WARN_UNUSED_RESULT bool SetPermissions(void* address, size_t size,
MemoryPermission access);
PageAllocator::Permission access);
// Convenience function that allocates a single system page with read and write
// permissions. |address| is a hint. Returns the base address of the memory and
......@@ -183,7 +175,8 @@ class V8_EXPORT_PRIVATE VirtualMemory {
// Sets permissions according to the access argument. address and size must be
// multiples of CommitPageSize(). Returns true on success, otherwise false.
bool SetPermissions(void* address, size_t size, MemoryPermission access);
bool SetPermissions(void* address, size_t size,
PageAllocator::Permission access);
// Releases memory after |free_start|. Returns the number of bytes released.
size_t Release(void* free_start);
......
......@@ -508,7 +508,7 @@ class ArrayBufferAllocator : public v8::ArrayBuffer::Allocator {
size_t page_size = i::AllocatePageSize();
size_t allocated = RoundUp(length, page_size);
void* address = i::AllocatePages(i::GetRandomMmapAddr(), allocated,
page_size, i::MemoryPermission::kNoAccess);
page_size, PageAllocator::kNoAccess);
return address;
}
......@@ -532,10 +532,10 @@ class ArrayBufferAllocator : public v8::ArrayBuffer::Allocator {
v8::ArrayBuffer::Allocator::Protection protection) {
DCHECK(protection == v8::ArrayBuffer::Allocator::Protection::kNoAccess ||
protection == v8::ArrayBuffer::Allocator::Protection::kReadWrite);
i::MemoryPermission permission =
PageAllocator::Permission permission =
(protection == v8::ArrayBuffer::Allocator::Protection::kReadWrite)
? i::MemoryPermission::kReadWrite
: i::MemoryPermission::kNoAccess;
? PageAllocator::kReadWrite
: PageAllocator::kNoAccess;
CHECK(i::SetPermissions(data, length, permission));
}
};
......
......@@ -169,7 +169,7 @@ MemCopyUint8Function CreateMemCopyUint8Function(Isolate* isolate,
DCHECK(!RelocInfo::RequiresRelocation(isolate, desc));
Assembler::FlushICache(isolate, buffer, allocated);
CHECK(SetPermissions(buffer, allocated, MemoryPermission::kReadExecute));
CHECK(SetPermissions(buffer, allocated, PageAllocator::kReadExecute));
return FUNCTION_CAST<MemCopyUint8Function>(buffer);
#endif
}
......@@ -258,7 +258,7 @@ MemCopyUint16Uint8Function CreateMemCopyUint16Uint8Function(
masm.GetCode(isolate, &desc);
Assembler::FlushICache(isolate, buffer, allocated);
CHECK(SetPermissions(buffer, allocated, MemoryPermission::kReadExecute));
CHECK(SetPermissions(buffer, allocated, PageAllocator::kReadExecute));
return FUNCTION_CAST<MemCopyUint16Uint8Function>(buffer);
#endif
}
......@@ -285,7 +285,7 @@ UnaryMathFunctionWithIsolate CreateSqrtFunction(Isolate* isolate) {
DCHECK(!RelocInfo::RequiresRelocation(isolate, desc));
Assembler::FlushICache(isolate, buffer, allocated);
CHECK(SetPermissions(buffer, allocated, MemoryPermission::kReadExecute));
CHECK(SetPermissions(buffer, allocated, PageAllocator::kReadExecute));
return FUNCTION_CAST<UnaryMathFunctionWithIsolate>(buffer);
#endif
}
......
include_rules = [
"-include",
"+include/v8config.h",
"+include/v8-platform.h",
"-src",
"+src/base",
]
// Copyright 2017 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "src/base/page-allocator.h"
#include "src/base/platform/platform.h"
namespace v8 {
namespace base {
#define STATIC_ASSERT_ENUM(a, b) \
static_assert(static_cast<int>(a) == static_cast<int>(b), \
"mismatching enum: " #a)
STATIC_ASSERT_ENUM(PageAllocator::kNoAccess,
base::OS::MemoryPermission::kNoAccess);
STATIC_ASSERT_ENUM(PageAllocator::kReadWrite,
base::OS::MemoryPermission::kReadWrite);
STATIC_ASSERT_ENUM(PageAllocator::kReadWriteExecute,
base::OS::MemoryPermission::kReadWriteExecute);
STATIC_ASSERT_ENUM(PageAllocator::kReadExecute,
base::OS::MemoryPermission::kReadExecute);
#undef STATIC_ASSERT_ENUM
size_t PageAllocator::AllocatePageSize() {
return base::OS::AllocatePageSize();
}
size_t PageAllocator::CommitPageSize() { return base::OS::CommitPageSize(); }
void PageAllocator::SetRandomMmapSeed(int64_t seed) {
base::OS::SetRandomMmapSeed(seed);
}
void* PageAllocator::GetRandomMmapAddr() {
return base::OS::GetRandomMmapAddr();
}
void* PageAllocator::AllocatePages(void* address, size_t size, size_t alignment,
PageAllocator::Permission access) {
return base::OS::Allocate(address, size, alignment,
static_cast<base::OS::MemoryPermission>(access));
}
bool PageAllocator::FreePages(void* address, size_t size) {
return base::OS::Free(address, size);
}
bool PageAllocator::ReleasePages(void* address, size_t size, size_t new_size) {
DCHECK_LT(new_size, size);
return base::OS::Release(reinterpret_cast<uint8_t*>(address) + new_size,
size - new_size);
}
bool PageAllocator::SetPermissions(void* address, size_t size,
PageAllocator::Permission access) {
return base::OS::SetPermissions(
address, size, static_cast<base::OS::MemoryPermission>(access));
}
} // namespace base
} // namespace v8
// Copyright 2017 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef V8_BASE_PAGE_ALLOCATOR_H_
#define V8_BASE_PAGE_ALLOCATOR_H_
#include "include/v8-platform.h"
#include "src/base/base-export.h"
#include "src/base/compiler-specific.h"
namespace v8 {
namespace base {
class V8_BASE_EXPORT PageAllocator
: public NON_EXPORTED_BASE(::v8::PageAllocator) {
public:
virtual ~PageAllocator() = default;
size_t AllocatePageSize() override;
size_t CommitPageSize() override;
void SetRandomMmapSeed(int64_t seed) override;
void* GetRandomMmapAddr() override;
void* AllocatePages(void* address, size_t size, size_t alignment,
PageAllocator::Permission access) override;
bool FreePages(void* address, size_t size) override;
bool ReleasePages(void* address, size_t size, size_t new_size) override;
bool SetPermissions(void* address, size_t size,
PageAllocator::Permission access) override;
};
} // namespace base
} // namespace v8
#endif // V8_BASE_PAGE_ALLOCATOR_H_
......@@ -37,11 +37,6 @@
namespace v8 {
namespace internal {
// TODO(bbudge) Move this to libplatform.
class DefaultMemoryManager;
} // namespace internal
namespace base {
// ----------------------------------------------------------------------------
......@@ -99,10 +94,9 @@ inline intptr_t InternalGetExistingThreadLocal(intptr_t index) {
#endif // V8_NO_FAST_TLS
class PageAllocator;
class TimezoneCache;
// ----------------------------------------------------------------------------
// OS
//
......@@ -161,9 +155,8 @@ class V8_BASE_EXPORT OS {
static PRINTF_FORMAT(1, 2) void PrintError(const char* format, ...);
static PRINTF_FORMAT(1, 0) void VPrintError(const char* format, va_list args);
// OS memory management API. Except for testing, use the equivalent API in
// v8::internal (src/allocation.h).
// Memory permissions. These should be kept in sync with the ones in
// v8::PageAllocator.
enum class MemoryPermission {
kNoAccess,
kReadWrite,
......@@ -256,7 +249,7 @@ class V8_BASE_EXPORT OS {
// These classes use the private memory management API below.
friend class MemoryMappedFile;
friend class PosixMemoryMappedFile;
friend class v8::internal::DefaultMemoryManager;
friend class v8::base::PageAllocator;
static size_t AllocatePageSize();
......
......@@ -148,7 +148,7 @@ class ShellArrayBufferAllocator : public ArrayBufferAllocatorBase {
// Rounding up could go over the limit.
if (allocated >= kTwoGB) return nullptr;
return i::AllocatePages(nullptr, allocated, page_size,
i::MemoryPermission::kReadWrite);
PageAllocator::kReadWrite);
}
void FreeVM(void* data, size_t length) {
......
......@@ -131,7 +131,7 @@ bool CodeRange::SetUp(size_t requested) {
// the beginning of an executable space.
if (reserved_area > 0) {
if (!reservation.SetPermissions(base, reserved_area,
MemoryPermission::kReadWrite))
PageAllocator::kReadWrite))
return false;
base += reserved_area;
......@@ -226,7 +226,7 @@ bool CodeRange::CommitRawMemory(Address start, size_t length) {
bool CodeRange::UncommitRawMemory(Address start, size_t length) {
return virtual_memory_.SetPermissions(start, length,
MemoryPermission::kNoAccess);
PageAllocator::kNoAccess);
}
......@@ -234,7 +234,7 @@ void CodeRange::FreeRawMemory(Address address, size_t length) {
DCHECK(IsAddressAligned(address, MemoryChunk::kAlignment));
base::LockGuard<base::Mutex> guard(&code_range_mutex_);
free_list_.emplace_back(address, length);
virtual_memory_.SetPermissions(address, length, MemoryPermission::kNoAccess);
virtual_memory_.SetPermissions(address, length, PageAllocator::kNoAccess);
}
bool CodeRange::ReserveBlock(const size_t requested_size, FreeBlock* block) {
......@@ -398,7 +398,7 @@ int MemoryAllocator::Unmapper::NumberOfChunks() {
bool MemoryAllocator::CommitMemory(Address base, size_t size,
Executability executable) {
if (!SetPermissions(base, size, MemoryPermission::kReadWrite)) {
if (!SetPermissions(base, size, PageAllocator::kReadWrite)) {
return false;
}
UpdateAllocatedSpaceLimits(base, base + size);
......@@ -460,7 +460,7 @@ Address MemoryAllocator::AllocateAlignedMemory(
}
} else {
if (reservation.SetPermissions(base, commit_size,
MemoryPermission::kReadWrite)) {
PageAllocator::kReadWrite)) {
UpdateAllocatedSpaceLimits(base, base + commit_size);
} else {
base = nullptr;
......@@ -525,7 +525,7 @@ void MemoryChunk::SetReadAndExecutable() {
DCHECK(IsAddressAligned(protect_start, page_size));
size_t protect_size = RoundUp(area_size(), page_size);
CHECK(SetPermissions(protect_start, protect_size,
MemoryPermission::kReadExecute));
PageAllocator::kReadExecute));
}
}
......@@ -544,7 +544,7 @@ void MemoryChunk::SetReadAndWritable() {
DCHECK(IsAddressAligned(unprotect_start, page_size));
size_t unprotect_size = RoundUp(area_size(), page_size);
CHECK(SetPermissions(unprotect_start, unprotect_size,
MemoryPermission::kReadWrite));
PageAllocator::kReadWrite));
}
}
......@@ -599,7 +599,7 @@ MemoryChunk* MemoryChunk::Initialize(Heap* heap, Address base, size_t size,
DCHECK(IsAddressAligned(area_start, page_size));
size_t area_size = RoundUp(area_end - area_start, page_size);
CHECK(SetPermissions(area_start, area_size,
MemoryPermission::kReadWriteExecute));
PageAllocator::kReadWriteExecute));
}
}
......@@ -939,7 +939,7 @@ void MemoryAllocator::PartialFreeMemory(MemoryChunk* chunk, Address start_free,
DCHECK_EQ(chunk->address() + chunk->size(),
chunk->area_end() + CodePageGuardSize());
reservation->SetPermissions(chunk->area_end_, page_size,
MemoryPermission::kNoAccess);
PageAllocator::kNoAccess);
}
// On e.g. Windows, a reservation may be larger than a page and releasing
// partially starting at |start_free| will also release the potentially
......@@ -1091,7 +1091,7 @@ bool MemoryAllocator::CommitBlock(Address start, size_t size,
bool MemoryAllocator::UncommitBlock(Address start, size_t size) {
if (!SetPermissions(start, size, MemoryPermission::kNoAccess)) return false;
if (!SetPermissions(start, size, PageAllocator::kNoAccess)) return false;
isolate_->counters()->memory_allocated()->Decrement(static_cast<int>(size));
return true;
}
......@@ -1158,24 +1158,23 @@ bool MemoryAllocator::CommitExecutableMemory(VirtualMemory* vm, Address start,
const Address code_area = start + code_area_offset;
const Address post_guard_page = start + reserved_size - guard_size;
// Commit the non-executable header, from start to pre-code guard page.
if (vm->SetPermissions(start, pre_guard_offset,
MemoryPermission::kReadWrite)) {
if (vm->SetPermissions(start, pre_guard_offset, PageAllocator::kReadWrite)) {
// Create the pre-code guard page, following the header.
if (vm->SetPermissions(pre_guard_page, page_size,
MemoryPermission::kNoAccess)) {
PageAllocator::kNoAccess)) {
// Commit the executable code body.
if (vm->SetPermissions(code_area, commit_size - pre_guard_offset,
MemoryPermission::kReadWrite)) {
PageAllocator::kReadWrite)) {
// Create the post-code guard page.
if (vm->SetPermissions(post_guard_page, page_size,
MemoryPermission::kNoAccess)) {
PageAllocator::kNoAccess)) {
UpdateAllocatedSpaceLimits(start, code_area + commit_size);
return true;
}
vm->SetPermissions(code_area, commit_size, MemoryPermission::kNoAccess);
vm->SetPermissions(code_area, commit_size, PageAllocator::kNoAccess);
}
}
vm->SetPermissions(start, pre_guard_offset, MemoryPermission::kNoAccess);
vm->SetPermissions(start, pre_guard_offset, PageAllocator::kNoAccess);
}
return false;
}
......
......@@ -58,7 +58,7 @@ void StoreBuffer::SetUp() {
if (!reservation.SetPermissions(reinterpret_cast<Address>(start_[0]),
kStoreBufferSize * kStoreBuffers,
MemoryPermission::kReadWrite)) {
PageAllocator::kReadWrite)) {
V8::FatalProcessOutOfMemory("StoreBuffer::SetUp");
}
current_ = 0;
......
......@@ -38,7 +38,7 @@ UnaryMathFunctionWithIsolate CreateSqrtFunction(Isolate* isolate) {
DCHECK(!RelocInfo::RequiresRelocation(isolate, desc));
Assembler::FlushICache(isolate, buffer, allocated);
CHECK(SetPermissions(buffer, allocated, MemoryPermission::kReadExecute));
CHECK(SetPermissions(buffer, allocated, PageAllocator::kReadExecute));
return FUNCTION_CAST<UnaryMathFunctionWithIsolate>(buffer);
}
......@@ -449,7 +449,7 @@ MemMoveFunction CreateMemMoveFunction(Isolate* isolate) {
masm.GetCode(isolate, &desc);
DCHECK(!RelocInfo::RequiresRelocation(isolate, desc));
Assembler::FlushICache(isolate, buffer, allocated);
CHECK(SetPermissions(buffer, allocated, MemoryPermission::kReadExecute));
CHECK(SetPermissions(buffer, allocated, PageAllocator::kReadExecute));
// TODO(jkummerow): It would be nice to register this code creation event
// with the PROFILE / GDBJIT system.
return FUNCTION_CAST<MemMoveFunction>(buffer);
......
......@@ -10,6 +10,7 @@
#include "include/libplatform/libplatform.h"
#include "src/base/debug/stack_trace.h"
#include "src/base/logging.h"
#include "src/base/page-allocator.h"
#include "src/base/platform/platform.h"
#include "src/base/platform/time.h"
#include "src/base/sys-info.h"
......@@ -84,6 +85,7 @@ DefaultPlatform::DefaultPlatform(
: thread_pool_size_(0),
idle_task_support_(idle_task_support),
tracing_controller_(std::move(tracing_controller)),
page_allocator_(new v8::base::PageAllocator()),
time_function_for_testing_(nullptr) {
if (!tracing_controller_) {
tracing::TracingController* controller = new tracing::TracingController();
......@@ -254,5 +256,9 @@ Platform::StackTracePrinter DefaultPlatform::GetStackTracePrinter() {
return PrintStackTrace;
}
v8::PageAllocator* DefaultPlatform::GetPageAllocator() {
return page_allocator_.get();
}
} // namespace platform
} // namespace v8
......@@ -27,6 +27,7 @@ class Thread;
class WorkerThread;
class DefaultForegroundTaskRunner;
class DefaultBackgroundTaskRunner;
class DefaultPageAllocator;
class V8_PLATFORM_EXPORT DefaultPlatform : public NON_EXPORTED_BASE(Platform) {
public:
......@@ -70,6 +71,7 @@ class V8_PLATFORM_EXPORT DefaultPlatform : public NON_EXPORTED_BASE(Platform) {
double CurrentClockTimeMillis() override;
v8::TracingController* GetTracingController() override;
StackTracePrinter GetStackTracePrinter() override;
v8::PageAllocator* GetPageAllocator() override;
private:
static const int kMaxThreadPoolSize;
......@@ -82,6 +84,7 @@ class V8_PLATFORM_EXPORT DefaultPlatform : public NON_EXPORTED_BASE(Platform) {
foreground_task_runner_map_;
std::unique_ptr<TracingController> tracing_controller_;
std::unique_ptr<PageAllocator> page_allocator_;
TimeFunction time_function_for_testing_;
DISALLOW_COPY_AND_ASSIGN(DefaultPlatform);
......
......@@ -544,7 +544,7 @@ MemCopyUint8Function CreateMemCopyUint8Function(Isolate* isolate,
DCHECK(!RelocInfo::RequiresRelocation(isolate, desc));
Assembler::FlushICache(isolate, buffer, allocated);
CHECK(SetPermissions(buffer, allocated, MemoryPermission::kReadExecute));
CHECK(SetPermissions(buffer, allocated, PageAllocator::kReadExecute));
return FUNCTION_CAST<MemCopyUint8Function>(buffer);
#endif
}
......@@ -571,7 +571,7 @@ UnaryMathFunctionWithIsolate CreateSqrtFunction(Isolate* isolate) {
DCHECK(!RelocInfo::RequiresRelocation(isolate, desc));
Assembler::FlushICache(isolate, buffer, allocated);
CHECK(SetPermissions(buffer, allocated, MemoryPermission::kReadExecute));
CHECK(SetPermissions(buffer, allocated, PageAllocator::kReadExecute));
return FUNCTION_CAST<UnaryMathFunctionWithIsolate>(buffer);
#endif
}
......
......@@ -545,7 +545,7 @@ MemCopyUint8Function CreateMemCopyUint8Function(Isolate* isolate,
DCHECK(!RelocInfo::RequiresRelocation(isolate, desc));
Assembler::FlushICache(isolate, buffer, allocated);
CHECK(SetPermissions(buffer, allocated, MemoryPermission::kReadExecute));
CHECK(SetPermissions(buffer, allocated, PageAllocator::kReadExecute));
return FUNCTION_CAST<MemCopyUint8Function>(buffer);
#endif
}
......@@ -572,7 +572,7 @@ UnaryMathFunctionWithIsolate CreateSqrtFunction(Isolate* isolate) {
DCHECK(!RelocInfo::RequiresRelocation(isolate, desc));
Assembler::FlushICache(isolate, buffer, allocated);
CHECK(SetPermissions(buffer, allocated, MemoryPermission::kReadExecute));
CHECK(SetPermissions(buffer, allocated, PageAllocator::kReadExecute));
return FUNCTION_CAST<UnaryMathFunctionWithIsolate>(buffer);
#endif
}
......
......@@ -40,7 +40,7 @@ UnaryMathFunctionWithIsolate CreateSqrtFunction(Isolate* isolate) {
!RelocInfo::RequiresRelocation(isolate, desc));
Assembler::FlushICache(isolate, buffer, allocated);
CHECK(SetPermissions(buffer, allocated, MemoryPermission::kReadExecute));
CHECK(SetPermissions(buffer, allocated, PageAllocator::kReadExecute));
return FUNCTION_CAST<UnaryMathFunctionWithIsolate>(buffer);
#endif
}
......
......@@ -37,7 +37,7 @@ UnaryMathFunctionWithIsolate CreateSqrtFunction(Isolate* isolate) {
!RelocInfo::RequiresRelocation(isolate, desc));
Assembler::FlushICache(isolate, buffer, allocated);
CHECK(SetPermissions(buffer, allocated, MemoryPermission::kReadExecute));
CHECK(SetPermissions(buffer, allocated, PageAllocator::kReadExecute));
return FUNCTION_CAST<UnaryMathFunctionWithIsolate>(buffer);
#endif
}
......
......@@ -1913,6 +1913,8 @@
'base/once.cc',
'base/once.h',
'base/optional.h',
'base/page-allocator.cc',
'base/page-allocator.h',
'base/platform/elapsed-timer.h',
'base/platform/time.cc',
'base/platform/time.h',
......
......@@ -693,7 +693,7 @@ bool WasmCodeManager::Commit(Address start, size_t size) {
remaining_uncommitted_.Increment(size);
return false;
}
bool ret = SetPermissions(start, size, MemoryPermission::kReadWrite);
bool ret = SetPermissions(start, size, PageAllocator::kReadWrite);
TRACE_HEAP("Setting rw permissions for %p:%p\n",
reinterpret_cast<void*>(start),
reinterpret_cast<void*>(start + size));
......@@ -794,8 +794,8 @@ bool NativeModule::SetExecutable(bool executable) {
if (is_executable_ == executable) return true;
TRACE_HEAP("Setting module %zu as executable: %d.\n", instance_id,
executable);
MemoryPermission permission = executable ? MemoryPermission::kReadExecute
: MemoryPermission::kReadWrite;
PageAllocator::Permission permission =
executable ? PageAllocator::kReadExecute : PageAllocator::kReadWrite;
#if V8_OS_WIN
// On windows, we need to switch permissions per separate virtual memory
......
......@@ -31,7 +31,7 @@ UnaryMathFunctionWithIsolate CreateSqrtFunction(Isolate* isolate) {
DCHECK(!RelocInfo::RequiresRelocation(isolate, desc));
Assembler::FlushICache(isolate, buffer, allocated);
CHECK(SetPermissions(buffer, allocated, MemoryPermission::kReadExecute));
CHECK(SetPermissions(buffer, allocated, PageAllocator::kReadExecute));
return FUNCTION_CAST<UnaryMathFunctionWithIsolate>(buffer);
}
......
......@@ -574,8 +574,7 @@ static inline uint8_t* AllocateAssemblerBuffer(
size_t page_size = v8::internal::AllocatePageSize();
size_t alloc_size = RoundUp(requested, page_size);
void* result = v8::internal::AllocatePages(
nullptr, alloc_size, page_size,
v8::internal::MemoryPermission::kReadWriteExecute);
nullptr, alloc_size, page_size, v8::PageAllocator::kReadWriteExecute);
CHECK(result);
*allocated = alloc_size;
return static_cast<uint8_t*>(result);
......@@ -583,8 +582,8 @@ static inline uint8_t* AllocateAssemblerBuffer(
static inline void MakeAssemblerBufferExecutable(uint8_t* buffer,
size_t allocated) {
bool result = v8::internal::SetPermissions(
buffer, allocated, v8::internal::MemoryPermission::kReadExecute);
bool result = v8::internal::SetPermissions(buffer, allocated,
v8::PageAllocator::kReadExecute);
CHECK(result);
}
......@@ -681,6 +680,10 @@ class ManualGCScope {
class TestPlatform : public v8::Platform {
public:
// v8::Platform implementation.
v8::PageAllocator* GetPageAllocator() override {
return old_platform_->GetPageAllocator();
}
void OnCriticalMemoryPressure() override {
old_platform_->OnCriticalMemoryPressure();
}
......
......@@ -93,7 +93,7 @@ class MemoryAllocationPermissionsTest : public ::testing::Test {
}
}
void TestPermissions(v8::internal::MemoryPermission permission, bool can_read,
void TestPermissions(PageAllocator::Permission permission, bool can_read,
bool can_write) {
const size_t page_size = AllocatePageSize();
int* buffer = static_cast<int*>(
......@@ -109,9 +109,9 @@ sigjmp_buf MemoryAllocationPermissionsTest::continuation_;
} // namespace
TEST_F(MemoryAllocationPermissionsTest, DoTest) {
TestPermissions(MemoryPermission::kNoAccess, false, false);
TestPermissions(MemoryPermission::kReadWrite, true, true);
TestPermissions(MemoryPermission::kReadWriteExecute, true, true);
TestPermissions(PageAllocator::Permission::kNoAccess, false, false);
TestPermissions(PageAllocator::Permission::kReadWrite, true, true);
TestPermissions(PageAllocator::Permission::kReadWriteExecute, true, true);
}
#endif // V8_OS_POSIX
......@@ -127,7 +127,7 @@ TEST(AllocationTest, AllocateAndFree) {
const size_t kAllocationSize = 1 * v8::internal::MB;
void* mem_addr = v8::internal::AllocatePages(
v8::internal::GetRandomMmapAddr(), kAllocationSize, page_size,
v8::internal::MemoryPermission::kReadWrite);
PageAllocator::Permission::kReadWrite);
CHECK_NOT_NULL(mem_addr);
CHECK(v8::internal::FreePages(mem_addr, kAllocationSize));
......@@ -135,7 +135,7 @@ TEST(AllocationTest, AllocateAndFree) {
const size_t kBigAlignment = 64 * v8::internal::MB;
void* aligned_mem_addr = v8::internal::AllocatePages(
v8::internal::GetRandomMmapAddr(), kAllocationSize, kBigAlignment,
v8::internal::MemoryPermission::kReadWrite);
PageAllocator::Permission::kReadWrite);
CHECK_NOT_NULL(aligned_mem_addr);
CHECK_EQ(aligned_mem_addr, AlignedAddress(aligned_mem_addr, kBigAlignment));
CHECK(v8::internal::FreePages(aligned_mem_addr, kAllocationSize));
......@@ -146,17 +146,17 @@ TEST(AllocationTest, ReserveMemory) {
const size_t kAllocationSize = 1 * v8::internal::MB;
void* mem_addr = v8::internal::AllocatePages(
v8::internal::GetRandomMmapAddr(), kAllocationSize, page_size,
v8::internal::MemoryPermission::kReadWrite);
PageAllocator::Permission::kReadWrite);
CHECK_NE(0, page_size);
CHECK_NOT_NULL(mem_addr);
size_t commit_size = v8::internal::CommitPageSize();
CHECK(v8::internal::SetPermissions(
mem_addr, commit_size, v8::internal::MemoryPermission::kReadWrite));
CHECK(v8::internal::SetPermissions(mem_addr, commit_size,
PageAllocator::Permission::kReadWrite));
// Check whether we can write to memory.
int* addr = static_cast<int*>(mem_addr);
addr[v8::internal::KB - 1] = 2;
CHECK(v8::internal::SetPermissions(
mem_addr, commit_size, v8::internal::MemoryPermission::kNoAccess));
CHECK(v8::internal::SetPermissions(mem_addr, commit_size,
PageAllocator::Permission::kNoAccess));
CHECK(v8::internal::FreePages(mem_addr, kAllocationSize));
}
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment