Line data Source code
1 : // Copyright 2018 the V8 project authors. All rights reserved.
2 : // Use of this source code is governed by a BSD-style license that can be
3 : // found in the LICENSE file.
4 :
5 : #include "src/base/bounded-page-allocator.h"
6 :
7 : namespace v8 {
8 : namespace base {
9 :
10 63938 : BoundedPageAllocator::BoundedPageAllocator(v8::PageAllocator* page_allocator,
11 : Address start, size_t size,
12 : size_t allocate_page_size)
13 : : allocate_page_size_(allocate_page_size),
14 63938 : commit_page_size_(page_allocator->CommitPageSize()),
15 : page_allocator_(page_allocator),
16 127876 : region_allocator_(start, size, allocate_page_size_) {
17 63938 : CHECK_NOT_NULL(page_allocator);
18 127876 : CHECK(IsAligned(allocate_page_size, page_allocator->AllocatePageSize()));
19 127876 : CHECK(IsAligned(allocate_page_size_, commit_page_size_));
20 63938 : }
21 :
22 0 : BoundedPageAllocator::Address BoundedPageAllocator::begin() const {
23 0 : return region_allocator_.begin();
24 : }
25 :
26 0 : size_t BoundedPageAllocator::size() const { return region_allocator_.size(); }
27 :
28 131637 : void* BoundedPageAllocator::AllocatePages(void* hint, size_t size,
29 : size_t alignment,
30 : PageAllocator::Permission access) {
31 131637 : MutexGuard guard(&mutex_);
32 131637 : CHECK(IsAligned(alignment, region_allocator_.page_size()));
33 :
34 : // Region allocator does not support alignments bigger than it's own
35 : // allocation alignment.
36 131637 : CHECK_LE(alignment, allocate_page_size_);
37 :
38 : // TODO(ishell): Consider using randomized version here.
39 131637 : Address address = region_allocator_.AllocateRegion(size);
40 131637 : if (address == RegionAllocator::kAllocationFailure) {
41 : return nullptr;
42 : }
43 131637 : CHECK(page_allocator_->SetPermissions(reinterpret_cast<void*>(address), size,
44 : access));
45 : return reinterpret_cast<void*>(address);
46 : }
47 :
48 1 : bool BoundedPageAllocator::AllocatePagesAt(Address address, size_t size,
49 : PageAllocator::Permission access) {
50 2 : CHECK(IsAligned(address, allocate_page_size_));
51 1 : CHECK(IsAligned(size, allocate_page_size_));
52 1 : CHECK(region_allocator_.contains(address, size));
53 :
54 1 : if (!region_allocator_.AllocateRegionAt(address, size)) {
55 : return false;
56 : }
57 1 : CHECK(page_allocator_->SetPermissions(reinterpret_cast<void*>(address), size,
58 : access));
59 : return true;
60 : }
61 :
62 131622 : bool BoundedPageAllocator::FreePages(void* raw_address, size_t size) {
63 131622 : MutexGuard guard(&mutex_);
64 :
65 131622 : Address address = reinterpret_cast<Address>(raw_address);
66 131622 : size_t freed_size = region_allocator_.FreeRegion(address);
67 131622 : if (freed_size != size) return false;
68 131622 : CHECK(page_allocator_->SetPermissions(raw_address, size,
69 : PageAllocator::kNoAccess));
70 : return true;
71 : }
72 :
73 62312 : bool BoundedPageAllocator::ReleasePages(void* raw_address, size_t size,
74 : size_t new_size) {
75 62312 : Address address = reinterpret_cast<Address>(raw_address);
76 124624 : CHECK(IsAligned(address, allocate_page_size_));
77 :
78 : DCHECK_LT(new_size, size);
79 : DCHECK(IsAligned(size - new_size, commit_page_size_));
80 :
81 : // Check if we freed any allocatable pages by this release.
82 62312 : size_t allocated_size = RoundUp(size, allocate_page_size_);
83 : size_t new_allocated_size = RoundUp(new_size, allocate_page_size_);
84 :
85 : #ifdef DEBUG
86 : {
87 : // There must be an allocated region at given |address| of a size not
88 : // smaller than |size|.
89 : MutexGuard guard(&mutex_);
90 : CHECK_EQ(allocated_size, region_allocator_.CheckRegion(address));
91 : }
92 : #endif
93 :
94 62312 : if (new_allocated_size < allocated_size) {
95 0 : MutexGuard guard(&mutex_);
96 0 : region_allocator_.TrimRegion(address, new_allocated_size);
97 : }
98 :
99 : // Keep the region in "used" state just uncommit some pages.
100 62312 : Address free_address = address + new_size;
101 62312 : size_t free_size = size - new_size;
102 124624 : return page_allocator_->SetPermissions(reinterpret_cast<void*>(free_address),
103 124624 : free_size, PageAllocator::kNoAccess);
104 : }
105 :
106 6648449 : bool BoundedPageAllocator::SetPermissions(void* address, size_t size,
107 : PageAllocator::Permission access) {
108 : DCHECK(IsAligned(reinterpret_cast<Address>(address), commit_page_size_));
109 : DCHECK(IsAligned(size, commit_page_size_));
110 : DCHECK(region_allocator_.contains(reinterpret_cast<Address>(address), size));
111 6648449 : return page_allocator_->SetPermissions(address, size, access);
112 : }
113 :
114 5336 : bool BoundedPageAllocator::DiscardSystemPages(void* address, size_t size) {
115 5336 : return page_allocator_->DiscardSystemPages(address, size);
116 : }
117 :
118 : } // namespace base
119 121996 : } // namespace v8
|