1*795d594fSAndroid Build Coastguard Worker /*
2*795d594fSAndroid Build Coastguard Worker * Copyright (C) 2013 The Android Open Source Project
3*795d594fSAndroid Build Coastguard Worker *
4*795d594fSAndroid Build Coastguard Worker * Licensed under the Apache License, Version 2.0 (the "License");
5*795d594fSAndroid Build Coastguard Worker * you may not use this file except in compliance with the License.
6*795d594fSAndroid Build Coastguard Worker * You may obtain a copy of the License at
7*795d594fSAndroid Build Coastguard Worker *
8*795d594fSAndroid Build Coastguard Worker * http://www.apache.org/licenses/LICENSE-2.0
9*795d594fSAndroid Build Coastguard Worker *
10*795d594fSAndroid Build Coastguard Worker * Unless required by applicable law or agreed to in writing, software
11*795d594fSAndroid Build Coastguard Worker * distributed under the License is distributed on an "AS IS" BASIS,
12*795d594fSAndroid Build Coastguard Worker * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*795d594fSAndroid Build Coastguard Worker * See the License for the specific language governing permissions and
14*795d594fSAndroid Build Coastguard Worker * limitations under the License.
15*795d594fSAndroid Build Coastguard Worker */
16*795d594fSAndroid Build Coastguard Worker
17*795d594fSAndroid Build Coastguard Worker #include "rosalloc-inl.h"
18*795d594fSAndroid Build Coastguard Worker
19*795d594fSAndroid Build Coastguard Worker #include <list>
20*795d594fSAndroid Build Coastguard Worker #include <map>
21*795d594fSAndroid Build Coastguard Worker #include <sstream>
22*795d594fSAndroid Build Coastguard Worker #include <vector>
23*795d594fSAndroid Build Coastguard Worker
24*795d594fSAndroid Build Coastguard Worker #include "android-base/stringprintf.h"
25*795d594fSAndroid Build Coastguard Worker
26*795d594fSAndroid Build Coastguard Worker #include "base/logging.h" // For VLOG
27*795d594fSAndroid Build Coastguard Worker #include "base/memory_tool.h"
28*795d594fSAndroid Build Coastguard Worker #include "base/mem_map.h"
29*795d594fSAndroid Build Coastguard Worker #include "base/mutex-inl.h"
30*795d594fSAndroid Build Coastguard Worker #include "gc/space/memory_tool_settings.h"
31*795d594fSAndroid Build Coastguard Worker #include "mirror/class-inl.h"
32*795d594fSAndroid Build Coastguard Worker #include "mirror/object-inl.h"
33*795d594fSAndroid Build Coastguard Worker #include "mirror/object.h"
34*795d594fSAndroid Build Coastguard Worker #include "thread-current-inl.h"
35*795d594fSAndroid Build Coastguard Worker #include "thread_list.h"
36*795d594fSAndroid Build Coastguard Worker
37*795d594fSAndroid Build Coastguard Worker namespace art HIDDEN {
38*795d594fSAndroid Build Coastguard Worker namespace gc {
39*795d594fSAndroid Build Coastguard Worker namespace allocator {
40*795d594fSAndroid Build Coastguard Worker
41*795d594fSAndroid Build Coastguard Worker using android::base::StringPrintf;
42*795d594fSAndroid Build Coastguard Worker
43*795d594fSAndroid Build Coastguard Worker static constexpr bool kUsePrefetchDuringAllocRun = false;
44*795d594fSAndroid Build Coastguard Worker static constexpr bool kPrefetchNewRunDataByZeroing = false;
45*795d594fSAndroid Build Coastguard Worker static constexpr size_t kPrefetchStride = 64;
46*795d594fSAndroid Build Coastguard Worker
47*795d594fSAndroid Build Coastguard Worker size_t RosAlloc::bracketSizes[kNumOfSizeBrackets];
48*795d594fSAndroid Build Coastguard Worker size_t RosAlloc::numOfPages[kNumOfSizeBrackets];
49*795d594fSAndroid Build Coastguard Worker size_t RosAlloc::numOfSlots[kNumOfSizeBrackets];
50*795d594fSAndroid Build Coastguard Worker size_t RosAlloc::headerSizes[kNumOfSizeBrackets];
51*795d594fSAndroid Build Coastguard Worker bool RosAlloc::initialized_ = false;
52*795d594fSAndroid Build Coastguard Worker size_t RosAlloc::dedicated_full_run_storage_[kMaxPageSize / sizeof(size_t)] = { 0 };
53*795d594fSAndroid Build Coastguard Worker RosAlloc::Run* RosAlloc::dedicated_full_run_ =
54*795d594fSAndroid Build Coastguard Worker reinterpret_cast<RosAlloc::Run*>(dedicated_full_run_storage_);
55*795d594fSAndroid Build Coastguard Worker
RosAlloc(void * base,size_t capacity,size_t max_capacity,PageReleaseMode page_release_mode,bool running_on_memory_tool,size_t page_release_size_threshold)56*795d594fSAndroid Build Coastguard Worker RosAlloc::RosAlloc(void* base, size_t capacity, size_t max_capacity,
57*795d594fSAndroid Build Coastguard Worker PageReleaseMode page_release_mode, bool running_on_memory_tool,
58*795d594fSAndroid Build Coastguard Worker size_t page_release_size_threshold)
59*795d594fSAndroid Build Coastguard Worker : base_(reinterpret_cast<uint8_t*>(base)), footprint_(capacity),
60*795d594fSAndroid Build Coastguard Worker capacity_(capacity), max_capacity_(max_capacity),
61*795d594fSAndroid Build Coastguard Worker lock_("rosalloc global lock", kRosAllocGlobalLock),
62*795d594fSAndroid Build Coastguard Worker bulk_free_lock_("rosalloc bulk free lock", kRosAllocBulkFreeLock),
63*795d594fSAndroid Build Coastguard Worker page_release_mode_(page_release_mode),
64*795d594fSAndroid Build Coastguard Worker page_release_size_threshold_(page_release_size_threshold),
65*795d594fSAndroid Build Coastguard Worker is_running_on_memory_tool_(running_on_memory_tool) {
66*795d594fSAndroid Build Coastguard Worker DCHECK_ALIGNED_PARAM(base, gPageSize);
67*795d594fSAndroid Build Coastguard Worker DCHECK_EQ(RoundUp(capacity, gPageSize), capacity);
68*795d594fSAndroid Build Coastguard Worker DCHECK_EQ(RoundUp(max_capacity, gPageSize), max_capacity);
69*795d594fSAndroid Build Coastguard Worker CHECK_LE(capacity, max_capacity);
70*795d594fSAndroid Build Coastguard Worker CHECK_ALIGNED_PARAM(page_release_size_threshold_, gPageSize);
71*795d594fSAndroid Build Coastguard Worker // Zero the memory explicitly (don't rely on that the mem map is zero-initialized).
72*795d594fSAndroid Build Coastguard Worker if (!kMadviseZeroes) {
73*795d594fSAndroid Build Coastguard Worker memset(base_, 0, max_capacity);
74*795d594fSAndroid Build Coastguard Worker }
75*795d594fSAndroid Build Coastguard Worker CHECK_EQ(madvise(base_, max_capacity, MADV_DONTNEED), 0);
76*795d594fSAndroid Build Coastguard Worker if (!initialized_) {
77*795d594fSAndroid Build Coastguard Worker Initialize();
78*795d594fSAndroid Build Coastguard Worker }
79*795d594fSAndroid Build Coastguard Worker VLOG(heap) << "RosAlloc base="
80*795d594fSAndroid Build Coastguard Worker << std::hex << (intptr_t)base_ << ", end="
81*795d594fSAndroid Build Coastguard Worker << std::hex << (intptr_t)(base_ + capacity_)
82*795d594fSAndroid Build Coastguard Worker << ", capacity=" << std::dec << capacity_
83*795d594fSAndroid Build Coastguard Worker << ", max_capacity=" << std::dec << max_capacity_;
84*795d594fSAndroid Build Coastguard Worker for (size_t i = 0; i < kNumOfSizeBrackets; i++) {
85*795d594fSAndroid Build Coastguard Worker size_bracket_lock_names_[i] =
86*795d594fSAndroid Build Coastguard Worker StringPrintf("an rosalloc size bracket %d lock", static_cast<int>(i));
87*795d594fSAndroid Build Coastguard Worker size_bracket_locks_[i] = new Mutex(size_bracket_lock_names_[i].c_str(), kRosAllocBracketLock);
88*795d594fSAndroid Build Coastguard Worker current_runs_[i] = dedicated_full_run_;
89*795d594fSAndroid Build Coastguard Worker }
90*795d594fSAndroid Build Coastguard Worker DCHECK_EQ(footprint_, capacity_);
91*795d594fSAndroid Build Coastguard Worker size_t num_of_pages = DivideByPageSize(footprint_);
92*795d594fSAndroid Build Coastguard Worker size_t max_num_of_pages = DivideByPageSize(max_capacity_);
93*795d594fSAndroid Build Coastguard Worker std::string error_msg;
94*795d594fSAndroid Build Coastguard Worker page_map_mem_map_ = MemMap::MapAnonymous("rosalloc page map",
95*795d594fSAndroid Build Coastguard Worker RoundUp(max_num_of_pages, gPageSize),
96*795d594fSAndroid Build Coastguard Worker PROT_READ | PROT_WRITE,
97*795d594fSAndroid Build Coastguard Worker /*low_4gb=*/ false,
98*795d594fSAndroid Build Coastguard Worker &error_msg);
99*795d594fSAndroid Build Coastguard Worker CHECK(page_map_mem_map_.IsValid()) << "Couldn't allocate the page map : " << error_msg;
100*795d594fSAndroid Build Coastguard Worker page_map_ = page_map_mem_map_.Begin();
101*795d594fSAndroid Build Coastguard Worker page_map_size_ = num_of_pages;
102*795d594fSAndroid Build Coastguard Worker max_page_map_size_ = max_num_of_pages;
103*795d594fSAndroid Build Coastguard Worker free_page_run_size_map_.resize(num_of_pages);
104*795d594fSAndroid Build Coastguard Worker FreePageRun* free_pages = reinterpret_cast<FreePageRun*>(base_);
105*795d594fSAndroid Build Coastguard Worker if (kIsDebugBuild) {
106*795d594fSAndroid Build Coastguard Worker free_pages->magic_num_ = kMagicNumFree;
107*795d594fSAndroid Build Coastguard Worker }
108*795d594fSAndroid Build Coastguard Worker free_pages->SetByteSize(this, capacity_);
109*795d594fSAndroid Build Coastguard Worker DCHECK_EQ(ModuloPageSize(capacity_), static_cast<size_t>(0));
110*795d594fSAndroid Build Coastguard Worker DCHECK(free_pages->IsFree());
111*795d594fSAndroid Build Coastguard Worker free_pages->ReleasePages(this);
112*795d594fSAndroid Build Coastguard Worker DCHECK(free_pages->IsFree());
113*795d594fSAndroid Build Coastguard Worker free_page_runs_.insert(free_pages);
114*795d594fSAndroid Build Coastguard Worker if (kTraceRosAlloc) {
115*795d594fSAndroid Build Coastguard Worker LOG(INFO) << "RosAlloc::RosAlloc() : Inserted run 0x" << std::hex
116*795d594fSAndroid Build Coastguard Worker << reinterpret_cast<intptr_t>(free_pages)
117*795d594fSAndroid Build Coastguard Worker << " into free_page_runs_";
118*795d594fSAndroid Build Coastguard Worker }
119*795d594fSAndroid Build Coastguard Worker }
120*795d594fSAndroid Build Coastguard Worker
~RosAlloc()121*795d594fSAndroid Build Coastguard Worker RosAlloc::~RosAlloc() {
122*795d594fSAndroid Build Coastguard Worker for (size_t i = 0; i < kNumOfSizeBrackets; i++) {
123*795d594fSAndroid Build Coastguard Worker delete size_bracket_locks_[i];
124*795d594fSAndroid Build Coastguard Worker }
125*795d594fSAndroid Build Coastguard Worker if (is_running_on_memory_tool_) {
126*795d594fSAndroid Build Coastguard Worker MEMORY_TOOL_MAKE_DEFINED(base_, capacity_);
127*795d594fSAndroid Build Coastguard Worker }
128*795d594fSAndroid Build Coastguard Worker }
129*795d594fSAndroid Build Coastguard Worker
AllocPages(Thread * self,size_t num_pages,uint8_t page_map_type)130*795d594fSAndroid Build Coastguard Worker void* RosAlloc::AllocPages(Thread* self, size_t num_pages, uint8_t page_map_type) {
131*795d594fSAndroid Build Coastguard Worker lock_.AssertHeld(self);
132*795d594fSAndroid Build Coastguard Worker DCHECK(page_map_type == kPageMapRun || page_map_type == kPageMapLargeObject);
133*795d594fSAndroid Build Coastguard Worker FreePageRun* res = nullptr;
134*795d594fSAndroid Build Coastguard Worker const size_t req_byte_size = num_pages * gPageSize;
135*795d594fSAndroid Build Coastguard Worker // Find the lowest address free page run that's large enough.
136*795d594fSAndroid Build Coastguard Worker for (auto it = free_page_runs_.begin(); it != free_page_runs_.end(); ) {
137*795d594fSAndroid Build Coastguard Worker FreePageRun* fpr = *it;
138*795d594fSAndroid Build Coastguard Worker DCHECK(fpr->IsFree());
139*795d594fSAndroid Build Coastguard Worker size_t fpr_byte_size = fpr->ByteSize(this);
140*795d594fSAndroid Build Coastguard Worker DCHECK_EQ(ModuloPageSize(fpr_byte_size), static_cast<size_t>(0));
141*795d594fSAndroid Build Coastguard Worker if (req_byte_size <= fpr_byte_size) {
142*795d594fSAndroid Build Coastguard Worker // Found one.
143*795d594fSAndroid Build Coastguard Worker it = free_page_runs_.erase(it);
144*795d594fSAndroid Build Coastguard Worker if (kTraceRosAlloc) {
145*795d594fSAndroid Build Coastguard Worker LOG(INFO) << "RosAlloc::AllocPages() : Erased run 0x"
146*795d594fSAndroid Build Coastguard Worker << std::hex << reinterpret_cast<intptr_t>(fpr)
147*795d594fSAndroid Build Coastguard Worker << " from free_page_runs_";
148*795d594fSAndroid Build Coastguard Worker }
149*795d594fSAndroid Build Coastguard Worker if (req_byte_size < fpr_byte_size) {
150*795d594fSAndroid Build Coastguard Worker // Split.
151*795d594fSAndroid Build Coastguard Worker FreePageRun* remainder =
152*795d594fSAndroid Build Coastguard Worker reinterpret_cast<FreePageRun*>(reinterpret_cast<uint8_t*>(fpr) + req_byte_size);
153*795d594fSAndroid Build Coastguard Worker if (kIsDebugBuild) {
154*795d594fSAndroid Build Coastguard Worker remainder->magic_num_ = kMagicNumFree;
155*795d594fSAndroid Build Coastguard Worker }
156*795d594fSAndroid Build Coastguard Worker remainder->SetByteSize(this, fpr_byte_size - req_byte_size);
157*795d594fSAndroid Build Coastguard Worker DCHECK_EQ(ModuloPageSize(remainder->ByteSize(this)), static_cast<size_t>(0));
158*795d594fSAndroid Build Coastguard Worker // Don't need to call madvise on remainder here.
159*795d594fSAndroid Build Coastguard Worker free_page_runs_.insert(remainder);
160*795d594fSAndroid Build Coastguard Worker if (kTraceRosAlloc) {
161*795d594fSAndroid Build Coastguard Worker LOG(INFO) << "RosAlloc::AllocPages() : Inserted run 0x" << std::hex
162*795d594fSAndroid Build Coastguard Worker << reinterpret_cast<intptr_t>(remainder)
163*795d594fSAndroid Build Coastguard Worker << " into free_page_runs_";
164*795d594fSAndroid Build Coastguard Worker }
165*795d594fSAndroid Build Coastguard Worker fpr->SetByteSize(this, req_byte_size);
166*795d594fSAndroid Build Coastguard Worker DCHECK_EQ(ModuloPageSize(fpr->ByteSize(this)), static_cast<size_t>(0));
167*795d594fSAndroid Build Coastguard Worker }
168*795d594fSAndroid Build Coastguard Worker res = fpr;
169*795d594fSAndroid Build Coastguard Worker break;
170*795d594fSAndroid Build Coastguard Worker } else {
171*795d594fSAndroid Build Coastguard Worker ++it;
172*795d594fSAndroid Build Coastguard Worker }
173*795d594fSAndroid Build Coastguard Worker }
174*795d594fSAndroid Build Coastguard Worker
175*795d594fSAndroid Build Coastguard Worker // Failed to allocate pages. Grow the footprint, if possible.
176*795d594fSAndroid Build Coastguard Worker if (UNLIKELY(res == nullptr && capacity_ > footprint_)) {
177*795d594fSAndroid Build Coastguard Worker FreePageRun* last_free_page_run = nullptr;
178*795d594fSAndroid Build Coastguard Worker size_t last_free_page_run_size;
179*795d594fSAndroid Build Coastguard Worker auto it = free_page_runs_.rbegin();
180*795d594fSAndroid Build Coastguard Worker if (it != free_page_runs_.rend() && (last_free_page_run = *it)->End(this) == base_ + footprint_) {
181*795d594fSAndroid Build Coastguard Worker // There is a free page run at the end.
182*795d594fSAndroid Build Coastguard Worker DCHECK(last_free_page_run->IsFree());
183*795d594fSAndroid Build Coastguard Worker DCHECK(IsFreePage(ToPageMapIndex(last_free_page_run)));
184*795d594fSAndroid Build Coastguard Worker last_free_page_run_size = last_free_page_run->ByteSize(this);
185*795d594fSAndroid Build Coastguard Worker } else {
186*795d594fSAndroid Build Coastguard Worker // There is no free page run at the end.
187*795d594fSAndroid Build Coastguard Worker last_free_page_run_size = 0;
188*795d594fSAndroid Build Coastguard Worker }
189*795d594fSAndroid Build Coastguard Worker DCHECK_LT(last_free_page_run_size, req_byte_size);
190*795d594fSAndroid Build Coastguard Worker if (capacity_ - footprint_ + last_free_page_run_size >= req_byte_size) {
191*795d594fSAndroid Build Coastguard Worker // If we grow the heap, we can allocate it.
192*795d594fSAndroid Build Coastguard Worker size_t increment = std::min(std::max(2 * MB, req_byte_size - last_free_page_run_size),
193*795d594fSAndroid Build Coastguard Worker capacity_ - footprint_);
194*795d594fSAndroid Build Coastguard Worker DCHECK_EQ(ModuloPageSize(increment), static_cast<size_t>(0));
195*795d594fSAndroid Build Coastguard Worker size_t new_footprint = footprint_ + increment;
196*795d594fSAndroid Build Coastguard Worker size_t new_num_of_pages = DivideByPageSize(new_footprint);
197*795d594fSAndroid Build Coastguard Worker DCHECK_LT(page_map_size_, new_num_of_pages);
198*795d594fSAndroid Build Coastguard Worker DCHECK_LT(free_page_run_size_map_.size(), new_num_of_pages);
199*795d594fSAndroid Build Coastguard Worker page_map_size_ = new_num_of_pages;
200*795d594fSAndroid Build Coastguard Worker DCHECK_LE(page_map_size_, max_page_map_size_);
201*795d594fSAndroid Build Coastguard Worker free_page_run_size_map_.resize(new_num_of_pages);
202*795d594fSAndroid Build Coastguard Worker ArtRosAllocMoreCore(this, increment);
203*795d594fSAndroid Build Coastguard Worker if (last_free_page_run_size > 0) {
204*795d594fSAndroid Build Coastguard Worker // There was a free page run at the end. Expand its size.
205*795d594fSAndroid Build Coastguard Worker DCHECK_EQ(last_free_page_run_size, last_free_page_run->ByteSize(this));
206*795d594fSAndroid Build Coastguard Worker last_free_page_run->SetByteSize(this, last_free_page_run_size + increment);
207*795d594fSAndroid Build Coastguard Worker DCHECK_EQ(ModuloPageSize(last_free_page_run->ByteSize(this)), static_cast<size_t>(0));
208*795d594fSAndroid Build Coastguard Worker DCHECK_EQ(last_free_page_run->End(this), base_ + new_footprint);
209*795d594fSAndroid Build Coastguard Worker } else {
210*795d594fSAndroid Build Coastguard Worker // Otherwise, insert a new free page run at the end.
211*795d594fSAndroid Build Coastguard Worker FreePageRun* new_free_page_run = reinterpret_cast<FreePageRun*>(base_ + footprint_);
212*795d594fSAndroid Build Coastguard Worker if (kIsDebugBuild) {
213*795d594fSAndroid Build Coastguard Worker new_free_page_run->magic_num_ = kMagicNumFree;
214*795d594fSAndroid Build Coastguard Worker }
215*795d594fSAndroid Build Coastguard Worker new_free_page_run->SetByteSize(this, increment);
216*795d594fSAndroid Build Coastguard Worker DCHECK_EQ(ModuloPageSize(new_free_page_run->ByteSize(this)), static_cast<size_t>(0));
217*795d594fSAndroid Build Coastguard Worker free_page_runs_.insert(new_free_page_run);
218*795d594fSAndroid Build Coastguard Worker DCHECK_EQ(*free_page_runs_.rbegin(), new_free_page_run);
219*795d594fSAndroid Build Coastguard Worker if (kTraceRosAlloc) {
220*795d594fSAndroid Build Coastguard Worker LOG(INFO) << "RosAlloc::AlloPages() : Grew the heap by inserting run 0x"
221*795d594fSAndroid Build Coastguard Worker << std::hex << reinterpret_cast<intptr_t>(new_free_page_run)
222*795d594fSAndroid Build Coastguard Worker << " into free_page_runs_";
223*795d594fSAndroid Build Coastguard Worker }
224*795d594fSAndroid Build Coastguard Worker }
225*795d594fSAndroid Build Coastguard Worker DCHECK_LE(footprint_ + increment, capacity_);
226*795d594fSAndroid Build Coastguard Worker if (kTraceRosAlloc) {
227*795d594fSAndroid Build Coastguard Worker LOG(INFO) << "RosAlloc::AllocPages() : increased the footprint from "
228*795d594fSAndroid Build Coastguard Worker << footprint_ << " to " << new_footprint;
229*795d594fSAndroid Build Coastguard Worker }
230*795d594fSAndroid Build Coastguard Worker footprint_ = new_footprint;
231*795d594fSAndroid Build Coastguard Worker
232*795d594fSAndroid Build Coastguard Worker // And retry the last free page run.
233*795d594fSAndroid Build Coastguard Worker it = free_page_runs_.rbegin();
234*795d594fSAndroid Build Coastguard Worker DCHECK(it != free_page_runs_.rend());
235*795d594fSAndroid Build Coastguard Worker FreePageRun* fpr = *it;
236*795d594fSAndroid Build Coastguard Worker if (kIsDebugBuild && last_free_page_run_size > 0) {
237*795d594fSAndroid Build Coastguard Worker DCHECK(last_free_page_run != nullptr);
238*795d594fSAndroid Build Coastguard Worker DCHECK_EQ(last_free_page_run, fpr);
239*795d594fSAndroid Build Coastguard Worker }
240*795d594fSAndroid Build Coastguard Worker size_t fpr_byte_size = fpr->ByteSize(this);
241*795d594fSAndroid Build Coastguard Worker DCHECK_EQ(ModuloPageSize(fpr_byte_size), static_cast<size_t>(0));
242*795d594fSAndroid Build Coastguard Worker DCHECK_LE(req_byte_size, fpr_byte_size);
243*795d594fSAndroid Build Coastguard Worker free_page_runs_.erase(fpr);
244*795d594fSAndroid Build Coastguard Worker if (kTraceRosAlloc) {
245*795d594fSAndroid Build Coastguard Worker LOG(INFO) << "RosAlloc::AllocPages() : Erased run 0x" << std::hex << reinterpret_cast<intptr_t>(fpr)
246*795d594fSAndroid Build Coastguard Worker << " from free_page_runs_";
247*795d594fSAndroid Build Coastguard Worker }
248*795d594fSAndroid Build Coastguard Worker if (req_byte_size < fpr_byte_size) {
249*795d594fSAndroid Build Coastguard Worker // Split if there's a remainder.
250*795d594fSAndroid Build Coastguard Worker FreePageRun* remainder = reinterpret_cast<FreePageRun*>(reinterpret_cast<uint8_t*>(fpr) + req_byte_size);
251*795d594fSAndroid Build Coastguard Worker if (kIsDebugBuild) {
252*795d594fSAndroid Build Coastguard Worker remainder->magic_num_ = kMagicNumFree;
253*795d594fSAndroid Build Coastguard Worker }
254*795d594fSAndroid Build Coastguard Worker remainder->SetByteSize(this, fpr_byte_size - req_byte_size);
255*795d594fSAndroid Build Coastguard Worker DCHECK_EQ(ModuloPageSize(remainder->ByteSize(this)), static_cast<size_t>(0));
256*795d594fSAndroid Build Coastguard Worker free_page_runs_.insert(remainder);
257*795d594fSAndroid Build Coastguard Worker if (kTraceRosAlloc) {
258*795d594fSAndroid Build Coastguard Worker LOG(INFO) << "RosAlloc::AllocPages() : Inserted run 0x" << std::hex
259*795d594fSAndroid Build Coastguard Worker << reinterpret_cast<intptr_t>(remainder)
260*795d594fSAndroid Build Coastguard Worker << " into free_page_runs_";
261*795d594fSAndroid Build Coastguard Worker }
262*795d594fSAndroid Build Coastguard Worker fpr->SetByteSize(this, req_byte_size);
263*795d594fSAndroid Build Coastguard Worker DCHECK_EQ(ModuloPageSize(fpr->ByteSize(this)), static_cast<size_t>(0));
264*795d594fSAndroid Build Coastguard Worker }
265*795d594fSAndroid Build Coastguard Worker res = fpr;
266*795d594fSAndroid Build Coastguard Worker }
267*795d594fSAndroid Build Coastguard Worker }
268*795d594fSAndroid Build Coastguard Worker if (LIKELY(res != nullptr)) {
269*795d594fSAndroid Build Coastguard Worker // Update the page map.
270*795d594fSAndroid Build Coastguard Worker size_t page_map_idx = ToPageMapIndex(res);
271*795d594fSAndroid Build Coastguard Worker for (size_t i = 0; i < num_pages; i++) {
272*795d594fSAndroid Build Coastguard Worker DCHECK(IsFreePage(page_map_idx + i));
273*795d594fSAndroid Build Coastguard Worker }
274*795d594fSAndroid Build Coastguard Worker switch (page_map_type) {
275*795d594fSAndroid Build Coastguard Worker case kPageMapRun:
276*795d594fSAndroid Build Coastguard Worker page_map_[page_map_idx] = kPageMapRun;
277*795d594fSAndroid Build Coastguard Worker for (size_t i = 1; i < num_pages; i++) {
278*795d594fSAndroid Build Coastguard Worker page_map_[page_map_idx + i] = kPageMapRunPart;
279*795d594fSAndroid Build Coastguard Worker }
280*795d594fSAndroid Build Coastguard Worker break;
281*795d594fSAndroid Build Coastguard Worker case kPageMapLargeObject:
282*795d594fSAndroid Build Coastguard Worker page_map_[page_map_idx] = kPageMapLargeObject;
283*795d594fSAndroid Build Coastguard Worker for (size_t i = 1; i < num_pages; i++) {
284*795d594fSAndroid Build Coastguard Worker page_map_[page_map_idx + i] = kPageMapLargeObjectPart;
285*795d594fSAndroid Build Coastguard Worker }
286*795d594fSAndroid Build Coastguard Worker break;
287*795d594fSAndroid Build Coastguard Worker default:
288*795d594fSAndroid Build Coastguard Worker LOG(FATAL) << "Unreachable - page map type: " << static_cast<int>(page_map_type);
289*795d594fSAndroid Build Coastguard Worker UNREACHABLE();
290*795d594fSAndroid Build Coastguard Worker }
291*795d594fSAndroid Build Coastguard Worker if (kIsDebugBuild) {
292*795d594fSAndroid Build Coastguard Worker // Clear the first page since it is not madvised due to the magic number.
293*795d594fSAndroid Build Coastguard Worker memset(res, 0, gPageSize);
294*795d594fSAndroid Build Coastguard Worker }
295*795d594fSAndroid Build Coastguard Worker if (kTraceRosAlloc) {
296*795d594fSAndroid Build Coastguard Worker LOG(INFO) << "RosAlloc::AllocPages() : 0x" << std::hex << reinterpret_cast<intptr_t>(res)
297*795d594fSAndroid Build Coastguard Worker << "-0x" << (reinterpret_cast<intptr_t>(res) + num_pages * gPageSize)
298*795d594fSAndroid Build Coastguard Worker << "(" << std::dec << (num_pages * gPageSize) << ")";
299*795d594fSAndroid Build Coastguard Worker }
300*795d594fSAndroid Build Coastguard Worker return res;
301*795d594fSAndroid Build Coastguard Worker }
302*795d594fSAndroid Build Coastguard Worker
303*795d594fSAndroid Build Coastguard Worker // Fail.
304*795d594fSAndroid Build Coastguard Worker if (kTraceRosAlloc) {
305*795d594fSAndroid Build Coastguard Worker LOG(INFO) << "RosAlloc::AllocPages() : nullptr";
306*795d594fSAndroid Build Coastguard Worker }
307*795d594fSAndroid Build Coastguard Worker return nullptr;
308*795d594fSAndroid Build Coastguard Worker }
309*795d594fSAndroid Build Coastguard Worker
FreePages(Thread * self,void * ptr,bool already_zero)310*795d594fSAndroid Build Coastguard Worker size_t RosAlloc::FreePages(Thread* self, void* ptr, bool already_zero) {
311*795d594fSAndroid Build Coastguard Worker lock_.AssertHeld(self);
312*795d594fSAndroid Build Coastguard Worker size_t pm_idx = ToPageMapIndex(ptr);
313*795d594fSAndroid Build Coastguard Worker DCHECK_LT(pm_idx, page_map_size_);
314*795d594fSAndroid Build Coastguard Worker uint8_t pm_type = page_map_[pm_idx];
315*795d594fSAndroid Build Coastguard Worker DCHECK(pm_type == kPageMapRun || pm_type == kPageMapLargeObject);
316*795d594fSAndroid Build Coastguard Worker uint8_t pm_part_type;
317*795d594fSAndroid Build Coastguard Worker switch (pm_type) {
318*795d594fSAndroid Build Coastguard Worker case kPageMapRun:
319*795d594fSAndroid Build Coastguard Worker pm_part_type = kPageMapRunPart;
320*795d594fSAndroid Build Coastguard Worker break;
321*795d594fSAndroid Build Coastguard Worker case kPageMapLargeObject:
322*795d594fSAndroid Build Coastguard Worker pm_part_type = kPageMapLargeObjectPart;
323*795d594fSAndroid Build Coastguard Worker break;
324*795d594fSAndroid Build Coastguard Worker default:
325*795d594fSAndroid Build Coastguard Worker LOG(FATAL) << "Unreachable - " << __PRETTY_FUNCTION__ << " : " << "pm_idx=" << pm_idx << ", pm_type="
326*795d594fSAndroid Build Coastguard Worker << static_cast<int>(pm_type) << ", ptr=" << std::hex
327*795d594fSAndroid Build Coastguard Worker << reinterpret_cast<intptr_t>(ptr);
328*795d594fSAndroid Build Coastguard Worker UNREACHABLE();
329*795d594fSAndroid Build Coastguard Worker }
330*795d594fSAndroid Build Coastguard Worker // Update the page map and count the number of pages.
331*795d594fSAndroid Build Coastguard Worker size_t num_pages = 1;
332*795d594fSAndroid Build Coastguard Worker page_map_[pm_idx] = kPageMapEmpty;
333*795d594fSAndroid Build Coastguard Worker size_t idx = pm_idx + 1;
334*795d594fSAndroid Build Coastguard Worker size_t end = page_map_size_;
335*795d594fSAndroid Build Coastguard Worker while (idx < end && page_map_[idx] == pm_part_type) {
336*795d594fSAndroid Build Coastguard Worker page_map_[idx] = kPageMapEmpty;
337*795d594fSAndroid Build Coastguard Worker num_pages++;
338*795d594fSAndroid Build Coastguard Worker idx++;
339*795d594fSAndroid Build Coastguard Worker }
340*795d594fSAndroid Build Coastguard Worker const size_t byte_size = num_pages * gPageSize;
341*795d594fSAndroid Build Coastguard Worker if (already_zero) {
342*795d594fSAndroid Build Coastguard Worker if (ShouldCheckZeroMemory()) {
343*795d594fSAndroid Build Coastguard Worker const uintptr_t* word_ptr = reinterpret_cast<uintptr_t*>(ptr);
344*795d594fSAndroid Build Coastguard Worker for (size_t i = 0; i < byte_size / sizeof(uintptr_t); ++i) {
345*795d594fSAndroid Build Coastguard Worker CHECK_EQ(word_ptr[i], 0U) << "words don't match at index " << i;
346*795d594fSAndroid Build Coastguard Worker }
347*795d594fSAndroid Build Coastguard Worker }
348*795d594fSAndroid Build Coastguard Worker } else if (!DoesReleaseAllPages()) {
349*795d594fSAndroid Build Coastguard Worker memset(ptr, 0, byte_size);
350*795d594fSAndroid Build Coastguard Worker }
351*795d594fSAndroid Build Coastguard Worker
352*795d594fSAndroid Build Coastguard Worker if (kTraceRosAlloc) {
353*795d594fSAndroid Build Coastguard Worker LOG(INFO) << __PRETTY_FUNCTION__ << " : 0x" << std::hex << reinterpret_cast<intptr_t>(ptr)
354*795d594fSAndroid Build Coastguard Worker << "-0x" << (reinterpret_cast<intptr_t>(ptr) + byte_size)
355*795d594fSAndroid Build Coastguard Worker << "(" << std::dec << (num_pages * gPageSize) << ")";
356*795d594fSAndroid Build Coastguard Worker }
357*795d594fSAndroid Build Coastguard Worker
358*795d594fSAndroid Build Coastguard Worker // Turn it into a free run.
359*795d594fSAndroid Build Coastguard Worker FreePageRun* fpr = reinterpret_cast<FreePageRun*>(ptr);
360*795d594fSAndroid Build Coastguard Worker if (kIsDebugBuild) {
361*795d594fSAndroid Build Coastguard Worker fpr->magic_num_ = kMagicNumFree;
362*795d594fSAndroid Build Coastguard Worker }
363*795d594fSAndroid Build Coastguard Worker fpr->SetByteSize(this, byte_size);
364*795d594fSAndroid Build Coastguard Worker DCHECK_ALIGNED_PARAM(fpr->ByteSize(this), gPageSize);
365*795d594fSAndroid Build Coastguard Worker
366*795d594fSAndroid Build Coastguard Worker DCHECK(free_page_runs_.find(fpr) == free_page_runs_.end());
367*795d594fSAndroid Build Coastguard Worker if (!free_page_runs_.empty()) {
368*795d594fSAndroid Build Coastguard Worker // Try to coalesce in the higher address direction.
369*795d594fSAndroid Build Coastguard Worker if (kTraceRosAlloc) {
370*795d594fSAndroid Build Coastguard Worker LOG(INFO) << __PRETTY_FUNCTION__ << "RosAlloc::FreePages() : trying to coalesce a free page run 0x"
371*795d594fSAndroid Build Coastguard Worker << std::hex << reinterpret_cast<uintptr_t>(fpr) << " [" << std::dec << pm_idx << "] -0x"
372*795d594fSAndroid Build Coastguard Worker << std::hex << reinterpret_cast<uintptr_t>(fpr->End(this)) << " [" << std::dec
373*795d594fSAndroid Build Coastguard Worker << (fpr->End(this) == End() ? page_map_size_ : ToPageMapIndex(fpr->End(this))) << "]";
374*795d594fSAndroid Build Coastguard Worker }
375*795d594fSAndroid Build Coastguard Worker for (auto it = free_page_runs_.upper_bound(fpr); it != free_page_runs_.end(); ) {
376*795d594fSAndroid Build Coastguard Worker FreePageRun* h = *it;
377*795d594fSAndroid Build Coastguard Worker DCHECK_EQ(ModuloPageSize(h->ByteSize(this)), static_cast<size_t>(0));
378*795d594fSAndroid Build Coastguard Worker if (kTraceRosAlloc) {
379*795d594fSAndroid Build Coastguard Worker LOG(INFO) << "RosAlloc::FreePages() : trying to coalesce with a higher free page run 0x"
380*795d594fSAndroid Build Coastguard Worker << std::hex << reinterpret_cast<uintptr_t>(h) << " [" << std::dec << ToPageMapIndex(h) << "] -0x"
381*795d594fSAndroid Build Coastguard Worker << std::hex << reinterpret_cast<uintptr_t>(h->End(this)) << " [" << std::dec
382*795d594fSAndroid Build Coastguard Worker << (h->End(this) == End() ? page_map_size_ : ToPageMapIndex(h->End(this))) << "]";
383*795d594fSAndroid Build Coastguard Worker }
384*795d594fSAndroid Build Coastguard Worker if (fpr->End(this) == h->Begin()) {
385*795d594fSAndroid Build Coastguard Worker if (kTraceRosAlloc) {
386*795d594fSAndroid Build Coastguard Worker LOG(INFO) << "Success";
387*795d594fSAndroid Build Coastguard Worker }
388*795d594fSAndroid Build Coastguard Worker // Clear magic num since this is no longer the start of a free page run.
389*795d594fSAndroid Build Coastguard Worker if (kIsDebugBuild) {
390*795d594fSAndroid Build Coastguard Worker h->magic_num_ = 0;
391*795d594fSAndroid Build Coastguard Worker }
392*795d594fSAndroid Build Coastguard Worker it = free_page_runs_.erase(it);
393*795d594fSAndroid Build Coastguard Worker if (kTraceRosAlloc) {
394*795d594fSAndroid Build Coastguard Worker LOG(INFO) << "RosAlloc::FreePages() : (coalesce) Erased run 0x" << std::hex
395*795d594fSAndroid Build Coastguard Worker << reinterpret_cast<intptr_t>(h)
396*795d594fSAndroid Build Coastguard Worker << " from free_page_runs_";
397*795d594fSAndroid Build Coastguard Worker }
398*795d594fSAndroid Build Coastguard Worker fpr->SetByteSize(this, fpr->ByteSize(this) + h->ByteSize(this));
399*795d594fSAndroid Build Coastguard Worker DCHECK_EQ(ModuloPageSize(fpr->ByteSize(this)), static_cast<size_t>(0));
400*795d594fSAndroid Build Coastguard Worker } else {
401*795d594fSAndroid Build Coastguard Worker // Not adjacent. Stop.
402*795d594fSAndroid Build Coastguard Worker if (kTraceRosAlloc) {
403*795d594fSAndroid Build Coastguard Worker LOG(INFO) << "Fail";
404*795d594fSAndroid Build Coastguard Worker }
405*795d594fSAndroid Build Coastguard Worker break;
406*795d594fSAndroid Build Coastguard Worker }
407*795d594fSAndroid Build Coastguard Worker }
408*795d594fSAndroid Build Coastguard Worker // Try to coalesce in the lower address direction.
409*795d594fSAndroid Build Coastguard Worker for (auto it = free_page_runs_.upper_bound(fpr); it != free_page_runs_.begin(); ) {
410*795d594fSAndroid Build Coastguard Worker --it;
411*795d594fSAndroid Build Coastguard Worker
412*795d594fSAndroid Build Coastguard Worker FreePageRun* l = *it;
413*795d594fSAndroid Build Coastguard Worker DCHECK_EQ(ModuloPageSize(l->ByteSize(this)), static_cast<size_t>(0));
414*795d594fSAndroid Build Coastguard Worker if (kTraceRosAlloc) {
415*795d594fSAndroid Build Coastguard Worker LOG(INFO) << "RosAlloc::FreePages() : trying to coalesce with a lower free page run 0x"
416*795d594fSAndroid Build Coastguard Worker << std::hex << reinterpret_cast<uintptr_t>(l) << " [" << std::dec << ToPageMapIndex(l) << "] -0x"
417*795d594fSAndroid Build Coastguard Worker << std::hex << reinterpret_cast<uintptr_t>(l->End(this)) << " [" << std::dec
418*795d594fSAndroid Build Coastguard Worker << (l->End(this) == End() ? page_map_size_ : ToPageMapIndex(l->End(this))) << "]";
419*795d594fSAndroid Build Coastguard Worker }
420*795d594fSAndroid Build Coastguard Worker if (l->End(this) == fpr->Begin()) {
421*795d594fSAndroid Build Coastguard Worker if (kTraceRosAlloc) {
422*795d594fSAndroid Build Coastguard Worker LOG(INFO) << "Success";
423*795d594fSAndroid Build Coastguard Worker }
424*795d594fSAndroid Build Coastguard Worker it = free_page_runs_.erase(it);
425*795d594fSAndroid Build Coastguard Worker if (kTraceRosAlloc) {
426*795d594fSAndroid Build Coastguard Worker LOG(INFO) << "RosAlloc::FreePages() : (coalesce) Erased run 0x" << std::hex
427*795d594fSAndroid Build Coastguard Worker << reinterpret_cast<intptr_t>(l)
428*795d594fSAndroid Build Coastguard Worker << " from free_page_runs_";
429*795d594fSAndroid Build Coastguard Worker }
430*795d594fSAndroid Build Coastguard Worker l->SetByteSize(this, l->ByteSize(this) + fpr->ByteSize(this));
431*795d594fSAndroid Build Coastguard Worker DCHECK_EQ(ModuloPageSize(l->ByteSize(this)), static_cast<size_t>(0));
432*795d594fSAndroid Build Coastguard Worker // Clear magic num since this is no longer the start of a free page run.
433*795d594fSAndroid Build Coastguard Worker if (kIsDebugBuild) {
434*795d594fSAndroid Build Coastguard Worker fpr->magic_num_ = 0;
435*795d594fSAndroid Build Coastguard Worker }
436*795d594fSAndroid Build Coastguard Worker fpr = l;
437*795d594fSAndroid Build Coastguard Worker } else {
438*795d594fSAndroid Build Coastguard Worker // Not adjacent. Stop.
439*795d594fSAndroid Build Coastguard Worker if (kTraceRosAlloc) {
440*795d594fSAndroid Build Coastguard Worker LOG(INFO) << "Fail";
441*795d594fSAndroid Build Coastguard Worker }
442*795d594fSAndroid Build Coastguard Worker break;
443*795d594fSAndroid Build Coastguard Worker }
444*795d594fSAndroid Build Coastguard Worker }
445*795d594fSAndroid Build Coastguard Worker }
446*795d594fSAndroid Build Coastguard Worker
447*795d594fSAndroid Build Coastguard Worker // Insert it.
448*795d594fSAndroid Build Coastguard Worker DCHECK_EQ(ModuloPageSize(fpr->ByteSize(this)), static_cast<size_t>(0));
449*795d594fSAndroid Build Coastguard Worker DCHECK(free_page_runs_.find(fpr) == free_page_runs_.end());
450*795d594fSAndroid Build Coastguard Worker DCHECK(fpr->IsFree());
451*795d594fSAndroid Build Coastguard Worker fpr->ReleasePages(this);
452*795d594fSAndroid Build Coastguard Worker DCHECK(fpr->IsFree());
453*795d594fSAndroid Build Coastguard Worker free_page_runs_.insert(fpr);
454*795d594fSAndroid Build Coastguard Worker DCHECK(free_page_runs_.find(fpr) != free_page_runs_.end());
455*795d594fSAndroid Build Coastguard Worker if (kTraceRosAlloc) {
456*795d594fSAndroid Build Coastguard Worker LOG(INFO) << "RosAlloc::FreePages() : Inserted run 0x" << std::hex << reinterpret_cast<intptr_t>(fpr)
457*795d594fSAndroid Build Coastguard Worker << " into free_page_runs_";
458*795d594fSAndroid Build Coastguard Worker }
459*795d594fSAndroid Build Coastguard Worker return byte_size;
460*795d594fSAndroid Build Coastguard Worker }
461*795d594fSAndroid Build Coastguard Worker
AllocLargeObject(Thread * self,size_t size,size_t * bytes_allocated,size_t * usable_size,size_t * bytes_tl_bulk_allocated)462*795d594fSAndroid Build Coastguard Worker void* RosAlloc::AllocLargeObject(Thread* self, size_t size, size_t* bytes_allocated,
463*795d594fSAndroid Build Coastguard Worker size_t* usable_size, size_t* bytes_tl_bulk_allocated) {
464*795d594fSAndroid Build Coastguard Worker DCHECK(bytes_allocated != nullptr);
465*795d594fSAndroid Build Coastguard Worker DCHECK(usable_size != nullptr);
466*795d594fSAndroid Build Coastguard Worker DCHECK_GT(size, kLargeSizeThreshold);
467*795d594fSAndroid Build Coastguard Worker size_t num_pages = DivideByPageSize(RoundUp(size, gPageSize));
468*795d594fSAndroid Build Coastguard Worker void* r;
469*795d594fSAndroid Build Coastguard Worker {
470*795d594fSAndroid Build Coastguard Worker MutexLock mu(self, lock_);
471*795d594fSAndroid Build Coastguard Worker r = AllocPages(self, num_pages, kPageMapLargeObject);
472*795d594fSAndroid Build Coastguard Worker }
473*795d594fSAndroid Build Coastguard Worker if (UNLIKELY(r == nullptr)) {
474*795d594fSAndroid Build Coastguard Worker if (kTraceRosAlloc) {
475*795d594fSAndroid Build Coastguard Worker LOG(INFO) << "RosAlloc::AllocLargeObject() : nullptr";
476*795d594fSAndroid Build Coastguard Worker }
477*795d594fSAndroid Build Coastguard Worker return nullptr;
478*795d594fSAndroid Build Coastguard Worker }
479*795d594fSAndroid Build Coastguard Worker const size_t total_bytes = num_pages * gPageSize;
480*795d594fSAndroid Build Coastguard Worker *bytes_allocated = total_bytes;
481*795d594fSAndroid Build Coastguard Worker *usable_size = total_bytes;
482*795d594fSAndroid Build Coastguard Worker *bytes_tl_bulk_allocated = total_bytes;
483*795d594fSAndroid Build Coastguard Worker if (kTraceRosAlloc) {
484*795d594fSAndroid Build Coastguard Worker LOG(INFO) << "RosAlloc::AllocLargeObject() : 0x" << std::hex << reinterpret_cast<intptr_t>(r)
485*795d594fSAndroid Build Coastguard Worker << "-0x" << (reinterpret_cast<intptr_t>(r) + num_pages * gPageSize)
486*795d594fSAndroid Build Coastguard Worker << "(" << std::dec << (num_pages * gPageSize) << ")";
487*795d594fSAndroid Build Coastguard Worker }
488*795d594fSAndroid Build Coastguard Worker // Check if the returned memory is really all zero.
489*795d594fSAndroid Build Coastguard Worker if (ShouldCheckZeroMemory()) {
490*795d594fSAndroid Build Coastguard Worker CHECK_EQ(total_bytes % sizeof(uintptr_t), 0U);
491*795d594fSAndroid Build Coastguard Worker const uintptr_t* words = reinterpret_cast<uintptr_t*>(r);
492*795d594fSAndroid Build Coastguard Worker for (size_t i = 0; i < total_bytes / sizeof(uintptr_t); ++i) {
493*795d594fSAndroid Build Coastguard Worker CHECK_EQ(words[i], 0U);
494*795d594fSAndroid Build Coastguard Worker }
495*795d594fSAndroid Build Coastguard Worker }
496*795d594fSAndroid Build Coastguard Worker return r;
497*795d594fSAndroid Build Coastguard Worker }
498*795d594fSAndroid Build Coastguard Worker
FreeInternal(Thread * self,void * ptr)499*795d594fSAndroid Build Coastguard Worker size_t RosAlloc::FreeInternal(Thread* self, void* ptr) {
500*795d594fSAndroid Build Coastguard Worker DCHECK_LE(base_, ptr);
501*795d594fSAndroid Build Coastguard Worker DCHECK_LT(ptr, base_ + footprint_);
502*795d594fSAndroid Build Coastguard Worker size_t pm_idx = RoundDownToPageMapIndex(ptr);
503*795d594fSAndroid Build Coastguard Worker Run* run = nullptr;
504*795d594fSAndroid Build Coastguard Worker {
505*795d594fSAndroid Build Coastguard Worker MutexLock mu(self, lock_);
506*795d594fSAndroid Build Coastguard Worker DCHECK_LT(pm_idx, page_map_size_);
507*795d594fSAndroid Build Coastguard Worker uint8_t page_map_entry = page_map_[pm_idx];
508*795d594fSAndroid Build Coastguard Worker if (kTraceRosAlloc) {
509*795d594fSAndroid Build Coastguard Worker LOG(INFO) << "RosAlloc::FreeInternal() : " << std::hex << ptr << ", pm_idx=" << std::dec << pm_idx
510*795d594fSAndroid Build Coastguard Worker << ", page_map_entry=" << static_cast<int>(page_map_entry);
511*795d594fSAndroid Build Coastguard Worker }
512*795d594fSAndroid Build Coastguard Worker switch (page_map_[pm_idx]) {
513*795d594fSAndroid Build Coastguard Worker case kPageMapLargeObject:
514*795d594fSAndroid Build Coastguard Worker return FreePages(self, ptr, false);
515*795d594fSAndroid Build Coastguard Worker case kPageMapLargeObjectPart:
516*795d594fSAndroid Build Coastguard Worker LOG(FATAL) << "Unreachable - page map type: " << static_cast<int>(page_map_[pm_idx]);
517*795d594fSAndroid Build Coastguard Worker UNREACHABLE();
518*795d594fSAndroid Build Coastguard Worker case kPageMapRunPart: {
519*795d594fSAndroid Build Coastguard Worker // Find the beginning of the run.
520*795d594fSAndroid Build Coastguard Worker do {
521*795d594fSAndroid Build Coastguard Worker --pm_idx;
522*795d594fSAndroid Build Coastguard Worker DCHECK_LT(pm_idx, DivideByPageSize(capacity_));
523*795d594fSAndroid Build Coastguard Worker } while (page_map_[pm_idx] != kPageMapRun);
524*795d594fSAndroid Build Coastguard Worker FALLTHROUGH_INTENDED;
525*795d594fSAndroid Build Coastguard Worker case kPageMapRun:
526*795d594fSAndroid Build Coastguard Worker run = reinterpret_cast<Run*>(base_ + pm_idx * gPageSize);
527*795d594fSAndroid Build Coastguard Worker DCHECK_EQ(run->magic_num_, kMagicNum);
528*795d594fSAndroid Build Coastguard Worker break;
529*795d594fSAndroid Build Coastguard Worker case kPageMapReleased:
530*795d594fSAndroid Build Coastguard Worker case kPageMapEmpty:
531*795d594fSAndroid Build Coastguard Worker LOG(FATAL) << "Unreachable - page map type: " << static_cast<int>(page_map_[pm_idx]);
532*795d594fSAndroid Build Coastguard Worker UNREACHABLE();
533*795d594fSAndroid Build Coastguard Worker }
534*795d594fSAndroid Build Coastguard Worker }
535*795d594fSAndroid Build Coastguard Worker }
536*795d594fSAndroid Build Coastguard Worker DCHECK(run != nullptr);
537*795d594fSAndroid Build Coastguard Worker return FreeFromRun(self, ptr, run);
538*795d594fSAndroid Build Coastguard Worker }
539*795d594fSAndroid Build Coastguard Worker
Free(Thread * self,void * ptr)540*795d594fSAndroid Build Coastguard Worker size_t RosAlloc::Free(Thread* self, void* ptr) {
541*795d594fSAndroid Build Coastguard Worker ReaderMutexLock rmu(self, bulk_free_lock_);
542*795d594fSAndroid Build Coastguard Worker return FreeInternal(self, ptr);
543*795d594fSAndroid Build Coastguard Worker }
544*795d594fSAndroid Build Coastguard Worker
AllocRun(Thread * self,size_t idx)545*795d594fSAndroid Build Coastguard Worker RosAlloc::Run* RosAlloc::AllocRun(Thread* self, size_t idx) {
546*795d594fSAndroid Build Coastguard Worker RosAlloc::Run* new_run = nullptr;
547*795d594fSAndroid Build Coastguard Worker {
548*795d594fSAndroid Build Coastguard Worker MutexLock mu(self, lock_);
549*795d594fSAndroid Build Coastguard Worker new_run = reinterpret_cast<Run*>(AllocPages(self, numOfPages[idx], kPageMapRun));
550*795d594fSAndroid Build Coastguard Worker }
551*795d594fSAndroid Build Coastguard Worker if (LIKELY(new_run != nullptr)) {
552*795d594fSAndroid Build Coastguard Worker if (kIsDebugBuild) {
553*795d594fSAndroid Build Coastguard Worker new_run->magic_num_ = kMagicNum;
554*795d594fSAndroid Build Coastguard Worker }
555*795d594fSAndroid Build Coastguard Worker new_run->size_bracket_idx_ = idx;
556*795d594fSAndroid Build Coastguard Worker DCHECK(!new_run->IsThreadLocal());
557*795d594fSAndroid Build Coastguard Worker DCHECK(!new_run->to_be_bulk_freed_);
558*795d594fSAndroid Build Coastguard Worker if (kUsePrefetchDuringAllocRun && idx < kNumThreadLocalSizeBrackets) {
559*795d594fSAndroid Build Coastguard Worker // Take ownership of the cache lines if we are likely to be thread local run.
560*795d594fSAndroid Build Coastguard Worker if (kPrefetchNewRunDataByZeroing) {
561*795d594fSAndroid Build Coastguard Worker // Zeroing the data is sometimes faster than prefetching but it increases memory usage
562*795d594fSAndroid Build Coastguard Worker // since we end up dirtying zero pages which may have been madvised.
563*795d594fSAndroid Build Coastguard Worker new_run->ZeroData();
564*795d594fSAndroid Build Coastguard Worker } else {
565*795d594fSAndroid Build Coastguard Worker const size_t num_of_slots = numOfSlots[idx];
566*795d594fSAndroid Build Coastguard Worker const size_t bracket_size = bracketSizes[idx];
567*795d594fSAndroid Build Coastguard Worker const size_t num_of_bytes = num_of_slots * bracket_size;
568*795d594fSAndroid Build Coastguard Worker uint8_t* begin = reinterpret_cast<uint8_t*>(new_run) + headerSizes[idx];
569*795d594fSAndroid Build Coastguard Worker for (size_t i = 0; i < num_of_bytes; i += kPrefetchStride) {
570*795d594fSAndroid Build Coastguard Worker __builtin_prefetch(begin + i);
571*795d594fSAndroid Build Coastguard Worker }
572*795d594fSAndroid Build Coastguard Worker }
573*795d594fSAndroid Build Coastguard Worker }
574*795d594fSAndroid Build Coastguard Worker new_run->InitFreeList();
575*795d594fSAndroid Build Coastguard Worker }
576*795d594fSAndroid Build Coastguard Worker return new_run;
577*795d594fSAndroid Build Coastguard Worker }
578*795d594fSAndroid Build Coastguard Worker
RefillRun(Thread * self,size_t idx)579*795d594fSAndroid Build Coastguard Worker RosAlloc::Run* RosAlloc::RefillRun(Thread* self, size_t idx) {
580*795d594fSAndroid Build Coastguard Worker // Get the lowest address non-full run from the binary tree.
581*795d594fSAndroid Build Coastguard Worker auto* const bt = &non_full_runs_[idx];
582*795d594fSAndroid Build Coastguard Worker if (!bt->empty()) {
583*795d594fSAndroid Build Coastguard Worker // If there's one, use it as the current run.
584*795d594fSAndroid Build Coastguard Worker auto it = bt->begin();
585*795d594fSAndroid Build Coastguard Worker Run* non_full_run = *it;
586*795d594fSAndroid Build Coastguard Worker DCHECK(non_full_run != nullptr);
587*795d594fSAndroid Build Coastguard Worker DCHECK(!non_full_run->IsThreadLocal());
588*795d594fSAndroid Build Coastguard Worker bt->erase(it);
589*795d594fSAndroid Build Coastguard Worker return non_full_run;
590*795d594fSAndroid Build Coastguard Worker }
591*795d594fSAndroid Build Coastguard Worker // If there's none, allocate a new run and use it as the current run.
592*795d594fSAndroid Build Coastguard Worker return AllocRun(self, idx);
593*795d594fSAndroid Build Coastguard Worker }
594*795d594fSAndroid Build Coastguard Worker
AllocFromCurrentRunUnlocked(Thread * self,size_t idx)595*795d594fSAndroid Build Coastguard Worker inline void* RosAlloc::AllocFromCurrentRunUnlocked(Thread* self, size_t idx) {
596*795d594fSAndroid Build Coastguard Worker Run* current_run = current_runs_[idx];
597*795d594fSAndroid Build Coastguard Worker DCHECK(current_run != nullptr);
598*795d594fSAndroid Build Coastguard Worker void* slot_addr = current_run->AllocSlot();
599*795d594fSAndroid Build Coastguard Worker if (UNLIKELY(slot_addr == nullptr)) {
600*795d594fSAndroid Build Coastguard Worker // The current run got full. Try to refill it.
601*795d594fSAndroid Build Coastguard Worker DCHECK(current_run->IsFull());
602*795d594fSAndroid Build Coastguard Worker if (kIsDebugBuild && current_run != dedicated_full_run_) {
603*795d594fSAndroid Build Coastguard Worker full_runs_[idx].insert(current_run);
604*795d594fSAndroid Build Coastguard Worker if (kTraceRosAlloc) {
605*795d594fSAndroid Build Coastguard Worker LOG(INFO) << __PRETTY_FUNCTION__ << " : Inserted run 0x" << std::hex
606*795d594fSAndroid Build Coastguard Worker << reinterpret_cast<intptr_t>(current_run)
607*795d594fSAndroid Build Coastguard Worker << " into full_runs_[" << std::dec << idx << "]";
608*795d594fSAndroid Build Coastguard Worker }
609*795d594fSAndroid Build Coastguard Worker DCHECK(non_full_runs_[idx].find(current_run) == non_full_runs_[idx].end());
610*795d594fSAndroid Build Coastguard Worker DCHECK(full_runs_[idx].find(current_run) != full_runs_[idx].end());
611*795d594fSAndroid Build Coastguard Worker }
612*795d594fSAndroid Build Coastguard Worker current_run = RefillRun(self, idx);
613*795d594fSAndroid Build Coastguard Worker if (UNLIKELY(current_run == nullptr)) {
614*795d594fSAndroid Build Coastguard Worker // Failed to allocate a new run, make sure that it is the dedicated full run.
615*795d594fSAndroid Build Coastguard Worker current_runs_[idx] = dedicated_full_run_;
616*795d594fSAndroid Build Coastguard Worker return nullptr;
617*795d594fSAndroid Build Coastguard Worker }
618*795d594fSAndroid Build Coastguard Worker DCHECK(current_run != nullptr);
619*795d594fSAndroid Build Coastguard Worker DCHECK(non_full_runs_[idx].find(current_run) == non_full_runs_[idx].end());
620*795d594fSAndroid Build Coastguard Worker DCHECK(full_runs_[idx].find(current_run) == full_runs_[idx].end());
621*795d594fSAndroid Build Coastguard Worker current_run->SetIsThreadLocal(false);
622*795d594fSAndroid Build Coastguard Worker current_runs_[idx] = current_run;
623*795d594fSAndroid Build Coastguard Worker DCHECK(!current_run->IsFull());
624*795d594fSAndroid Build Coastguard Worker slot_addr = current_run->AllocSlot();
625*795d594fSAndroid Build Coastguard Worker // Must succeed now with a new run.
626*795d594fSAndroid Build Coastguard Worker DCHECK(slot_addr != nullptr);
627*795d594fSAndroid Build Coastguard Worker }
628*795d594fSAndroid Build Coastguard Worker return slot_addr;
629*795d594fSAndroid Build Coastguard Worker }
630*795d594fSAndroid Build Coastguard Worker
AllocFromRunThreadUnsafe(Thread * self,size_t size,size_t * bytes_allocated,size_t * usable_size,size_t * bytes_tl_bulk_allocated)631*795d594fSAndroid Build Coastguard Worker void* RosAlloc::AllocFromRunThreadUnsafe(Thread* self, size_t size, size_t* bytes_allocated,
632*795d594fSAndroid Build Coastguard Worker size_t* usable_size,
633*795d594fSAndroid Build Coastguard Worker size_t* bytes_tl_bulk_allocated) {
634*795d594fSAndroid Build Coastguard Worker DCHECK(bytes_allocated != nullptr);
635*795d594fSAndroid Build Coastguard Worker DCHECK(usable_size != nullptr);
636*795d594fSAndroid Build Coastguard Worker DCHECK(bytes_tl_bulk_allocated != nullptr);
637*795d594fSAndroid Build Coastguard Worker DCHECK_LE(size, kLargeSizeThreshold);
638*795d594fSAndroid Build Coastguard Worker size_t bracket_size;
639*795d594fSAndroid Build Coastguard Worker size_t idx = SizeToIndexAndBracketSize(size, &bracket_size);
640*795d594fSAndroid Build Coastguard Worker Locks::mutator_lock_->AssertExclusiveHeld(self);
641*795d594fSAndroid Build Coastguard Worker void* slot_addr = AllocFromCurrentRunUnlocked(self, idx);
642*795d594fSAndroid Build Coastguard Worker if (LIKELY(slot_addr != nullptr)) {
643*795d594fSAndroid Build Coastguard Worker *bytes_allocated = bracket_size;
644*795d594fSAndroid Build Coastguard Worker *usable_size = bracket_size;
645*795d594fSAndroid Build Coastguard Worker *bytes_tl_bulk_allocated = bracket_size;
646*795d594fSAndroid Build Coastguard Worker }
647*795d594fSAndroid Build Coastguard Worker // Caller verifies that it is all 0.
648*795d594fSAndroid Build Coastguard Worker return slot_addr;
649*795d594fSAndroid Build Coastguard Worker }
650*795d594fSAndroid Build Coastguard Worker
AllocFromRun(Thread * self,size_t size,size_t * bytes_allocated,size_t * usable_size,size_t * bytes_tl_bulk_allocated)651*795d594fSAndroid Build Coastguard Worker void* RosAlloc::AllocFromRun(Thread* self, size_t size, size_t* bytes_allocated,
652*795d594fSAndroid Build Coastguard Worker size_t* usable_size, size_t* bytes_tl_bulk_allocated) {
653*795d594fSAndroid Build Coastguard Worker DCHECK(bytes_allocated != nullptr);
654*795d594fSAndroid Build Coastguard Worker DCHECK(usable_size != nullptr);
655*795d594fSAndroid Build Coastguard Worker DCHECK(bytes_tl_bulk_allocated != nullptr);
656*795d594fSAndroid Build Coastguard Worker DCHECK_LE(size, kLargeSizeThreshold);
657*795d594fSAndroid Build Coastguard Worker size_t bracket_size;
658*795d594fSAndroid Build Coastguard Worker size_t idx = SizeToIndexAndBracketSize(size, &bracket_size);
659*795d594fSAndroid Build Coastguard Worker void* slot_addr;
660*795d594fSAndroid Build Coastguard Worker if (LIKELY(idx < kNumThreadLocalSizeBrackets)) {
661*795d594fSAndroid Build Coastguard Worker // Use a thread-local run.
662*795d594fSAndroid Build Coastguard Worker Run* thread_local_run = reinterpret_cast<Run*>(self->GetRosAllocRun(idx));
663*795d594fSAndroid Build Coastguard Worker // Allow invalid since this will always fail the allocation.
664*795d594fSAndroid Build Coastguard Worker if (kIsDebugBuild) {
665*795d594fSAndroid Build Coastguard Worker // Need the lock to prevent race conditions.
666*795d594fSAndroid Build Coastguard Worker MutexLock mu(self, *size_bracket_locks_[idx]);
667*795d594fSAndroid Build Coastguard Worker CHECK(non_full_runs_[idx].find(thread_local_run) == non_full_runs_[idx].end());
668*795d594fSAndroid Build Coastguard Worker CHECK(full_runs_[idx].find(thread_local_run) == full_runs_[idx].end());
669*795d594fSAndroid Build Coastguard Worker }
670*795d594fSAndroid Build Coastguard Worker DCHECK(thread_local_run != nullptr);
671*795d594fSAndroid Build Coastguard Worker DCHECK(thread_local_run->IsThreadLocal() || thread_local_run == dedicated_full_run_);
672*795d594fSAndroid Build Coastguard Worker slot_addr = thread_local_run->AllocSlot();
673*795d594fSAndroid Build Coastguard Worker // The allocation must fail if the run is invalid.
674*795d594fSAndroid Build Coastguard Worker DCHECK_IMPLIES(thread_local_run == dedicated_full_run_, slot_addr == nullptr)
675*795d594fSAndroid Build Coastguard Worker << "allocated from an invalid run";
676*795d594fSAndroid Build Coastguard Worker if (UNLIKELY(slot_addr == nullptr)) {
677*795d594fSAndroid Build Coastguard Worker // The run got full. Try to free slots.
678*795d594fSAndroid Build Coastguard Worker DCHECK(thread_local_run->IsFull());
679*795d594fSAndroid Build Coastguard Worker MutexLock mu(self, *size_bracket_locks_[idx]);
680*795d594fSAndroid Build Coastguard Worker bool is_all_free_after_merge;
681*795d594fSAndroid Build Coastguard Worker // This is safe to do for the dedicated_full_run_ since the bitmaps are empty.
682*795d594fSAndroid Build Coastguard Worker if (thread_local_run->MergeThreadLocalFreeListToFreeList(&is_all_free_after_merge)) {
683*795d594fSAndroid Build Coastguard Worker DCHECK_NE(thread_local_run, dedicated_full_run_);
684*795d594fSAndroid Build Coastguard Worker // Some slot got freed. Keep it.
685*795d594fSAndroid Build Coastguard Worker DCHECK(!thread_local_run->IsFull());
686*795d594fSAndroid Build Coastguard Worker DCHECK_EQ(is_all_free_after_merge, thread_local_run->IsAllFree());
687*795d594fSAndroid Build Coastguard Worker } else {
688*795d594fSAndroid Build Coastguard Worker // No slots got freed. Try to refill the thread-local run.
689*795d594fSAndroid Build Coastguard Worker DCHECK(thread_local_run->IsFull());
690*795d594fSAndroid Build Coastguard Worker if (thread_local_run != dedicated_full_run_) {
691*795d594fSAndroid Build Coastguard Worker thread_local_run->SetIsThreadLocal(false);
692*795d594fSAndroid Build Coastguard Worker if (kIsDebugBuild) {
693*795d594fSAndroid Build Coastguard Worker full_runs_[idx].insert(thread_local_run);
694*795d594fSAndroid Build Coastguard Worker if (kTraceRosAlloc) {
695*795d594fSAndroid Build Coastguard Worker LOG(INFO) << "RosAlloc::AllocFromRun() : Inserted run 0x" << std::hex
696*795d594fSAndroid Build Coastguard Worker << reinterpret_cast<intptr_t>(thread_local_run)
697*795d594fSAndroid Build Coastguard Worker << " into full_runs_[" << std::dec << idx << "]";
698*795d594fSAndroid Build Coastguard Worker }
699*795d594fSAndroid Build Coastguard Worker }
700*795d594fSAndroid Build Coastguard Worker DCHECK(non_full_runs_[idx].find(thread_local_run) == non_full_runs_[idx].end());
701*795d594fSAndroid Build Coastguard Worker DCHECK(full_runs_[idx].find(thread_local_run) != full_runs_[idx].end());
702*795d594fSAndroid Build Coastguard Worker }
703*795d594fSAndroid Build Coastguard Worker
704*795d594fSAndroid Build Coastguard Worker thread_local_run = RefillRun(self, idx);
705*795d594fSAndroid Build Coastguard Worker if (UNLIKELY(thread_local_run == nullptr)) {
706*795d594fSAndroid Build Coastguard Worker self->SetRosAllocRun(idx, dedicated_full_run_);
707*795d594fSAndroid Build Coastguard Worker return nullptr;
708*795d594fSAndroid Build Coastguard Worker }
709*795d594fSAndroid Build Coastguard Worker DCHECK(non_full_runs_[idx].find(thread_local_run) == non_full_runs_[idx].end());
710*795d594fSAndroid Build Coastguard Worker DCHECK(full_runs_[idx].find(thread_local_run) == full_runs_[idx].end());
711*795d594fSAndroid Build Coastguard Worker thread_local_run->SetIsThreadLocal(true);
712*795d594fSAndroid Build Coastguard Worker self->SetRosAllocRun(idx, thread_local_run);
713*795d594fSAndroid Build Coastguard Worker DCHECK(!thread_local_run->IsFull());
714*795d594fSAndroid Build Coastguard Worker }
715*795d594fSAndroid Build Coastguard Worker DCHECK(thread_local_run != nullptr);
716*795d594fSAndroid Build Coastguard Worker DCHECK(!thread_local_run->IsFull());
717*795d594fSAndroid Build Coastguard Worker DCHECK(thread_local_run->IsThreadLocal());
718*795d594fSAndroid Build Coastguard Worker // Account for all the free slots in the new or refreshed thread local run.
719*795d594fSAndroid Build Coastguard Worker *bytes_tl_bulk_allocated = thread_local_run->NumberOfFreeSlots() * bracket_size;
720*795d594fSAndroid Build Coastguard Worker slot_addr = thread_local_run->AllocSlot();
721*795d594fSAndroid Build Coastguard Worker // Must succeed now with a new run.
722*795d594fSAndroid Build Coastguard Worker DCHECK(slot_addr != nullptr);
723*795d594fSAndroid Build Coastguard Worker } else {
724*795d594fSAndroid Build Coastguard Worker // The slot is already counted. Leave it as is.
725*795d594fSAndroid Build Coastguard Worker *bytes_tl_bulk_allocated = 0;
726*795d594fSAndroid Build Coastguard Worker }
727*795d594fSAndroid Build Coastguard Worker DCHECK(slot_addr != nullptr);
728*795d594fSAndroid Build Coastguard Worker if (kTraceRosAlloc) {
729*795d594fSAndroid Build Coastguard Worker LOG(INFO) << "RosAlloc::AllocFromRun() thread-local : 0x" << std::hex
730*795d594fSAndroid Build Coastguard Worker << reinterpret_cast<intptr_t>(slot_addr)
731*795d594fSAndroid Build Coastguard Worker << "-0x" << (reinterpret_cast<intptr_t>(slot_addr) + bracket_size)
732*795d594fSAndroid Build Coastguard Worker << "(" << std::dec << (bracket_size) << ")";
733*795d594fSAndroid Build Coastguard Worker }
734*795d594fSAndroid Build Coastguard Worker *bytes_allocated = bracket_size;
735*795d594fSAndroid Build Coastguard Worker *usable_size = bracket_size;
736*795d594fSAndroid Build Coastguard Worker } else {
737*795d594fSAndroid Build Coastguard Worker // Use the (shared) current run.
738*795d594fSAndroid Build Coastguard Worker MutexLock mu(self, *size_bracket_locks_[idx]);
739*795d594fSAndroid Build Coastguard Worker slot_addr = AllocFromCurrentRunUnlocked(self, idx);
740*795d594fSAndroid Build Coastguard Worker if (kTraceRosAlloc) {
741*795d594fSAndroid Build Coastguard Worker LOG(INFO) << "RosAlloc::AllocFromRun() : 0x" << std::hex
742*795d594fSAndroid Build Coastguard Worker << reinterpret_cast<intptr_t>(slot_addr)
743*795d594fSAndroid Build Coastguard Worker << "-0x" << (reinterpret_cast<intptr_t>(slot_addr) + bracket_size)
744*795d594fSAndroid Build Coastguard Worker << "(" << std::dec << (bracket_size) << ")";
745*795d594fSAndroid Build Coastguard Worker }
746*795d594fSAndroid Build Coastguard Worker if (LIKELY(slot_addr != nullptr)) {
747*795d594fSAndroid Build Coastguard Worker *bytes_allocated = bracket_size;
748*795d594fSAndroid Build Coastguard Worker *usable_size = bracket_size;
749*795d594fSAndroid Build Coastguard Worker *bytes_tl_bulk_allocated = bracket_size;
750*795d594fSAndroid Build Coastguard Worker }
751*795d594fSAndroid Build Coastguard Worker }
752*795d594fSAndroid Build Coastguard Worker // Caller verifies that it is all 0.
753*795d594fSAndroid Build Coastguard Worker return slot_addr;
754*795d594fSAndroid Build Coastguard Worker }
755*795d594fSAndroid Build Coastguard Worker
FreeFromRun(Thread * self,void * ptr,Run * run)756*795d594fSAndroid Build Coastguard Worker size_t RosAlloc::FreeFromRun(Thread* self, void* ptr, Run* run) {
757*795d594fSAndroid Build Coastguard Worker DCHECK_EQ(run->magic_num_, kMagicNum);
758*795d594fSAndroid Build Coastguard Worker DCHECK_LT(run, ptr);
759*795d594fSAndroid Build Coastguard Worker DCHECK_LT(ptr, run->End());
760*795d594fSAndroid Build Coastguard Worker const size_t idx = run->size_bracket_idx_;
761*795d594fSAndroid Build Coastguard Worker const size_t bracket_size = bracketSizes[idx];
762*795d594fSAndroid Build Coastguard Worker bool run_was_full = false;
763*795d594fSAndroid Build Coastguard Worker MutexLock brackets_mu(self, *size_bracket_locks_[idx]);
764*795d594fSAndroid Build Coastguard Worker if (kIsDebugBuild) {
765*795d594fSAndroid Build Coastguard Worker run_was_full = run->IsFull();
766*795d594fSAndroid Build Coastguard Worker }
767*795d594fSAndroid Build Coastguard Worker if (kTraceRosAlloc) {
768*795d594fSAndroid Build Coastguard Worker LOG(INFO) << "RosAlloc::FreeFromRun() : 0x" << std::hex << reinterpret_cast<intptr_t>(ptr);
769*795d594fSAndroid Build Coastguard Worker }
770*795d594fSAndroid Build Coastguard Worker if (LIKELY(run->IsThreadLocal())) {
771*795d594fSAndroid Build Coastguard Worker // It's a thread-local run. Just mark the thread-local free bit map and return.
772*795d594fSAndroid Build Coastguard Worker DCHECK_LT(run->size_bracket_idx_, kNumThreadLocalSizeBrackets);
773*795d594fSAndroid Build Coastguard Worker DCHECK(non_full_runs_[idx].find(run) == non_full_runs_[idx].end());
774*795d594fSAndroid Build Coastguard Worker DCHECK(full_runs_[idx].find(run) == full_runs_[idx].end());
775*795d594fSAndroid Build Coastguard Worker run->AddToThreadLocalFreeList(ptr);
776*795d594fSAndroid Build Coastguard Worker if (kTraceRosAlloc) {
777*795d594fSAndroid Build Coastguard Worker LOG(INFO) << "RosAlloc::FreeFromRun() : Freed a slot in a thread local run 0x" << std::hex
778*795d594fSAndroid Build Coastguard Worker << reinterpret_cast<intptr_t>(run);
779*795d594fSAndroid Build Coastguard Worker }
780*795d594fSAndroid Build Coastguard Worker // A thread local run will be kept as a thread local even if it's become all free.
781*795d594fSAndroid Build Coastguard Worker return bracket_size;
782*795d594fSAndroid Build Coastguard Worker }
783*795d594fSAndroid Build Coastguard Worker // Free the slot in the run.
784*795d594fSAndroid Build Coastguard Worker run->FreeSlot(ptr);
785*795d594fSAndroid Build Coastguard Worker auto* non_full_runs = &non_full_runs_[idx];
786*795d594fSAndroid Build Coastguard Worker if (run->IsAllFree()) {
787*795d594fSAndroid Build Coastguard Worker // It has just become completely free. Free the pages of this run.
788*795d594fSAndroid Build Coastguard Worker std::set<Run*>::iterator pos = non_full_runs->find(run);
789*795d594fSAndroid Build Coastguard Worker if (pos != non_full_runs->end()) {
790*795d594fSAndroid Build Coastguard Worker non_full_runs->erase(pos);
791*795d594fSAndroid Build Coastguard Worker if (kTraceRosAlloc) {
792*795d594fSAndroid Build Coastguard Worker LOG(INFO) << "RosAlloc::FreeFromRun() : Erased run 0x" << std::hex
793*795d594fSAndroid Build Coastguard Worker << reinterpret_cast<intptr_t>(run) << " from non_full_runs_";
794*795d594fSAndroid Build Coastguard Worker }
795*795d594fSAndroid Build Coastguard Worker }
796*795d594fSAndroid Build Coastguard Worker if (run == current_runs_[idx]) {
797*795d594fSAndroid Build Coastguard Worker current_runs_[idx] = dedicated_full_run_;
798*795d594fSAndroid Build Coastguard Worker }
799*795d594fSAndroid Build Coastguard Worker DCHECK(non_full_runs_[idx].find(run) == non_full_runs_[idx].end());
800*795d594fSAndroid Build Coastguard Worker DCHECK(full_runs_[idx].find(run) == full_runs_[idx].end());
801*795d594fSAndroid Build Coastguard Worker run->ZeroHeaderAndSlotHeaders();
802*795d594fSAndroid Build Coastguard Worker {
803*795d594fSAndroid Build Coastguard Worker MutexLock lock_mu(self, lock_);
804*795d594fSAndroid Build Coastguard Worker FreePages(self, run, true);
805*795d594fSAndroid Build Coastguard Worker }
806*795d594fSAndroid Build Coastguard Worker } else {
807*795d594fSAndroid Build Coastguard Worker // It is not completely free. If it wasn't the current run or
808*795d594fSAndroid Build Coastguard Worker // already in the non-full run set (i.e., it was full) insert it
809*795d594fSAndroid Build Coastguard Worker // into the non-full run set.
810*795d594fSAndroid Build Coastguard Worker if (run != current_runs_[idx]) {
811*795d594fSAndroid Build Coastguard Worker auto* full_runs = kIsDebugBuild ? &full_runs_[idx] : nullptr;
812*795d594fSAndroid Build Coastguard Worker auto pos = non_full_runs->find(run);
813*795d594fSAndroid Build Coastguard Worker if (pos == non_full_runs->end()) {
814*795d594fSAndroid Build Coastguard Worker DCHECK(run_was_full);
815*795d594fSAndroid Build Coastguard Worker DCHECK(full_runs->find(run) != full_runs->end());
816*795d594fSAndroid Build Coastguard Worker if (kIsDebugBuild) {
817*795d594fSAndroid Build Coastguard Worker full_runs->erase(run);
818*795d594fSAndroid Build Coastguard Worker if (kTraceRosAlloc) {
819*795d594fSAndroid Build Coastguard Worker LOG(INFO) << "RosAlloc::FreeFromRun() : Erased run 0x" << std::hex
820*795d594fSAndroid Build Coastguard Worker << reinterpret_cast<intptr_t>(run) << " from full_runs_";
821*795d594fSAndroid Build Coastguard Worker }
822*795d594fSAndroid Build Coastguard Worker }
823*795d594fSAndroid Build Coastguard Worker non_full_runs->insert(run);
824*795d594fSAndroid Build Coastguard Worker DCHECK(!run->IsFull());
825*795d594fSAndroid Build Coastguard Worker if (kTraceRosAlloc) {
826*795d594fSAndroid Build Coastguard Worker LOG(INFO) << "RosAlloc::FreeFromRun() : Inserted run 0x" << std::hex
827*795d594fSAndroid Build Coastguard Worker << reinterpret_cast<intptr_t>(run)
828*795d594fSAndroid Build Coastguard Worker << " into non_full_runs_[" << std::dec << idx << "]";
829*795d594fSAndroid Build Coastguard Worker }
830*795d594fSAndroid Build Coastguard Worker }
831*795d594fSAndroid Build Coastguard Worker }
832*795d594fSAndroid Build Coastguard Worker }
833*795d594fSAndroid Build Coastguard Worker return bracket_size;
834*795d594fSAndroid Build Coastguard Worker }
835*795d594fSAndroid Build Coastguard Worker
836*795d594fSAndroid Build Coastguard Worker template<bool kUseTail>
FreeListToStr(SlotFreeList<kUseTail> * free_list)837*795d594fSAndroid Build Coastguard Worker std::string RosAlloc::Run::FreeListToStr(SlotFreeList<kUseTail>* free_list) {
838*795d594fSAndroid Build Coastguard Worker std::string free_list_str;
839*795d594fSAndroid Build Coastguard Worker const uint8_t idx = size_bracket_idx_;
840*795d594fSAndroid Build Coastguard Worker const size_t bracket_size = bracketSizes[idx];
841*795d594fSAndroid Build Coastguard Worker for (Slot* slot = free_list->Head(); slot != nullptr; slot = slot->Next()) {
842*795d594fSAndroid Build Coastguard Worker bool is_last = slot->Next() == nullptr;
843*795d594fSAndroid Build Coastguard Worker uintptr_t slot_offset = reinterpret_cast<uintptr_t>(slot) -
844*795d594fSAndroid Build Coastguard Worker reinterpret_cast<uintptr_t>(FirstSlot());
845*795d594fSAndroid Build Coastguard Worker DCHECK_EQ(slot_offset % bracket_size, 0U);
846*795d594fSAndroid Build Coastguard Worker uintptr_t slot_idx = slot_offset / bracket_size;
847*795d594fSAndroid Build Coastguard Worker if (!is_last) {
848*795d594fSAndroid Build Coastguard Worker free_list_str.append(StringPrintf("%u-", static_cast<uint32_t>(slot_idx)));
849*795d594fSAndroid Build Coastguard Worker } else {
850*795d594fSAndroid Build Coastguard Worker free_list_str.append(StringPrintf("%u", static_cast<uint32_t>(slot_idx)));
851*795d594fSAndroid Build Coastguard Worker }
852*795d594fSAndroid Build Coastguard Worker }
853*795d594fSAndroid Build Coastguard Worker return free_list_str;
854*795d594fSAndroid Build Coastguard Worker }
855*795d594fSAndroid Build Coastguard Worker
Dump()856*795d594fSAndroid Build Coastguard Worker std::string RosAlloc::Run::Dump() {
857*795d594fSAndroid Build Coastguard Worker size_t idx = size_bracket_idx_;
858*795d594fSAndroid Build Coastguard Worker std::ostringstream stream;
859*795d594fSAndroid Build Coastguard Worker stream << "RosAlloc Run = " << reinterpret_cast<void*>(this)
860*795d594fSAndroid Build Coastguard Worker << "{ magic_num=" << static_cast<int>(magic_num_)
861*795d594fSAndroid Build Coastguard Worker << " size_bracket_idx=" << idx
862*795d594fSAndroid Build Coastguard Worker << " is_thread_local=" << static_cast<int>(is_thread_local_)
863*795d594fSAndroid Build Coastguard Worker << " to_be_bulk_freed=" << static_cast<int>(to_be_bulk_freed_)
864*795d594fSAndroid Build Coastguard Worker << " free_list=" << FreeListToStr(&free_list_)
865*795d594fSAndroid Build Coastguard Worker << " bulk_free_list=" << FreeListToStr(&bulk_free_list_)
866*795d594fSAndroid Build Coastguard Worker << " thread_local_list=" << FreeListToStr(&thread_local_free_list_)
867*795d594fSAndroid Build Coastguard Worker << " }" << std::endl;
868*795d594fSAndroid Build Coastguard Worker return stream.str();
869*795d594fSAndroid Build Coastguard Worker }
870*795d594fSAndroid Build Coastguard Worker
FreeSlot(void * ptr)871*795d594fSAndroid Build Coastguard Worker void RosAlloc::Run::FreeSlot(void* ptr) {
872*795d594fSAndroid Build Coastguard Worker DCHECK(!IsThreadLocal());
873*795d594fSAndroid Build Coastguard Worker const uint8_t idx = size_bracket_idx_;
874*795d594fSAndroid Build Coastguard Worker const size_t bracket_size = bracketSizes[idx];
875*795d594fSAndroid Build Coastguard Worker Slot* slot = ToSlot(ptr);
876*795d594fSAndroid Build Coastguard Worker // Zero out the memory.
877*795d594fSAndroid Build Coastguard Worker // TODO: Investigate alternate memset since ptr is guaranteed to be aligned to 16.
878*795d594fSAndroid Build Coastguard Worker memset(slot, 0, bracket_size);
879*795d594fSAndroid Build Coastguard Worker free_list_.Add(slot);
880*795d594fSAndroid Build Coastguard Worker if (kTraceRosAlloc) {
881*795d594fSAndroid Build Coastguard Worker LOG(INFO) << "RosAlloc::Run::FreeSlot() : " << slot
882*795d594fSAndroid Build Coastguard Worker << ", bracket_size=" << std::dec << bracket_size << ", slot_idx=" << SlotIndex(slot);
883*795d594fSAndroid Build Coastguard Worker }
884*795d594fSAndroid Build Coastguard Worker }
885*795d594fSAndroid Build Coastguard Worker
MergeThreadLocalFreeListToFreeList(bool * is_all_free_after_out)886*795d594fSAndroid Build Coastguard Worker inline bool RosAlloc::Run::MergeThreadLocalFreeListToFreeList(bool* is_all_free_after_out) {
887*795d594fSAndroid Build Coastguard Worker DCHECK(IsThreadLocal());
888*795d594fSAndroid Build Coastguard Worker // Merge the thread local free list into the free list and clear the thread local free list.
889*795d594fSAndroid Build Coastguard Worker const uint8_t idx = size_bracket_idx_;
890*795d594fSAndroid Build Coastguard Worker size_t thread_local_free_list_size = thread_local_free_list_.Size();
891*795d594fSAndroid Build Coastguard Worker const size_t size_before = free_list_.Size();
892*795d594fSAndroid Build Coastguard Worker free_list_.Merge(&thread_local_free_list_);
893*795d594fSAndroid Build Coastguard Worker const size_t size_after = free_list_.Size();
894*795d594fSAndroid Build Coastguard Worker DCHECK_EQ(size_before < size_after, thread_local_free_list_size > 0);
895*795d594fSAndroid Build Coastguard Worker DCHECK_LE(size_before, size_after);
896*795d594fSAndroid Build Coastguard Worker *is_all_free_after_out = free_list_.Size() == numOfSlots[idx];
897*795d594fSAndroid Build Coastguard Worker // Return true at least one slot was added to the free list.
898*795d594fSAndroid Build Coastguard Worker return size_before < size_after;
899*795d594fSAndroid Build Coastguard Worker }
900*795d594fSAndroid Build Coastguard Worker
MergeBulkFreeListToFreeList()901*795d594fSAndroid Build Coastguard Worker inline void RosAlloc::Run::MergeBulkFreeListToFreeList() {
902*795d594fSAndroid Build Coastguard Worker DCHECK(!IsThreadLocal());
903*795d594fSAndroid Build Coastguard Worker // Merge the bulk free list into the free list and clear the bulk free list.
904*795d594fSAndroid Build Coastguard Worker free_list_.Merge(&bulk_free_list_);
905*795d594fSAndroid Build Coastguard Worker }
906*795d594fSAndroid Build Coastguard Worker
MergeBulkFreeListToThreadLocalFreeList()907*795d594fSAndroid Build Coastguard Worker inline void RosAlloc::Run::MergeBulkFreeListToThreadLocalFreeList() {
908*795d594fSAndroid Build Coastguard Worker DCHECK(IsThreadLocal());
909*795d594fSAndroid Build Coastguard Worker // Merge the bulk free list into the thread local free list and clear the bulk free list.
910*795d594fSAndroid Build Coastguard Worker thread_local_free_list_.Merge(&bulk_free_list_);
911*795d594fSAndroid Build Coastguard Worker }
912*795d594fSAndroid Build Coastguard Worker
AddToThreadLocalFreeList(void * ptr)913*795d594fSAndroid Build Coastguard Worker inline void RosAlloc::Run::AddToThreadLocalFreeList(void* ptr) {
914*795d594fSAndroid Build Coastguard Worker DCHECK(IsThreadLocal());
915*795d594fSAndroid Build Coastguard Worker AddToFreeListShared(ptr, &thread_local_free_list_, __FUNCTION__);
916*795d594fSAndroid Build Coastguard Worker }
917*795d594fSAndroid Build Coastguard Worker
AddToBulkFreeList(void * ptr)918*795d594fSAndroid Build Coastguard Worker inline size_t RosAlloc::Run::AddToBulkFreeList(void* ptr) {
919*795d594fSAndroid Build Coastguard Worker return AddToFreeListShared(ptr, &bulk_free_list_, __FUNCTION__);
920*795d594fSAndroid Build Coastguard Worker }
921*795d594fSAndroid Build Coastguard Worker
AddToFreeListShared(void * ptr,SlotFreeList<true> * free_list,const char * caller_name)922*795d594fSAndroid Build Coastguard Worker inline size_t RosAlloc::Run::AddToFreeListShared(void* ptr,
923*795d594fSAndroid Build Coastguard Worker SlotFreeList<true>* free_list,
924*795d594fSAndroid Build Coastguard Worker const char* caller_name) {
925*795d594fSAndroid Build Coastguard Worker const uint8_t idx = size_bracket_idx_;
926*795d594fSAndroid Build Coastguard Worker const size_t bracket_size = bracketSizes[idx];
927*795d594fSAndroid Build Coastguard Worker Slot* slot = ToSlot(ptr);
928*795d594fSAndroid Build Coastguard Worker memset(slot, 0, bracket_size);
929*795d594fSAndroid Build Coastguard Worker free_list->Add(slot);
930*795d594fSAndroid Build Coastguard Worker if (kTraceRosAlloc) {
931*795d594fSAndroid Build Coastguard Worker LOG(INFO) << "RosAlloc::Run::" << caller_name << "() : " << ptr
932*795d594fSAndroid Build Coastguard Worker << ", bracket_size=" << std::dec << bracket_size << ", slot_idx=" << SlotIndex(slot);
933*795d594fSAndroid Build Coastguard Worker }
934*795d594fSAndroid Build Coastguard Worker return bracket_size;
935*795d594fSAndroid Build Coastguard Worker }
936*795d594fSAndroid Build Coastguard Worker
ZeroHeaderAndSlotHeaders()937*795d594fSAndroid Build Coastguard Worker inline void RosAlloc::Run::ZeroHeaderAndSlotHeaders() {
938*795d594fSAndroid Build Coastguard Worker DCHECK(IsAllFree());
939*795d594fSAndroid Build Coastguard Worker const uint8_t idx = size_bracket_idx_;
940*795d594fSAndroid Build Coastguard Worker // Zero the slot header (next pointers).
941*795d594fSAndroid Build Coastguard Worker for (Slot* slot = free_list_.Head(); slot != nullptr; ) {
942*795d594fSAndroid Build Coastguard Worker Slot* next_slot = slot->Next();
943*795d594fSAndroid Build Coastguard Worker slot->Clear();
944*795d594fSAndroid Build Coastguard Worker slot = next_slot;
945*795d594fSAndroid Build Coastguard Worker }
946*795d594fSAndroid Build Coastguard Worker // Zero the header.
947*795d594fSAndroid Build Coastguard Worker memset(this, 0, headerSizes[idx]);
948*795d594fSAndroid Build Coastguard Worker // Check that the entire run is all zero.
949*795d594fSAndroid Build Coastguard Worker if (kIsDebugBuild) {
950*795d594fSAndroid Build Coastguard Worker const size_t size = numOfPages[idx] * gPageSize;
951*795d594fSAndroid Build Coastguard Worker const uintptr_t* word_ptr = reinterpret_cast<uintptr_t*>(this);
952*795d594fSAndroid Build Coastguard Worker for (size_t i = 0; i < size / sizeof(uintptr_t); ++i) {
953*795d594fSAndroid Build Coastguard Worker CHECK_EQ(word_ptr[i], 0U) << "words don't match at index " << i;
954*795d594fSAndroid Build Coastguard Worker }
955*795d594fSAndroid Build Coastguard Worker }
956*795d594fSAndroid Build Coastguard Worker }
957*795d594fSAndroid Build Coastguard Worker
ZeroData()958*795d594fSAndroid Build Coastguard Worker inline void RosAlloc::Run::ZeroData() {
959*795d594fSAndroid Build Coastguard Worker const uint8_t idx = size_bracket_idx_;
960*795d594fSAndroid Build Coastguard Worker uint8_t* slot_begin = reinterpret_cast<uint8_t*>(FirstSlot());
961*795d594fSAndroid Build Coastguard Worker memset(slot_begin, 0, numOfSlots[idx] * bracketSizes[idx]);
962*795d594fSAndroid Build Coastguard Worker }
963*795d594fSAndroid Build Coastguard Worker
InspectAllSlots(void (* handler)(void * start,void * end,size_t used_bytes,void * callback_arg),void * arg)964*795d594fSAndroid Build Coastguard Worker void RosAlloc::Run::InspectAllSlots(void (*handler)(void* start, void* end, size_t used_bytes, void* callback_arg),
965*795d594fSAndroid Build Coastguard Worker void* arg) {
966*795d594fSAndroid Build Coastguard Worker size_t idx = size_bracket_idx_;
967*795d594fSAndroid Build Coastguard Worker uint8_t* slot_base = reinterpret_cast<uint8_t*>(this) + headerSizes[idx];
968*795d594fSAndroid Build Coastguard Worker size_t num_slots = numOfSlots[idx];
969*795d594fSAndroid Build Coastguard Worker size_t bracket_size = IndexToBracketSize(idx);
970*795d594fSAndroid Build Coastguard Worker DCHECK_EQ(slot_base + num_slots * bracket_size,
971*795d594fSAndroid Build Coastguard Worker reinterpret_cast<uint8_t*>(this) + numOfPages[idx] * gPageSize);
972*795d594fSAndroid Build Coastguard Worker // Free slots are on the free list and the allocated/used slots are not. We traverse the free list
973*795d594fSAndroid Build Coastguard Worker // to find out and record which slots are free in the is_free array.
974*795d594fSAndroid Build Coastguard Worker std::unique_ptr<bool[]> is_free(new bool[num_slots]()); // zero initialized
975*795d594fSAndroid Build Coastguard Worker for (Slot* slot = free_list_.Head(); slot != nullptr; slot = slot->Next()) {
976*795d594fSAndroid Build Coastguard Worker size_t slot_idx = SlotIndex(slot);
977*795d594fSAndroid Build Coastguard Worker DCHECK_LT(slot_idx, num_slots);
978*795d594fSAndroid Build Coastguard Worker is_free[slot_idx] = true;
979*795d594fSAndroid Build Coastguard Worker }
980*795d594fSAndroid Build Coastguard Worker if (IsThreadLocal()) {
981*795d594fSAndroid Build Coastguard Worker for (Slot* slot = thread_local_free_list_.Head(); slot != nullptr; slot = slot->Next()) {
982*795d594fSAndroid Build Coastguard Worker size_t slot_idx = SlotIndex(slot);
983*795d594fSAndroid Build Coastguard Worker DCHECK_LT(slot_idx, num_slots);
984*795d594fSAndroid Build Coastguard Worker is_free[slot_idx] = true;
985*795d594fSAndroid Build Coastguard Worker }
986*795d594fSAndroid Build Coastguard Worker }
987*795d594fSAndroid Build Coastguard Worker for (size_t slot_idx = 0; slot_idx < num_slots; ++slot_idx) {
988*795d594fSAndroid Build Coastguard Worker uint8_t* slot_addr = slot_base + slot_idx * bracket_size;
989*795d594fSAndroid Build Coastguard Worker if (!is_free[slot_idx]) {
990*795d594fSAndroid Build Coastguard Worker handler(slot_addr, slot_addr + bracket_size, bracket_size, arg);
991*795d594fSAndroid Build Coastguard Worker } else {
992*795d594fSAndroid Build Coastguard Worker handler(slot_addr, slot_addr + bracket_size, 0, arg);
993*795d594fSAndroid Build Coastguard Worker }
994*795d594fSAndroid Build Coastguard Worker }
995*795d594fSAndroid Build Coastguard Worker }
996*795d594fSAndroid Build Coastguard Worker
997*795d594fSAndroid Build Coastguard Worker // If true, read the page map entries in BulkFree() without using the
998*795d594fSAndroid Build Coastguard Worker // lock for better performance, assuming that the existence of an
999*795d594fSAndroid Build Coastguard Worker // allocated chunk/pointer being freed in BulkFree() guarantees that
1000*795d594fSAndroid Build Coastguard Worker // the page map entry won't change.
1001*795d594fSAndroid Build Coastguard Worker static constexpr bool kReadPageMapEntryWithoutLockInBulkFree = true;
1002*795d594fSAndroid Build Coastguard Worker
BulkFree(Thread * self,void ** ptrs,size_t num_ptrs)1003*795d594fSAndroid Build Coastguard Worker size_t RosAlloc::BulkFree(Thread* self, void** ptrs, size_t num_ptrs) {
1004*795d594fSAndroid Build Coastguard Worker size_t freed_bytes = 0;
1005*795d594fSAndroid Build Coastguard Worker if ((false)) {
1006*795d594fSAndroid Build Coastguard Worker // Used only to test Free() as GC uses only BulkFree().
1007*795d594fSAndroid Build Coastguard Worker for (size_t i = 0; i < num_ptrs; ++i) {
1008*795d594fSAndroid Build Coastguard Worker freed_bytes += FreeInternal(self, ptrs[i]);
1009*795d594fSAndroid Build Coastguard Worker }
1010*795d594fSAndroid Build Coastguard Worker return freed_bytes;
1011*795d594fSAndroid Build Coastguard Worker }
1012*795d594fSAndroid Build Coastguard Worker
1013*795d594fSAndroid Build Coastguard Worker WriterMutexLock wmu(self, bulk_free_lock_);
1014*795d594fSAndroid Build Coastguard Worker
1015*795d594fSAndroid Build Coastguard Worker // First mark slots to free in the bulk free bit map without locking the
1016*795d594fSAndroid Build Coastguard Worker // size bracket locks. On host, unordered_set is faster than vector + flag.
1017*795d594fSAndroid Build Coastguard Worker #ifdef ART_TARGET_ANDROID
1018*795d594fSAndroid Build Coastguard Worker std::vector<Run*> runs;
1019*795d594fSAndroid Build Coastguard Worker #else
1020*795d594fSAndroid Build Coastguard Worker std::unordered_set<Run*, hash_run, eq_run> runs;
1021*795d594fSAndroid Build Coastguard Worker #endif
1022*795d594fSAndroid Build Coastguard Worker for (size_t i = 0; i < num_ptrs; i++) {
1023*795d594fSAndroid Build Coastguard Worker void* ptr = ptrs[i];
1024*795d594fSAndroid Build Coastguard Worker DCHECK_LE(base_, ptr);
1025*795d594fSAndroid Build Coastguard Worker DCHECK_LT(ptr, base_ + footprint_);
1026*795d594fSAndroid Build Coastguard Worker size_t pm_idx = RoundDownToPageMapIndex(ptr);
1027*795d594fSAndroid Build Coastguard Worker Run* run = nullptr;
1028*795d594fSAndroid Build Coastguard Worker if (kReadPageMapEntryWithoutLockInBulkFree) {
1029*795d594fSAndroid Build Coastguard Worker // Read the page map entries without locking the lock.
1030*795d594fSAndroid Build Coastguard Worker uint8_t page_map_entry = page_map_[pm_idx];
1031*795d594fSAndroid Build Coastguard Worker if (kTraceRosAlloc) {
1032*795d594fSAndroid Build Coastguard Worker LOG(INFO) << "RosAlloc::BulkFree() : " << std::hex << ptr << ", pm_idx="
1033*795d594fSAndroid Build Coastguard Worker << std::dec << pm_idx
1034*795d594fSAndroid Build Coastguard Worker << ", page_map_entry=" << static_cast<int>(page_map_entry);
1035*795d594fSAndroid Build Coastguard Worker }
1036*795d594fSAndroid Build Coastguard Worker if (LIKELY(page_map_entry == kPageMapRun)) {
1037*795d594fSAndroid Build Coastguard Worker run = reinterpret_cast<Run*>(base_ + pm_idx * gPageSize);
1038*795d594fSAndroid Build Coastguard Worker } else if (LIKELY(page_map_entry == kPageMapRunPart)) {
1039*795d594fSAndroid Build Coastguard Worker size_t pi = pm_idx;
1040*795d594fSAndroid Build Coastguard Worker // Find the beginning of the run.
1041*795d594fSAndroid Build Coastguard Worker do {
1042*795d594fSAndroid Build Coastguard Worker --pi;
1043*795d594fSAndroid Build Coastguard Worker DCHECK_LT(pi, DivideByPageSize(capacity_));
1044*795d594fSAndroid Build Coastguard Worker } while (page_map_[pi] != kPageMapRun);
1045*795d594fSAndroid Build Coastguard Worker run = reinterpret_cast<Run*>(base_ + pi * gPageSize);
1046*795d594fSAndroid Build Coastguard Worker } else if (page_map_entry == kPageMapLargeObject) {
1047*795d594fSAndroid Build Coastguard Worker MutexLock mu(self, lock_);
1048*795d594fSAndroid Build Coastguard Worker freed_bytes += FreePages(self, ptr, false);
1049*795d594fSAndroid Build Coastguard Worker continue;
1050*795d594fSAndroid Build Coastguard Worker } else {
1051*795d594fSAndroid Build Coastguard Worker LOG(FATAL) << "Unreachable - page map type: " << static_cast<int>(page_map_entry);
1052*795d594fSAndroid Build Coastguard Worker }
1053*795d594fSAndroid Build Coastguard Worker } else {
1054*795d594fSAndroid Build Coastguard Worker // Read the page map entries with a lock.
1055*795d594fSAndroid Build Coastguard Worker MutexLock mu(self, lock_);
1056*795d594fSAndroid Build Coastguard Worker DCHECK_LT(pm_idx, page_map_size_);
1057*795d594fSAndroid Build Coastguard Worker uint8_t page_map_entry = page_map_[pm_idx];
1058*795d594fSAndroid Build Coastguard Worker if (kTraceRosAlloc) {
1059*795d594fSAndroid Build Coastguard Worker LOG(INFO) << "RosAlloc::BulkFree() : " << std::hex << ptr << ", pm_idx="
1060*795d594fSAndroid Build Coastguard Worker << std::dec << pm_idx
1061*795d594fSAndroid Build Coastguard Worker << ", page_map_entry=" << static_cast<int>(page_map_entry);
1062*795d594fSAndroid Build Coastguard Worker }
1063*795d594fSAndroid Build Coastguard Worker if (LIKELY(page_map_entry == kPageMapRun)) {
1064*795d594fSAndroid Build Coastguard Worker run = reinterpret_cast<Run*>(base_ + pm_idx * gPageSize);
1065*795d594fSAndroid Build Coastguard Worker } else if (LIKELY(page_map_entry == kPageMapRunPart)) {
1066*795d594fSAndroid Build Coastguard Worker size_t pi = pm_idx;
1067*795d594fSAndroid Build Coastguard Worker // Find the beginning of the run.
1068*795d594fSAndroid Build Coastguard Worker do {
1069*795d594fSAndroid Build Coastguard Worker --pi;
1070*795d594fSAndroid Build Coastguard Worker DCHECK_LT(pi, DivideByPageSize(capacity_));
1071*795d594fSAndroid Build Coastguard Worker } while (page_map_[pi] != kPageMapRun);
1072*795d594fSAndroid Build Coastguard Worker run = reinterpret_cast<Run*>(base_ + pi * gPageSize);
1073*795d594fSAndroid Build Coastguard Worker } else if (page_map_entry == kPageMapLargeObject) {
1074*795d594fSAndroid Build Coastguard Worker freed_bytes += FreePages(self, ptr, false);
1075*795d594fSAndroid Build Coastguard Worker continue;
1076*795d594fSAndroid Build Coastguard Worker } else {
1077*795d594fSAndroid Build Coastguard Worker LOG(FATAL) << "Unreachable - page map type: " << static_cast<int>(page_map_entry);
1078*795d594fSAndroid Build Coastguard Worker }
1079*795d594fSAndroid Build Coastguard Worker }
1080*795d594fSAndroid Build Coastguard Worker DCHECK(run != nullptr);
1081*795d594fSAndroid Build Coastguard Worker DCHECK_EQ(run->magic_num_, kMagicNum);
1082*795d594fSAndroid Build Coastguard Worker // Set the bit in the bulk free bit map.
1083*795d594fSAndroid Build Coastguard Worker freed_bytes += run->AddToBulkFreeList(ptr);
1084*795d594fSAndroid Build Coastguard Worker #ifdef ART_TARGET_ANDROID
1085*795d594fSAndroid Build Coastguard Worker if (!run->to_be_bulk_freed_) {
1086*795d594fSAndroid Build Coastguard Worker run->to_be_bulk_freed_ = true;
1087*795d594fSAndroid Build Coastguard Worker runs.push_back(run);
1088*795d594fSAndroid Build Coastguard Worker }
1089*795d594fSAndroid Build Coastguard Worker #else
1090*795d594fSAndroid Build Coastguard Worker runs.insert(run);
1091*795d594fSAndroid Build Coastguard Worker #endif
1092*795d594fSAndroid Build Coastguard Worker }
1093*795d594fSAndroid Build Coastguard Worker
1094*795d594fSAndroid Build Coastguard Worker // Now, iterate over the affected runs and update the alloc bit map
1095*795d594fSAndroid Build Coastguard Worker // based on the bulk free bit map (for non-thread-local runs) and
1096*795d594fSAndroid Build Coastguard Worker // union the bulk free bit map into the thread-local free bit map
1097*795d594fSAndroid Build Coastguard Worker // (for thread-local runs.)
1098*795d594fSAndroid Build Coastguard Worker for (Run* run : runs) {
1099*795d594fSAndroid Build Coastguard Worker #ifdef ART_TARGET_ANDROID
1100*795d594fSAndroid Build Coastguard Worker DCHECK(run->to_be_bulk_freed_);
1101*795d594fSAndroid Build Coastguard Worker run->to_be_bulk_freed_ = false;
1102*795d594fSAndroid Build Coastguard Worker #endif
1103*795d594fSAndroid Build Coastguard Worker size_t idx = run->size_bracket_idx_;
1104*795d594fSAndroid Build Coastguard Worker MutexLock brackets_mu(self, *size_bracket_locks_[idx]);
1105*795d594fSAndroid Build Coastguard Worker if (run->IsThreadLocal()) {
1106*795d594fSAndroid Build Coastguard Worker DCHECK_LT(run->size_bracket_idx_, kNumThreadLocalSizeBrackets);
1107*795d594fSAndroid Build Coastguard Worker DCHECK(non_full_runs_[idx].find(run) == non_full_runs_[idx].end());
1108*795d594fSAndroid Build Coastguard Worker DCHECK(full_runs_[idx].find(run) == full_runs_[idx].end());
1109*795d594fSAndroid Build Coastguard Worker run->MergeBulkFreeListToThreadLocalFreeList();
1110*795d594fSAndroid Build Coastguard Worker if (kTraceRosAlloc) {
1111*795d594fSAndroid Build Coastguard Worker LOG(INFO) << "RosAlloc::BulkFree() : Freed slot(s) in a thread local run 0x"
1112*795d594fSAndroid Build Coastguard Worker << std::hex << reinterpret_cast<intptr_t>(run);
1113*795d594fSAndroid Build Coastguard Worker }
1114*795d594fSAndroid Build Coastguard Worker DCHECK(run->IsThreadLocal());
1115*795d594fSAndroid Build Coastguard Worker // A thread local run will be kept as a thread local even if
1116*795d594fSAndroid Build Coastguard Worker // it's become all free.
1117*795d594fSAndroid Build Coastguard Worker } else {
1118*795d594fSAndroid Build Coastguard Worker bool run_was_full = run->IsFull();
1119*795d594fSAndroid Build Coastguard Worker run->MergeBulkFreeListToFreeList();
1120*795d594fSAndroid Build Coastguard Worker if (kTraceRosAlloc) {
1121*795d594fSAndroid Build Coastguard Worker LOG(INFO) << "RosAlloc::BulkFree() : Freed slot(s) in a run 0x" << std::hex
1122*795d594fSAndroid Build Coastguard Worker << reinterpret_cast<intptr_t>(run);
1123*795d594fSAndroid Build Coastguard Worker }
1124*795d594fSAndroid Build Coastguard Worker // Check if the run should be moved to non_full_runs_ or
1125*795d594fSAndroid Build Coastguard Worker // free_page_runs_.
1126*795d594fSAndroid Build Coastguard Worker auto* non_full_runs = &non_full_runs_[idx];
1127*795d594fSAndroid Build Coastguard Worker auto* full_runs = kIsDebugBuild ? &full_runs_[idx] : nullptr;
1128*795d594fSAndroid Build Coastguard Worker if (run->IsAllFree()) {
1129*795d594fSAndroid Build Coastguard Worker // It has just become completely free. Free the pages of the
1130*795d594fSAndroid Build Coastguard Worker // run.
1131*795d594fSAndroid Build Coastguard Worker bool run_was_current = run == current_runs_[idx];
1132*795d594fSAndroid Build Coastguard Worker if (run_was_current) {
1133*795d594fSAndroid Build Coastguard Worker DCHECK(full_runs->find(run) == full_runs->end());
1134*795d594fSAndroid Build Coastguard Worker DCHECK(non_full_runs->find(run) == non_full_runs->end());
1135*795d594fSAndroid Build Coastguard Worker // If it was a current run, reuse it.
1136*795d594fSAndroid Build Coastguard Worker } else if (run_was_full) {
1137*795d594fSAndroid Build Coastguard Worker // If it was full, remove it from the full run set (debug
1138*795d594fSAndroid Build Coastguard Worker // only.)
1139*795d594fSAndroid Build Coastguard Worker if (kIsDebugBuild) {
1140*795d594fSAndroid Build Coastguard Worker std::unordered_set<Run*, hash_run, eq_run>::iterator pos = full_runs->find(run);
1141*795d594fSAndroid Build Coastguard Worker DCHECK(pos != full_runs->end());
1142*795d594fSAndroid Build Coastguard Worker full_runs->erase(pos);
1143*795d594fSAndroid Build Coastguard Worker if (kTraceRosAlloc) {
1144*795d594fSAndroid Build Coastguard Worker LOG(INFO) << "RosAlloc::BulkFree() : Erased run 0x" << std::hex
1145*795d594fSAndroid Build Coastguard Worker << reinterpret_cast<intptr_t>(run)
1146*795d594fSAndroid Build Coastguard Worker << " from full_runs_";
1147*795d594fSAndroid Build Coastguard Worker }
1148*795d594fSAndroid Build Coastguard Worker DCHECK(full_runs->find(run) == full_runs->end());
1149*795d594fSAndroid Build Coastguard Worker }
1150*795d594fSAndroid Build Coastguard Worker } else {
1151*795d594fSAndroid Build Coastguard Worker // If it was in a non full run set, remove it from the set.
1152*795d594fSAndroid Build Coastguard Worker DCHECK(full_runs->find(run) == full_runs->end());
1153*795d594fSAndroid Build Coastguard Worker DCHECK(non_full_runs->find(run) != non_full_runs->end());
1154*795d594fSAndroid Build Coastguard Worker non_full_runs->erase(run);
1155*795d594fSAndroid Build Coastguard Worker if (kTraceRosAlloc) {
1156*795d594fSAndroid Build Coastguard Worker LOG(INFO) << "RosAlloc::BulkFree() : Erased run 0x" << std::hex
1157*795d594fSAndroid Build Coastguard Worker << reinterpret_cast<intptr_t>(run)
1158*795d594fSAndroid Build Coastguard Worker << " from non_full_runs_";
1159*795d594fSAndroid Build Coastguard Worker }
1160*795d594fSAndroid Build Coastguard Worker DCHECK(non_full_runs->find(run) == non_full_runs->end());
1161*795d594fSAndroid Build Coastguard Worker }
1162*795d594fSAndroid Build Coastguard Worker if (!run_was_current) {
1163*795d594fSAndroid Build Coastguard Worker run->ZeroHeaderAndSlotHeaders();
1164*795d594fSAndroid Build Coastguard Worker MutexLock lock_mu(self, lock_);
1165*795d594fSAndroid Build Coastguard Worker FreePages(self, run, true);
1166*795d594fSAndroid Build Coastguard Worker }
1167*795d594fSAndroid Build Coastguard Worker } else {
1168*795d594fSAndroid Build Coastguard Worker // It is not completely free. If it wasn't the current run or
1169*795d594fSAndroid Build Coastguard Worker // already in the non-full run set (i.e., it was full) insert
1170*795d594fSAndroid Build Coastguard Worker // it into the non-full run set.
1171*795d594fSAndroid Build Coastguard Worker if (run == current_runs_[idx]) {
1172*795d594fSAndroid Build Coastguard Worker DCHECK(non_full_runs->find(run) == non_full_runs->end());
1173*795d594fSAndroid Build Coastguard Worker DCHECK(full_runs->find(run) == full_runs->end());
1174*795d594fSAndroid Build Coastguard Worker // If it was a current run, keep it.
1175*795d594fSAndroid Build Coastguard Worker } else if (run_was_full) {
1176*795d594fSAndroid Build Coastguard Worker // If it was full, remove it from the full run set (debug
1177*795d594fSAndroid Build Coastguard Worker // only) and insert into the non-full run set.
1178*795d594fSAndroid Build Coastguard Worker DCHECK(full_runs->find(run) != full_runs->end());
1179*795d594fSAndroid Build Coastguard Worker DCHECK(non_full_runs->find(run) == non_full_runs->end());
1180*795d594fSAndroid Build Coastguard Worker if (kIsDebugBuild) {
1181*795d594fSAndroid Build Coastguard Worker full_runs->erase(run);
1182*795d594fSAndroid Build Coastguard Worker if (kTraceRosAlloc) {
1183*795d594fSAndroid Build Coastguard Worker LOG(INFO) << "RosAlloc::BulkFree() : Erased run 0x" << std::hex
1184*795d594fSAndroid Build Coastguard Worker << reinterpret_cast<intptr_t>(run)
1185*795d594fSAndroid Build Coastguard Worker << " from full_runs_";
1186*795d594fSAndroid Build Coastguard Worker }
1187*795d594fSAndroid Build Coastguard Worker }
1188*795d594fSAndroid Build Coastguard Worker non_full_runs->insert(run);
1189*795d594fSAndroid Build Coastguard Worker if (kTraceRosAlloc) {
1190*795d594fSAndroid Build Coastguard Worker LOG(INFO) << "RosAlloc::BulkFree() : Inserted run 0x" << std::hex
1191*795d594fSAndroid Build Coastguard Worker << reinterpret_cast<intptr_t>(run)
1192*795d594fSAndroid Build Coastguard Worker << " into non_full_runs_[" << std::dec << idx;
1193*795d594fSAndroid Build Coastguard Worker }
1194*795d594fSAndroid Build Coastguard Worker } else {
1195*795d594fSAndroid Build Coastguard Worker // If it was not full, so leave it in the non full run set.
1196*795d594fSAndroid Build Coastguard Worker DCHECK(full_runs->find(run) == full_runs->end());
1197*795d594fSAndroid Build Coastguard Worker DCHECK(non_full_runs->find(run) != non_full_runs->end());
1198*795d594fSAndroid Build Coastguard Worker }
1199*795d594fSAndroid Build Coastguard Worker }
1200*795d594fSAndroid Build Coastguard Worker }
1201*795d594fSAndroid Build Coastguard Worker }
1202*795d594fSAndroid Build Coastguard Worker return freed_bytes;
1203*795d594fSAndroid Build Coastguard Worker }
1204*795d594fSAndroid Build Coastguard Worker
DumpPageMap()1205*795d594fSAndroid Build Coastguard Worker std::string RosAlloc::DumpPageMap() {
1206*795d594fSAndroid Build Coastguard Worker std::ostringstream stream;
1207*795d594fSAndroid Build Coastguard Worker stream << "RosAlloc PageMap: " << std::endl;
1208*795d594fSAndroid Build Coastguard Worker lock_.AssertHeld(Thread::Current());
1209*795d594fSAndroid Build Coastguard Worker size_t end = page_map_size_;
1210*795d594fSAndroid Build Coastguard Worker FreePageRun* curr_fpr = nullptr;
1211*795d594fSAndroid Build Coastguard Worker size_t curr_fpr_size = 0;
1212*795d594fSAndroid Build Coastguard Worker size_t remaining_curr_fpr_size = 0;
1213*795d594fSAndroid Build Coastguard Worker size_t num_running_empty_pages = 0;
1214*795d594fSAndroid Build Coastguard Worker for (size_t i = 0; i < end; ++i) {
1215*795d594fSAndroid Build Coastguard Worker uint8_t pm = page_map_[i];
1216*795d594fSAndroid Build Coastguard Worker switch (pm) {
1217*795d594fSAndroid Build Coastguard Worker case kPageMapReleased:
1218*795d594fSAndroid Build Coastguard Worker // Fall-through.
1219*795d594fSAndroid Build Coastguard Worker case kPageMapEmpty: {
1220*795d594fSAndroid Build Coastguard Worker FreePageRun* fpr = reinterpret_cast<FreePageRun*>(base_ + i * gPageSize);
1221*795d594fSAndroid Build Coastguard Worker if (free_page_runs_.find(fpr) != free_page_runs_.end()) {
1222*795d594fSAndroid Build Coastguard Worker // Encountered a fresh free page run.
1223*795d594fSAndroid Build Coastguard Worker DCHECK_EQ(remaining_curr_fpr_size, static_cast<size_t>(0));
1224*795d594fSAndroid Build Coastguard Worker DCHECK(fpr->IsFree());
1225*795d594fSAndroid Build Coastguard Worker DCHECK(curr_fpr == nullptr);
1226*795d594fSAndroid Build Coastguard Worker DCHECK_EQ(curr_fpr_size, static_cast<size_t>(0));
1227*795d594fSAndroid Build Coastguard Worker curr_fpr = fpr;
1228*795d594fSAndroid Build Coastguard Worker curr_fpr_size = fpr->ByteSize(this);
1229*795d594fSAndroid Build Coastguard Worker DCHECK_EQ(ModuloPageSize(curr_fpr_size), static_cast<size_t>(0));
1230*795d594fSAndroid Build Coastguard Worker remaining_curr_fpr_size = curr_fpr_size - gPageSize;
1231*795d594fSAndroid Build Coastguard Worker stream << "[" << i << "]=" << (pm == kPageMapReleased ? "Released" : "Empty")
1232*795d594fSAndroid Build Coastguard Worker << " (FPR start) fpr_size=" << curr_fpr_size
1233*795d594fSAndroid Build Coastguard Worker << " remaining_fpr_size=" << remaining_curr_fpr_size << std::endl;
1234*795d594fSAndroid Build Coastguard Worker if (remaining_curr_fpr_size == 0) {
1235*795d594fSAndroid Build Coastguard Worker // Reset at the end of the current free page run.
1236*795d594fSAndroid Build Coastguard Worker curr_fpr = nullptr;
1237*795d594fSAndroid Build Coastguard Worker curr_fpr_size = 0;
1238*795d594fSAndroid Build Coastguard Worker }
1239*795d594fSAndroid Build Coastguard Worker stream << "curr_fpr=0x" << std::hex << reinterpret_cast<intptr_t>(curr_fpr) << std::endl;
1240*795d594fSAndroid Build Coastguard Worker DCHECK_EQ(num_running_empty_pages, static_cast<size_t>(0));
1241*795d594fSAndroid Build Coastguard Worker } else {
1242*795d594fSAndroid Build Coastguard Worker // Still part of the current free page run.
1243*795d594fSAndroid Build Coastguard Worker DCHECK_NE(num_running_empty_pages, static_cast<size_t>(0));
1244*795d594fSAndroid Build Coastguard Worker DCHECK(curr_fpr != nullptr && curr_fpr_size > 0 && remaining_curr_fpr_size > 0);
1245*795d594fSAndroid Build Coastguard Worker DCHECK_EQ(ModuloPageSize(remaining_curr_fpr_size), static_cast<size_t>(0));
1246*795d594fSAndroid Build Coastguard Worker DCHECK_GE(remaining_curr_fpr_size, static_cast<size_t>(gPageSize));
1247*795d594fSAndroid Build Coastguard Worker remaining_curr_fpr_size -= gPageSize;
1248*795d594fSAndroid Build Coastguard Worker stream << "[" << i << "]=Empty (FPR part)"
1249*795d594fSAndroid Build Coastguard Worker << " remaining_fpr_size=" << remaining_curr_fpr_size << std::endl;
1250*795d594fSAndroid Build Coastguard Worker if (remaining_curr_fpr_size == 0) {
1251*795d594fSAndroid Build Coastguard Worker // Reset at the end of the current free page run.
1252*795d594fSAndroid Build Coastguard Worker curr_fpr = nullptr;
1253*795d594fSAndroid Build Coastguard Worker curr_fpr_size = 0;
1254*795d594fSAndroid Build Coastguard Worker }
1255*795d594fSAndroid Build Coastguard Worker }
1256*795d594fSAndroid Build Coastguard Worker num_running_empty_pages++;
1257*795d594fSAndroid Build Coastguard Worker break;
1258*795d594fSAndroid Build Coastguard Worker }
1259*795d594fSAndroid Build Coastguard Worker case kPageMapLargeObject: {
1260*795d594fSAndroid Build Coastguard Worker DCHECK_EQ(remaining_curr_fpr_size, static_cast<size_t>(0));
1261*795d594fSAndroid Build Coastguard Worker num_running_empty_pages = 0;
1262*795d594fSAndroid Build Coastguard Worker stream << "[" << i << "]=Large (start)" << std::endl;
1263*795d594fSAndroid Build Coastguard Worker break;
1264*795d594fSAndroid Build Coastguard Worker }
1265*795d594fSAndroid Build Coastguard Worker case kPageMapLargeObjectPart:
1266*795d594fSAndroid Build Coastguard Worker DCHECK_EQ(remaining_curr_fpr_size, static_cast<size_t>(0));
1267*795d594fSAndroid Build Coastguard Worker num_running_empty_pages = 0;
1268*795d594fSAndroid Build Coastguard Worker stream << "[" << i << "]=Large (part)" << std::endl;
1269*795d594fSAndroid Build Coastguard Worker break;
1270*795d594fSAndroid Build Coastguard Worker case kPageMapRun: {
1271*795d594fSAndroid Build Coastguard Worker DCHECK_EQ(remaining_curr_fpr_size, static_cast<size_t>(0));
1272*795d594fSAndroid Build Coastguard Worker num_running_empty_pages = 0;
1273*795d594fSAndroid Build Coastguard Worker Run* run = reinterpret_cast<Run*>(base_ + i * gPageSize);
1274*795d594fSAndroid Build Coastguard Worker size_t idx = run->size_bracket_idx_;
1275*795d594fSAndroid Build Coastguard Worker stream << "[" << i << "]=Run (start)"
1276*795d594fSAndroid Build Coastguard Worker << " idx=" << idx
1277*795d594fSAndroid Build Coastguard Worker << " numOfPages=" << numOfPages[idx]
1278*795d594fSAndroid Build Coastguard Worker << " is_thread_local=" << run->is_thread_local_
1279*795d594fSAndroid Build Coastguard Worker << " is_all_free=" << (run->IsAllFree() ? 1 : 0)
1280*795d594fSAndroid Build Coastguard Worker << std::endl;
1281*795d594fSAndroid Build Coastguard Worker break;
1282*795d594fSAndroid Build Coastguard Worker }
1283*795d594fSAndroid Build Coastguard Worker case kPageMapRunPart:
1284*795d594fSAndroid Build Coastguard Worker DCHECK_EQ(remaining_curr_fpr_size, static_cast<size_t>(0));
1285*795d594fSAndroid Build Coastguard Worker num_running_empty_pages = 0;
1286*795d594fSAndroid Build Coastguard Worker stream << "[" << i << "]=Run (part)" << std::endl;
1287*795d594fSAndroid Build Coastguard Worker break;
1288*795d594fSAndroid Build Coastguard Worker default:
1289*795d594fSAndroid Build Coastguard Worker stream << "[" << i << "]=Unrecognizable page map type: " << pm;
1290*795d594fSAndroid Build Coastguard Worker break;
1291*795d594fSAndroid Build Coastguard Worker }
1292*795d594fSAndroid Build Coastguard Worker }
1293*795d594fSAndroid Build Coastguard Worker return stream.str();
1294*795d594fSAndroid Build Coastguard Worker }
1295*795d594fSAndroid Build Coastguard Worker
UsableSize(const void * ptr)1296*795d594fSAndroid Build Coastguard Worker size_t RosAlloc::UsableSize(const void* ptr) {
1297*795d594fSAndroid Build Coastguard Worker DCHECK_LE(base_, ptr);
1298*795d594fSAndroid Build Coastguard Worker DCHECK_LT(ptr, base_ + footprint_);
1299*795d594fSAndroid Build Coastguard Worker size_t pm_idx = RoundDownToPageMapIndex(ptr);
1300*795d594fSAndroid Build Coastguard Worker MutexLock mu(Thread::Current(), lock_);
1301*795d594fSAndroid Build Coastguard Worker switch (page_map_[pm_idx]) {
1302*795d594fSAndroid Build Coastguard Worker case kPageMapReleased:
1303*795d594fSAndroid Build Coastguard Worker // Fall-through.
1304*795d594fSAndroid Build Coastguard Worker case kPageMapEmpty:
1305*795d594fSAndroid Build Coastguard Worker LOG(FATAL) << "Unreachable - " << __PRETTY_FUNCTION__ << ": pm_idx=" << pm_idx << ", ptr="
1306*795d594fSAndroid Build Coastguard Worker << std::hex << reinterpret_cast<intptr_t>(ptr);
1307*795d594fSAndroid Build Coastguard Worker UNREACHABLE();
1308*795d594fSAndroid Build Coastguard Worker case kPageMapLargeObject: {
1309*795d594fSAndroid Build Coastguard Worker size_t num_pages = 1;
1310*795d594fSAndroid Build Coastguard Worker size_t idx = pm_idx + 1;
1311*795d594fSAndroid Build Coastguard Worker size_t end = page_map_size_;
1312*795d594fSAndroid Build Coastguard Worker while (idx < end && page_map_[idx] == kPageMapLargeObjectPart) {
1313*795d594fSAndroid Build Coastguard Worker num_pages++;
1314*795d594fSAndroid Build Coastguard Worker idx++;
1315*795d594fSAndroid Build Coastguard Worker }
1316*795d594fSAndroid Build Coastguard Worker return num_pages * gPageSize;
1317*795d594fSAndroid Build Coastguard Worker }
1318*795d594fSAndroid Build Coastguard Worker case kPageMapLargeObjectPart:
1319*795d594fSAndroid Build Coastguard Worker LOG(FATAL) << "Unreachable - " << __PRETTY_FUNCTION__ << ": pm_idx=" << pm_idx << ", ptr="
1320*795d594fSAndroid Build Coastguard Worker << std::hex << reinterpret_cast<intptr_t>(ptr);
1321*795d594fSAndroid Build Coastguard Worker UNREACHABLE();
1322*795d594fSAndroid Build Coastguard Worker case kPageMapRun:
1323*795d594fSAndroid Build Coastguard Worker case kPageMapRunPart: {
1324*795d594fSAndroid Build Coastguard Worker // Find the beginning of the run.
1325*795d594fSAndroid Build Coastguard Worker while (page_map_[pm_idx] != kPageMapRun) {
1326*795d594fSAndroid Build Coastguard Worker pm_idx--;
1327*795d594fSAndroid Build Coastguard Worker DCHECK_LT(pm_idx, DivideByPageSize(capacity_));
1328*795d594fSAndroid Build Coastguard Worker }
1329*795d594fSAndroid Build Coastguard Worker DCHECK_EQ(page_map_[pm_idx], kPageMapRun);
1330*795d594fSAndroid Build Coastguard Worker Run* run = reinterpret_cast<Run*>(base_ + pm_idx * gPageSize);
1331*795d594fSAndroid Build Coastguard Worker DCHECK_EQ(run->magic_num_, kMagicNum);
1332*795d594fSAndroid Build Coastguard Worker size_t idx = run->size_bracket_idx_;
1333*795d594fSAndroid Build Coastguard Worker size_t offset_from_slot_base = reinterpret_cast<const uint8_t*>(ptr)
1334*795d594fSAndroid Build Coastguard Worker - (reinterpret_cast<uint8_t*>(run) + headerSizes[idx]);
1335*795d594fSAndroid Build Coastguard Worker DCHECK_EQ(offset_from_slot_base % bracketSizes[idx], static_cast<size_t>(0));
1336*795d594fSAndroid Build Coastguard Worker return IndexToBracketSize(idx);
1337*795d594fSAndroid Build Coastguard Worker }
1338*795d594fSAndroid Build Coastguard Worker default: {
1339*795d594fSAndroid Build Coastguard Worker LOG(FATAL) << "Unreachable - page map type: " << static_cast<int>(page_map_[pm_idx]);
1340*795d594fSAndroid Build Coastguard Worker UNREACHABLE();
1341*795d594fSAndroid Build Coastguard Worker }
1342*795d594fSAndroid Build Coastguard Worker }
1343*795d594fSAndroid Build Coastguard Worker }
1344*795d594fSAndroid Build Coastguard Worker
Trim()1345*795d594fSAndroid Build Coastguard Worker bool RosAlloc::Trim() {
1346*795d594fSAndroid Build Coastguard Worker MutexLock mu(Thread::Current(), lock_);
1347*795d594fSAndroid Build Coastguard Worker FreePageRun* last_free_page_run;
1348*795d594fSAndroid Build Coastguard Worker DCHECK_EQ(ModuloPageSize(footprint_), static_cast<size_t>(0));
1349*795d594fSAndroid Build Coastguard Worker auto it = free_page_runs_.rbegin();
1350*795d594fSAndroid Build Coastguard Worker if (it != free_page_runs_.rend() && (last_free_page_run = *it)->End(this) == base_ + footprint_) {
1351*795d594fSAndroid Build Coastguard Worker // Remove the last free page run, if any.
1352*795d594fSAndroid Build Coastguard Worker DCHECK(last_free_page_run->IsFree());
1353*795d594fSAndroid Build Coastguard Worker DCHECK(IsFreePage(ToPageMapIndex(last_free_page_run)));
1354*795d594fSAndroid Build Coastguard Worker DCHECK_EQ(ModuloPageSize(last_free_page_run->ByteSize(this)), static_cast<size_t>(0));
1355*795d594fSAndroid Build Coastguard Worker DCHECK_EQ(last_free_page_run->End(this), base_ + footprint_);
1356*795d594fSAndroid Build Coastguard Worker free_page_runs_.erase(last_free_page_run);
1357*795d594fSAndroid Build Coastguard Worker size_t decrement = last_free_page_run->ByteSize(this);
1358*795d594fSAndroid Build Coastguard Worker size_t new_footprint = footprint_ - decrement;
1359*795d594fSAndroid Build Coastguard Worker DCHECK_EQ(ModuloPageSize(new_footprint), static_cast<size_t>(0));
1360*795d594fSAndroid Build Coastguard Worker size_t new_num_of_pages = DivideByPageSize(new_footprint);
1361*795d594fSAndroid Build Coastguard Worker DCHECK_GE(page_map_size_, new_num_of_pages);
1362*795d594fSAndroid Build Coastguard Worker // Zero out the tail of the page map.
1363*795d594fSAndroid Build Coastguard Worker uint8_t* zero_begin = const_cast<uint8_t*>(page_map_) + new_num_of_pages;
1364*795d594fSAndroid Build Coastguard Worker uint8_t* madvise_begin = AlignUp(zero_begin, gPageSize);
1365*795d594fSAndroid Build Coastguard Worker DCHECK_LE(madvise_begin, page_map_mem_map_.End());
1366*795d594fSAndroid Build Coastguard Worker size_t madvise_size = page_map_mem_map_.End() - madvise_begin;
1367*795d594fSAndroid Build Coastguard Worker if (madvise_size > 0) {
1368*795d594fSAndroid Build Coastguard Worker DCHECK_ALIGNED_PARAM(madvise_begin, gPageSize);
1369*795d594fSAndroid Build Coastguard Worker DCHECK_EQ(RoundUp(madvise_size, gPageSize), madvise_size);
1370*795d594fSAndroid Build Coastguard Worker if (!kMadviseZeroes) {
1371*795d594fSAndroid Build Coastguard Worker memset(madvise_begin, 0, madvise_size);
1372*795d594fSAndroid Build Coastguard Worker }
1373*795d594fSAndroid Build Coastguard Worker CHECK_EQ(madvise(madvise_begin, madvise_size, MADV_DONTNEED), 0);
1374*795d594fSAndroid Build Coastguard Worker }
1375*795d594fSAndroid Build Coastguard Worker if (madvise_begin - zero_begin) {
1376*795d594fSAndroid Build Coastguard Worker memset(zero_begin, 0, madvise_begin - zero_begin);
1377*795d594fSAndroid Build Coastguard Worker }
1378*795d594fSAndroid Build Coastguard Worker page_map_size_ = new_num_of_pages;
1379*795d594fSAndroid Build Coastguard Worker free_page_run_size_map_.resize(new_num_of_pages);
1380*795d594fSAndroid Build Coastguard Worker DCHECK_EQ(free_page_run_size_map_.size(), new_num_of_pages);
1381*795d594fSAndroid Build Coastguard Worker ArtRosAllocMoreCore(this, -(static_cast<intptr_t>(decrement)));
1382*795d594fSAndroid Build Coastguard Worker if (kTraceRosAlloc) {
1383*795d594fSAndroid Build Coastguard Worker LOG(INFO) << "RosAlloc::Trim() : decreased the footprint from "
1384*795d594fSAndroid Build Coastguard Worker << footprint_ << " to " << new_footprint;
1385*795d594fSAndroid Build Coastguard Worker }
1386*795d594fSAndroid Build Coastguard Worker DCHECK_LT(new_footprint, footprint_);
1387*795d594fSAndroid Build Coastguard Worker DCHECK_LT(new_footprint, capacity_);
1388*795d594fSAndroid Build Coastguard Worker footprint_ = new_footprint;
1389*795d594fSAndroid Build Coastguard Worker return true;
1390*795d594fSAndroid Build Coastguard Worker }
1391*795d594fSAndroid Build Coastguard Worker return false;
1392*795d594fSAndroid Build Coastguard Worker }
1393*795d594fSAndroid Build Coastguard Worker
InspectAll(void (* handler)(void * start,void * end,size_t used_bytes,void * callback_arg),void * arg)1394*795d594fSAndroid Build Coastguard Worker void RosAlloc::InspectAll(void (*handler)(void* start, void* end, size_t used_bytes, void* callback_arg),
1395*795d594fSAndroid Build Coastguard Worker void* arg) {
1396*795d594fSAndroid Build Coastguard Worker // Note: no need to use this to release pages as we already do so in FreePages().
1397*795d594fSAndroid Build Coastguard Worker if (handler == nullptr) {
1398*795d594fSAndroid Build Coastguard Worker return;
1399*795d594fSAndroid Build Coastguard Worker }
1400*795d594fSAndroid Build Coastguard Worker MutexLock mu(Thread::Current(), lock_);
1401*795d594fSAndroid Build Coastguard Worker size_t pm_end = page_map_size_;
1402*795d594fSAndroid Build Coastguard Worker size_t i = 0;
1403*795d594fSAndroid Build Coastguard Worker while (i < pm_end) {
1404*795d594fSAndroid Build Coastguard Worker uint8_t pm = page_map_[i];
1405*795d594fSAndroid Build Coastguard Worker switch (pm) {
1406*795d594fSAndroid Build Coastguard Worker case kPageMapReleased:
1407*795d594fSAndroid Build Coastguard Worker // Fall-through.
1408*795d594fSAndroid Build Coastguard Worker case kPageMapEmpty: {
1409*795d594fSAndroid Build Coastguard Worker // The start of a free page run.
1410*795d594fSAndroid Build Coastguard Worker FreePageRun* fpr = reinterpret_cast<FreePageRun*>(base_ + i * gPageSize);
1411*795d594fSAndroid Build Coastguard Worker DCHECK(free_page_runs_.find(fpr) != free_page_runs_.end());
1412*795d594fSAndroid Build Coastguard Worker size_t fpr_size = fpr->ByteSize(this);
1413*795d594fSAndroid Build Coastguard Worker DCHECK_ALIGNED_PARAM(fpr_size, gPageSize);
1414*795d594fSAndroid Build Coastguard Worker void* start = fpr;
1415*795d594fSAndroid Build Coastguard Worker if (kIsDebugBuild) {
1416*795d594fSAndroid Build Coastguard Worker // In the debug build, the first page of a free page run
1417*795d594fSAndroid Build Coastguard Worker // contains a magic number for debugging. Exclude it.
1418*795d594fSAndroid Build Coastguard Worker start = reinterpret_cast<uint8_t*>(fpr) + gPageSize;
1419*795d594fSAndroid Build Coastguard Worker }
1420*795d594fSAndroid Build Coastguard Worker void* end = reinterpret_cast<uint8_t*>(fpr) + fpr_size;
1421*795d594fSAndroid Build Coastguard Worker handler(start, end, 0, arg);
1422*795d594fSAndroid Build Coastguard Worker size_t num_pages = DivideByPageSize(fpr_size);
1423*795d594fSAndroid Build Coastguard Worker if (kIsDebugBuild) {
1424*795d594fSAndroid Build Coastguard Worker for (size_t j = i + 1; j < i + num_pages; ++j) {
1425*795d594fSAndroid Build Coastguard Worker DCHECK(IsFreePage(j));
1426*795d594fSAndroid Build Coastguard Worker }
1427*795d594fSAndroid Build Coastguard Worker }
1428*795d594fSAndroid Build Coastguard Worker i += DivideByPageSize(fpr_size);
1429*795d594fSAndroid Build Coastguard Worker DCHECK_LE(i, pm_end);
1430*795d594fSAndroid Build Coastguard Worker break;
1431*795d594fSAndroid Build Coastguard Worker }
1432*795d594fSAndroid Build Coastguard Worker case kPageMapLargeObject: {
1433*795d594fSAndroid Build Coastguard Worker // The start of a large object.
1434*795d594fSAndroid Build Coastguard Worker size_t num_pages = 1;
1435*795d594fSAndroid Build Coastguard Worker size_t idx = i + 1;
1436*795d594fSAndroid Build Coastguard Worker while (idx < pm_end && page_map_[idx] == kPageMapLargeObjectPart) {
1437*795d594fSAndroid Build Coastguard Worker num_pages++;
1438*795d594fSAndroid Build Coastguard Worker idx++;
1439*795d594fSAndroid Build Coastguard Worker }
1440*795d594fSAndroid Build Coastguard Worker void* start = base_ + i * gPageSize;
1441*795d594fSAndroid Build Coastguard Worker void* end = base_ + (i + num_pages) * gPageSize;
1442*795d594fSAndroid Build Coastguard Worker size_t used_bytes = num_pages * gPageSize;
1443*795d594fSAndroid Build Coastguard Worker handler(start, end, used_bytes, arg);
1444*795d594fSAndroid Build Coastguard Worker if (kIsDebugBuild) {
1445*795d594fSAndroid Build Coastguard Worker for (size_t j = i + 1; j < i + num_pages; ++j) {
1446*795d594fSAndroid Build Coastguard Worker DCHECK_EQ(page_map_[j], kPageMapLargeObjectPart);
1447*795d594fSAndroid Build Coastguard Worker }
1448*795d594fSAndroid Build Coastguard Worker }
1449*795d594fSAndroid Build Coastguard Worker i += num_pages;
1450*795d594fSAndroid Build Coastguard Worker DCHECK_LE(i, pm_end);
1451*795d594fSAndroid Build Coastguard Worker break;
1452*795d594fSAndroid Build Coastguard Worker }
1453*795d594fSAndroid Build Coastguard Worker case kPageMapLargeObjectPart:
1454*795d594fSAndroid Build Coastguard Worker LOG(FATAL) << "Unreachable - page map type: " << static_cast<int>(pm);
1455*795d594fSAndroid Build Coastguard Worker UNREACHABLE();
1456*795d594fSAndroid Build Coastguard Worker case kPageMapRun: {
1457*795d594fSAndroid Build Coastguard Worker // The start of a run.
1458*795d594fSAndroid Build Coastguard Worker Run* run = reinterpret_cast<Run*>(base_ + i * gPageSize);
1459*795d594fSAndroid Build Coastguard Worker DCHECK_EQ(run->magic_num_, kMagicNum);
1460*795d594fSAndroid Build Coastguard Worker // The dedicated full run doesn't contain any real allocations, don't visit the slots in
1461*795d594fSAndroid Build Coastguard Worker // there.
1462*795d594fSAndroid Build Coastguard Worker run->InspectAllSlots(handler, arg);
1463*795d594fSAndroid Build Coastguard Worker size_t num_pages = numOfPages[run->size_bracket_idx_];
1464*795d594fSAndroid Build Coastguard Worker if (kIsDebugBuild) {
1465*795d594fSAndroid Build Coastguard Worker for (size_t j = i + 1; j < i + num_pages; ++j) {
1466*795d594fSAndroid Build Coastguard Worker DCHECK_EQ(page_map_[j], kPageMapRunPart);
1467*795d594fSAndroid Build Coastguard Worker }
1468*795d594fSAndroid Build Coastguard Worker }
1469*795d594fSAndroid Build Coastguard Worker i += num_pages;
1470*795d594fSAndroid Build Coastguard Worker DCHECK_LE(i, pm_end);
1471*795d594fSAndroid Build Coastguard Worker break;
1472*795d594fSAndroid Build Coastguard Worker }
1473*795d594fSAndroid Build Coastguard Worker case kPageMapRunPart:
1474*795d594fSAndroid Build Coastguard Worker LOG(FATAL) << "Unreachable - page map type: " << static_cast<int>(pm);
1475*795d594fSAndroid Build Coastguard Worker UNREACHABLE();
1476*795d594fSAndroid Build Coastguard Worker }
1477*795d594fSAndroid Build Coastguard Worker }
1478*795d594fSAndroid Build Coastguard Worker }
1479*795d594fSAndroid Build Coastguard Worker
Footprint()1480*795d594fSAndroid Build Coastguard Worker size_t RosAlloc::Footprint() {
1481*795d594fSAndroid Build Coastguard Worker MutexLock mu(Thread::Current(), lock_);
1482*795d594fSAndroid Build Coastguard Worker return footprint_;
1483*795d594fSAndroid Build Coastguard Worker }
1484*795d594fSAndroid Build Coastguard Worker
FootprintLimit()1485*795d594fSAndroid Build Coastguard Worker size_t RosAlloc::FootprintLimit() {
1486*795d594fSAndroid Build Coastguard Worker MutexLock mu(Thread::Current(), lock_);
1487*795d594fSAndroid Build Coastguard Worker return capacity_;
1488*795d594fSAndroid Build Coastguard Worker }
1489*795d594fSAndroid Build Coastguard Worker
SetFootprintLimit(size_t new_capacity)1490*795d594fSAndroid Build Coastguard Worker void RosAlloc::SetFootprintLimit(size_t new_capacity) {
1491*795d594fSAndroid Build Coastguard Worker MutexLock mu(Thread::Current(), lock_);
1492*795d594fSAndroid Build Coastguard Worker DCHECK_EQ(RoundUp(new_capacity, gPageSize), new_capacity);
1493*795d594fSAndroid Build Coastguard Worker // Only growing is supported here. But Trim() is supported.
1494*795d594fSAndroid Build Coastguard Worker if (capacity_ < new_capacity) {
1495*795d594fSAndroid Build Coastguard Worker CHECK_LE(new_capacity, max_capacity_);
1496*795d594fSAndroid Build Coastguard Worker capacity_ = new_capacity;
1497*795d594fSAndroid Build Coastguard Worker VLOG(heap) << "new capacity=" << capacity_;
1498*795d594fSAndroid Build Coastguard Worker }
1499*795d594fSAndroid Build Coastguard Worker }
1500*795d594fSAndroid Build Coastguard Worker
1501*795d594fSAndroid Build Coastguard Worker // Below may be called by mutator itself just before thread termination.
RevokeThreadLocalRuns(Thread * thread)1502*795d594fSAndroid Build Coastguard Worker size_t RosAlloc::RevokeThreadLocalRuns(Thread* thread) {
1503*795d594fSAndroid Build Coastguard Worker Thread* self = Thread::Current();
1504*795d594fSAndroid Build Coastguard Worker size_t free_bytes = 0U;
1505*795d594fSAndroid Build Coastguard Worker for (size_t idx = 0; idx < kNumThreadLocalSizeBrackets; idx++) {
1506*795d594fSAndroid Build Coastguard Worker MutexLock mu(self, *size_bracket_locks_[idx]);
1507*795d594fSAndroid Build Coastguard Worker Run* thread_local_run = reinterpret_cast<Run*>(thread->GetRosAllocRun(idx));
1508*795d594fSAndroid Build Coastguard Worker CHECK(thread_local_run != nullptr);
1509*795d594fSAndroid Build Coastguard Worker // Invalid means already revoked.
1510*795d594fSAndroid Build Coastguard Worker DCHECK(thread_local_run->IsThreadLocal());
1511*795d594fSAndroid Build Coastguard Worker if (thread_local_run != dedicated_full_run_) {
1512*795d594fSAndroid Build Coastguard Worker // Note the thread local run may not be full here.
1513*795d594fSAndroid Build Coastguard Worker thread->SetRosAllocRun(idx, dedicated_full_run_);
1514*795d594fSAndroid Build Coastguard Worker DCHECK_EQ(thread_local_run->magic_num_, kMagicNum);
1515*795d594fSAndroid Build Coastguard Worker // Count the number of free slots left.
1516*795d594fSAndroid Build Coastguard Worker size_t num_free_slots = thread_local_run->NumberOfFreeSlots();
1517*795d594fSAndroid Build Coastguard Worker free_bytes += num_free_slots * bracketSizes[idx];
1518*795d594fSAndroid Build Coastguard Worker // The above bracket index lock guards thread local free list to avoid race condition
1519*795d594fSAndroid Build Coastguard Worker // with unioning bulk free list to thread local free list by GC thread in BulkFree.
1520*795d594fSAndroid Build Coastguard Worker // If thread local run is true, GC thread will help update thread local free list
1521*795d594fSAndroid Build Coastguard Worker // in BulkFree. And the latest thread local free list will be merged to free list
1522*795d594fSAndroid Build Coastguard Worker // either when this thread local run is full or when revoking this run here. In this
1523*795d594fSAndroid Build Coastguard Worker // case the free list wll be updated. If thread local run is false, GC thread will help
1524*795d594fSAndroid Build Coastguard Worker // merge bulk free list in next BulkFree.
1525*795d594fSAndroid Build Coastguard Worker // Thus no need to merge bulk free list to free list again here.
1526*795d594fSAndroid Build Coastguard Worker bool dont_care;
1527*795d594fSAndroid Build Coastguard Worker thread_local_run->MergeThreadLocalFreeListToFreeList(&dont_care);
1528*795d594fSAndroid Build Coastguard Worker thread_local_run->SetIsThreadLocal(false);
1529*795d594fSAndroid Build Coastguard Worker DCHECK(non_full_runs_[idx].find(thread_local_run) == non_full_runs_[idx].end());
1530*795d594fSAndroid Build Coastguard Worker DCHECK(full_runs_[idx].find(thread_local_run) == full_runs_[idx].end());
1531*795d594fSAndroid Build Coastguard Worker RevokeRun(self, idx, thread_local_run);
1532*795d594fSAndroid Build Coastguard Worker }
1533*795d594fSAndroid Build Coastguard Worker }
1534*795d594fSAndroid Build Coastguard Worker return free_bytes;
1535*795d594fSAndroid Build Coastguard Worker }
1536*795d594fSAndroid Build Coastguard Worker
RevokeRun(Thread * self,size_t idx,Run * run)1537*795d594fSAndroid Build Coastguard Worker void RosAlloc::RevokeRun(Thread* self, size_t idx, Run* run) {
1538*795d594fSAndroid Build Coastguard Worker size_bracket_locks_[idx]->AssertHeld(self);
1539*795d594fSAndroid Build Coastguard Worker DCHECK(run != dedicated_full_run_);
1540*795d594fSAndroid Build Coastguard Worker if (run->IsFull()) {
1541*795d594fSAndroid Build Coastguard Worker if (kIsDebugBuild) {
1542*795d594fSAndroid Build Coastguard Worker full_runs_[idx].insert(run);
1543*795d594fSAndroid Build Coastguard Worker DCHECK(full_runs_[idx].find(run) != full_runs_[idx].end());
1544*795d594fSAndroid Build Coastguard Worker if (kTraceRosAlloc) {
1545*795d594fSAndroid Build Coastguard Worker LOG(INFO) << __PRETTY_FUNCTION__ << " : Inserted run 0x" << std::hex
1546*795d594fSAndroid Build Coastguard Worker << reinterpret_cast<intptr_t>(run)
1547*795d594fSAndroid Build Coastguard Worker << " into full_runs_[" << std::dec << idx << "]";
1548*795d594fSAndroid Build Coastguard Worker }
1549*795d594fSAndroid Build Coastguard Worker }
1550*795d594fSAndroid Build Coastguard Worker } else if (run->IsAllFree()) {
1551*795d594fSAndroid Build Coastguard Worker run->ZeroHeaderAndSlotHeaders();
1552*795d594fSAndroid Build Coastguard Worker MutexLock mu(self, lock_);
1553*795d594fSAndroid Build Coastguard Worker FreePages(self, run, true);
1554*795d594fSAndroid Build Coastguard Worker } else {
1555*795d594fSAndroid Build Coastguard Worker non_full_runs_[idx].insert(run);
1556*795d594fSAndroid Build Coastguard Worker DCHECK(non_full_runs_[idx].find(run) != non_full_runs_[idx].end());
1557*795d594fSAndroid Build Coastguard Worker if (kTraceRosAlloc) {
1558*795d594fSAndroid Build Coastguard Worker LOG(INFO) << __PRETTY_FUNCTION__ << " : Inserted run 0x" << std::hex
1559*795d594fSAndroid Build Coastguard Worker << reinterpret_cast<intptr_t>(run)
1560*795d594fSAndroid Build Coastguard Worker << " into non_full_runs_[" << std::dec << idx << "]";
1561*795d594fSAndroid Build Coastguard Worker }
1562*795d594fSAndroid Build Coastguard Worker }
1563*795d594fSAndroid Build Coastguard Worker }
1564*795d594fSAndroid Build Coastguard Worker
RevokeThreadUnsafeCurrentRuns()1565*795d594fSAndroid Build Coastguard Worker void RosAlloc::RevokeThreadUnsafeCurrentRuns() {
1566*795d594fSAndroid Build Coastguard Worker // Revoke the current runs which share the same idx as thread local runs.
1567*795d594fSAndroid Build Coastguard Worker Thread* self = Thread::Current();
1568*795d594fSAndroid Build Coastguard Worker for (size_t idx = 0; idx < kNumThreadLocalSizeBrackets; ++idx) {
1569*795d594fSAndroid Build Coastguard Worker MutexLock mu(self, *size_bracket_locks_[idx]);
1570*795d594fSAndroid Build Coastguard Worker if (current_runs_[idx] != dedicated_full_run_) {
1571*795d594fSAndroid Build Coastguard Worker RevokeRun(self, idx, current_runs_[idx]);
1572*795d594fSAndroid Build Coastguard Worker current_runs_[idx] = dedicated_full_run_;
1573*795d594fSAndroid Build Coastguard Worker }
1574*795d594fSAndroid Build Coastguard Worker }
1575*795d594fSAndroid Build Coastguard Worker }
1576*795d594fSAndroid Build Coastguard Worker
RevokeAllThreadLocalRuns()1577*795d594fSAndroid Build Coastguard Worker size_t RosAlloc::RevokeAllThreadLocalRuns() {
1578*795d594fSAndroid Build Coastguard Worker // This is called when a mutator thread won't allocate such as at
1579*795d594fSAndroid Build Coastguard Worker // the Zygote creation time or during the GC pause.
1580*795d594fSAndroid Build Coastguard Worker MutexLock mu(Thread::Current(), *Locks::runtime_shutdown_lock_);
1581*795d594fSAndroid Build Coastguard Worker MutexLock mu2(Thread::Current(), *Locks::thread_list_lock_);
1582*795d594fSAndroid Build Coastguard Worker std::list<Thread*> thread_list = Runtime::Current()->GetThreadList()->GetList();
1583*795d594fSAndroid Build Coastguard Worker size_t free_bytes = 0U;
1584*795d594fSAndroid Build Coastguard Worker for (Thread* thread : thread_list) {
1585*795d594fSAndroid Build Coastguard Worker free_bytes += RevokeThreadLocalRuns(thread);
1586*795d594fSAndroid Build Coastguard Worker }
1587*795d594fSAndroid Build Coastguard Worker RevokeThreadUnsafeCurrentRuns();
1588*795d594fSAndroid Build Coastguard Worker return free_bytes;
1589*795d594fSAndroid Build Coastguard Worker }
1590*795d594fSAndroid Build Coastguard Worker
AssertThreadLocalRunsAreRevoked(Thread * thread)1591*795d594fSAndroid Build Coastguard Worker void RosAlloc::AssertThreadLocalRunsAreRevoked(Thread* thread) {
1592*795d594fSAndroid Build Coastguard Worker if (kIsDebugBuild) {
1593*795d594fSAndroid Build Coastguard Worker Thread* self = Thread::Current();
1594*795d594fSAndroid Build Coastguard Worker // Avoid race conditions on the bulk free bit maps with BulkFree() (GC).
1595*795d594fSAndroid Build Coastguard Worker ReaderMutexLock wmu(self, bulk_free_lock_);
1596*795d594fSAndroid Build Coastguard Worker for (size_t idx = 0; idx < kNumThreadLocalSizeBrackets; idx++) {
1597*795d594fSAndroid Build Coastguard Worker MutexLock mu(self, *size_bracket_locks_[idx]);
1598*795d594fSAndroid Build Coastguard Worker Run* thread_local_run = reinterpret_cast<Run*>(thread->GetRosAllocRun(idx));
1599*795d594fSAndroid Build Coastguard Worker DCHECK(thread_local_run == nullptr || thread_local_run == dedicated_full_run_);
1600*795d594fSAndroid Build Coastguard Worker }
1601*795d594fSAndroid Build Coastguard Worker }
1602*795d594fSAndroid Build Coastguard Worker }
1603*795d594fSAndroid Build Coastguard Worker
AssertAllThreadLocalRunsAreRevoked()1604*795d594fSAndroid Build Coastguard Worker void RosAlloc::AssertAllThreadLocalRunsAreRevoked() {
1605*795d594fSAndroid Build Coastguard Worker if (kIsDebugBuild) {
1606*795d594fSAndroid Build Coastguard Worker Thread* self = Thread::Current();
1607*795d594fSAndroid Build Coastguard Worker MutexLock shutdown_mu(self, *Locks::runtime_shutdown_lock_);
1608*795d594fSAndroid Build Coastguard Worker MutexLock thread_list_mu(self, *Locks::thread_list_lock_);
1609*795d594fSAndroid Build Coastguard Worker std::list<Thread*> thread_list = Runtime::Current()->GetThreadList()->GetList();
1610*795d594fSAndroid Build Coastguard Worker for (Thread* t : thread_list) {
1611*795d594fSAndroid Build Coastguard Worker AssertThreadLocalRunsAreRevoked(t);
1612*795d594fSAndroid Build Coastguard Worker }
1613*795d594fSAndroid Build Coastguard Worker for (size_t idx = 0; idx < kNumThreadLocalSizeBrackets; ++idx) {
1614*795d594fSAndroid Build Coastguard Worker MutexLock brackets_mu(self, *size_bracket_locks_[idx]);
1615*795d594fSAndroid Build Coastguard Worker CHECK_EQ(current_runs_[idx], dedicated_full_run_);
1616*795d594fSAndroid Build Coastguard Worker }
1617*795d594fSAndroid Build Coastguard Worker }
1618*795d594fSAndroid Build Coastguard Worker }
1619*795d594fSAndroid Build Coastguard Worker
Initialize()1620*795d594fSAndroid Build Coastguard Worker void RosAlloc::Initialize() {
1621*795d594fSAndroid Build Coastguard Worker // bracketSizes.
1622*795d594fSAndroid Build Coastguard Worker static_assert(kNumRegularSizeBrackets == kNumOfSizeBrackets - 2,
1623*795d594fSAndroid Build Coastguard Worker "There should be two non-regular brackets");
1624*795d594fSAndroid Build Coastguard Worker for (size_t i = 0; i < kNumOfSizeBrackets; i++) {
1625*795d594fSAndroid Build Coastguard Worker if (i < kNumThreadLocalSizeBrackets) {
1626*795d594fSAndroid Build Coastguard Worker bracketSizes[i] = kThreadLocalBracketQuantumSize * (i + 1);
1627*795d594fSAndroid Build Coastguard Worker } else if (i < kNumRegularSizeBrackets) {
1628*795d594fSAndroid Build Coastguard Worker bracketSizes[i] = kBracketQuantumSize * (i - kNumThreadLocalSizeBrackets + 1) +
1629*795d594fSAndroid Build Coastguard Worker (kThreadLocalBracketQuantumSize * kNumThreadLocalSizeBrackets);
1630*795d594fSAndroid Build Coastguard Worker } else if (i == kNumOfSizeBrackets - 2) {
1631*795d594fSAndroid Build Coastguard Worker bracketSizes[i] = 1 * KB;
1632*795d594fSAndroid Build Coastguard Worker } else {
1633*795d594fSAndroid Build Coastguard Worker DCHECK_EQ(i, kNumOfSizeBrackets - 1);
1634*795d594fSAndroid Build Coastguard Worker bracketSizes[i] = 2 * KB;
1635*795d594fSAndroid Build Coastguard Worker }
1636*795d594fSAndroid Build Coastguard Worker if (kTraceRosAlloc) {
1637*795d594fSAndroid Build Coastguard Worker LOG(INFO) << "bracketSizes[" << i << "]=" << bracketSizes[i];
1638*795d594fSAndroid Build Coastguard Worker }
1639*795d594fSAndroid Build Coastguard Worker }
1640*795d594fSAndroid Build Coastguard Worker // numOfPages.
1641*795d594fSAndroid Build Coastguard Worker for (size_t i = 0; i < kNumOfSizeBrackets; i++) {
1642*795d594fSAndroid Build Coastguard Worker if (i < kNumThreadLocalSizeBrackets) {
1643*795d594fSAndroid Build Coastguard Worker numOfPages[i] = 1;
1644*795d594fSAndroid Build Coastguard Worker } else if (i < (kNumThreadLocalSizeBrackets + kNumRegularSizeBrackets) / 2) {
1645*795d594fSAndroid Build Coastguard Worker numOfPages[i] = 1;
1646*795d594fSAndroid Build Coastguard Worker } else if (i < kNumRegularSizeBrackets) {
1647*795d594fSAndroid Build Coastguard Worker numOfPages[i] = 1;
1648*795d594fSAndroid Build Coastguard Worker } else if (i == kNumOfSizeBrackets - 2) {
1649*795d594fSAndroid Build Coastguard Worker numOfPages[i] = 2;
1650*795d594fSAndroid Build Coastguard Worker } else {
1651*795d594fSAndroid Build Coastguard Worker DCHECK_EQ(i, kNumOfSizeBrackets - 1);
1652*795d594fSAndroid Build Coastguard Worker numOfPages[i] = 4;
1653*795d594fSAndroid Build Coastguard Worker }
1654*795d594fSAndroid Build Coastguard Worker if (kTraceRosAlloc) {
1655*795d594fSAndroid Build Coastguard Worker LOG(INFO) << "numOfPages[" << i << "]=" << numOfPages[i];
1656*795d594fSAndroid Build Coastguard Worker }
1657*795d594fSAndroid Build Coastguard Worker }
1658*795d594fSAndroid Build Coastguard Worker // Compute numOfSlots and slotOffsets.
1659*795d594fSAndroid Build Coastguard Worker for (size_t i = 0; i < kNumOfSizeBrackets; i++) {
1660*795d594fSAndroid Build Coastguard Worker size_t bracket_size = bracketSizes[i];
1661*795d594fSAndroid Build Coastguard Worker size_t run_size = gPageSize * numOfPages[i];
1662*795d594fSAndroid Build Coastguard Worker size_t max_num_of_slots = run_size / bracket_size;
1663*795d594fSAndroid Build Coastguard Worker // Compute the actual number of slots by taking the header and
1664*795d594fSAndroid Build Coastguard Worker // alignment into account.
1665*795d594fSAndroid Build Coastguard Worker size_t fixed_header_size = RoundUp(Run::fixed_header_size(), sizeof(uint64_t));
1666*795d594fSAndroid Build Coastguard Worker DCHECK_EQ(fixed_header_size, 80U);
1667*795d594fSAndroid Build Coastguard Worker size_t header_size = 0;
1668*795d594fSAndroid Build Coastguard Worker size_t num_of_slots = 0;
1669*795d594fSAndroid Build Coastguard Worker // Search for the maximum number of slots that allows enough space
1670*795d594fSAndroid Build Coastguard Worker // for the header.
1671*795d594fSAndroid Build Coastguard Worker for (int s = max_num_of_slots; s >= 0; s--) {
1672*795d594fSAndroid Build Coastguard Worker size_t tmp_slots_size = bracket_size * s;
1673*795d594fSAndroid Build Coastguard Worker size_t tmp_unaligned_header_size = fixed_header_size;
1674*795d594fSAndroid Build Coastguard Worker // Align up the unaligned header size. bracket_size may not be a power of two.
1675*795d594fSAndroid Build Coastguard Worker size_t tmp_header_size = (tmp_unaligned_header_size % bracket_size == 0) ?
1676*795d594fSAndroid Build Coastguard Worker tmp_unaligned_header_size :
1677*795d594fSAndroid Build Coastguard Worker tmp_unaligned_header_size + (bracket_size - tmp_unaligned_header_size % bracket_size);
1678*795d594fSAndroid Build Coastguard Worker DCHECK_EQ(tmp_header_size % bracket_size, 0U);
1679*795d594fSAndroid Build Coastguard Worker DCHECK_EQ(tmp_header_size % sizeof(uint64_t), 0U);
1680*795d594fSAndroid Build Coastguard Worker if (tmp_slots_size + tmp_header_size <= run_size) {
1681*795d594fSAndroid Build Coastguard Worker // Found the right number of slots, that is, there was enough
1682*795d594fSAndroid Build Coastguard Worker // space for the header (including the bit maps.)
1683*795d594fSAndroid Build Coastguard Worker num_of_slots = s;
1684*795d594fSAndroid Build Coastguard Worker header_size = tmp_header_size;
1685*795d594fSAndroid Build Coastguard Worker break;
1686*795d594fSAndroid Build Coastguard Worker }
1687*795d594fSAndroid Build Coastguard Worker }
1688*795d594fSAndroid Build Coastguard Worker DCHECK_GT(num_of_slots, 0U) << i;
1689*795d594fSAndroid Build Coastguard Worker DCHECK_GT(header_size, 0U) << i;
1690*795d594fSAndroid Build Coastguard Worker // Add the padding for the alignment remainder.
1691*795d594fSAndroid Build Coastguard Worker header_size += run_size % bracket_size;
1692*795d594fSAndroid Build Coastguard Worker DCHECK_EQ(header_size + num_of_slots * bracket_size, run_size);
1693*795d594fSAndroid Build Coastguard Worker numOfSlots[i] = num_of_slots;
1694*795d594fSAndroid Build Coastguard Worker headerSizes[i] = header_size;
1695*795d594fSAndroid Build Coastguard Worker if (kTraceRosAlloc) {
1696*795d594fSAndroid Build Coastguard Worker LOG(INFO) << "numOfSlots[" << i << "]=" << numOfSlots[i]
1697*795d594fSAndroid Build Coastguard Worker << ", headerSizes[" << i << "]=" << headerSizes[i];
1698*795d594fSAndroid Build Coastguard Worker }
1699*795d594fSAndroid Build Coastguard Worker }
1700*795d594fSAndroid Build Coastguard Worker // Set up the dedicated full run so that nobody can successfully allocate from it.
1701*795d594fSAndroid Build Coastguard Worker if (kIsDebugBuild) {
1702*795d594fSAndroid Build Coastguard Worker dedicated_full_run_->magic_num_ = kMagicNum;
1703*795d594fSAndroid Build Coastguard Worker }
1704*795d594fSAndroid Build Coastguard Worker // It doesn't matter which size bracket we use since the main goal is to have the allocation
1705*795d594fSAndroid Build Coastguard Worker // fail 100% of the time you attempt to allocate into the dedicated full run.
1706*795d594fSAndroid Build Coastguard Worker dedicated_full_run_->size_bracket_idx_ = 0;
1707*795d594fSAndroid Build Coastguard Worker DCHECK_EQ(dedicated_full_run_->FreeList()->Size(), 0U); // It looks full.
1708*795d594fSAndroid Build Coastguard Worker dedicated_full_run_->SetIsThreadLocal(true);
1709*795d594fSAndroid Build Coastguard Worker
1710*795d594fSAndroid Build Coastguard Worker // The smallest bracket size must be at least as large as the sizeof(Slot).
1711*795d594fSAndroid Build Coastguard Worker DCHECK_LE(sizeof(Slot), bracketSizes[0]) << "sizeof(Slot) <= the smallest bracket size";
1712*795d594fSAndroid Build Coastguard Worker // Check the invariants between the max bracket sizes and the number of brackets.
1713*795d594fSAndroid Build Coastguard Worker DCHECK_EQ(kMaxThreadLocalBracketSize, bracketSizes[kNumThreadLocalSizeBrackets - 1]);
1714*795d594fSAndroid Build Coastguard Worker DCHECK_EQ(kMaxRegularBracketSize, bracketSizes[kNumRegularSizeBrackets - 1]);
1715*795d594fSAndroid Build Coastguard Worker }
1716*795d594fSAndroid Build Coastguard Worker
BytesAllocatedCallback(void * start,void * end,size_t used_bytes,void * arg)1717*795d594fSAndroid Build Coastguard Worker void RosAlloc::BytesAllocatedCallback([[maybe_unused]] void* start,
1718*795d594fSAndroid Build Coastguard Worker [[maybe_unused]] void* end,
1719*795d594fSAndroid Build Coastguard Worker size_t used_bytes,
1720*795d594fSAndroid Build Coastguard Worker void* arg) {
1721*795d594fSAndroid Build Coastguard Worker if (used_bytes == 0) {
1722*795d594fSAndroid Build Coastguard Worker return;
1723*795d594fSAndroid Build Coastguard Worker }
1724*795d594fSAndroid Build Coastguard Worker size_t* bytes_allocated = reinterpret_cast<size_t*>(arg);
1725*795d594fSAndroid Build Coastguard Worker *bytes_allocated += used_bytes;
1726*795d594fSAndroid Build Coastguard Worker }
1727*795d594fSAndroid Build Coastguard Worker
ObjectsAllocatedCallback(void * start,void * end,size_t used_bytes,void * arg)1728*795d594fSAndroid Build Coastguard Worker void RosAlloc::ObjectsAllocatedCallback([[maybe_unused]] void* start,
1729*795d594fSAndroid Build Coastguard Worker [[maybe_unused]] void* end,
1730*795d594fSAndroid Build Coastguard Worker size_t used_bytes,
1731*795d594fSAndroid Build Coastguard Worker void* arg) {
1732*795d594fSAndroid Build Coastguard Worker if (used_bytes == 0) {
1733*795d594fSAndroid Build Coastguard Worker return;
1734*795d594fSAndroid Build Coastguard Worker }
1735*795d594fSAndroid Build Coastguard Worker size_t* objects_allocated = reinterpret_cast<size_t*>(arg);
1736*795d594fSAndroid Build Coastguard Worker ++(*objects_allocated);
1737*795d594fSAndroid Build Coastguard Worker }
1738*795d594fSAndroid Build Coastguard Worker
Verify()1739*795d594fSAndroid Build Coastguard Worker void RosAlloc::Verify() {
1740*795d594fSAndroid Build Coastguard Worker Thread* self = Thread::Current();
1741*795d594fSAndroid Build Coastguard Worker CHECK(Locks::mutator_lock_->IsExclusiveHeld(self))
1742*795d594fSAndroid Build Coastguard Worker << "The mutator locks isn't exclusively locked at " << __PRETTY_FUNCTION__;
1743*795d594fSAndroid Build Coastguard Worker MutexLock thread_list_mu(self, *Locks::thread_list_lock_);
1744*795d594fSAndroid Build Coastguard Worker ReaderMutexLock wmu(self, bulk_free_lock_);
1745*795d594fSAndroid Build Coastguard Worker std::vector<Run*> runs;
1746*795d594fSAndroid Build Coastguard Worker {
1747*795d594fSAndroid Build Coastguard Worker MutexLock lock_mu(self, lock_);
1748*795d594fSAndroid Build Coastguard Worker size_t pm_end = page_map_size_;
1749*795d594fSAndroid Build Coastguard Worker size_t i = 0;
1750*795d594fSAndroid Build Coastguard Worker size_t memory_tool_modifier = is_running_on_memory_tool_ ?
1751*795d594fSAndroid Build Coastguard Worker 2 * ::art::gc::space::kDefaultMemoryToolRedZoneBytes : // Redzones before and after.
1752*795d594fSAndroid Build Coastguard Worker 0;
1753*795d594fSAndroid Build Coastguard Worker while (i < pm_end) {
1754*795d594fSAndroid Build Coastguard Worker uint8_t pm = page_map_[i];
1755*795d594fSAndroid Build Coastguard Worker switch (pm) {
1756*795d594fSAndroid Build Coastguard Worker case kPageMapReleased:
1757*795d594fSAndroid Build Coastguard Worker // Fall-through.
1758*795d594fSAndroid Build Coastguard Worker case kPageMapEmpty: {
1759*795d594fSAndroid Build Coastguard Worker // The start of a free page run.
1760*795d594fSAndroid Build Coastguard Worker FreePageRun* fpr = reinterpret_cast<FreePageRun*>(base_ + i * gPageSize);
1761*795d594fSAndroid Build Coastguard Worker DCHECK_EQ(fpr->magic_num_, kMagicNumFree);
1762*795d594fSAndroid Build Coastguard Worker CHECK(free_page_runs_.find(fpr) != free_page_runs_.end())
1763*795d594fSAndroid Build Coastguard Worker << "An empty page must belong to the free page run set";
1764*795d594fSAndroid Build Coastguard Worker size_t fpr_size = fpr->ByteSize(this);
1765*795d594fSAndroid Build Coastguard Worker CHECK_ALIGNED_PARAM(fpr_size, gPageSize)
1766*795d594fSAndroid Build Coastguard Worker << "A free page run size isn't page-aligned : " << fpr_size;
1767*795d594fSAndroid Build Coastguard Worker size_t num_pages = DivideByPageSize(fpr_size);
1768*795d594fSAndroid Build Coastguard Worker CHECK_GT(num_pages, static_cast<uintptr_t>(0))
1769*795d594fSAndroid Build Coastguard Worker << "A free page run size must be > 0 : " << fpr_size;
1770*795d594fSAndroid Build Coastguard Worker for (size_t j = i + 1; j < i + num_pages; ++j) {
1771*795d594fSAndroid Build Coastguard Worker CHECK(IsFreePage(j))
1772*795d594fSAndroid Build Coastguard Worker << "A mismatch between the page map table for kPageMapEmpty "
1773*795d594fSAndroid Build Coastguard Worker << " at page index " << j
1774*795d594fSAndroid Build Coastguard Worker << " and the free page run size : page index range : "
1775*795d594fSAndroid Build Coastguard Worker << i << " to " << (i + num_pages) << std::endl << DumpPageMap();
1776*795d594fSAndroid Build Coastguard Worker }
1777*795d594fSAndroid Build Coastguard Worker i += num_pages;
1778*795d594fSAndroid Build Coastguard Worker CHECK_LE(i, pm_end) << "Page map index " << i << " out of range < " << pm_end
1779*795d594fSAndroid Build Coastguard Worker << std::endl << DumpPageMap();
1780*795d594fSAndroid Build Coastguard Worker break;
1781*795d594fSAndroid Build Coastguard Worker }
1782*795d594fSAndroid Build Coastguard Worker case kPageMapLargeObject: {
1783*795d594fSAndroid Build Coastguard Worker // The start of a large object.
1784*795d594fSAndroid Build Coastguard Worker size_t num_pages = 1;
1785*795d594fSAndroid Build Coastguard Worker size_t idx = i + 1;
1786*795d594fSAndroid Build Coastguard Worker while (idx < pm_end && page_map_[idx] == kPageMapLargeObjectPart) {
1787*795d594fSAndroid Build Coastguard Worker num_pages++;
1788*795d594fSAndroid Build Coastguard Worker idx++;
1789*795d594fSAndroid Build Coastguard Worker }
1790*795d594fSAndroid Build Coastguard Worker uint8_t* start = base_ + i * gPageSize;
1791*795d594fSAndroid Build Coastguard Worker if (is_running_on_memory_tool_) {
1792*795d594fSAndroid Build Coastguard Worker start += ::art::gc::space::kDefaultMemoryToolRedZoneBytes;
1793*795d594fSAndroid Build Coastguard Worker }
1794*795d594fSAndroid Build Coastguard Worker mirror::Object* obj = reinterpret_cast<mirror::Object*>(start);
1795*795d594fSAndroid Build Coastguard Worker size_t obj_size = obj->SizeOf();
1796*795d594fSAndroid Build Coastguard Worker CHECK_GT(obj_size + memory_tool_modifier, kLargeSizeThreshold)
1797*795d594fSAndroid Build Coastguard Worker << "A rosalloc large object size must be > " << kLargeSizeThreshold;
1798*795d594fSAndroid Build Coastguard Worker CHECK_EQ(num_pages, DivideByPageSize(RoundUp(obj_size + memory_tool_modifier, gPageSize)))
1799*795d594fSAndroid Build Coastguard Worker << "A rosalloc large object size " << obj_size + memory_tool_modifier
1800*795d594fSAndroid Build Coastguard Worker << " does not match the page map table " << (num_pages * gPageSize)
1801*795d594fSAndroid Build Coastguard Worker << std::endl << DumpPageMap();
1802*795d594fSAndroid Build Coastguard Worker i += num_pages;
1803*795d594fSAndroid Build Coastguard Worker CHECK_LE(i, pm_end) << "Page map index " << i << " out of range < " << pm_end
1804*795d594fSAndroid Build Coastguard Worker << std::endl << DumpPageMap();
1805*795d594fSAndroid Build Coastguard Worker break;
1806*795d594fSAndroid Build Coastguard Worker }
1807*795d594fSAndroid Build Coastguard Worker case kPageMapLargeObjectPart:
1808*795d594fSAndroid Build Coastguard Worker LOG(FATAL) << "Unreachable - page map type: " << static_cast<int>(pm) << std::endl << DumpPageMap();
1809*795d594fSAndroid Build Coastguard Worker UNREACHABLE();
1810*795d594fSAndroid Build Coastguard Worker case kPageMapRun: {
1811*795d594fSAndroid Build Coastguard Worker // The start of a run.
1812*795d594fSAndroid Build Coastguard Worker Run* run = reinterpret_cast<Run*>(base_ + i * gPageSize);
1813*795d594fSAndroid Build Coastguard Worker DCHECK_EQ(run->magic_num_, kMagicNum);
1814*795d594fSAndroid Build Coastguard Worker size_t idx = run->size_bracket_idx_;
1815*795d594fSAndroid Build Coastguard Worker CHECK_LT(idx, kNumOfSizeBrackets) << "Out of range size bracket index : " << idx;
1816*795d594fSAndroid Build Coastguard Worker size_t num_pages = numOfPages[idx];
1817*795d594fSAndroid Build Coastguard Worker CHECK_GT(num_pages, static_cast<uintptr_t>(0))
1818*795d594fSAndroid Build Coastguard Worker << "Run size must be > 0 : " << num_pages;
1819*795d594fSAndroid Build Coastguard Worker for (size_t j = i + 1; j < i + num_pages; ++j) {
1820*795d594fSAndroid Build Coastguard Worker CHECK_EQ(page_map_[j], kPageMapRunPart)
1821*795d594fSAndroid Build Coastguard Worker << "A mismatch between the page map table for kPageMapRunPart "
1822*795d594fSAndroid Build Coastguard Worker << " at page index " << j
1823*795d594fSAndroid Build Coastguard Worker << " and the run size : page index range " << i << " to " << (i + num_pages)
1824*795d594fSAndroid Build Coastguard Worker << std::endl << DumpPageMap();
1825*795d594fSAndroid Build Coastguard Worker }
1826*795d594fSAndroid Build Coastguard Worker // Don't verify the dedicated_full_run_ since it doesn't have any real allocations.
1827*795d594fSAndroid Build Coastguard Worker runs.push_back(run);
1828*795d594fSAndroid Build Coastguard Worker i += num_pages;
1829*795d594fSAndroid Build Coastguard Worker CHECK_LE(i, pm_end) << "Page map index " << i << " out of range < " << pm_end
1830*795d594fSAndroid Build Coastguard Worker << std::endl << DumpPageMap();
1831*795d594fSAndroid Build Coastguard Worker break;
1832*795d594fSAndroid Build Coastguard Worker }
1833*795d594fSAndroid Build Coastguard Worker case kPageMapRunPart:
1834*795d594fSAndroid Build Coastguard Worker LOG(FATAL) << "Unreachable - page map type: " << static_cast<int>(pm) << std::endl << DumpPageMap();
1835*795d594fSAndroid Build Coastguard Worker UNREACHABLE();
1836*795d594fSAndroid Build Coastguard Worker }
1837*795d594fSAndroid Build Coastguard Worker }
1838*795d594fSAndroid Build Coastguard Worker }
1839*795d594fSAndroid Build Coastguard Worker std::list<Thread*> threads = Runtime::Current()->GetThreadList()->GetList();
1840*795d594fSAndroid Build Coastguard Worker for (Thread* thread : threads) {
1841*795d594fSAndroid Build Coastguard Worker for (size_t i = 0; i < kNumThreadLocalSizeBrackets; ++i) {
1842*795d594fSAndroid Build Coastguard Worker MutexLock brackets_mu(self, *size_bracket_locks_[i]);
1843*795d594fSAndroid Build Coastguard Worker Run* thread_local_run = reinterpret_cast<Run*>(thread->GetRosAllocRun(i));
1844*795d594fSAndroid Build Coastguard Worker CHECK(thread_local_run != nullptr);
1845*795d594fSAndroid Build Coastguard Worker CHECK(thread_local_run->IsThreadLocal());
1846*795d594fSAndroid Build Coastguard Worker CHECK(thread_local_run == dedicated_full_run_ ||
1847*795d594fSAndroid Build Coastguard Worker thread_local_run->size_bracket_idx_ == i);
1848*795d594fSAndroid Build Coastguard Worker }
1849*795d594fSAndroid Build Coastguard Worker }
1850*795d594fSAndroid Build Coastguard Worker for (size_t i = 0; i < kNumOfSizeBrackets; i++) {
1851*795d594fSAndroid Build Coastguard Worker MutexLock brackets_mu(self, *size_bracket_locks_[i]);
1852*795d594fSAndroid Build Coastguard Worker Run* current_run = current_runs_[i];
1853*795d594fSAndroid Build Coastguard Worker CHECK(current_run != nullptr);
1854*795d594fSAndroid Build Coastguard Worker if (current_run != dedicated_full_run_) {
1855*795d594fSAndroid Build Coastguard Worker // The dedicated full run is currently marked as thread local.
1856*795d594fSAndroid Build Coastguard Worker CHECK(!current_run->IsThreadLocal());
1857*795d594fSAndroid Build Coastguard Worker CHECK_EQ(current_run->size_bracket_idx_, i);
1858*795d594fSAndroid Build Coastguard Worker }
1859*795d594fSAndroid Build Coastguard Worker }
1860*795d594fSAndroid Build Coastguard Worker // Call Verify() here for the lock order.
1861*795d594fSAndroid Build Coastguard Worker for (auto& run : runs) {
1862*795d594fSAndroid Build Coastguard Worker run->Verify(self, this, is_running_on_memory_tool_);
1863*795d594fSAndroid Build Coastguard Worker }
1864*795d594fSAndroid Build Coastguard Worker }
1865*795d594fSAndroid Build Coastguard Worker
Verify(Thread * self,RosAlloc * rosalloc,bool running_on_memory_tool)1866*795d594fSAndroid Build Coastguard Worker void RosAlloc::Run::Verify(Thread* self, RosAlloc* rosalloc, bool running_on_memory_tool) {
1867*795d594fSAndroid Build Coastguard Worker DCHECK_EQ(magic_num_, kMagicNum) << "Bad magic number : " << Dump();
1868*795d594fSAndroid Build Coastguard Worker const size_t idx = size_bracket_idx_;
1869*795d594fSAndroid Build Coastguard Worker CHECK_LT(idx, kNumOfSizeBrackets) << "Out of range size bracket index : " << Dump();
1870*795d594fSAndroid Build Coastguard Worker uint8_t* slot_base = reinterpret_cast<uint8_t*>(this) + headerSizes[idx];
1871*795d594fSAndroid Build Coastguard Worker const size_t num_slots = numOfSlots[idx];
1872*795d594fSAndroid Build Coastguard Worker size_t bracket_size = IndexToBracketSize(idx);
1873*795d594fSAndroid Build Coastguard Worker CHECK_EQ(slot_base + num_slots * bracket_size,
1874*795d594fSAndroid Build Coastguard Worker reinterpret_cast<uint8_t*>(this) + numOfPages[idx] * gPageSize)
1875*795d594fSAndroid Build Coastguard Worker << "Mismatch in the end address of the run " << Dump();
1876*795d594fSAndroid Build Coastguard Worker // Check that the bulk free list is empty. It's only used during BulkFree().
1877*795d594fSAndroid Build Coastguard Worker CHECK(IsBulkFreeListEmpty()) << "The bulk free isn't empty " << Dump();
1878*795d594fSAndroid Build Coastguard Worker // Check the thread local runs, the current runs, and the run sets.
1879*795d594fSAndroid Build Coastguard Worker if (IsThreadLocal()) {
1880*795d594fSAndroid Build Coastguard Worker // If it's a thread local run, then it must be pointed to by an owner thread.
1881*795d594fSAndroid Build Coastguard Worker bool owner_found = false;
1882*795d594fSAndroid Build Coastguard Worker std::list<Thread*> thread_list = Runtime::Current()->GetThreadList()->GetList();
1883*795d594fSAndroid Build Coastguard Worker for (auto it = thread_list.begin(); it != thread_list.end(); ++it) {
1884*795d594fSAndroid Build Coastguard Worker Thread* thread = *it;
1885*795d594fSAndroid Build Coastguard Worker for (size_t i = 0; i < kNumThreadLocalSizeBrackets; i++) {
1886*795d594fSAndroid Build Coastguard Worker MutexLock mu(self, *rosalloc->size_bracket_locks_[i]);
1887*795d594fSAndroid Build Coastguard Worker Run* thread_local_run = reinterpret_cast<Run*>(thread->GetRosAllocRun(i));
1888*795d594fSAndroid Build Coastguard Worker if (thread_local_run == this) {
1889*795d594fSAndroid Build Coastguard Worker CHECK(!owner_found)
1890*795d594fSAndroid Build Coastguard Worker << "A thread local run has more than one owner thread " << Dump();
1891*795d594fSAndroid Build Coastguard Worker CHECK_EQ(i, idx)
1892*795d594fSAndroid Build Coastguard Worker << "A mismatching size bracket index in a thread local run " << Dump();
1893*795d594fSAndroid Build Coastguard Worker owner_found = true;
1894*795d594fSAndroid Build Coastguard Worker }
1895*795d594fSAndroid Build Coastguard Worker }
1896*795d594fSAndroid Build Coastguard Worker }
1897*795d594fSAndroid Build Coastguard Worker CHECK(owner_found) << "A thread local run has no owner thread " << Dump();
1898*795d594fSAndroid Build Coastguard Worker } else {
1899*795d594fSAndroid Build Coastguard Worker // If it's not thread local, check that the thread local free list is empty.
1900*795d594fSAndroid Build Coastguard Worker CHECK(IsThreadLocalFreeListEmpty())
1901*795d594fSAndroid Build Coastguard Worker << "A non-thread-local run's thread local free list isn't empty "
1902*795d594fSAndroid Build Coastguard Worker << Dump();
1903*795d594fSAndroid Build Coastguard Worker // Check if it's a current run for the size bracket.
1904*795d594fSAndroid Build Coastguard Worker bool is_current_run = false;
1905*795d594fSAndroid Build Coastguard Worker for (size_t i = 0; i < kNumOfSizeBrackets; i++) {
1906*795d594fSAndroid Build Coastguard Worker MutexLock mu(self, *rosalloc->size_bracket_locks_[i]);
1907*795d594fSAndroid Build Coastguard Worker Run* current_run = rosalloc->current_runs_[i];
1908*795d594fSAndroid Build Coastguard Worker if (idx == i) {
1909*795d594fSAndroid Build Coastguard Worker if (this == current_run) {
1910*795d594fSAndroid Build Coastguard Worker is_current_run = true;
1911*795d594fSAndroid Build Coastguard Worker }
1912*795d594fSAndroid Build Coastguard Worker } else {
1913*795d594fSAndroid Build Coastguard Worker // If the size bucket index does not match, then it must not
1914*795d594fSAndroid Build Coastguard Worker // be a current run.
1915*795d594fSAndroid Build Coastguard Worker CHECK_NE(this, current_run)
1916*795d594fSAndroid Build Coastguard Worker << "A current run points to a run with a wrong size bracket index " << Dump();
1917*795d594fSAndroid Build Coastguard Worker }
1918*795d594fSAndroid Build Coastguard Worker }
1919*795d594fSAndroid Build Coastguard Worker // If it's neither a thread local or current run, then it must be
1920*795d594fSAndroid Build Coastguard Worker // in a run set.
1921*795d594fSAndroid Build Coastguard Worker if (!is_current_run) {
1922*795d594fSAndroid Build Coastguard Worker MutexLock mu(self, rosalloc->lock_);
1923*795d594fSAndroid Build Coastguard Worker auto& non_full_runs = rosalloc->non_full_runs_[idx];
1924*795d594fSAndroid Build Coastguard Worker // If it's all free, it must be a free page run rather than a run.
1925*795d594fSAndroid Build Coastguard Worker CHECK(!IsAllFree()) << "A free run must be in a free page run set " << Dump();
1926*795d594fSAndroid Build Coastguard Worker if (!IsFull()) {
1927*795d594fSAndroid Build Coastguard Worker // If it's not full, it must in the non-full run set.
1928*795d594fSAndroid Build Coastguard Worker CHECK(non_full_runs.find(this) != non_full_runs.end())
1929*795d594fSAndroid Build Coastguard Worker << "A non-full run isn't in the non-full run set " << Dump();
1930*795d594fSAndroid Build Coastguard Worker } else {
1931*795d594fSAndroid Build Coastguard Worker // If it's full, it must in the full run set (debug build only.)
1932*795d594fSAndroid Build Coastguard Worker if (kIsDebugBuild) {
1933*795d594fSAndroid Build Coastguard Worker auto& full_runs = rosalloc->full_runs_[idx];
1934*795d594fSAndroid Build Coastguard Worker CHECK(full_runs.find(this) != full_runs.end())
1935*795d594fSAndroid Build Coastguard Worker << " A full run isn't in the full run set " << Dump();
1936*795d594fSAndroid Build Coastguard Worker }
1937*795d594fSAndroid Build Coastguard Worker }
1938*795d594fSAndroid Build Coastguard Worker }
1939*795d594fSAndroid Build Coastguard Worker }
1940*795d594fSAndroid Build Coastguard Worker // Check each slot.
1941*795d594fSAndroid Build Coastguard Worker size_t memory_tool_modifier = running_on_memory_tool ?
1942*795d594fSAndroid Build Coastguard Worker 2 * ::art::gc::space::kDefaultMemoryToolRedZoneBytes :
1943*795d594fSAndroid Build Coastguard Worker 0U;
1944*795d594fSAndroid Build Coastguard Worker // TODO: reuse InspectAllSlots().
1945*795d594fSAndroid Build Coastguard Worker std::unique_ptr<bool[]> is_free(new bool[num_slots]()); // zero initialized
1946*795d594fSAndroid Build Coastguard Worker // Mark the free slots and the remaining ones are allocated.
1947*795d594fSAndroid Build Coastguard Worker for (Slot* slot = free_list_.Head(); slot != nullptr; slot = slot->Next()) {
1948*795d594fSAndroid Build Coastguard Worker size_t slot_idx = SlotIndex(slot);
1949*795d594fSAndroid Build Coastguard Worker DCHECK_LT(slot_idx, num_slots);
1950*795d594fSAndroid Build Coastguard Worker is_free[slot_idx] = true;
1951*795d594fSAndroid Build Coastguard Worker }
1952*795d594fSAndroid Build Coastguard Worker if (IsThreadLocal()) {
1953*795d594fSAndroid Build Coastguard Worker for (Slot* slot = thread_local_free_list_.Head(); slot != nullptr; slot = slot->Next()) {
1954*795d594fSAndroid Build Coastguard Worker size_t slot_idx = SlotIndex(slot);
1955*795d594fSAndroid Build Coastguard Worker DCHECK_LT(slot_idx, num_slots);
1956*795d594fSAndroid Build Coastguard Worker is_free[slot_idx] = true;
1957*795d594fSAndroid Build Coastguard Worker }
1958*795d594fSAndroid Build Coastguard Worker }
1959*795d594fSAndroid Build Coastguard Worker for (size_t slot_idx = 0; slot_idx < num_slots; ++slot_idx) {
1960*795d594fSAndroid Build Coastguard Worker uint8_t* slot_addr = slot_base + slot_idx * bracket_size;
1961*795d594fSAndroid Build Coastguard Worker if (running_on_memory_tool) {
1962*795d594fSAndroid Build Coastguard Worker slot_addr += ::art::gc::space::kDefaultMemoryToolRedZoneBytes;
1963*795d594fSAndroid Build Coastguard Worker }
1964*795d594fSAndroid Build Coastguard Worker if (!is_free[slot_idx]) {
1965*795d594fSAndroid Build Coastguard Worker // The slot is allocated
1966*795d594fSAndroid Build Coastguard Worker mirror::Object* obj = reinterpret_cast<mirror::Object*>(slot_addr);
1967*795d594fSAndroid Build Coastguard Worker size_t obj_size = obj->SizeOf();
1968*795d594fSAndroid Build Coastguard Worker CHECK_LE(obj_size + memory_tool_modifier, kLargeSizeThreshold)
1969*795d594fSAndroid Build Coastguard Worker << "A run slot contains a large object " << Dump();
1970*795d594fSAndroid Build Coastguard Worker CHECK_EQ(SizeToIndex(obj_size + memory_tool_modifier), idx)
1971*795d594fSAndroid Build Coastguard Worker << obj->PrettyTypeOf() << " "
1972*795d594fSAndroid Build Coastguard Worker << "obj_size=" << obj_size << "(" << obj_size + memory_tool_modifier << "), idx=" << idx
1973*795d594fSAndroid Build Coastguard Worker << " A run slot contains an object with wrong size " << Dump();
1974*795d594fSAndroid Build Coastguard Worker }
1975*795d594fSAndroid Build Coastguard Worker }
1976*795d594fSAndroid Build Coastguard Worker }
1977*795d594fSAndroid Build Coastguard Worker
ReleasePages()1978*795d594fSAndroid Build Coastguard Worker size_t RosAlloc::ReleasePages() {
1979*795d594fSAndroid Build Coastguard Worker VLOG(heap) << "RosAlloc::ReleasePages()";
1980*795d594fSAndroid Build Coastguard Worker DCHECK(!DoesReleaseAllPages());
1981*795d594fSAndroid Build Coastguard Worker Thread* self = Thread::Current();
1982*795d594fSAndroid Build Coastguard Worker size_t reclaimed_bytes = 0;
1983*795d594fSAndroid Build Coastguard Worker size_t i = 0;
1984*795d594fSAndroid Build Coastguard Worker // Check the page map size which might have changed due to grow/shrink.
1985*795d594fSAndroid Build Coastguard Worker while (i < page_map_size_) {
1986*795d594fSAndroid Build Coastguard Worker // Reading the page map without a lock is racy but the race is benign since it should only
1987*795d594fSAndroid Build Coastguard Worker // result in occasionally not releasing pages which we could release.
1988*795d594fSAndroid Build Coastguard Worker uint8_t pm = page_map_[i];
1989*795d594fSAndroid Build Coastguard Worker switch (pm) {
1990*795d594fSAndroid Build Coastguard Worker case kPageMapReleased:
1991*795d594fSAndroid Build Coastguard Worker // Fall through.
1992*795d594fSAndroid Build Coastguard Worker case kPageMapEmpty: {
1993*795d594fSAndroid Build Coastguard Worker // This is currently the start of a free page run.
1994*795d594fSAndroid Build Coastguard Worker // Acquire the lock to prevent other threads racing in and modifying the page map.
1995*795d594fSAndroid Build Coastguard Worker MutexLock mu(self, lock_);
1996*795d594fSAndroid Build Coastguard Worker // Check that it's still empty after we acquired the lock since another thread could have
1997*795d594fSAndroid Build Coastguard Worker // raced in and placed an allocation here.
1998*795d594fSAndroid Build Coastguard Worker if (IsFreePage(i)) {
1999*795d594fSAndroid Build Coastguard Worker // Free page runs can start with a released page if we coalesced a released page free
2000*795d594fSAndroid Build Coastguard Worker // page run with an empty page run.
2001*795d594fSAndroid Build Coastguard Worker FreePageRun* fpr = reinterpret_cast<FreePageRun*>(base_ + i * gPageSize);
2002*795d594fSAndroid Build Coastguard Worker // There is a race condition where FreePage can coalesce fpr with the previous
2003*795d594fSAndroid Build Coastguard Worker // free page run before we acquire lock_. In that case free_page_runs_.find will not find
2004*795d594fSAndroid Build Coastguard Worker // a run starting at fpr. To handle this race, we skip reclaiming the page range and go
2005*795d594fSAndroid Build Coastguard Worker // to the next page.
2006*795d594fSAndroid Build Coastguard Worker if (free_page_runs_.find(fpr) != free_page_runs_.end()) {
2007*795d594fSAndroid Build Coastguard Worker size_t fpr_size = fpr->ByteSize(this);
2008*795d594fSAndroid Build Coastguard Worker DCHECK_ALIGNED_PARAM(fpr_size, gPageSize);
2009*795d594fSAndroid Build Coastguard Worker uint8_t* start = reinterpret_cast<uint8_t*>(fpr);
2010*795d594fSAndroid Build Coastguard Worker reclaimed_bytes += ReleasePageRange(start, start + fpr_size);
2011*795d594fSAndroid Build Coastguard Worker size_t pages = DivideByPageSize(fpr_size);
2012*795d594fSAndroid Build Coastguard Worker CHECK_GT(pages, 0U) << "Infinite loop probable";
2013*795d594fSAndroid Build Coastguard Worker i += pages;
2014*795d594fSAndroid Build Coastguard Worker DCHECK_LE(i, page_map_size_);
2015*795d594fSAndroid Build Coastguard Worker break;
2016*795d594fSAndroid Build Coastguard Worker }
2017*795d594fSAndroid Build Coastguard Worker }
2018*795d594fSAndroid Build Coastguard Worker FALLTHROUGH_INTENDED;
2019*795d594fSAndroid Build Coastguard Worker }
2020*795d594fSAndroid Build Coastguard Worker case kPageMapLargeObject: // Fall through.
2021*795d594fSAndroid Build Coastguard Worker case kPageMapLargeObjectPart: // Fall through.
2022*795d594fSAndroid Build Coastguard Worker case kPageMapRun: // Fall through.
2023*795d594fSAndroid Build Coastguard Worker case kPageMapRunPart: // Fall through.
2024*795d594fSAndroid Build Coastguard Worker ++i;
2025*795d594fSAndroid Build Coastguard Worker break; // Skip.
2026*795d594fSAndroid Build Coastguard Worker }
2027*795d594fSAndroid Build Coastguard Worker }
2028*795d594fSAndroid Build Coastguard Worker return reclaimed_bytes;
2029*795d594fSAndroid Build Coastguard Worker }
2030*795d594fSAndroid Build Coastguard Worker
ReleasePageRange(uint8_t * start,uint8_t * end)2031*795d594fSAndroid Build Coastguard Worker size_t RosAlloc::ReleasePageRange(uint8_t* start, uint8_t* end) {
2032*795d594fSAndroid Build Coastguard Worker DCHECK_ALIGNED_PARAM(start, gPageSize);
2033*795d594fSAndroid Build Coastguard Worker DCHECK_ALIGNED_PARAM(end, gPageSize);
2034*795d594fSAndroid Build Coastguard Worker DCHECK_LT(start, end);
2035*795d594fSAndroid Build Coastguard Worker if (kIsDebugBuild) {
2036*795d594fSAndroid Build Coastguard Worker // In the debug build, the first page of a free page run
2037*795d594fSAndroid Build Coastguard Worker // contains a magic number for debugging. Exclude it.
2038*795d594fSAndroid Build Coastguard Worker start += gPageSize;
2039*795d594fSAndroid Build Coastguard Worker
2040*795d594fSAndroid Build Coastguard Worker // Single pages won't be released.
2041*795d594fSAndroid Build Coastguard Worker if (start == end) {
2042*795d594fSAndroid Build Coastguard Worker return 0;
2043*795d594fSAndroid Build Coastguard Worker }
2044*795d594fSAndroid Build Coastguard Worker }
2045*795d594fSAndroid Build Coastguard Worker if (!kMadviseZeroes) {
2046*795d594fSAndroid Build Coastguard Worker // TODO: Do this when we resurrect the page instead.
2047*795d594fSAndroid Build Coastguard Worker memset(start, 0, end - start);
2048*795d594fSAndroid Build Coastguard Worker }
2049*795d594fSAndroid Build Coastguard Worker CHECK_EQ(madvise(start, end - start, MADV_DONTNEED), 0);
2050*795d594fSAndroid Build Coastguard Worker size_t pm_idx = ToPageMapIndex(start);
2051*795d594fSAndroid Build Coastguard Worker size_t reclaimed_bytes = 0;
2052*795d594fSAndroid Build Coastguard Worker // Calculate reclaimed bytes and upate page map.
2053*795d594fSAndroid Build Coastguard Worker const size_t max_idx = pm_idx + DivideByPageSize(end - start);
2054*795d594fSAndroid Build Coastguard Worker for (; pm_idx < max_idx; ++pm_idx) {
2055*795d594fSAndroid Build Coastguard Worker DCHECK(IsFreePage(pm_idx));
2056*795d594fSAndroid Build Coastguard Worker if (page_map_[pm_idx] == kPageMapEmpty) {
2057*795d594fSAndroid Build Coastguard Worker // Mark the page as released and update how many bytes we released.
2058*795d594fSAndroid Build Coastguard Worker reclaimed_bytes += gPageSize;
2059*795d594fSAndroid Build Coastguard Worker page_map_[pm_idx] = kPageMapReleased;
2060*795d594fSAndroid Build Coastguard Worker }
2061*795d594fSAndroid Build Coastguard Worker }
2062*795d594fSAndroid Build Coastguard Worker return reclaimed_bytes;
2063*795d594fSAndroid Build Coastguard Worker }
2064*795d594fSAndroid Build Coastguard Worker
LogFragmentationAllocFailure(std::ostream & os,size_t failed_alloc_bytes)2065*795d594fSAndroid Build Coastguard Worker bool RosAlloc::LogFragmentationAllocFailure(std::ostream& os, size_t failed_alloc_bytes) {
2066*795d594fSAndroid Build Coastguard Worker Thread* self = Thread::Current();
2067*795d594fSAndroid Build Coastguard Worker size_t largest_continuous_free_pages = 0;
2068*795d594fSAndroid Build Coastguard Worker WriterMutexLock wmu(self, bulk_free_lock_);
2069*795d594fSAndroid Build Coastguard Worker MutexLock mu(self, lock_);
2070*795d594fSAndroid Build Coastguard Worker uint64_t total_free = 0;
2071*795d594fSAndroid Build Coastguard Worker for (FreePageRun* fpr : free_page_runs_) {
2072*795d594fSAndroid Build Coastguard Worker largest_continuous_free_pages = std::max(largest_continuous_free_pages,
2073*795d594fSAndroid Build Coastguard Worker fpr->ByteSize(this));
2074*795d594fSAndroid Build Coastguard Worker total_free += fpr->ByteSize(this);
2075*795d594fSAndroid Build Coastguard Worker }
2076*795d594fSAndroid Build Coastguard Worker size_t required_bytes = 0;
2077*795d594fSAndroid Build Coastguard Worker const char* new_buffer_msg = "";
2078*795d594fSAndroid Build Coastguard Worker if (failed_alloc_bytes > kLargeSizeThreshold) {
2079*795d594fSAndroid Build Coastguard Worker // Large allocation.
2080*795d594fSAndroid Build Coastguard Worker required_bytes = RoundUp(failed_alloc_bytes, gPageSize);
2081*795d594fSAndroid Build Coastguard Worker } else {
2082*795d594fSAndroid Build Coastguard Worker // Non-large allocation.
2083*795d594fSAndroid Build Coastguard Worker required_bytes = numOfPages[SizeToIndex(failed_alloc_bytes)] * gPageSize;
2084*795d594fSAndroid Build Coastguard Worker new_buffer_msg = " for a new buffer";
2085*795d594fSAndroid Build Coastguard Worker }
2086*795d594fSAndroid Build Coastguard Worker if (required_bytes > largest_continuous_free_pages) {
2087*795d594fSAndroid Build Coastguard Worker os << "; failed due to fragmentation ("
2088*795d594fSAndroid Build Coastguard Worker << "required contiguous free " << required_bytes << " bytes" << new_buffer_msg
2089*795d594fSAndroid Build Coastguard Worker << ", largest contiguous free " << largest_continuous_free_pages << " bytes"
2090*795d594fSAndroid Build Coastguard Worker << ", total free pages " << total_free << " bytes"
2091*795d594fSAndroid Build Coastguard Worker << ", space footprint " << footprint_ << " bytes"
2092*795d594fSAndroid Build Coastguard Worker << ", space max capacity " << max_capacity_ << " bytes"
2093*795d594fSAndroid Build Coastguard Worker << ")" << std::endl;
2094*795d594fSAndroid Build Coastguard Worker return true;
2095*795d594fSAndroid Build Coastguard Worker }
2096*795d594fSAndroid Build Coastguard Worker return false;
2097*795d594fSAndroid Build Coastguard Worker }
2098*795d594fSAndroid Build Coastguard Worker
DumpStats(std::ostream & os)2099*795d594fSAndroid Build Coastguard Worker void RosAlloc::DumpStats(std::ostream& os) {
2100*795d594fSAndroid Build Coastguard Worker Thread* self = Thread::Current();
2101*795d594fSAndroid Build Coastguard Worker CHECK(Locks::mutator_lock_->IsExclusiveHeld(self))
2102*795d594fSAndroid Build Coastguard Worker << "The mutator locks isn't exclusively locked at " << __PRETTY_FUNCTION__;
2103*795d594fSAndroid Build Coastguard Worker size_t num_large_objects = 0;
2104*795d594fSAndroid Build Coastguard Worker size_t num_pages_large_objects = 0;
2105*795d594fSAndroid Build Coastguard Worker // These arrays are zero initialized.
2106*795d594fSAndroid Build Coastguard Worker std::unique_ptr<size_t[]> num_runs(new size_t[kNumOfSizeBrackets]());
2107*795d594fSAndroid Build Coastguard Worker std::unique_ptr<size_t[]> num_pages_runs(new size_t[kNumOfSizeBrackets]());
2108*795d594fSAndroid Build Coastguard Worker std::unique_ptr<size_t[]> num_slots(new size_t[kNumOfSizeBrackets]());
2109*795d594fSAndroid Build Coastguard Worker std::unique_ptr<size_t[]> num_used_slots(new size_t[kNumOfSizeBrackets]());
2110*795d594fSAndroid Build Coastguard Worker std::unique_ptr<size_t[]> num_metadata_bytes(new size_t[kNumOfSizeBrackets]());
2111*795d594fSAndroid Build Coastguard Worker ReaderMutexLock rmu(self, bulk_free_lock_);
2112*795d594fSAndroid Build Coastguard Worker MutexLock lock_mu(self, lock_);
2113*795d594fSAndroid Build Coastguard Worker for (size_t i = 0; i < page_map_size_; ) {
2114*795d594fSAndroid Build Coastguard Worker uint8_t pm = page_map_[i];
2115*795d594fSAndroid Build Coastguard Worker switch (pm) {
2116*795d594fSAndroid Build Coastguard Worker case kPageMapReleased:
2117*795d594fSAndroid Build Coastguard Worker case kPageMapEmpty:
2118*795d594fSAndroid Build Coastguard Worker ++i;
2119*795d594fSAndroid Build Coastguard Worker break;
2120*795d594fSAndroid Build Coastguard Worker case kPageMapLargeObject: {
2121*795d594fSAndroid Build Coastguard Worker size_t num_pages = 1;
2122*795d594fSAndroid Build Coastguard Worker size_t idx = i + 1;
2123*795d594fSAndroid Build Coastguard Worker while (idx < page_map_size_ && page_map_[idx] == kPageMapLargeObjectPart) {
2124*795d594fSAndroid Build Coastguard Worker num_pages++;
2125*795d594fSAndroid Build Coastguard Worker idx++;
2126*795d594fSAndroid Build Coastguard Worker }
2127*795d594fSAndroid Build Coastguard Worker num_large_objects++;
2128*795d594fSAndroid Build Coastguard Worker num_pages_large_objects += num_pages;
2129*795d594fSAndroid Build Coastguard Worker i += num_pages;
2130*795d594fSAndroid Build Coastguard Worker break;
2131*795d594fSAndroid Build Coastguard Worker }
2132*795d594fSAndroid Build Coastguard Worker case kPageMapLargeObjectPart:
2133*795d594fSAndroid Build Coastguard Worker LOG(FATAL) << "Unreachable - page map type: " << static_cast<int>(pm) << std::endl
2134*795d594fSAndroid Build Coastguard Worker << DumpPageMap();
2135*795d594fSAndroid Build Coastguard Worker UNREACHABLE();
2136*795d594fSAndroid Build Coastguard Worker case kPageMapRun: {
2137*795d594fSAndroid Build Coastguard Worker Run* run = reinterpret_cast<Run*>(base_ + i * gPageSize);
2138*795d594fSAndroid Build Coastguard Worker size_t idx = run->size_bracket_idx_;
2139*795d594fSAndroid Build Coastguard Worker size_t num_pages = numOfPages[idx];
2140*795d594fSAndroid Build Coastguard Worker num_runs[idx]++;
2141*795d594fSAndroid Build Coastguard Worker num_pages_runs[idx] += num_pages;
2142*795d594fSAndroid Build Coastguard Worker num_slots[idx] += numOfSlots[idx];
2143*795d594fSAndroid Build Coastguard Worker size_t num_free_slots = run->NumberOfFreeSlots();
2144*795d594fSAndroid Build Coastguard Worker num_used_slots[idx] += numOfSlots[idx] - num_free_slots;
2145*795d594fSAndroid Build Coastguard Worker num_metadata_bytes[idx] += headerSizes[idx];
2146*795d594fSAndroid Build Coastguard Worker i += num_pages;
2147*795d594fSAndroid Build Coastguard Worker break;
2148*795d594fSAndroid Build Coastguard Worker }
2149*795d594fSAndroid Build Coastguard Worker case kPageMapRunPart:
2150*795d594fSAndroid Build Coastguard Worker LOG(FATAL) << "Unreachable - page map type: " << static_cast<int>(pm) << std::endl
2151*795d594fSAndroid Build Coastguard Worker << DumpPageMap();
2152*795d594fSAndroid Build Coastguard Worker UNREACHABLE();
2153*795d594fSAndroid Build Coastguard Worker }
2154*795d594fSAndroid Build Coastguard Worker }
2155*795d594fSAndroid Build Coastguard Worker os << "RosAlloc stats:\n";
2156*795d594fSAndroid Build Coastguard Worker for (size_t i = 0; i < kNumOfSizeBrackets; ++i) {
2157*795d594fSAndroid Build Coastguard Worker os << "Bracket " << i << " (" << bracketSizes[i] << "):"
2158*795d594fSAndroid Build Coastguard Worker << " #runs=" << num_runs[i]
2159*795d594fSAndroid Build Coastguard Worker << " #pages=" << num_pages_runs[i]
2160*795d594fSAndroid Build Coastguard Worker << " (" << PrettySize(num_pages_runs[i] * gPageSize) << ")"
2161*795d594fSAndroid Build Coastguard Worker << " #metadata_bytes=" << PrettySize(num_metadata_bytes[i])
2162*795d594fSAndroid Build Coastguard Worker << " #slots=" << num_slots[i] << " (" << PrettySize(num_slots[i] * bracketSizes[i]) << ")"
2163*795d594fSAndroid Build Coastguard Worker << " #used_slots=" << num_used_slots[i]
2164*795d594fSAndroid Build Coastguard Worker << " (" << PrettySize(num_used_slots[i] * bracketSizes[i]) << ")\n";
2165*795d594fSAndroid Build Coastguard Worker }
2166*795d594fSAndroid Build Coastguard Worker os << "Large #allocations=" << num_large_objects
2167*795d594fSAndroid Build Coastguard Worker << " #pages=" << num_pages_large_objects
2168*795d594fSAndroid Build Coastguard Worker << " (" << PrettySize(num_pages_large_objects * gPageSize) << ")\n";
2169*795d594fSAndroid Build Coastguard Worker size_t total_num_pages = 0;
2170*795d594fSAndroid Build Coastguard Worker size_t total_metadata_bytes = 0;
2171*795d594fSAndroid Build Coastguard Worker size_t total_allocated_bytes = 0;
2172*795d594fSAndroid Build Coastguard Worker for (size_t i = 0; i < kNumOfSizeBrackets; ++i) {
2173*795d594fSAndroid Build Coastguard Worker total_num_pages += num_pages_runs[i];
2174*795d594fSAndroid Build Coastguard Worker total_metadata_bytes += num_metadata_bytes[i];
2175*795d594fSAndroid Build Coastguard Worker total_allocated_bytes += num_used_slots[i] * bracketSizes[i];
2176*795d594fSAndroid Build Coastguard Worker }
2177*795d594fSAndroid Build Coastguard Worker total_num_pages += num_pages_large_objects;
2178*795d594fSAndroid Build Coastguard Worker total_allocated_bytes += num_pages_large_objects * gPageSize;
2179*795d594fSAndroid Build Coastguard Worker os << "Total #total_bytes=" << PrettySize(total_num_pages * gPageSize)
2180*795d594fSAndroid Build Coastguard Worker << " #metadata_bytes=" << PrettySize(total_metadata_bytes)
2181*795d594fSAndroid Build Coastguard Worker << " #used_bytes=" << PrettySize(total_allocated_bytes) << "\n";
2182*795d594fSAndroid Build Coastguard Worker os << "\n";
2183*795d594fSAndroid Build Coastguard Worker }
2184*795d594fSAndroid Build Coastguard Worker
2185*795d594fSAndroid Build Coastguard Worker } // namespace allocator
2186*795d594fSAndroid Build Coastguard Worker } // namespace gc
2187*795d594fSAndroid Build Coastguard Worker } // namespace art
2188