mirror of
https://github.com/dart-lang/sdk
synced 2024-09-05 00:13:50 +00:00
![Ryan Macnak](/assets/img/avatar_default.png)
TEST=build Change-Id: I33f93ed93699899ed3a1bea727522d268190da58 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/215882 Reviewed-by: Liam Appelbe <liama@google.com> Commit-Queue: Ryan Macnak <rmacnak@google.com>
151 lines
5 KiB
C++
151 lines
5 KiB
C++
// Copyright (c) 2021, the Dart project authors. Please see the AUTHORS file
|
|
// for details. All rights reserved. Use of this source code is governed by a
|
|
// BSD-style license that can be found in the LICENSE file.
|
|
|
|
#include "vm/virtual_memory_compressed.h"
|
|
|
|
#include "platform/utils.h"
|
|
|
|
#if defined(DART_COMPRESSED_HEAP)
|
|
|
|
namespace dart {
|
|
|
|
uword VirtualMemoryCompressedHeap::base_ = 0;
|
|
uword VirtualMemoryCompressedHeap::size_ = 0;
|
|
uint8_t* VirtualMemoryCompressedHeap::pages_ = nullptr;
|
|
uword VirtualMemoryCompressedHeap::minimum_free_page_id_ = 0;
|
|
Mutex* VirtualMemoryCompressedHeap::mutex_ = nullptr;
|
|
|
|
uint8_t PageMask(uword page_id) {
|
|
return static_cast<uint8_t>(1 << (page_id % 8));
|
|
}
|
|
|
|
bool VirtualMemoryCompressedHeap::IsPageUsed(uword page_id) {
|
|
if (page_id >= kCompressedHeapNumPages) return false;
|
|
return pages_[page_id / 8] & PageMask(page_id);
|
|
}
|
|
|
|
void VirtualMemoryCompressedHeap::SetPageUsed(uword page_id) {
|
|
ASSERT(page_id < kCompressedHeapNumPages);
|
|
pages_[page_id / 8] |= PageMask(page_id);
|
|
}
|
|
|
|
void VirtualMemoryCompressedHeap::ClearPageUsed(uword page_id) {
|
|
ASSERT(page_id < kCompressedHeapNumPages);
|
|
pages_[page_id / 8] &= ~PageMask(page_id);
|
|
}
|
|
|
|
void VirtualMemoryCompressedHeap::Init(void* compressed_heap_region,
|
|
size_t size) {
|
|
pages_ = new uint8_t[kCompressedHeapBitmapSize];
|
|
memset(pages_, 0, kCompressedHeapBitmapSize);
|
|
ASSERT(size > 0);
|
|
ASSERT(size <= kCompressedHeapSize);
|
|
for (intptr_t page_id = size / kCompressedHeapPageSize;
|
|
page_id < kCompressedHeapNumPages; page_id++) {
|
|
SetPageUsed(page_id);
|
|
}
|
|
base_ = reinterpret_cast<uword>(compressed_heap_region);
|
|
size_ = size;
|
|
ASSERT(base_ != 0);
|
|
ASSERT(size_ != 0);
|
|
ASSERT(size_ <= kCompressedHeapSize);
|
|
ASSERT(Utils::IsAligned(base_, kCompressedHeapPageSize));
|
|
ASSERT(Utils::IsAligned(size_, kCompressedHeapPageSize));
|
|
// base_ is not necessarily 4GB-aligned, because on some systems we can't make
|
|
// a large enough reservation to guarantee it. Instead, we have only the
|
|
// weaker property that all addresses in [base_, base_ + size_) have the same
|
|
// same upper 32 bits, which is what we really need for compressed pointers.
|
|
intptr_t mask = ~(kCompressedHeapAlignment - 1);
|
|
ASSERT((base_ & mask) == ((base_ + size_ - 1) & mask));
|
|
mutex_ = new Mutex(NOT_IN_PRODUCT("compressed_heap_mutex"));
|
|
}
|
|
|
|
void VirtualMemoryCompressedHeap::Cleanup() {
|
|
delete[] pages_;
|
|
delete mutex_;
|
|
base_ = 0;
|
|
size_ = 0;
|
|
pages_ = nullptr;
|
|
minimum_free_page_id_ = 0;
|
|
mutex_ = nullptr;
|
|
}
|
|
|
|
void* VirtualMemoryCompressedHeap::GetRegion() {
|
|
return reinterpret_cast<void*>(base_);
|
|
}
|
|
|
|
MemoryRegion VirtualMemoryCompressedHeap::Allocate(intptr_t size,
|
|
intptr_t alignment) {
|
|
ASSERT(alignment <= kCompressedHeapAlignment);
|
|
const intptr_t allocated_size = Utils::RoundUp(size, kCompressedHeapPageSize);
|
|
uword pages = allocated_size / kCompressedHeapPageSize;
|
|
uword page_alignment = alignment > kCompressedHeapPageSize
|
|
? alignment / kCompressedHeapPageSize
|
|
: 1;
|
|
MutexLocker ml(mutex_);
|
|
|
|
// Find a gap with enough empty pages, using the bitmap. Note that reading
|
|
// outside the bitmap range always returns 0, so this loop will terminate.
|
|
uword page_id = Utils::RoundUp(minimum_free_page_id_, page_alignment);
|
|
for (uword gap = 0;;) {
|
|
if (IsPageUsed(page_id)) {
|
|
gap = 0;
|
|
page_id = Utils::RoundUp(page_id + 1, page_alignment);
|
|
} else {
|
|
++gap;
|
|
if (gap >= pages) {
|
|
page_id += 1 - gap;
|
|
break;
|
|
}
|
|
++page_id;
|
|
}
|
|
}
|
|
ASSERT(page_id % page_alignment == 0);
|
|
|
|
// Make sure we're not trying to allocate past the end of the heap.
|
|
uword end = page_id + pages;
|
|
if (end > kCompressedHeapSize / kCompressedHeapPageSize) {
|
|
return MemoryRegion();
|
|
}
|
|
|
|
// Mark all the pages in the bitmap as allocated.
|
|
for (uword i = page_id; i < end; ++i) {
|
|
ASSERT(!IsPageUsed(i));
|
|
SetPageUsed(i);
|
|
}
|
|
|
|
// Find the next free page, to speed up subsequent allocations.
|
|
while (IsPageUsed(minimum_free_page_id_)) {
|
|
++minimum_free_page_id_;
|
|
}
|
|
|
|
uword address = base_ + page_id * kCompressedHeapPageSize;
|
|
ASSERT(Utils::IsAligned(address, kCompressedHeapPageSize));
|
|
return MemoryRegion(reinterpret_cast<void*>(address), allocated_size);
|
|
}
|
|
|
|
void VirtualMemoryCompressedHeap::Free(void* address, intptr_t size) {
|
|
uword start = reinterpret_cast<uword>(address);
|
|
ASSERT(Utils::IsAligned(start, kCompressedHeapPageSize));
|
|
ASSERT(Utils::IsAligned(size, kCompressedHeapPageSize));
|
|
MutexLocker ml(mutex_);
|
|
ASSERT(start >= base_);
|
|
uword page_id = (start - base_) / kCompressedHeapPageSize;
|
|
uword end = page_id + size / kCompressedHeapPageSize;
|
|
for (uword i = page_id; i < end; ++i) {
|
|
ClearPageUsed(i);
|
|
}
|
|
if (page_id < minimum_free_page_id_) {
|
|
minimum_free_page_id_ = page_id;
|
|
}
|
|
}
|
|
|
|
bool VirtualMemoryCompressedHeap::Contains(void* address) {
|
|
return (reinterpret_cast<uword>(address) - base_) < size_;
|
|
}
|
|
|
|
} // namespace dart
|
|
|
|
#endif // defined(DART_COMPRESSED_HEAP)
|