Commit 8c1e0383 authored by Igor Sheludko's avatar Igor Sheludko Committed by Commit Bot

[ptr-compr] Extend RegionAllocator functionality + a bit of cleanup.

This CL adds CheckRange() which will be used in DCHECKs in BoundedPageAllocator
and renames "min_region_size" to "page_size" for better readability.

Bug: v8:8096
Change-Id: I62cf7a92e50d0a11d462a9fbc34ddc5eda5456e1
Reviewed-on: https://chromium-review.googlesource.com/1209284Reviewed-by: 's avatarMichael Lippautz <mlippautz@chromium.org>
Commit-Queue: Igor Sheludko <ishell@chromium.org>
Cr-Commit-Position: refs/heads/master@{#55692}
parent 66398521
...@@ -17,18 +17,17 @@ constexpr double kMaxLoadFactorForRandomization = 0.40; ...@@ -17,18 +17,17 @@ constexpr double kMaxLoadFactorForRandomization = 0.40;
constexpr int kMaxRandomizationAttempts = 3; constexpr int kMaxRandomizationAttempts = 3;
RegionAllocator::RegionAllocator(Address memory_region_begin, RegionAllocator::RegionAllocator(Address memory_region_begin,
size_t memory_region_size, size_t memory_region_size, size_t page_size)
size_t min_region_size)
: whole_region_(memory_region_begin, memory_region_size, false), : whole_region_(memory_region_begin, memory_region_size, false),
region_size_in_min_regions_(size() / min_region_size), region_size_in_pages_(size() / page_size),
max_load_for_randomization_( max_load_for_randomization_(
static_cast<size_t>(size() * kMaxLoadFactorForRandomization)), static_cast<size_t>(size() * kMaxLoadFactorForRandomization)),
free_size_(0), free_size_(0),
min_region_size_(min_region_size) { page_size_(page_size) {
DCHECK_LT(begin(), end()); CHECK_LT(begin(), end());
DCHECK(base::bits::IsPowerOfTwo(min_region_size_)); CHECK(base::bits::IsPowerOfTwo(page_size_));
CHECK(IsAligned(size(), min_region_size_)); CHECK(IsAligned(size(), page_size_));
CHECK(IsAligned(begin(), min_region_size_)); CHECK(IsAligned(begin(), page_size_));
// Initial region. // Initial region.
Region* region = new Region(whole_region_); Region* region = new Region(whole_region_);
...@@ -70,8 +69,10 @@ RegionAllocator::Region* RegionAllocator::FreeListFindRegion(size_t size) { ...@@ -70,8 +69,10 @@ RegionAllocator::Region* RegionAllocator::FreeListFindRegion(size_t size) {
} }
void RegionAllocator::FreeListRemoveRegion(Region* region) { void RegionAllocator::FreeListRemoveRegion(Region* region) {
DCHECK(!region->is_used());
auto iter = free_regions_.find(region); auto iter = free_regions_.find(region);
DCHECK_NE(iter, free_regions_.end()); DCHECK_NE(iter, free_regions_.end());
DCHECK_EQ(region, *iter);
DCHECK_LE(region->size(), free_size_); DCHECK_LE(region->size(), free_size_);
free_size_ -= region->size(); free_size_ -= region->size();
free_regions_.erase(iter); free_regions_.erase(iter);
...@@ -79,13 +80,14 @@ void RegionAllocator::FreeListRemoveRegion(Region* region) { ...@@ -79,13 +80,14 @@ void RegionAllocator::FreeListRemoveRegion(Region* region) {
RegionAllocator::Region* RegionAllocator::Split(Region* region, RegionAllocator::Region* RegionAllocator::Split(Region* region,
size_t new_size) { size_t new_size) {
DCHECK(IsAligned(new_size, min_region_size_)); DCHECK(IsAligned(new_size, page_size_));
DCHECK_GT(region->size(), new_size); DCHECK_GT(region->size(), new_size);
// Create new region and put it to the lists after the |region|. // Create new region and put it to the lists after the |region|.
bool used = region->is_used();
Region* new_region = Region* new_region =
new Region(region->begin() + new_size, region->size() - new_size, false); new Region(region->begin() + new_size, region->size() - new_size, used);
if (!region->is_used()) { if (!used) {
// Remove region from the free list before updating it's size. // Remove region from the free list before updating it's size.
FreeListRemoveRegion(region); FreeListRemoveRegion(region);
} }
...@@ -93,8 +95,10 @@ RegionAllocator::Region* RegionAllocator::Split(Region* region, ...@@ -93,8 +95,10 @@ RegionAllocator::Region* RegionAllocator::Split(Region* region,
all_regions_.insert(new_region); all_regions_.insert(new_region);
if (!used) {
FreeListAddRegion(region); FreeListAddRegion(region);
FreeListAddRegion(new_region); FreeListAddRegion(new_region);
}
return new_region; return new_region;
} }
...@@ -114,7 +118,7 @@ void RegionAllocator::Merge(AllRegionsSet::iterator prev_iter, ...@@ -114,7 +118,7 @@ void RegionAllocator::Merge(AllRegionsSet::iterator prev_iter,
RegionAllocator::Address RegionAllocator::AllocateRegion(size_t size) { RegionAllocator::Address RegionAllocator::AllocateRegion(size_t size) {
DCHECK_NE(size, 0); DCHECK_NE(size, 0);
DCHECK(IsAligned(size, min_region_size_)); DCHECK(IsAligned(size, page_size_));
Region* region = FreeListFindRegion(size); Region* region = FreeListFindRegion(size);
if (region == nullptr) return kAllocationFailure; if (region == nullptr) return kAllocationFailure;
...@@ -122,7 +126,7 @@ RegionAllocator::Address RegionAllocator::AllocateRegion(size_t size) { ...@@ -122,7 +126,7 @@ RegionAllocator::Address RegionAllocator::AllocateRegion(size_t size) {
if (region->size() != size) { if (region->size() != size) {
Split(region, size); Split(region, size);
} }
DCHECK(IsAligned(region->begin(), min_region_size_)); DCHECK(IsAligned(region->begin(), page_size_));
DCHECK_EQ(region->size(), size); DCHECK_EQ(region->size(), size);
// Mark region as used. // Mark region as used.
...@@ -139,8 +143,7 @@ RegionAllocator::Address RegionAllocator::AllocateRegion( ...@@ -139,8 +143,7 @@ RegionAllocator::Address RegionAllocator::AllocateRegion(
for (int i = 0; i < kMaxRandomizationAttempts; i++) { for (int i = 0; i < kMaxRandomizationAttempts; i++) {
rng->NextBytes(&random, sizeof(random)); rng->NextBytes(&random, sizeof(random));
size_t random_offset = size_t random_offset = page_size_ * (random % region_size_in_pages_);
min_region_size_ * (random % region_size_in_min_regions_);
Address address = begin() + random_offset; Address address = begin() + random_offset;
if (AllocateRegionAt(address, size)) { if (AllocateRegionAt(address, size)) {
return address; return address;
...@@ -152,9 +155,9 @@ RegionAllocator::Address RegionAllocator::AllocateRegion( ...@@ -152,9 +155,9 @@ RegionAllocator::Address RegionAllocator::AllocateRegion(
} }
bool RegionAllocator::AllocateRegionAt(Address requested_address, size_t size) { bool RegionAllocator::AllocateRegionAt(Address requested_address, size_t size) {
DCHECK(IsAligned(requested_address, min_region_size_)); DCHECK(IsAligned(requested_address, page_size_));
DCHECK_NE(size, 0); DCHECK_NE(size, 0);
DCHECK(IsAligned(size, min_region_size_)); DCHECK(IsAligned(size, page_size_));
Address requested_end = requested_address + size; Address requested_end = requested_address + size;
DCHECK_LE(requested_end, end()); DCHECK_LE(requested_end, end());
...@@ -174,7 +177,7 @@ bool RegionAllocator::AllocateRegionAt(Address requested_address, size_t size) { ...@@ -174,7 +177,7 @@ bool RegionAllocator::AllocateRegionAt(Address requested_address, size_t size) {
if (region->begin() != requested_address) { if (region->begin() != requested_address) {
// Split the region at the |requested_address| boundary. // Split the region at the |requested_address| boundary.
size_t new_size = requested_address - region->begin(); size_t new_size = requested_address - region->begin();
DCHECK(IsAligned(new_size, min_region_size_)); DCHECK(IsAligned(new_size, page_size_));
region = Split(region, new_size); region = Split(region, new_size);
} }
if (region->end() != requested_end) { if (region->end() != requested_end) {
...@@ -236,6 +239,18 @@ size_t RegionAllocator::FreeRegion(Address address) { ...@@ -236,6 +239,18 @@ size_t RegionAllocator::FreeRegion(Address address) {
return size; return size;
} }
size_t RegionAllocator::CheckRegion(Address address) {
AllRegionsSet::iterator region_iter = FindRegion(address);
if (region_iter == all_regions_.end()) {
return 0;
}
Region* region = *region_iter;
if (region->begin() != address || !region->is_used()) {
return 0;
}
return region->size();
}
void RegionAllocator::Region::Print(std::ostream& os) const { void RegionAllocator::Region::Print(std::ostream& os) const {
std::ios::fmtflags flags = os.flags(std::ios::hex | std::ios::showbase); std::ios::fmtflags flags = os.flags(std::ios::hex | std::ios::showbase);
os << "[" << begin() << ", " << end() << "), size: " << size(); os << "[" << begin() << ", " << end() << "), size: " << size();
...@@ -248,7 +263,7 @@ void RegionAllocator::Print(std::ostream& os) const { ...@@ -248,7 +263,7 @@ void RegionAllocator::Print(std::ostream& os) const {
os << "RegionAllocator: [" << begin() << ", " << end() << ")"; os << "RegionAllocator: [" << begin() << ", " << end() << ")";
os << "\nsize: " << size(); os << "\nsize: " << size();
os << "\nfree_size: " << free_size(); os << "\nfree_size: " << free_size();
os << "\nmin_region_size: " << min_region_size_; os << "\npage_size: " << page_size_;
os << "\nall regions: "; os << "\nall regions: ";
for (const Region* region : all_regions_) { for (const Region* region : all_regions_) {
......
...@@ -14,8 +14,8 @@ namespace v8 { ...@@ -14,8 +14,8 @@ namespace v8 {
namespace base { namespace base {
// Helper class for managing used/free regions within [address, address+size) // Helper class for managing used/free regions within [address, address+size)
// region. Minimum allocation unit is |min_region_size|. // region. Minimum allocation unit is |page_size|. Requested allocation size
// Requested allocation size is rounded up to |min_region_size|. // is rounded up to |page_size|.
// The region allocation algorithm implements best-fit with coalescing strategy: // The region allocation algorithm implements best-fit with coalescing strategy:
// it tries to find a smallest suitable free region upon allocation and tries // it tries to find a smallest suitable free region upon allocation and tries
// to merge region with its neighbors upon freeing. // to merge region with its neighbors upon freeing.
...@@ -28,33 +28,46 @@ class V8_BASE_EXPORT RegionAllocator final { ...@@ -28,33 +28,46 @@ class V8_BASE_EXPORT RegionAllocator final {
static constexpr Address kAllocationFailure = static_cast<Address>(-1); static constexpr Address kAllocationFailure = static_cast<Address>(-1);
RegionAllocator(Address address, size_t size, size_t min_region_size); RegionAllocator(Address address, size_t size, size_t page_size);
~RegionAllocator(); ~RegionAllocator();
// Allocates region of |size| (must be |min_region_size|-aligned). Returns // Allocates region of |size| (must be |page_size|-aligned). Returns
// the address of the region on success or kAllocationFailure. // the address of the region on success or kAllocationFailure.
Address AllocateRegion(size_t size); Address AllocateRegion(size_t size);
// Same as above but tries to randomize the region displacement. // Same as above but tries to randomize the region displacement.
Address AllocateRegion(RandomNumberGenerator* rng, size_t size); Address AllocateRegion(RandomNumberGenerator* rng, size_t size);
// Allocates region of |size| at |requested_address| if it's free. Both the // Allocates region of |size| at |requested_address| if it's free. Both the
// address and the size must be |min_region_size|-aligned. On success returns // address and the size must be |page_size|-aligned. On success returns
// true. // true.
// This kind of allocation is supposed to be used during setup phase to mark // This kind of allocation is supposed to be used during setup phase to mark
// certain regions as used or for randomizing regions displacement. // certain regions as used or for randomizing regions displacement.
bool AllocateRegionAt(Address requested_address, size_t size); bool AllocateRegionAt(Address requested_address, size_t size);
// Frees region at given |address|, returns the size of the region. // Frees region at given |address|, returns the size of the region.
// The region must be previously allocated. Return 0 on failure. // There must be a used region starting at given address otherwise nothing
// will be freed and 0 will be returned.
size_t FreeRegion(Address address); size_t FreeRegion(Address address);
// If there is a used region starting at given address returns its size
// otherwise 0.
size_t CheckRegion(Address address);
Address begin() const { return whole_region_.begin(); } Address begin() const { return whole_region_.begin(); }
Address end() const { return whole_region_.end(); } Address end() const { return whole_region_.end(); }
size_t size() const { return whole_region_.size(); } size_t size() const { return whole_region_.size(); }
bool contains(Address address) const {
return whole_region_.contains(address);
}
// Total size of not yet aquired regions. // Total size of not yet aquired regions.
size_t free_size() const { return free_size_; } size_t free_size() const { return free_size_; }
// The alignment of the allocated region's addresses and granularity of
// the allocated region's sizes.
size_t page_size() const { return page_size_; }
void Print(std::ostream& os) const; void Print(std::ostream& os) const;
private: private:
...@@ -88,8 +101,8 @@ class V8_BASE_EXPORT RegionAllocator final { ...@@ -88,8 +101,8 @@ class V8_BASE_EXPORT RegionAllocator final {
// The whole region. // The whole region.
const Region whole_region_; const Region whole_region_;
// Number of |min_region_size_| in the whole region. // Number of |page_size_| in the whole region.
const size_t region_size_in_min_regions_; const size_t region_size_in_pages_;
// If the free size is less than this value - stop trying to randomize the // If the free size is less than this value - stop trying to randomize the
// allocation addresses. // allocation addresses.
...@@ -99,7 +112,7 @@ class V8_BASE_EXPORT RegionAllocator final { ...@@ -99,7 +112,7 @@ class V8_BASE_EXPORT RegionAllocator final {
size_t free_size_; size_t free_size_;
// Minimum region size. Must be a pow of 2. // Minimum region size. Must be a pow of 2.
const size_t min_region_size_; const size_t page_size_;
struct AddressEndOrder { struct AddressEndOrder {
bool operator()(const Region* a, const Region* b) const { bool operator()(const Region* a, const Region* b) const {
......
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