xref: /aosp_15_r20/art/runtime/jni/local_reference_table.cc (revision 795d594fd825385562da6b089ea9b2033f3abf5a)
1*795d594fSAndroid Build Coastguard Worker /*
2*795d594fSAndroid Build Coastguard Worker  * Copyright (C) 2022 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 "local_reference_table-inl.h"
18*795d594fSAndroid Build Coastguard Worker 
19*795d594fSAndroid Build Coastguard Worker #include "base/bit_utils.h"
20*795d594fSAndroid Build Coastguard Worker #include "base/casts.h"
21*795d594fSAndroid Build Coastguard Worker #include "base/globals.h"
22*795d594fSAndroid Build Coastguard Worker #include "base/mutator_locked_dumpable.h"
23*795d594fSAndroid Build Coastguard Worker #include "base/systrace.h"
24*795d594fSAndroid Build Coastguard Worker #include "base/utils.h"
25*795d594fSAndroid Build Coastguard Worker #include "indirect_reference_table.h"
26*795d594fSAndroid Build Coastguard Worker #include "jni/java_vm_ext.h"
27*795d594fSAndroid Build Coastguard Worker #include "jni/jni_internal.h"
28*795d594fSAndroid Build Coastguard Worker #include "mirror/object-inl.h"
29*795d594fSAndroid Build Coastguard Worker #include "nth_caller_visitor.h"
30*795d594fSAndroid Build Coastguard Worker #include "reference_table.h"
31*795d594fSAndroid Build Coastguard Worker #include "runtime-inl.h"
32*795d594fSAndroid Build Coastguard Worker #include "scoped_thread_state_change-inl.h"
33*795d594fSAndroid Build Coastguard Worker #include "thread.h"
34*795d594fSAndroid Build Coastguard Worker 
35*795d594fSAndroid Build Coastguard Worker #include <cstdlib>
36*795d594fSAndroid Build Coastguard Worker 
37*795d594fSAndroid Build Coastguard Worker namespace art HIDDEN {
38*795d594fSAndroid Build Coastguard Worker namespace jni {
39*795d594fSAndroid Build Coastguard Worker 
40*795d594fSAndroid Build Coastguard Worker static constexpr bool kDumpStackOnNonLocalReference = false;
41*795d594fSAndroid Build Coastguard Worker 
42*795d594fSAndroid Build Coastguard Worker // Mmap an "indirect ref table region. Table_bytes is a multiple of a page size.
NewLRTMap(size_t table_bytes,std::string * error_msg)43*795d594fSAndroid Build Coastguard Worker static inline MemMap NewLRTMap(size_t table_bytes, std::string* error_msg) {
44*795d594fSAndroid Build Coastguard Worker   return MemMap::MapAnonymous("local ref table",
45*795d594fSAndroid Build Coastguard Worker                               table_bytes,
46*795d594fSAndroid Build Coastguard Worker                               PROT_READ | PROT_WRITE,
47*795d594fSAndroid Build Coastguard Worker                               /*low_4gb=*/ false,
48*795d594fSAndroid Build Coastguard Worker                               error_msg);
49*795d594fSAndroid Build Coastguard Worker }
50*795d594fSAndroid Build Coastguard Worker 
SmallLrtAllocator()51*795d594fSAndroid Build Coastguard Worker SmallLrtAllocator::SmallLrtAllocator()
52*795d594fSAndroid Build Coastguard Worker     : free_lists_(num_lrt_slots_, nullptr),
53*795d594fSAndroid Build Coastguard Worker       shared_lrt_maps_(),
54*795d594fSAndroid Build Coastguard Worker       lock_("Small LRT allocator lock", LockLevel::kGenericBottomLock) {
55*795d594fSAndroid Build Coastguard Worker }
56*795d594fSAndroid Build Coastguard Worker 
GetIndex(size_t size)57*795d594fSAndroid Build Coastguard Worker inline size_t SmallLrtAllocator::GetIndex(size_t size) {
58*795d594fSAndroid Build Coastguard Worker   DCHECK_GE(size, kSmallLrtEntries);
59*795d594fSAndroid Build Coastguard Worker   DCHECK_LT(size, gPageSize / sizeof(LrtEntry));
60*795d594fSAndroid Build Coastguard Worker   DCHECK(IsPowerOfTwo(size));
61*795d594fSAndroid Build Coastguard Worker   size_t index = WhichPowerOf2(size / kSmallLrtEntries);
62*795d594fSAndroid Build Coastguard Worker   DCHECK_LT(index, num_lrt_slots_);
63*795d594fSAndroid Build Coastguard Worker   return index;
64*795d594fSAndroid Build Coastguard Worker }
65*795d594fSAndroid Build Coastguard Worker 
Allocate(size_t size,std::string * error_msg)66*795d594fSAndroid Build Coastguard Worker LrtEntry* SmallLrtAllocator::Allocate(size_t size, std::string* error_msg) {
67*795d594fSAndroid Build Coastguard Worker   size_t index = GetIndex(size);
68*795d594fSAndroid Build Coastguard Worker   MutexLock lock(Thread::Current(), lock_);
69*795d594fSAndroid Build Coastguard Worker   size_t fill_from = index;
70*795d594fSAndroid Build Coastguard Worker   while (fill_from != num_lrt_slots_ && free_lists_[fill_from] == nullptr) {
71*795d594fSAndroid Build Coastguard Worker     ++fill_from;
72*795d594fSAndroid Build Coastguard Worker   }
73*795d594fSAndroid Build Coastguard Worker   void* result = nullptr;
74*795d594fSAndroid Build Coastguard Worker   if (fill_from != num_lrt_slots_) {
75*795d594fSAndroid Build Coastguard Worker     // We found a slot with enough memory.
76*795d594fSAndroid Build Coastguard Worker     result = free_lists_[fill_from];
77*795d594fSAndroid Build Coastguard Worker     free_lists_[fill_from] = *reinterpret_cast<void**>(result);
78*795d594fSAndroid Build Coastguard Worker   } else {
79*795d594fSAndroid Build Coastguard Worker     // We need to allocate a new page and split it into smaller pieces.
80*795d594fSAndroid Build Coastguard Worker     MemMap map = NewLRTMap(gPageSize, error_msg);
81*795d594fSAndroid Build Coastguard Worker     if (!map.IsValid()) {
82*795d594fSAndroid Build Coastguard Worker       return nullptr;
83*795d594fSAndroid Build Coastguard Worker     }
84*795d594fSAndroid Build Coastguard Worker     result = map.Begin();
85*795d594fSAndroid Build Coastguard Worker     shared_lrt_maps_.emplace_back(std::move(map));
86*795d594fSAndroid Build Coastguard Worker   }
87*795d594fSAndroid Build Coastguard Worker   while (fill_from != index) {
88*795d594fSAndroid Build Coastguard Worker     --fill_from;
89*795d594fSAndroid Build Coastguard Worker     // Store the second half of the current buffer in appropriate free list slot.
90*795d594fSAndroid Build Coastguard Worker     void* mid = reinterpret_cast<uint8_t*>(result) + (kInitialLrtBytes << fill_from);
91*795d594fSAndroid Build Coastguard Worker     DCHECK(free_lists_[fill_from] == nullptr);
92*795d594fSAndroid Build Coastguard Worker     *reinterpret_cast<void**>(mid) = nullptr;
93*795d594fSAndroid Build Coastguard Worker     free_lists_[fill_from] = mid;
94*795d594fSAndroid Build Coastguard Worker   }
95*795d594fSAndroid Build Coastguard Worker   // Clear the memory we return to the caller.
96*795d594fSAndroid Build Coastguard Worker   std::memset(result, 0, kInitialLrtBytes << index);
97*795d594fSAndroid Build Coastguard Worker   return reinterpret_cast<LrtEntry*>(result);
98*795d594fSAndroid Build Coastguard Worker }
99*795d594fSAndroid Build Coastguard Worker 
Deallocate(LrtEntry * unneeded,size_t size)100*795d594fSAndroid Build Coastguard Worker void SmallLrtAllocator::Deallocate(LrtEntry* unneeded, size_t size) {
101*795d594fSAndroid Build Coastguard Worker   size_t index = GetIndex(size);
102*795d594fSAndroid Build Coastguard Worker   MutexLock lock(Thread::Current(), lock_);
103*795d594fSAndroid Build Coastguard Worker   while (index < num_lrt_slots_) {
104*795d594fSAndroid Build Coastguard Worker     // Check if we can merge this free block with another block with the same size.
105*795d594fSAndroid Build Coastguard Worker     void** other = reinterpret_cast<void**>(
106*795d594fSAndroid Build Coastguard Worker         reinterpret_cast<uintptr_t>(unneeded) ^ (kInitialLrtBytes << index));
107*795d594fSAndroid Build Coastguard Worker     void** before = &free_lists_[index];
108*795d594fSAndroid Build Coastguard Worker     if (index + 1u == num_lrt_slots_ && *before == other && *other == nullptr) {
109*795d594fSAndroid Build Coastguard Worker       // Do not unmap the page if we do not have other free blocks with index `num_lrt_slots_ - 1`.
110*795d594fSAndroid Build Coastguard Worker       // (Keep at least one free block to avoid a situation where creating and destroying a single
111*795d594fSAndroid Build Coastguard Worker       // thread with no local references would map and unmap a page in the `SmallLrtAllocator`.)
112*795d594fSAndroid Build Coastguard Worker       break;
113*795d594fSAndroid Build Coastguard Worker     }
114*795d594fSAndroid Build Coastguard Worker     while (*before != nullptr && *before != other) {
115*795d594fSAndroid Build Coastguard Worker       before = reinterpret_cast<void**>(*before);
116*795d594fSAndroid Build Coastguard Worker     }
117*795d594fSAndroid Build Coastguard Worker     if (*before == nullptr) {
118*795d594fSAndroid Build Coastguard Worker       break;
119*795d594fSAndroid Build Coastguard Worker     }
120*795d594fSAndroid Build Coastguard Worker     // Remove `other` from the free list and merge it with the `unneeded` block.
121*795d594fSAndroid Build Coastguard Worker     DCHECK(*before == other);
122*795d594fSAndroid Build Coastguard Worker     *before = *reinterpret_cast<void**>(other);
123*795d594fSAndroid Build Coastguard Worker     ++index;
124*795d594fSAndroid Build Coastguard Worker     unneeded = reinterpret_cast<LrtEntry*>(
125*795d594fSAndroid Build Coastguard Worker         reinterpret_cast<uintptr_t>(unneeded) & reinterpret_cast<uintptr_t>(other));
126*795d594fSAndroid Build Coastguard Worker   }
127*795d594fSAndroid Build Coastguard Worker   if (index == num_lrt_slots_) {
128*795d594fSAndroid Build Coastguard Worker     // Free the entire page.
129*795d594fSAndroid Build Coastguard Worker     DCHECK(free_lists_[num_lrt_slots_ - 1u] != nullptr);
130*795d594fSAndroid Build Coastguard Worker     auto match = [=](MemMap& map) { return unneeded == reinterpret_cast<LrtEntry*>(map.Begin()); };
131*795d594fSAndroid Build Coastguard Worker     auto it = std::find_if(shared_lrt_maps_.begin(), shared_lrt_maps_.end(), match);
132*795d594fSAndroid Build Coastguard Worker     DCHECK(it != shared_lrt_maps_.end());
133*795d594fSAndroid Build Coastguard Worker     shared_lrt_maps_.erase(it);
134*795d594fSAndroid Build Coastguard Worker     DCHECK(!shared_lrt_maps_.empty());
135*795d594fSAndroid Build Coastguard Worker     return;
136*795d594fSAndroid Build Coastguard Worker   }
137*795d594fSAndroid Build Coastguard Worker   *reinterpret_cast<void**>(unneeded) = free_lists_[index];
138*795d594fSAndroid Build Coastguard Worker   free_lists_[index] = unneeded;
139*795d594fSAndroid Build Coastguard Worker }
140*795d594fSAndroid Build Coastguard Worker 
LocalReferenceTable(bool check_jni)141*795d594fSAndroid Build Coastguard Worker LocalReferenceTable::LocalReferenceTable(bool check_jni)
142*795d594fSAndroid Build Coastguard Worker     : previous_state_(kLRTFirstSegment),
143*795d594fSAndroid Build Coastguard Worker       segment_state_(kLRTFirstSegment),
144*795d594fSAndroid Build Coastguard Worker       max_entries_(0u),
145*795d594fSAndroid Build Coastguard Worker       free_entries_list_(
146*795d594fSAndroid Build Coastguard Worker           FirstFreeField::Update(kFreeListEnd, check_jni ? 1u << kFlagCheckJni : 0u)),
147*795d594fSAndroid Build Coastguard Worker       small_table_(nullptr),
148*795d594fSAndroid Build Coastguard Worker       tables_(),
149*795d594fSAndroid Build Coastguard Worker       table_mem_maps_() {
150*795d594fSAndroid Build Coastguard Worker }
151*795d594fSAndroid Build Coastguard Worker 
SetCheckJniEnabled(bool enabled)152*795d594fSAndroid Build Coastguard Worker void LocalReferenceTable::SetCheckJniEnabled(bool enabled) {
153*795d594fSAndroid Build Coastguard Worker   free_entries_list_ =
154*795d594fSAndroid Build Coastguard Worker       (free_entries_list_ & ~(1u << kFlagCheckJni)) | (enabled ? 1u << kFlagCheckJni : 0u);
155*795d594fSAndroid Build Coastguard Worker }
156*795d594fSAndroid Build Coastguard Worker 
Initialize(size_t max_count,std::string * error_msg)157*795d594fSAndroid Build Coastguard Worker bool LocalReferenceTable::Initialize(size_t max_count, std::string* error_msg) {
158*795d594fSAndroid Build Coastguard Worker   CHECK(error_msg != nullptr);
159*795d594fSAndroid Build Coastguard Worker 
160*795d594fSAndroid Build Coastguard Worker   // Overflow and maximum check.
161*795d594fSAndroid Build Coastguard Worker   CHECK_LE(max_count, kMaxTableSizeInBytes / sizeof(LrtEntry));
162*795d594fSAndroid Build Coastguard Worker   if (IsCheckJniEnabled()) {
163*795d594fSAndroid Build Coastguard Worker     CHECK_LE(max_count, kMaxTableSizeInBytes / sizeof(LrtEntry) / kCheckJniEntriesPerReference);
164*795d594fSAndroid Build Coastguard Worker     max_count *= kCheckJniEntriesPerReference;
165*795d594fSAndroid Build Coastguard Worker   }
166*795d594fSAndroid Build Coastguard Worker 
167*795d594fSAndroid Build Coastguard Worker   SmallLrtAllocator* small_lrt_allocator = Runtime::Current()->GetSmallLrtAllocator();
168*795d594fSAndroid Build Coastguard Worker   LrtEntry* first_table = small_lrt_allocator->Allocate(kSmallLrtEntries, error_msg);
169*795d594fSAndroid Build Coastguard Worker   if (first_table == nullptr) {
170*795d594fSAndroid Build Coastguard Worker     DCHECK(!error_msg->empty());
171*795d594fSAndroid Build Coastguard Worker     return false;
172*795d594fSAndroid Build Coastguard Worker   }
173*795d594fSAndroid Build Coastguard Worker   DCHECK_ALIGNED(first_table, kCheckJniEntriesPerReference * sizeof(LrtEntry));
174*795d594fSAndroid Build Coastguard Worker   small_table_ = first_table;
175*795d594fSAndroid Build Coastguard Worker   max_entries_ = kSmallLrtEntries;
176*795d594fSAndroid Build Coastguard Worker   return (max_count <= kSmallLrtEntries) || Resize(max_count, error_msg);
177*795d594fSAndroid Build Coastguard Worker }
178*795d594fSAndroid Build Coastguard Worker 
~LocalReferenceTable()179*795d594fSAndroid Build Coastguard Worker LocalReferenceTable::~LocalReferenceTable() {
180*795d594fSAndroid Build Coastguard Worker   SmallLrtAllocator* small_lrt_allocator =
181*795d594fSAndroid Build Coastguard Worker       max_entries_ != 0u ? Runtime::Current()->GetSmallLrtAllocator() : nullptr;
182*795d594fSAndroid Build Coastguard Worker   if (small_table_ != nullptr) {
183*795d594fSAndroid Build Coastguard Worker     small_lrt_allocator->Deallocate(small_table_, kSmallLrtEntries);
184*795d594fSAndroid Build Coastguard Worker     DCHECK(tables_.empty());
185*795d594fSAndroid Build Coastguard Worker   } else {
186*795d594fSAndroid Build Coastguard Worker     size_t num_small_tables = std::min(tables_.size(), MaxSmallTables());
187*795d594fSAndroid Build Coastguard Worker     for (size_t i = 0; i != num_small_tables; ++i) {
188*795d594fSAndroid Build Coastguard Worker       small_lrt_allocator->Deallocate(tables_[i], GetTableSize(i));
189*795d594fSAndroid Build Coastguard Worker     }
190*795d594fSAndroid Build Coastguard Worker   }
191*795d594fSAndroid Build Coastguard Worker }
192*795d594fSAndroid Build Coastguard Worker 
Resize(size_t new_size,std::string * error_msg)193*795d594fSAndroid Build Coastguard Worker bool LocalReferenceTable::Resize(size_t new_size, std::string* error_msg) {
194*795d594fSAndroid Build Coastguard Worker   DCHECK_GE(max_entries_, kSmallLrtEntries);
195*795d594fSAndroid Build Coastguard Worker   DCHECK(IsPowerOfTwo(max_entries_));
196*795d594fSAndroid Build Coastguard Worker   DCHECK_GT(new_size, max_entries_);
197*795d594fSAndroid Build Coastguard Worker   DCHECK_LE(new_size, kMaxTableSizeInBytes / sizeof(LrtEntry));
198*795d594fSAndroid Build Coastguard Worker   size_t required_size = RoundUpToPowerOfTwo(new_size);
199*795d594fSAndroid Build Coastguard Worker   size_t num_required_tables = NumTablesForSize(required_size);
200*795d594fSAndroid Build Coastguard Worker   DCHECK_GE(num_required_tables, 2u);
201*795d594fSAndroid Build Coastguard Worker   // Delay moving the `small_table_` to `tables_` until after the next table allocation succeeds.
202*795d594fSAndroid Build Coastguard Worker   size_t num_tables = (small_table_ != nullptr) ? 1u : tables_.size();
203*795d594fSAndroid Build Coastguard Worker   DCHECK_EQ(num_tables, NumTablesForSize(max_entries_));
204*795d594fSAndroid Build Coastguard Worker   for (; num_tables != num_required_tables; ++num_tables) {
205*795d594fSAndroid Build Coastguard Worker     size_t new_table_size = GetTableSize(num_tables);
206*795d594fSAndroid Build Coastguard Worker     if (num_tables < MaxSmallTables()) {
207*795d594fSAndroid Build Coastguard Worker       SmallLrtAllocator* small_lrt_allocator = Runtime::Current()->GetSmallLrtAllocator();
208*795d594fSAndroid Build Coastguard Worker       LrtEntry* new_table = small_lrt_allocator->Allocate(new_table_size, error_msg);
209*795d594fSAndroid Build Coastguard Worker       if (new_table == nullptr) {
210*795d594fSAndroid Build Coastguard Worker         DCHECK(!error_msg->empty());
211*795d594fSAndroid Build Coastguard Worker         return false;
212*795d594fSAndroid Build Coastguard Worker       }
213*795d594fSAndroid Build Coastguard Worker       DCHECK_ALIGNED(new_table, kCheckJniEntriesPerReference * sizeof(LrtEntry));
214*795d594fSAndroid Build Coastguard Worker       tables_.push_back(new_table);
215*795d594fSAndroid Build Coastguard Worker     } else {
216*795d594fSAndroid Build Coastguard Worker       MemMap new_map = NewLRTMap(new_table_size * sizeof(LrtEntry), error_msg);
217*795d594fSAndroid Build Coastguard Worker       if (!new_map.IsValid()) {
218*795d594fSAndroid Build Coastguard Worker         DCHECK(!error_msg->empty());
219*795d594fSAndroid Build Coastguard Worker         return false;
220*795d594fSAndroid Build Coastguard Worker       }
221*795d594fSAndroid Build Coastguard Worker       DCHECK_ALIGNED(new_map.Begin(), kCheckJniEntriesPerReference * sizeof(LrtEntry));
222*795d594fSAndroid Build Coastguard Worker       tables_.push_back(reinterpret_cast<LrtEntry*>(new_map.Begin()));
223*795d594fSAndroid Build Coastguard Worker       table_mem_maps_.push_back(std::move(new_map));
224*795d594fSAndroid Build Coastguard Worker     }
225*795d594fSAndroid Build Coastguard Worker     DCHECK_EQ(num_tables == 1u, small_table_ != nullptr);
226*795d594fSAndroid Build Coastguard Worker     if (num_tables == 1u) {
227*795d594fSAndroid Build Coastguard Worker       tables_.insert(tables_.begin(), small_table_);
228*795d594fSAndroid Build Coastguard Worker       small_table_ = nullptr;
229*795d594fSAndroid Build Coastguard Worker     }
230*795d594fSAndroid Build Coastguard Worker     // Record the new available capacity after each successful allocation.
231*795d594fSAndroid Build Coastguard Worker     DCHECK_EQ(max_entries_, new_table_size);
232*795d594fSAndroid Build Coastguard Worker     max_entries_ = 2u * new_table_size;
233*795d594fSAndroid Build Coastguard Worker   }
234*795d594fSAndroid Build Coastguard Worker   DCHECK_EQ(num_required_tables, tables_.size());
235*795d594fSAndroid Build Coastguard Worker   return true;
236*795d594fSAndroid Build Coastguard Worker }
237*795d594fSAndroid Build Coastguard Worker 
238*795d594fSAndroid Build Coastguard Worker template <typename EntryGetter>
PrunePoppedFreeEntries(EntryGetter && get_entry)239*795d594fSAndroid Build Coastguard Worker inline void LocalReferenceTable::PrunePoppedFreeEntries(EntryGetter&& get_entry) {
240*795d594fSAndroid Build Coastguard Worker   const uint32_t top_index = segment_state_.top_index;
241*795d594fSAndroid Build Coastguard Worker   uint32_t free_entries_list = free_entries_list_;
242*795d594fSAndroid Build Coastguard Worker   uint32_t free_entry_index = FirstFreeField::Decode(free_entries_list);
243*795d594fSAndroid Build Coastguard Worker   DCHECK_NE(free_entry_index, kFreeListEnd);
244*795d594fSAndroid Build Coastguard Worker   DCHECK_GE(free_entry_index, top_index);
245*795d594fSAndroid Build Coastguard Worker   do {
246*795d594fSAndroid Build Coastguard Worker     free_entry_index = get_entry(free_entry_index)->GetNextFree();
247*795d594fSAndroid Build Coastguard Worker   } while (free_entry_index != kFreeListEnd && free_entry_index >= top_index);
248*795d594fSAndroid Build Coastguard Worker   free_entries_list_ = FirstFreeField::Update(free_entry_index, free_entries_list);
249*795d594fSAndroid Build Coastguard Worker }
250*795d594fSAndroid Build Coastguard Worker 
IncrementSerialNumber(LrtEntry * serial_number_entry)251*795d594fSAndroid Build Coastguard Worker inline uint32_t LocalReferenceTable::IncrementSerialNumber(LrtEntry* serial_number_entry) {
252*795d594fSAndroid Build Coastguard Worker   DCHECK_EQ(serial_number_entry, GetCheckJniSerialNumberEntry(serial_number_entry));
253*795d594fSAndroid Build Coastguard Worker   // The old serial number can be 0 if it was not used before. It can also be bits from the
254*795d594fSAndroid Build Coastguard Worker   // representation of an object reference, or a link to the next free entry written in this
255*795d594fSAndroid Build Coastguard Worker   // slot before enabling the CheckJNI. (Some gtests repeatedly enable and disable CheckJNI.)
256*795d594fSAndroid Build Coastguard Worker   uint32_t old_serial_number =
257*795d594fSAndroid Build Coastguard Worker       serial_number_entry->GetSerialNumberUnchecked() % kCheckJniEntriesPerReference;
258*795d594fSAndroid Build Coastguard Worker   uint32_t new_serial_number =
259*795d594fSAndroid Build Coastguard Worker       (old_serial_number + 1u) != kCheckJniEntriesPerReference ? old_serial_number + 1u : 1u;
260*795d594fSAndroid Build Coastguard Worker   DCHECK(IsValidSerialNumber(new_serial_number));
261*795d594fSAndroid Build Coastguard Worker   serial_number_entry->SetSerialNumber(new_serial_number);
262*795d594fSAndroid Build Coastguard Worker   return new_serial_number;
263*795d594fSAndroid Build Coastguard Worker }
264*795d594fSAndroid Build Coastguard Worker 
Add(ObjPtr<mirror::Object> obj,std::string * error_msg)265*795d594fSAndroid Build Coastguard Worker IndirectRef LocalReferenceTable::Add(ObjPtr<mirror::Object> obj, std::string* error_msg) {
266*795d594fSAndroid Build Coastguard Worker   if (kDebugLRT) {
267*795d594fSAndroid Build Coastguard Worker     LOG(INFO) << "+++ Add: previous_state=" << previous_state_.top_index
268*795d594fSAndroid Build Coastguard Worker               << " top_index=" << segment_state_.top_index;
269*795d594fSAndroid Build Coastguard Worker   }
270*795d594fSAndroid Build Coastguard Worker 
271*795d594fSAndroid Build Coastguard Worker   DCHECK(obj != nullptr);
272*795d594fSAndroid Build Coastguard Worker   VerifyObject(obj);
273*795d594fSAndroid Build Coastguard Worker 
274*795d594fSAndroid Build Coastguard Worker   DCHECK_LE(previous_state_.top_index, segment_state_.top_index);
275*795d594fSAndroid Build Coastguard Worker   DCHECK(max_entries_ == kSmallLrtEntries ? small_table_ != nullptr : !tables_.empty());
276*795d594fSAndroid Build Coastguard Worker 
277*795d594fSAndroid Build Coastguard Worker   auto store_obj = [obj, this](LrtEntry* free_entry, const char* tag)
278*795d594fSAndroid Build Coastguard Worker       REQUIRES_SHARED(Locks::mutator_lock_) {
279*795d594fSAndroid Build Coastguard Worker     free_entry->SetReference(obj);
280*795d594fSAndroid Build Coastguard Worker     IndirectRef result = ToIndirectRef(free_entry);
281*795d594fSAndroid Build Coastguard Worker     if (kDebugLRT) {
282*795d594fSAndroid Build Coastguard Worker       LOG(INFO) << "+++ " << tag << ": added at index " << GetReferenceEntryIndex(result)
283*795d594fSAndroid Build Coastguard Worker                 << ", top=" << segment_state_.top_index;
284*795d594fSAndroid Build Coastguard Worker     }
285*795d594fSAndroid Build Coastguard Worker     return result;
286*795d594fSAndroid Build Coastguard Worker   };
287*795d594fSAndroid Build Coastguard Worker 
288*795d594fSAndroid Build Coastguard Worker   // Fast-path for small table with CheckJNI disabled.
289*795d594fSAndroid Build Coastguard Worker   uint32_t top_index = segment_state_.top_index;
290*795d594fSAndroid Build Coastguard Worker   LrtEntry* const small_table = small_table_;
291*795d594fSAndroid Build Coastguard Worker   if (LIKELY(small_table != nullptr)) {
292*795d594fSAndroid Build Coastguard Worker     DCHECK_EQ(max_entries_, kSmallLrtEntries);
293*795d594fSAndroid Build Coastguard Worker     DCHECK_LE(segment_state_.top_index, kSmallLrtEntries);
294*795d594fSAndroid Build Coastguard Worker     auto get_entry = [small_table](uint32_t index) ALWAYS_INLINE {
295*795d594fSAndroid Build Coastguard Worker       DCHECK_LT(index, kSmallLrtEntries);
296*795d594fSAndroid Build Coastguard Worker       return &small_table[index];
297*795d594fSAndroid Build Coastguard Worker     };
298*795d594fSAndroid Build Coastguard Worker     if (LIKELY(free_entries_list_ == kEmptyFreeListAndCheckJniDisabled)) {
299*795d594fSAndroid Build Coastguard Worker       if (LIKELY(top_index != kSmallLrtEntries)) {
300*795d594fSAndroid Build Coastguard Worker         LrtEntry* free_entry = get_entry(top_index);
301*795d594fSAndroid Build Coastguard Worker         segment_state_.top_index = top_index + 1u;
302*795d594fSAndroid Build Coastguard Worker         return store_obj(free_entry, "small_table/empty-free-list");
303*795d594fSAndroid Build Coastguard Worker       }
304*795d594fSAndroid Build Coastguard Worker     } else if (LIKELY(!IsCheckJniEnabled())) {
305*795d594fSAndroid Build Coastguard Worker       uint32_t first_free_index = GetFirstFreeIndex();
306*795d594fSAndroid Build Coastguard Worker       DCHECK_NE(first_free_index, kFreeListEnd);
307*795d594fSAndroid Build Coastguard Worker       if (UNLIKELY(first_free_index >= top_index)) {
308*795d594fSAndroid Build Coastguard Worker         PrunePoppedFreeEntries(get_entry);
309*795d594fSAndroid Build Coastguard Worker         first_free_index = GetFirstFreeIndex();
310*795d594fSAndroid Build Coastguard Worker       }
311*795d594fSAndroid Build Coastguard Worker       if (first_free_index != kFreeListEnd && first_free_index >= previous_state_.top_index) {
312*795d594fSAndroid Build Coastguard Worker         DCHECK_LT(first_free_index, segment_state_.top_index);  // Popped entries pruned above.
313*795d594fSAndroid Build Coastguard Worker         LrtEntry* free_entry = get_entry(first_free_index);
314*795d594fSAndroid Build Coastguard Worker         // Use the `free_entry` only if it was created with CheckJNI disabled.
315*795d594fSAndroid Build Coastguard Worker         LrtEntry* serial_number_entry = GetCheckJniSerialNumberEntry(free_entry);
316*795d594fSAndroid Build Coastguard Worker         if (!serial_number_entry->IsSerialNumber()) {
317*795d594fSAndroid Build Coastguard Worker           free_entries_list_ = FirstFreeField::Update(free_entry->GetNextFree(), 0u);
318*795d594fSAndroid Build Coastguard Worker           return store_obj(free_entry, "small_table/reuse-empty-slot");
319*795d594fSAndroid Build Coastguard Worker         }
320*795d594fSAndroid Build Coastguard Worker       }
321*795d594fSAndroid Build Coastguard Worker       if (top_index != kSmallLrtEntries) {
322*795d594fSAndroid Build Coastguard Worker         LrtEntry* free_entry = get_entry(top_index);
323*795d594fSAndroid Build Coastguard Worker         segment_state_.top_index = top_index + 1u;
324*795d594fSAndroid Build Coastguard Worker         return store_obj(free_entry, "small_table/pruned-free-list");
325*795d594fSAndroid Build Coastguard Worker       }
326*795d594fSAndroid Build Coastguard Worker     }
327*795d594fSAndroid Build Coastguard Worker   }
328*795d594fSAndroid Build Coastguard Worker   DCHECK(IsCheckJniEnabled() || small_table == nullptr || top_index == kSmallLrtEntries);
329*795d594fSAndroid Build Coastguard Worker 
330*795d594fSAndroid Build Coastguard Worker   // Process free list: prune, reuse free entry or pad for CheckJNI.
331*795d594fSAndroid Build Coastguard Worker   uint32_t first_free_index = GetFirstFreeIndex();
332*795d594fSAndroid Build Coastguard Worker   if (first_free_index != kFreeListEnd && first_free_index >= top_index) {
333*795d594fSAndroid Build Coastguard Worker     PrunePoppedFreeEntries([&](size_t index) { return GetEntry(index); });
334*795d594fSAndroid Build Coastguard Worker     first_free_index = GetFirstFreeIndex();
335*795d594fSAndroid Build Coastguard Worker   }
336*795d594fSAndroid Build Coastguard Worker   if (first_free_index != kFreeListEnd && first_free_index >= previous_state_.top_index) {
337*795d594fSAndroid Build Coastguard Worker     // Reuse the free entry if it was created with the same CheckJNI setting.
338*795d594fSAndroid Build Coastguard Worker     DCHECK_LT(first_free_index, top_index);  // Popped entries have been pruned above.
339*795d594fSAndroid Build Coastguard Worker     LrtEntry* free_entry = GetEntry(first_free_index);
340*795d594fSAndroid Build Coastguard Worker     LrtEntry* serial_number_entry = GetCheckJniSerialNumberEntry(free_entry);
341*795d594fSAndroid Build Coastguard Worker     if (serial_number_entry->IsSerialNumber() == IsCheckJniEnabled()) {
342*795d594fSAndroid Build Coastguard Worker       free_entries_list_ = FirstFreeField::Update(free_entry->GetNextFree(), free_entries_list_);
343*795d594fSAndroid Build Coastguard Worker       if (UNLIKELY(IsCheckJniEnabled())) {
344*795d594fSAndroid Build Coastguard Worker         DCHECK_NE(free_entry, serial_number_entry);
345*795d594fSAndroid Build Coastguard Worker         uint32_t serial_number = IncrementSerialNumber(serial_number_entry);
346*795d594fSAndroid Build Coastguard Worker         free_entry = serial_number_entry + serial_number;
347*795d594fSAndroid Build Coastguard Worker         DCHECK_EQ(
348*795d594fSAndroid Build Coastguard Worker             free_entry,
349*795d594fSAndroid Build Coastguard Worker             GetEntry(RoundDown(first_free_index, kCheckJniEntriesPerReference) + serial_number));
350*795d594fSAndroid Build Coastguard Worker       }
351*795d594fSAndroid Build Coastguard Worker       return store_obj(free_entry, "reuse-empty-slot");
352*795d594fSAndroid Build Coastguard Worker     }
353*795d594fSAndroid Build Coastguard Worker   }
354*795d594fSAndroid Build Coastguard Worker   if (UNLIKELY(IsCheckJniEnabled()) && !IsAligned<kCheckJniEntriesPerReference>(top_index)) {
355*795d594fSAndroid Build Coastguard Worker     // Add non-CheckJNI holes up to the next serial number entry.
356*795d594fSAndroid Build Coastguard Worker     for (; !IsAligned<kCheckJniEntriesPerReference>(top_index); ++top_index) {
357*795d594fSAndroid Build Coastguard Worker       GetEntry(top_index)->SetNextFree(first_free_index);
358*795d594fSAndroid Build Coastguard Worker       first_free_index = top_index;
359*795d594fSAndroid Build Coastguard Worker     }
360*795d594fSAndroid Build Coastguard Worker     free_entries_list_ = FirstFreeField::Update(first_free_index, 1u << kFlagCheckJni);
361*795d594fSAndroid Build Coastguard Worker     segment_state_.top_index = top_index;
362*795d594fSAndroid Build Coastguard Worker   }
363*795d594fSAndroid Build Coastguard Worker 
364*795d594fSAndroid Build Coastguard Worker   // Resize (double the space) if needed.
365*795d594fSAndroid Build Coastguard Worker   if (UNLIKELY(top_index == max_entries_)) {
366*795d594fSAndroid Build Coastguard Worker     static_assert(IsPowerOfTwo(kMaxTableSizeInBytes));
367*795d594fSAndroid Build Coastguard Worker     static_assert(IsPowerOfTwo(sizeof(LrtEntry)));
368*795d594fSAndroid Build Coastguard Worker     DCHECK(IsPowerOfTwo(max_entries_));
369*795d594fSAndroid Build Coastguard Worker     if (kMaxTableSizeInBytes == max_entries_ * sizeof(LrtEntry)) {
370*795d594fSAndroid Build Coastguard Worker       std::ostringstream oss;
371*795d594fSAndroid Build Coastguard Worker       oss << "JNI ERROR (app bug): " << kLocal << " table overflow "
372*795d594fSAndroid Build Coastguard Worker           << "(max=" << max_entries_ << ")" << std::endl
373*795d594fSAndroid Build Coastguard Worker           << MutatorLockedDumpable<LocalReferenceTable>(*this)
374*795d594fSAndroid Build Coastguard Worker           << " Resizing failed: Cannot resize over the maximum permitted size.";
375*795d594fSAndroid Build Coastguard Worker       *error_msg = oss.str();
376*795d594fSAndroid Build Coastguard Worker       return nullptr;
377*795d594fSAndroid Build Coastguard Worker     }
378*795d594fSAndroid Build Coastguard Worker 
379*795d594fSAndroid Build Coastguard Worker     std::string inner_error_msg;
380*795d594fSAndroid Build Coastguard Worker     if (!Resize(max_entries_ * 2u, &inner_error_msg)) {
381*795d594fSAndroid Build Coastguard Worker       std::ostringstream oss;
382*795d594fSAndroid Build Coastguard Worker       oss << "JNI ERROR (app bug): " << kLocal << " table overflow "
383*795d594fSAndroid Build Coastguard Worker           << "(max=" << max_entries_ << ")" << std::endl
384*795d594fSAndroid Build Coastguard Worker           << MutatorLockedDumpable<LocalReferenceTable>(*this)
385*795d594fSAndroid Build Coastguard Worker           << " Resizing failed: " << inner_error_msg;
386*795d594fSAndroid Build Coastguard Worker       *error_msg = oss.str();
387*795d594fSAndroid Build Coastguard Worker       return nullptr;
388*795d594fSAndroid Build Coastguard Worker     }
389*795d594fSAndroid Build Coastguard Worker   }
390*795d594fSAndroid Build Coastguard Worker 
391*795d594fSAndroid Build Coastguard Worker   // Use the next entry.
392*795d594fSAndroid Build Coastguard Worker   if (UNLIKELY(IsCheckJniEnabled())) {
393*795d594fSAndroid Build Coastguard Worker     DCHECK_ALIGNED(top_index, kCheckJniEntriesPerReference);
394*795d594fSAndroid Build Coastguard Worker     DCHECK_ALIGNED(previous_state_.top_index, kCheckJniEntriesPerReference);
395*795d594fSAndroid Build Coastguard Worker     DCHECK_ALIGNED(max_entries_, kCheckJniEntriesPerReference);
396*795d594fSAndroid Build Coastguard Worker     LrtEntry* serial_number_entry = GetEntry(top_index);
397*795d594fSAndroid Build Coastguard Worker     uint32_t serial_number = IncrementSerialNumber(serial_number_entry);
398*795d594fSAndroid Build Coastguard Worker     LrtEntry* free_entry = serial_number_entry + serial_number;
399*795d594fSAndroid Build Coastguard Worker     DCHECK_EQ(free_entry, GetEntry(top_index + serial_number));
400*795d594fSAndroid Build Coastguard Worker     segment_state_.top_index = top_index + kCheckJniEntriesPerReference;
401*795d594fSAndroid Build Coastguard Worker     return store_obj(free_entry, "slow-path/check-jni");
402*795d594fSAndroid Build Coastguard Worker   }
403*795d594fSAndroid Build Coastguard Worker   LrtEntry* free_entry = GetEntry(top_index);
404*795d594fSAndroid Build Coastguard Worker   segment_state_.top_index = top_index + 1u;
405*795d594fSAndroid Build Coastguard Worker   return store_obj(free_entry, "slow-path");
406*795d594fSAndroid Build Coastguard Worker }
407*795d594fSAndroid Build Coastguard Worker 
408*795d594fSAndroid Build Coastguard Worker // Removes an object.
409*795d594fSAndroid Build Coastguard Worker //
410*795d594fSAndroid Build Coastguard Worker // This method is not called when a local frame is popped; this is only used
411*795d594fSAndroid Build Coastguard Worker // for explicit single removals.
412*795d594fSAndroid Build Coastguard Worker //
413*795d594fSAndroid Build Coastguard Worker // If the entry is not at the top, we just add it to the free entry list.
414*795d594fSAndroid Build Coastguard Worker // If the entry is at the top, we pop it from the top and check if there are
415*795d594fSAndroid Build Coastguard Worker // free entries under it to remove in order to reduce the size of the table.
416*795d594fSAndroid Build Coastguard Worker //
417*795d594fSAndroid Build Coastguard Worker // Returns "false" if nothing was removed.
Remove(IndirectRef iref)418*795d594fSAndroid Build Coastguard Worker bool LocalReferenceTable::Remove(IndirectRef iref) {
419*795d594fSAndroid Build Coastguard Worker   if (kDebugLRT) {
420*795d594fSAndroid Build Coastguard Worker     LOG(INFO) << "+++ Remove: previous_state=" << previous_state_.top_index
421*795d594fSAndroid Build Coastguard Worker               << " top_index=" << segment_state_.top_index;
422*795d594fSAndroid Build Coastguard Worker   }
423*795d594fSAndroid Build Coastguard Worker 
424*795d594fSAndroid Build Coastguard Worker   IndirectRefKind kind = IndirectReferenceTable::GetIndirectRefKind(iref);
425*795d594fSAndroid Build Coastguard Worker   if (UNLIKELY(kind != kLocal)) {
426*795d594fSAndroid Build Coastguard Worker     Thread* self = Thread::Current();
427*795d594fSAndroid Build Coastguard Worker     if (kind == kJniTransition) {
428*795d594fSAndroid Build Coastguard Worker       if (self->IsJniTransitionReference(reinterpret_cast<jobject>(iref))) {
429*795d594fSAndroid Build Coastguard Worker         // Transition references count as local but they cannot be deleted.
430*795d594fSAndroid Build Coastguard Worker         // TODO: They could actually be cleared on the stack, except for the `jclass`
431*795d594fSAndroid Build Coastguard Worker         // reference for static methods that points to the method's declaring class.
432*795d594fSAndroid Build Coastguard Worker         JNIEnvExt* env = self->GetJniEnv();
433*795d594fSAndroid Build Coastguard Worker         DCHECK(env != nullptr);
434*795d594fSAndroid Build Coastguard Worker         if (env->IsCheckJniEnabled()) {
435*795d594fSAndroid Build Coastguard Worker           const char* msg = kDumpStackOnNonLocalReference
436*795d594fSAndroid Build Coastguard Worker               ? "Attempt to remove non-JNI local reference, dumping thread"
437*795d594fSAndroid Build Coastguard Worker               : "Attempt to remove non-JNI local reference";
438*795d594fSAndroid Build Coastguard Worker           LOG(WARNING) << msg;
439*795d594fSAndroid Build Coastguard Worker           if (kDumpStackOnNonLocalReference) {
440*795d594fSAndroid Build Coastguard Worker             self->Dump(LOG_STREAM(WARNING));
441*795d594fSAndroid Build Coastguard Worker           }
442*795d594fSAndroid Build Coastguard Worker         }
443*795d594fSAndroid Build Coastguard Worker         return true;
444*795d594fSAndroid Build Coastguard Worker       }
445*795d594fSAndroid Build Coastguard Worker     }
446*795d594fSAndroid Build Coastguard Worker     if (kDumpStackOnNonLocalReference && IsCheckJniEnabled()) {
447*795d594fSAndroid Build Coastguard Worker       // Log the error message and stack. Repeat the message as FATAL later.
448*795d594fSAndroid Build Coastguard Worker       LOG(ERROR) << "Attempt to delete " << kind
449*795d594fSAndroid Build Coastguard Worker                  << " reference as local JNI reference, dumping stack";
450*795d594fSAndroid Build Coastguard Worker       self->Dump(LOG_STREAM(ERROR));
451*795d594fSAndroid Build Coastguard Worker     }
452*795d594fSAndroid Build Coastguard Worker     LOG(IsCheckJniEnabled() ? ERROR : FATAL)
453*795d594fSAndroid Build Coastguard Worker         << "Attempt to delete " << kind << " reference as local JNI reference";
454*795d594fSAndroid Build Coastguard Worker     return false;
455*795d594fSAndroid Build Coastguard Worker   }
456*795d594fSAndroid Build Coastguard Worker 
457*795d594fSAndroid Build Coastguard Worker   DCHECK_LE(previous_state_.top_index, segment_state_.top_index);
458*795d594fSAndroid Build Coastguard Worker   DCHECK(max_entries_ == kSmallLrtEntries ? small_table_ != nullptr : !tables_.empty());
459*795d594fSAndroid Build Coastguard Worker   DCheckValidReference(iref);
460*795d594fSAndroid Build Coastguard Worker 
461*795d594fSAndroid Build Coastguard Worker   LrtEntry* entry = ToLrtEntry(iref);
462*795d594fSAndroid Build Coastguard Worker   uint32_t entry_index = GetReferenceEntryIndex(iref);
463*795d594fSAndroid Build Coastguard Worker   uint32_t top_index = segment_state_.top_index;
464*795d594fSAndroid Build Coastguard Worker   const uint32_t bottom_index = previous_state_.top_index;
465*795d594fSAndroid Build Coastguard Worker 
466*795d594fSAndroid Build Coastguard Worker   if (entry_index < bottom_index) {
467*795d594fSAndroid Build Coastguard Worker     // Wrong segment.
468*795d594fSAndroid Build Coastguard Worker     LOG(WARNING) << "Attempt to remove index outside index area (" << entry_index
469*795d594fSAndroid Build Coastguard Worker                  << " vs " << bottom_index << "-" << top_index << ")";
470*795d594fSAndroid Build Coastguard Worker     return false;
471*795d594fSAndroid Build Coastguard Worker   }
472*795d594fSAndroid Build Coastguard Worker 
473*795d594fSAndroid Build Coastguard Worker   if (UNLIKELY(IsCheckJniEnabled())) {
474*795d594fSAndroid Build Coastguard Worker     // Ignore invalid references. CheckJNI should have aborted before passing this reference
475*795d594fSAndroid Build Coastguard Worker     // to `LocalReferenceTable::Remove()` but gtests intercept the abort and proceed anyway.
476*795d594fSAndroid Build Coastguard Worker     std::string error_msg;
477*795d594fSAndroid Build Coastguard Worker     if (!IsValidReference(iref, &error_msg)) {
478*795d594fSAndroid Build Coastguard Worker       LOG(WARNING) << "Attempt to remove invalid reference: " << error_msg;
479*795d594fSAndroid Build Coastguard Worker       return false;
480*795d594fSAndroid Build Coastguard Worker     }
481*795d594fSAndroid Build Coastguard Worker   }
482*795d594fSAndroid Build Coastguard Worker   DCHECK_LT(entry_index, top_index);
483*795d594fSAndroid Build Coastguard Worker 
484*795d594fSAndroid Build Coastguard Worker   // Workaround for double `DeleteLocalRef` bug. b/298297411
485*795d594fSAndroid Build Coastguard Worker   if (entry->IsFree()) {
486*795d594fSAndroid Build Coastguard Worker     // In debug build or with CheckJNI enabled, we would have detected this above.
487*795d594fSAndroid Build Coastguard Worker     LOG(ERROR) << "App error: `DeleteLocalRef()` on already deleted local ref. b/298297411";
488*795d594fSAndroid Build Coastguard Worker     return false;
489*795d594fSAndroid Build Coastguard Worker   }
490*795d594fSAndroid Build Coastguard Worker 
491*795d594fSAndroid Build Coastguard Worker   // Prune the free entry list if a segment with holes was popped before the `Remove()` call.
492*795d594fSAndroid Build Coastguard Worker   uint32_t first_free_index = GetFirstFreeIndex();
493*795d594fSAndroid Build Coastguard Worker   if (first_free_index != kFreeListEnd && first_free_index >= top_index) {
494*795d594fSAndroid Build Coastguard Worker     PrunePoppedFreeEntries([&](size_t index) { return GetEntry(index); });
495*795d594fSAndroid Build Coastguard Worker   }
496*795d594fSAndroid Build Coastguard Worker 
497*795d594fSAndroid Build Coastguard Worker   // Check if we're removing the top entry (created with any CheckJNI setting).
498*795d594fSAndroid Build Coastguard Worker   bool is_top_entry = false;
499*795d594fSAndroid Build Coastguard Worker   uint32_t prune_end = entry_index;
500*795d594fSAndroid Build Coastguard Worker   if (GetCheckJniSerialNumberEntry(entry)->IsSerialNumber()) {
501*795d594fSAndroid Build Coastguard Worker     LrtEntry* serial_number_entry = GetCheckJniSerialNumberEntry(entry);
502*795d594fSAndroid Build Coastguard Worker     uint32_t serial_number = dchecked_integral_cast<uint32_t>(entry - serial_number_entry);
503*795d594fSAndroid Build Coastguard Worker     DCHECK_EQ(serial_number, serial_number_entry->GetSerialNumber());
504*795d594fSAndroid Build Coastguard Worker     prune_end = entry_index - serial_number;
505*795d594fSAndroid Build Coastguard Worker     is_top_entry = (prune_end == top_index - kCheckJniEntriesPerReference);
506*795d594fSAndroid Build Coastguard Worker   } else {
507*795d594fSAndroid Build Coastguard Worker     is_top_entry = (entry_index == top_index - 1u);
508*795d594fSAndroid Build Coastguard Worker   }
509*795d594fSAndroid Build Coastguard Worker   if (is_top_entry) {
510*795d594fSAndroid Build Coastguard Worker     // Top-most entry. Scan up and consume holes created with the current CheckJNI setting.
511*795d594fSAndroid Build Coastguard Worker     constexpr uint32_t kDeadLocalValue = 0xdead10c0;
512*795d594fSAndroid Build Coastguard Worker     entry->SetReference(reinterpret_cast32<mirror::Object*>(kDeadLocalValue));
513*795d594fSAndroid Build Coastguard Worker 
514*795d594fSAndroid Build Coastguard Worker     // TODO: Maybe we should not prune free entries from the top of the segment
515*795d594fSAndroid Build Coastguard Worker     // because it has quadratic worst-case complexity. We could still prune while
516*795d594fSAndroid Build Coastguard Worker     // the first free list entry is at the top.
517*795d594fSAndroid Build Coastguard Worker     uint32_t prune_start = prune_end;
518*795d594fSAndroid Build Coastguard Worker     size_t prune_count;
519*795d594fSAndroid Build Coastguard Worker     auto find_prune_range = [&](size_t chunk_size, auto is_prev_entry_free) {
520*795d594fSAndroid Build Coastguard Worker       while (prune_start > bottom_index && is_prev_entry_free(prune_start)) {
521*795d594fSAndroid Build Coastguard Worker         prune_start -= chunk_size;
522*795d594fSAndroid Build Coastguard Worker       }
523*795d594fSAndroid Build Coastguard Worker       prune_count = (prune_end - prune_start) / chunk_size;
524*795d594fSAndroid Build Coastguard Worker     };
525*795d594fSAndroid Build Coastguard Worker 
526*795d594fSAndroid Build Coastguard Worker     if (UNLIKELY(IsCheckJniEnabled())) {
527*795d594fSAndroid Build Coastguard Worker       auto is_prev_entry_free = [&](size_t index) {
528*795d594fSAndroid Build Coastguard Worker         DCHECK_ALIGNED(index, kCheckJniEntriesPerReference);
529*795d594fSAndroid Build Coastguard Worker         LrtEntry* serial_number_entry = GetEntry(index - kCheckJniEntriesPerReference);
530*795d594fSAndroid Build Coastguard Worker         DCHECK_ALIGNED(serial_number_entry, kCheckJniEntriesPerReference * sizeof(LrtEntry));
531*795d594fSAndroid Build Coastguard Worker         if (!serial_number_entry->IsSerialNumber()) {
532*795d594fSAndroid Build Coastguard Worker           return false;
533*795d594fSAndroid Build Coastguard Worker         }
534*795d594fSAndroid Build Coastguard Worker         uint32_t serial_number = serial_number_entry->GetSerialNumber();
535*795d594fSAndroid Build Coastguard Worker         DCHECK(IsValidSerialNumber(serial_number));
536*795d594fSAndroid Build Coastguard Worker         LrtEntry* entry = serial_number_entry + serial_number;
537*795d594fSAndroid Build Coastguard Worker         DCHECK_EQ(entry, GetEntry(prune_start - kCheckJniEntriesPerReference + serial_number));
538*795d594fSAndroid Build Coastguard Worker         return entry->IsFree();
539*795d594fSAndroid Build Coastguard Worker       };
540*795d594fSAndroid Build Coastguard Worker       find_prune_range(kCheckJniEntriesPerReference, is_prev_entry_free);
541*795d594fSAndroid Build Coastguard Worker     } else {
542*795d594fSAndroid Build Coastguard Worker       auto is_prev_entry_free = [&](size_t index) {
543*795d594fSAndroid Build Coastguard Worker         LrtEntry* entry = GetEntry(index - 1u);
544*795d594fSAndroid Build Coastguard Worker         return entry->IsFree() && !GetCheckJniSerialNumberEntry(entry)->IsSerialNumber();
545*795d594fSAndroid Build Coastguard Worker       };
546*795d594fSAndroid Build Coastguard Worker       find_prune_range(1u, is_prev_entry_free);
547*795d594fSAndroid Build Coastguard Worker     }
548*795d594fSAndroid Build Coastguard Worker 
549*795d594fSAndroid Build Coastguard Worker     if (prune_count != 0u) {
550*795d594fSAndroid Build Coastguard Worker       // Remove pruned entries from the free list.
551*795d594fSAndroid Build Coastguard Worker       size_t remaining = prune_count;
552*795d594fSAndroid Build Coastguard Worker       uint32_t free_index = GetFirstFreeIndex();
553*795d594fSAndroid Build Coastguard Worker       while (remaining != 0u && free_index >= prune_start) {
554*795d594fSAndroid Build Coastguard Worker         DCHECK_NE(free_index, kFreeListEnd);
555*795d594fSAndroid Build Coastguard Worker         LrtEntry* pruned_entry = GetEntry(free_index);
556*795d594fSAndroid Build Coastguard Worker         free_index = pruned_entry->GetNextFree();
557*795d594fSAndroid Build Coastguard Worker         pruned_entry->SetReference(reinterpret_cast32<mirror::Object*>(kDeadLocalValue));
558*795d594fSAndroid Build Coastguard Worker         --remaining;
559*795d594fSAndroid Build Coastguard Worker       }
560*795d594fSAndroid Build Coastguard Worker       free_entries_list_ = FirstFreeField::Update(free_index, free_entries_list_);
561*795d594fSAndroid Build Coastguard Worker       while (remaining != 0u) {
562*795d594fSAndroid Build Coastguard Worker         DCHECK_NE(free_index, kFreeListEnd);
563*795d594fSAndroid Build Coastguard Worker         DCHECK_LT(free_index, prune_start);
564*795d594fSAndroid Build Coastguard Worker         DCHECK_GE(free_index, bottom_index);
565*795d594fSAndroid Build Coastguard Worker         LrtEntry* free_entry = GetEntry(free_index);
566*795d594fSAndroid Build Coastguard Worker         while (free_entry->GetNextFree() < prune_start) {
567*795d594fSAndroid Build Coastguard Worker           free_index = free_entry->GetNextFree();
568*795d594fSAndroid Build Coastguard Worker           DCHECK_GE(free_index, bottom_index);
569*795d594fSAndroid Build Coastguard Worker           free_entry = GetEntry(free_index);
570*795d594fSAndroid Build Coastguard Worker         }
571*795d594fSAndroid Build Coastguard Worker         LrtEntry* pruned_entry = GetEntry(free_entry->GetNextFree());
572*795d594fSAndroid Build Coastguard Worker         free_entry->SetNextFree(pruned_entry->GetNextFree());
573*795d594fSAndroid Build Coastguard Worker         pruned_entry->SetReference(reinterpret_cast32<mirror::Object*>(kDeadLocalValue));
574*795d594fSAndroid Build Coastguard Worker         --remaining;
575*795d594fSAndroid Build Coastguard Worker       }
576*795d594fSAndroid Build Coastguard Worker       DCHECK(free_index == kFreeListEnd || free_index < prune_start)
577*795d594fSAndroid Build Coastguard Worker           << "free_index=" << free_index << ", prune_start=" << prune_start;
578*795d594fSAndroid Build Coastguard Worker     }
579*795d594fSAndroid Build Coastguard Worker     segment_state_.top_index = prune_start;
580*795d594fSAndroid Build Coastguard Worker     if (kDebugLRT) {
581*795d594fSAndroid Build Coastguard Worker       LOG(INFO) << "+++ removed last entry, pruned " << prune_count
582*795d594fSAndroid Build Coastguard Worker                 << ", new top= " << segment_state_.top_index;
583*795d594fSAndroid Build Coastguard Worker     }
584*795d594fSAndroid Build Coastguard Worker   } else {
585*795d594fSAndroid Build Coastguard Worker     // Not the top-most entry. This creates a hole.
586*795d594fSAndroid Build Coastguard Worker     entry->SetNextFree(GetFirstFreeIndex());
587*795d594fSAndroid Build Coastguard Worker     free_entries_list_ = FirstFreeField::Update(entry_index, free_entries_list_);
588*795d594fSAndroid Build Coastguard Worker     if (kDebugLRT) {
589*795d594fSAndroid Build Coastguard Worker       LOG(INFO) << "+++ removed entry and left hole at " << entry_index;
590*795d594fSAndroid Build Coastguard Worker     }
591*795d594fSAndroid Build Coastguard Worker   }
592*795d594fSAndroid Build Coastguard Worker 
593*795d594fSAndroid Build Coastguard Worker   return true;
594*795d594fSAndroid Build Coastguard Worker }
595*795d594fSAndroid Build Coastguard Worker 
AssertEmpty()596*795d594fSAndroid Build Coastguard Worker void LocalReferenceTable::AssertEmpty() {
597*795d594fSAndroid Build Coastguard Worker   CHECK_EQ(Capacity(), 0u) << "Internal Error: non-empty local reference table.";
598*795d594fSAndroid Build Coastguard Worker }
599*795d594fSAndroid Build Coastguard Worker 
Trim()600*795d594fSAndroid Build Coastguard Worker void LocalReferenceTable::Trim() {
601*795d594fSAndroid Build Coastguard Worker   ScopedTrace trace(__PRETTY_FUNCTION__);
602*795d594fSAndroid Build Coastguard Worker   const size_t num_mem_maps = table_mem_maps_.size();
603*795d594fSAndroid Build Coastguard Worker   if (num_mem_maps == 0u) {
604*795d594fSAndroid Build Coastguard Worker     // Only small tables; nothing to do here. (Do not unnecessarily prune popped free entries.)
605*795d594fSAndroid Build Coastguard Worker     return;
606*795d594fSAndroid Build Coastguard Worker   }
607*795d594fSAndroid Build Coastguard Worker   DCHECK_EQ(tables_.size(), num_mem_maps + MaxSmallTables());
608*795d594fSAndroid Build Coastguard Worker   const size_t top_index = segment_state_.top_index;
609*795d594fSAndroid Build Coastguard Worker   // Prune popped free entries before potentially losing their memory.
610*795d594fSAndroid Build Coastguard Worker   if (UNLIKELY(GetFirstFreeIndex() != kFreeListEnd) &&
611*795d594fSAndroid Build Coastguard Worker       UNLIKELY(GetFirstFreeIndex() >= segment_state_.top_index)) {
612*795d594fSAndroid Build Coastguard Worker     PrunePoppedFreeEntries([&](size_t index) { return GetEntry(index); });
613*795d594fSAndroid Build Coastguard Worker   }
614*795d594fSAndroid Build Coastguard Worker   // Small tables can hold as many entries as the next table.
615*795d594fSAndroid Build Coastguard Worker   const size_t small_tables_capacity = GetTableSize(MaxSmallTables());
616*795d594fSAndroid Build Coastguard Worker   size_t mem_map_index = 0u;
617*795d594fSAndroid Build Coastguard Worker   if (top_index > small_tables_capacity) {
618*795d594fSAndroid Build Coastguard Worker     const size_t table_size = TruncToPowerOfTwo(top_index);
619*795d594fSAndroid Build Coastguard Worker     const size_t table_index = NumTablesForSize(table_size);
620*795d594fSAndroid Build Coastguard Worker     const size_t start_index = top_index - table_size;
621*795d594fSAndroid Build Coastguard Worker     mem_map_index = table_index - MaxSmallTables();
622*795d594fSAndroid Build Coastguard Worker     if (start_index != 0u) {
623*795d594fSAndroid Build Coastguard Worker       ++mem_map_index;
624*795d594fSAndroid Build Coastguard Worker       LrtEntry* table = tables_[table_index];
625*795d594fSAndroid Build Coastguard Worker       uint8_t* release_start = AlignUp(reinterpret_cast<uint8_t*>(&table[start_index]), gPageSize);
626*795d594fSAndroid Build Coastguard Worker       uint8_t* release_end = reinterpret_cast<uint8_t*>(&table[table_size]);
627*795d594fSAndroid Build Coastguard Worker       DCHECK_GE(reinterpret_cast<uintptr_t>(release_end),
628*795d594fSAndroid Build Coastguard Worker                 reinterpret_cast<uintptr_t>(release_start));
629*795d594fSAndroid Build Coastguard Worker       DCHECK_ALIGNED_PARAM(release_end, gPageSize);
630*795d594fSAndroid Build Coastguard Worker       DCHECK_ALIGNED_PARAM(release_end - release_start, gPageSize);
631*795d594fSAndroid Build Coastguard Worker       if (release_start != release_end) {
632*795d594fSAndroid Build Coastguard Worker         madvise(release_start, release_end - release_start, MADV_DONTNEED);
633*795d594fSAndroid Build Coastguard Worker       }
634*795d594fSAndroid Build Coastguard Worker     }
635*795d594fSAndroid Build Coastguard Worker   }
636*795d594fSAndroid Build Coastguard Worker   for (MemMap& mem_map : ArrayRef<MemMap>(table_mem_maps_).SubArray(mem_map_index)) {
637*795d594fSAndroid Build Coastguard Worker     madvise(mem_map.Begin(), mem_map.Size(), MADV_DONTNEED);
638*795d594fSAndroid Build Coastguard Worker   }
639*795d594fSAndroid Build Coastguard Worker }
640*795d594fSAndroid Build Coastguard Worker 
641*795d594fSAndroid Build Coastguard Worker template <typename Visitor>
VisitRootsInternal(Visitor && visitor) const642*795d594fSAndroid Build Coastguard Worker void LocalReferenceTable::VisitRootsInternal(Visitor&& visitor) const {
643*795d594fSAndroid Build Coastguard Worker   auto visit_table = [&](LrtEntry* table, size_t count) REQUIRES_SHARED(Locks::mutator_lock_) {
644*795d594fSAndroid Build Coastguard Worker     for (size_t i = 0; i != count; ) {
645*795d594fSAndroid Build Coastguard Worker       LrtEntry* entry;
646*795d594fSAndroid Build Coastguard Worker       if (i % kCheckJniEntriesPerReference == 0u && table[i].IsSerialNumber()) {
647*795d594fSAndroid Build Coastguard Worker         entry = &table[i + table[i].GetSerialNumber()];
648*795d594fSAndroid Build Coastguard Worker         i += kCheckJniEntriesPerReference;
649*795d594fSAndroid Build Coastguard Worker         DCHECK_LE(i, count);
650*795d594fSAndroid Build Coastguard Worker       } else {
651*795d594fSAndroid Build Coastguard Worker         entry = &table[i];
652*795d594fSAndroid Build Coastguard Worker         i += 1u;
653*795d594fSAndroid Build Coastguard Worker       }
654*795d594fSAndroid Build Coastguard Worker       DCHECK(!entry->IsSerialNumber());
655*795d594fSAndroid Build Coastguard Worker       if (!entry->IsFree()) {
656*795d594fSAndroid Build Coastguard Worker         GcRoot<mirror::Object>* root = entry->GetRootAddress();
657*795d594fSAndroid Build Coastguard Worker         DCHECK(!root->IsNull());
658*795d594fSAndroid Build Coastguard Worker         visitor(root);
659*795d594fSAndroid Build Coastguard Worker       }
660*795d594fSAndroid Build Coastguard Worker     }
661*795d594fSAndroid Build Coastguard Worker   };
662*795d594fSAndroid Build Coastguard Worker 
663*795d594fSAndroid Build Coastguard Worker   if (small_table_ != nullptr) {
664*795d594fSAndroid Build Coastguard Worker     visit_table(small_table_, segment_state_.top_index);
665*795d594fSAndroid Build Coastguard Worker   } else {
666*795d594fSAndroid Build Coastguard Worker     uint32_t remaining = segment_state_.top_index;
667*795d594fSAndroid Build Coastguard Worker     size_t table_index = 0u;
668*795d594fSAndroid Build Coastguard Worker     while (remaining != 0u) {
669*795d594fSAndroid Build Coastguard Worker       size_t count = std::min<size_t>(remaining, GetTableSize(table_index));
670*795d594fSAndroid Build Coastguard Worker       visit_table(tables_[table_index], count);
671*795d594fSAndroid Build Coastguard Worker       ++table_index;
672*795d594fSAndroid Build Coastguard Worker       remaining -= count;
673*795d594fSAndroid Build Coastguard Worker     }
674*795d594fSAndroid Build Coastguard Worker   }
675*795d594fSAndroid Build Coastguard Worker }
676*795d594fSAndroid Build Coastguard Worker 
VisitRoots(RootVisitor * visitor,const RootInfo & root_info)677*795d594fSAndroid Build Coastguard Worker void LocalReferenceTable::VisitRoots(RootVisitor* visitor, const RootInfo& root_info) {
678*795d594fSAndroid Build Coastguard Worker   BufferedRootVisitor<kDefaultBufferedRootCount> root_visitor(visitor, root_info);
679*795d594fSAndroid Build Coastguard Worker   VisitRootsInternal([&](GcRoot<mirror::Object>* root) REQUIRES_SHARED(Locks::mutator_lock_) {
680*795d594fSAndroid Build Coastguard Worker                        root_visitor.VisitRoot(*root);
681*795d594fSAndroid Build Coastguard Worker                      });
682*795d594fSAndroid Build Coastguard Worker }
683*795d594fSAndroid Build Coastguard Worker 
Dump(std::ostream & os) const684*795d594fSAndroid Build Coastguard Worker void LocalReferenceTable::Dump(std::ostream& os) const {
685*795d594fSAndroid Build Coastguard Worker   os << kLocal << " table dump:\n";
686*795d594fSAndroid Build Coastguard Worker   ReferenceTable::Table entries;
687*795d594fSAndroid Build Coastguard Worker   VisitRootsInternal([&](GcRoot<mirror::Object>* root) REQUIRES_SHARED(Locks::mutator_lock_) {
688*795d594fSAndroid Build Coastguard Worker                        entries.push_back(*root);
689*795d594fSAndroid Build Coastguard Worker                      });
690*795d594fSAndroid Build Coastguard Worker   ReferenceTable::Dump(os, entries);
691*795d594fSAndroid Build Coastguard Worker }
692*795d594fSAndroid Build Coastguard Worker 
EnsureFreeCapacity(size_t free_capacity,std::string * error_msg)693*795d594fSAndroid Build Coastguard Worker bool LocalReferenceTable::EnsureFreeCapacity(size_t free_capacity, std::string* error_msg) {
694*795d594fSAndroid Build Coastguard Worker   // TODO: Pass `previous_state` so that we can check holes.
695*795d594fSAndroid Build Coastguard Worker   DCHECK_GE(free_capacity, static_cast<size_t>(1));
696*795d594fSAndroid Build Coastguard Worker   size_t top_index = segment_state_.top_index;
697*795d594fSAndroid Build Coastguard Worker   DCHECK_LE(top_index, max_entries_);
698*795d594fSAndroid Build Coastguard Worker 
699*795d594fSAndroid Build Coastguard Worker   if (IsCheckJniEnabled()) {
700*795d594fSAndroid Build Coastguard Worker     // High values lead to the maximum size check failing below.
701*795d594fSAndroid Build Coastguard Worker     if (free_capacity >= std::numeric_limits<size_t>::max() / kCheckJniEntriesPerReference) {
702*795d594fSAndroid Build Coastguard Worker       free_capacity = std::numeric_limits<size_t>::max();
703*795d594fSAndroid Build Coastguard Worker     } else {
704*795d594fSAndroid Build Coastguard Worker       free_capacity *= kCheckJniEntriesPerReference;
705*795d594fSAndroid Build Coastguard Worker     }
706*795d594fSAndroid Build Coastguard Worker   }
707*795d594fSAndroid Build Coastguard Worker 
708*795d594fSAndroid Build Coastguard Worker   // TODO: Include holes from the current segment in the calculation.
709*795d594fSAndroid Build Coastguard Worker   if (free_capacity <= max_entries_ - top_index) {
710*795d594fSAndroid Build Coastguard Worker     return true;
711*795d594fSAndroid Build Coastguard Worker   }
712*795d594fSAndroid Build Coastguard Worker 
713*795d594fSAndroid Build Coastguard Worker   if (free_capacity > kMaxTableSize - top_index) {
714*795d594fSAndroid Build Coastguard Worker     *error_msg = android::base::StringPrintf(
715*795d594fSAndroid Build Coastguard Worker         "Requested size exceeds maximum: %zu > %zu (%zu used)",
716*795d594fSAndroid Build Coastguard Worker         free_capacity,
717*795d594fSAndroid Build Coastguard Worker         kMaxTableSize - top_index,
718*795d594fSAndroid Build Coastguard Worker         top_index);
719*795d594fSAndroid Build Coastguard Worker     return false;
720*795d594fSAndroid Build Coastguard Worker   }
721*795d594fSAndroid Build Coastguard Worker 
722*795d594fSAndroid Build Coastguard Worker   // Try to increase the table size.
723*795d594fSAndroid Build Coastguard Worker   if (!Resize(top_index + free_capacity, error_msg)) {
724*795d594fSAndroid Build Coastguard Worker     LOG(WARNING) << "JNI ERROR: Unable to reserve space in EnsureFreeCapacity (" << free_capacity
725*795d594fSAndroid Build Coastguard Worker                  << "): " << std::endl
726*795d594fSAndroid Build Coastguard Worker                  << MutatorLockedDumpable<LocalReferenceTable>(*this)
727*795d594fSAndroid Build Coastguard Worker                  << " Resizing failed: " << *error_msg;
728*795d594fSAndroid Build Coastguard Worker     return false;
729*795d594fSAndroid Build Coastguard Worker   }
730*795d594fSAndroid Build Coastguard Worker   return true;
731*795d594fSAndroid Build Coastguard Worker }
732*795d594fSAndroid Build Coastguard Worker 
FreeCapacity() const733*795d594fSAndroid Build Coastguard Worker size_t LocalReferenceTable::FreeCapacity() const {
734*795d594fSAndroid Build Coastguard Worker   // TODO: Include holes in current segment.
735*795d594fSAndroid Build Coastguard Worker   if (IsCheckJniEnabled()) {
736*795d594fSAndroid Build Coastguard Worker     DCHECK_ALIGNED(max_entries_, kCheckJniEntriesPerReference);
737*795d594fSAndroid Build Coastguard Worker     // The `segment_state_.top_index` is not necessarily aligned; rounding down.
738*795d594fSAndroid Build Coastguard Worker     return (max_entries_ - segment_state_.top_index) / kCheckJniEntriesPerReference;
739*795d594fSAndroid Build Coastguard Worker   } else {
740*795d594fSAndroid Build Coastguard Worker     return max_entries_ - segment_state_.top_index;
741*795d594fSAndroid Build Coastguard Worker   }
742*795d594fSAndroid Build Coastguard Worker }
743*795d594fSAndroid Build Coastguard Worker 
744*795d594fSAndroid Build Coastguard Worker }  // namespace jni
745*795d594fSAndroid Build Coastguard Worker }  // namespace art
746