xref: /aosp_15_r20/art/runtime/gc/allocator/rosalloc.cc (revision 795d594fd825385562da6b089ea9b2033f3abf5a)
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