xref: /aosp_15_r20/art/runtime/indirect_reference_table.cc (revision 795d594fd825385562da6b089ea9b2033f3abf5a)
1*795d594fSAndroid Build Coastguard Worker /*
2*795d594fSAndroid Build Coastguard Worker  * Copyright (C) 2009 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 "indirect_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/globals.h"
21*795d594fSAndroid Build Coastguard Worker #include "base/mutator_locked_dumpable.h"
22*795d594fSAndroid Build Coastguard Worker #include "base/systrace.h"
23*795d594fSAndroid Build Coastguard Worker #include "base/utils.h"
24*795d594fSAndroid Build Coastguard Worker #include "indirect_reference_table.h"
25*795d594fSAndroid Build Coastguard Worker #include "jni/java_vm_ext.h"
26*795d594fSAndroid Build Coastguard Worker #include "jni/jni_internal.h"
27*795d594fSAndroid Build Coastguard Worker #include "mirror/object-inl.h"
28*795d594fSAndroid Build Coastguard Worker #include "nth_caller_visitor.h"
29*795d594fSAndroid Build Coastguard Worker #include "object_callbacks.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 
39*795d594fSAndroid Build Coastguard Worker static constexpr bool kDebugIRT = false;
40*795d594fSAndroid Build Coastguard Worker 
41*795d594fSAndroid Build Coastguard Worker // Maximum table size we allow.
42*795d594fSAndroid Build Coastguard Worker static constexpr size_t kMaxTableSizeInBytes = 128 * MB;
43*795d594fSAndroid Build Coastguard Worker 
GetIndirectRefKindString(IndirectRefKind kind)44*795d594fSAndroid Build Coastguard Worker const char* GetIndirectRefKindString(IndirectRefKind kind) {
45*795d594fSAndroid Build Coastguard Worker   switch (kind) {
46*795d594fSAndroid Build Coastguard Worker     case kJniTransition:
47*795d594fSAndroid Build Coastguard Worker       return "JniTransition";
48*795d594fSAndroid Build Coastguard Worker     case kLocal:
49*795d594fSAndroid Build Coastguard Worker       return "Local";
50*795d594fSAndroid Build Coastguard Worker     case kGlobal:
51*795d594fSAndroid Build Coastguard Worker       return "Global";
52*795d594fSAndroid Build Coastguard Worker     case kWeakGlobal:
53*795d594fSAndroid Build Coastguard Worker       return "WeakGlobal";
54*795d594fSAndroid Build Coastguard Worker   }
55*795d594fSAndroid Build Coastguard Worker   return "IndirectRefKind Error";
56*795d594fSAndroid Build Coastguard Worker }
57*795d594fSAndroid Build Coastguard Worker 
AbortIfNoCheckJNI(const std::string & msg)58*795d594fSAndroid Build Coastguard Worker void IndirectReferenceTable::AbortIfNoCheckJNI(const std::string& msg) {
59*795d594fSAndroid Build Coastguard Worker   // If -Xcheck:jni is on, it'll give a more detailed error before aborting.
60*795d594fSAndroid Build Coastguard Worker   JavaVMExt* vm = Runtime::Current()->GetJavaVM();
61*795d594fSAndroid Build Coastguard Worker   if (!vm->IsCheckJniEnabled()) {
62*795d594fSAndroid Build Coastguard Worker     // Otherwise, we want to abort rather than hand back a bad reference.
63*795d594fSAndroid Build Coastguard Worker     LOG(FATAL) << msg;
64*795d594fSAndroid Build Coastguard Worker   } else {
65*795d594fSAndroid Build Coastguard Worker     LOG(ERROR) << msg;
66*795d594fSAndroid Build Coastguard Worker   }
67*795d594fSAndroid Build Coastguard Worker }
68*795d594fSAndroid Build Coastguard Worker 
69*795d594fSAndroid Build Coastguard Worker // Mmap an "indirect ref table region. Table_bytes is a multiple of a page size.
NewIRTMap(size_t table_bytes,std::string * error_msg)70*795d594fSAndroid Build Coastguard Worker static inline MemMap NewIRTMap(size_t table_bytes, std::string* error_msg) {
71*795d594fSAndroid Build Coastguard Worker   MemMap result = MemMap::MapAnonymous("indirect ref table",
72*795d594fSAndroid Build Coastguard Worker                                        table_bytes,
73*795d594fSAndroid Build Coastguard Worker                                        PROT_READ | PROT_WRITE,
74*795d594fSAndroid Build Coastguard Worker                                        /*low_4gb=*/ false,
75*795d594fSAndroid Build Coastguard Worker                                        error_msg);
76*795d594fSAndroid Build Coastguard Worker   if (!result.IsValid() && error_msg->empty()) {
77*795d594fSAndroid Build Coastguard Worker       *error_msg = "Unable to map memory for indirect ref table";
78*795d594fSAndroid Build Coastguard Worker   }
79*795d594fSAndroid Build Coastguard Worker   return result;
80*795d594fSAndroid Build Coastguard Worker }
81*795d594fSAndroid Build Coastguard Worker 
IndirectReferenceTable(IndirectRefKind kind)82*795d594fSAndroid Build Coastguard Worker IndirectReferenceTable::IndirectReferenceTable(IndirectRefKind kind)
83*795d594fSAndroid Build Coastguard Worker     : table_mem_map_(),
84*795d594fSAndroid Build Coastguard Worker       table_(nullptr),
85*795d594fSAndroid Build Coastguard Worker       kind_(kind),
86*795d594fSAndroid Build Coastguard Worker       top_index_(0u),
87*795d594fSAndroid Build Coastguard Worker       max_entries_(0u),
88*795d594fSAndroid Build Coastguard Worker       current_num_holes_(0) {
89*795d594fSAndroid Build Coastguard Worker   CHECK_NE(kind, kJniTransition);
90*795d594fSAndroid Build Coastguard Worker   CHECK_NE(kind, kLocal);
91*795d594fSAndroid Build Coastguard Worker }
92*795d594fSAndroid Build Coastguard Worker 
Initialize(size_t max_count,std::string * error_msg)93*795d594fSAndroid Build Coastguard Worker bool IndirectReferenceTable::Initialize(size_t max_count, std::string* error_msg) {
94*795d594fSAndroid Build Coastguard Worker   CHECK(error_msg != nullptr);
95*795d594fSAndroid Build Coastguard Worker 
96*795d594fSAndroid Build Coastguard Worker   // Overflow and maximum check.
97*795d594fSAndroid Build Coastguard Worker   CHECK_LE(max_count, kMaxTableSizeInBytes / sizeof(IrtEntry));
98*795d594fSAndroid Build Coastguard Worker 
99*795d594fSAndroid Build Coastguard Worker   const size_t table_bytes = RoundUp(max_count * sizeof(IrtEntry), gPageSize);
100*795d594fSAndroid Build Coastguard Worker   table_mem_map_ = NewIRTMap(table_bytes, error_msg);
101*795d594fSAndroid Build Coastguard Worker   if (!table_mem_map_.IsValid()) {
102*795d594fSAndroid Build Coastguard Worker     DCHECK(!error_msg->empty());
103*795d594fSAndroid Build Coastguard Worker     return false;
104*795d594fSAndroid Build Coastguard Worker   }
105*795d594fSAndroid Build Coastguard Worker 
106*795d594fSAndroid Build Coastguard Worker   table_ = reinterpret_cast<IrtEntry*>(table_mem_map_.Begin());
107*795d594fSAndroid Build Coastguard Worker   // Take into account the actual length.
108*795d594fSAndroid Build Coastguard Worker   max_entries_ = table_bytes / sizeof(IrtEntry);
109*795d594fSAndroid Build Coastguard Worker   return true;
110*795d594fSAndroid Build Coastguard Worker }
111*795d594fSAndroid Build Coastguard Worker 
~IndirectReferenceTable()112*795d594fSAndroid Build Coastguard Worker IndirectReferenceTable::~IndirectReferenceTable() {
113*795d594fSAndroid Build Coastguard Worker }
114*795d594fSAndroid Build Coastguard Worker 
ConstexprChecks()115*795d594fSAndroid Build Coastguard Worker void IndirectReferenceTable::ConstexprChecks() {
116*795d594fSAndroid Build Coastguard Worker   // Use this for some assertions. They can't be put into the header as C++ wants the class
117*795d594fSAndroid Build Coastguard Worker   // to be complete.
118*795d594fSAndroid Build Coastguard Worker 
119*795d594fSAndroid Build Coastguard Worker   // Check kind.
120*795d594fSAndroid Build Coastguard Worker   static_assert((EncodeIndirectRefKind(kLocal) & (~kKindMask)) == 0, "Kind encoding error");
121*795d594fSAndroid Build Coastguard Worker   static_assert((EncodeIndirectRefKind(kGlobal) & (~kKindMask)) == 0, "Kind encoding error");
122*795d594fSAndroid Build Coastguard Worker   static_assert((EncodeIndirectRefKind(kWeakGlobal) & (~kKindMask)) == 0, "Kind encoding error");
123*795d594fSAndroid Build Coastguard Worker   static_assert(DecodeIndirectRefKind(EncodeIndirectRefKind(kLocal)) == kLocal,
124*795d594fSAndroid Build Coastguard Worker                 "Kind encoding error");
125*795d594fSAndroid Build Coastguard Worker   static_assert(DecodeIndirectRefKind(EncodeIndirectRefKind(kGlobal)) == kGlobal,
126*795d594fSAndroid Build Coastguard Worker                 "Kind encoding error");
127*795d594fSAndroid Build Coastguard Worker   static_assert(DecodeIndirectRefKind(EncodeIndirectRefKind(kWeakGlobal)) == kWeakGlobal,
128*795d594fSAndroid Build Coastguard Worker                 "Kind encoding error");
129*795d594fSAndroid Build Coastguard Worker 
130*795d594fSAndroid Build Coastguard Worker   // Check serial.
131*795d594fSAndroid Build Coastguard Worker   static_assert(DecodeSerial(EncodeSerial(0u)) == 0u, "Serial encoding error");
132*795d594fSAndroid Build Coastguard Worker   static_assert(DecodeSerial(EncodeSerial(1u)) == 1u, "Serial encoding error");
133*795d594fSAndroid Build Coastguard Worker   static_assert(DecodeSerial(EncodeSerial(2u)) == 2u, "Serial encoding error");
134*795d594fSAndroid Build Coastguard Worker   static_assert(DecodeSerial(EncodeSerial(3u)) == 3u, "Serial encoding error");
135*795d594fSAndroid Build Coastguard Worker 
136*795d594fSAndroid Build Coastguard Worker   // Table index.
137*795d594fSAndroid Build Coastguard Worker   static_assert(DecodeIndex(EncodeIndex(0u)) == 0u, "Index encoding error");
138*795d594fSAndroid Build Coastguard Worker   static_assert(DecodeIndex(EncodeIndex(1u)) == 1u, "Index encoding error");
139*795d594fSAndroid Build Coastguard Worker   static_assert(DecodeIndex(EncodeIndex(2u)) == 2u, "Index encoding error");
140*795d594fSAndroid Build Coastguard Worker   static_assert(DecodeIndex(EncodeIndex(3u)) == 3u, "Index encoding error");
141*795d594fSAndroid Build Coastguard Worker 
142*795d594fSAndroid Build Coastguard Worker   // Distinguishing between local and (weak) global references.
143*795d594fSAndroid Build Coastguard Worker   static_assert((GetGlobalOrWeakGlobalMask() & EncodeIndirectRefKind(kJniTransition)) == 0u);
144*795d594fSAndroid Build Coastguard Worker   static_assert((GetGlobalOrWeakGlobalMask() & EncodeIndirectRefKind(kLocal)) == 0u);
145*795d594fSAndroid Build Coastguard Worker   static_assert((GetGlobalOrWeakGlobalMask() & EncodeIndirectRefKind(kGlobal)) != 0u);
146*795d594fSAndroid Build Coastguard Worker   static_assert((GetGlobalOrWeakGlobalMask() & EncodeIndirectRefKind(kWeakGlobal)) != 0u);
147*795d594fSAndroid Build Coastguard Worker }
148*795d594fSAndroid Build Coastguard Worker 
149*795d594fSAndroid Build Coastguard Worker // Holes:
150*795d594fSAndroid Build Coastguard Worker //
151*795d594fSAndroid Build Coastguard Worker // To keep the IRT compact, we want to fill "holes" created by non-stack-discipline Add & Remove
152*795d594fSAndroid Build Coastguard Worker // operation sequences. For simplicity and lower memory overhead, we do not use a free list or
153*795d594fSAndroid Build Coastguard Worker // similar. Instead, we scan for holes, with the expectation that we will find holes fast as they
154*795d594fSAndroid Build Coastguard Worker // are usually near the end of the table (see the header, TODO: verify this assumption). To avoid
155*795d594fSAndroid Build Coastguard Worker // scans when there are no holes, the number of known holes should be tracked.
156*795d594fSAndroid Build Coastguard Worker 
CountNullEntries(const IrtEntry * table,size_t to)157*795d594fSAndroid Build Coastguard Worker static size_t CountNullEntries(const IrtEntry* table, size_t to) {
158*795d594fSAndroid Build Coastguard Worker   size_t count = 0;
159*795d594fSAndroid Build Coastguard Worker   for (size_t index = 0u; index != to; ++index) {
160*795d594fSAndroid Build Coastguard Worker     if (table[index].GetReference()->IsNull()) {
161*795d594fSAndroid Build Coastguard Worker       count++;
162*795d594fSAndroid Build Coastguard Worker     }
163*795d594fSAndroid Build Coastguard Worker   }
164*795d594fSAndroid Build Coastguard Worker   return count;
165*795d594fSAndroid Build Coastguard Worker }
166*795d594fSAndroid Build Coastguard Worker 
167*795d594fSAndroid Build Coastguard Worker ALWAYS_INLINE
CheckHoleCount(IrtEntry * table,size_t exp_num_holes,size_t top_index)168*795d594fSAndroid Build Coastguard Worker static inline void CheckHoleCount(IrtEntry* table,
169*795d594fSAndroid Build Coastguard Worker                                   size_t exp_num_holes,
170*795d594fSAndroid Build Coastguard Worker                                   size_t top_index) {
171*795d594fSAndroid Build Coastguard Worker   if (kIsDebugBuild) {
172*795d594fSAndroid Build Coastguard Worker     size_t count = CountNullEntries(table, top_index);
173*795d594fSAndroid Build Coastguard Worker     CHECK_EQ(exp_num_holes, count) << " topIndex=" << top_index;
174*795d594fSAndroid Build Coastguard Worker   }
175*795d594fSAndroid Build Coastguard Worker }
176*795d594fSAndroid Build Coastguard Worker 
Add(ObjPtr<mirror::Object> obj,std::string * error_msg)177*795d594fSAndroid Build Coastguard Worker IndirectRef IndirectReferenceTable::Add(ObjPtr<mirror::Object> obj, std::string* error_msg) {
178*795d594fSAndroid Build Coastguard Worker   if (kDebugIRT) {
179*795d594fSAndroid Build Coastguard Worker     LOG(INFO) << "+++ Add: top_index=" << top_index_
180*795d594fSAndroid Build Coastguard Worker               << " holes=" << current_num_holes_;
181*795d594fSAndroid Build Coastguard Worker   }
182*795d594fSAndroid Build Coastguard Worker 
183*795d594fSAndroid Build Coastguard Worker   CHECK(obj != nullptr);
184*795d594fSAndroid Build Coastguard Worker   VerifyObject(obj);
185*795d594fSAndroid Build Coastguard Worker   DCHECK(table_ != nullptr);
186*795d594fSAndroid Build Coastguard Worker 
187*795d594fSAndroid Build Coastguard Worker   if (top_index_ == max_entries_) {
188*795d594fSAndroid Build Coastguard Worker     // TODO: Fill holes before reporting error.
189*795d594fSAndroid Build Coastguard Worker     std::ostringstream oss;
190*795d594fSAndroid Build Coastguard Worker     oss << "JNI ERROR (app bug): " << kind_ << " table overflow "
191*795d594fSAndroid Build Coastguard Worker         << "(max=" << max_entries_ << ")"
192*795d594fSAndroid Build Coastguard Worker         << MutatorLockedDumpable<IndirectReferenceTable>(*this);
193*795d594fSAndroid Build Coastguard Worker     *error_msg = oss.str();
194*795d594fSAndroid Build Coastguard Worker     return nullptr;
195*795d594fSAndroid Build Coastguard Worker   }
196*795d594fSAndroid Build Coastguard Worker 
197*795d594fSAndroid Build Coastguard Worker   CheckHoleCount(table_, current_num_holes_, top_index_);
198*795d594fSAndroid Build Coastguard Worker 
199*795d594fSAndroid Build Coastguard Worker   // We know there's enough room in the table.  Now we just need to find
200*795d594fSAndroid Build Coastguard Worker   // the right spot.  If there's a hole, find it and fill it; otherwise,
201*795d594fSAndroid Build Coastguard Worker   // add to the end of the list.
202*795d594fSAndroid Build Coastguard Worker   IndirectRef result;
203*795d594fSAndroid Build Coastguard Worker   size_t index;
204*795d594fSAndroid Build Coastguard Worker   if (current_num_holes_ > 0) {
205*795d594fSAndroid Build Coastguard Worker     DCHECK_GT(top_index_, 1U);
206*795d594fSAndroid Build Coastguard Worker     // Find the first hole; likely to be near the end of the list.
207*795d594fSAndroid Build Coastguard Worker     IrtEntry* p_scan = &table_[top_index_ - 1];
208*795d594fSAndroid Build Coastguard Worker     DCHECK(!p_scan->GetReference()->IsNull());
209*795d594fSAndroid Build Coastguard Worker     --p_scan;
210*795d594fSAndroid Build Coastguard Worker     while (!p_scan->GetReference()->IsNull()) {
211*795d594fSAndroid Build Coastguard Worker       DCHECK_GT(p_scan, table_);
212*795d594fSAndroid Build Coastguard Worker       --p_scan;
213*795d594fSAndroid Build Coastguard Worker     }
214*795d594fSAndroid Build Coastguard Worker     index = p_scan - table_;
215*795d594fSAndroid Build Coastguard Worker     current_num_holes_--;
216*795d594fSAndroid Build Coastguard Worker   } else {
217*795d594fSAndroid Build Coastguard Worker     // Add to the end.
218*795d594fSAndroid Build Coastguard Worker     index = top_index_;
219*795d594fSAndroid Build Coastguard Worker     ++top_index_;
220*795d594fSAndroid Build Coastguard Worker   }
221*795d594fSAndroid Build Coastguard Worker   table_[index].Add(obj);
222*795d594fSAndroid Build Coastguard Worker   result = ToIndirectRef(index);
223*795d594fSAndroid Build Coastguard Worker   if (kDebugIRT) {
224*795d594fSAndroid Build Coastguard Worker     LOG(INFO) << "+++ added at " << ExtractIndex(result) << " top=" << top_index_
225*795d594fSAndroid Build Coastguard Worker               << " holes=" << current_num_holes_;
226*795d594fSAndroid Build Coastguard Worker   }
227*795d594fSAndroid Build Coastguard Worker 
228*795d594fSAndroid Build Coastguard Worker   DCHECK(result != nullptr);
229*795d594fSAndroid Build Coastguard Worker   return result;
230*795d594fSAndroid Build Coastguard Worker }
231*795d594fSAndroid Build Coastguard Worker 
232*795d594fSAndroid Build Coastguard Worker // Removes an object. We extract the table offset bits from "iref"
233*795d594fSAndroid Build Coastguard Worker // and zap the corresponding entry, leaving a hole if it's not at the top.
234*795d594fSAndroid Build Coastguard Worker // Returns "false" if nothing was removed.
Remove(IndirectRef iref)235*795d594fSAndroid Build Coastguard Worker bool IndirectReferenceTable::Remove(IndirectRef iref) {
236*795d594fSAndroid Build Coastguard Worker   if (kDebugIRT) {
237*795d594fSAndroid Build Coastguard Worker     LOG(INFO) << "+++ Remove: top_index=" << top_index_
238*795d594fSAndroid Build Coastguard Worker               << " holes=" << current_num_holes_;
239*795d594fSAndroid Build Coastguard Worker   }
240*795d594fSAndroid Build Coastguard Worker 
241*795d594fSAndroid Build Coastguard Worker   // TODO: We should eagerly check the ref kind against the `kind_` instead of postponing until
242*795d594fSAndroid Build Coastguard Worker   // `CheckEntry()` below. Passing the wrong kind shall currently result in misleading warnings.
243*795d594fSAndroid Build Coastguard Worker 
244*795d594fSAndroid Build Coastguard Worker   const uint32_t top_index = top_index_;
245*795d594fSAndroid Build Coastguard Worker 
246*795d594fSAndroid Build Coastguard Worker   DCHECK(table_ != nullptr);
247*795d594fSAndroid Build Coastguard Worker 
248*795d594fSAndroid Build Coastguard Worker   const uint32_t idx = ExtractIndex(iref);
249*795d594fSAndroid Build Coastguard Worker   if (idx >= top_index) {
250*795d594fSAndroid Build Coastguard Worker     // Bad --- stale reference?
251*795d594fSAndroid Build Coastguard Worker     LOG(WARNING) << "Attempt to remove invalid index " << idx
252*795d594fSAndroid Build Coastguard Worker                  << " (top=" << top_index << ")";
253*795d594fSAndroid Build Coastguard Worker     return false;
254*795d594fSAndroid Build Coastguard Worker   }
255*795d594fSAndroid Build Coastguard Worker 
256*795d594fSAndroid Build Coastguard Worker   CheckHoleCount(table_, current_num_holes_, top_index_);
257*795d594fSAndroid Build Coastguard Worker 
258*795d594fSAndroid Build Coastguard Worker   if (idx == top_index - 1) {
259*795d594fSAndroid Build Coastguard Worker     // Top-most entry.  Scan up and consume holes.
260*795d594fSAndroid Build Coastguard Worker 
261*795d594fSAndroid Build Coastguard Worker     if (!CheckEntry("remove", iref, idx)) {
262*795d594fSAndroid Build Coastguard Worker       return false;
263*795d594fSAndroid Build Coastguard Worker     }
264*795d594fSAndroid Build Coastguard Worker 
265*795d594fSAndroid Build Coastguard Worker     *table_[idx].GetReference() = GcRoot<mirror::Object>(nullptr);
266*795d594fSAndroid Build Coastguard Worker     if (current_num_holes_ != 0) {
267*795d594fSAndroid Build Coastguard Worker       uint32_t collapse_top_index = top_index;
268*795d594fSAndroid Build Coastguard Worker       while (--collapse_top_index > 0u && current_num_holes_ != 0) {
269*795d594fSAndroid Build Coastguard Worker         if (kDebugIRT) {
270*795d594fSAndroid Build Coastguard Worker           ScopedObjectAccess soa(Thread::Current());
271*795d594fSAndroid Build Coastguard Worker           LOG(INFO) << "+++ checking for hole at " << collapse_top_index - 1 << " val="
272*795d594fSAndroid Build Coastguard Worker                     << table_[collapse_top_index - 1].GetReference()->Read<kWithoutReadBarrier>();
273*795d594fSAndroid Build Coastguard Worker         }
274*795d594fSAndroid Build Coastguard Worker         if (!table_[collapse_top_index - 1].GetReference()->IsNull()) {
275*795d594fSAndroid Build Coastguard Worker           break;
276*795d594fSAndroid Build Coastguard Worker         }
277*795d594fSAndroid Build Coastguard Worker         if (kDebugIRT) {
278*795d594fSAndroid Build Coastguard Worker           LOG(INFO) << "+++ ate hole at " << (collapse_top_index - 1);
279*795d594fSAndroid Build Coastguard Worker         }
280*795d594fSAndroid Build Coastguard Worker         current_num_holes_--;
281*795d594fSAndroid Build Coastguard Worker       }
282*795d594fSAndroid Build Coastguard Worker       top_index_ = collapse_top_index;
283*795d594fSAndroid Build Coastguard Worker 
284*795d594fSAndroid Build Coastguard Worker       CheckHoleCount(table_, current_num_holes_, top_index_);
285*795d594fSAndroid Build Coastguard Worker     } else {
286*795d594fSAndroid Build Coastguard Worker       top_index_ = top_index - 1;
287*795d594fSAndroid Build Coastguard Worker       if (kDebugIRT) {
288*795d594fSAndroid Build Coastguard Worker         LOG(INFO) << "+++ ate last entry " << top_index - 1;
289*795d594fSAndroid Build Coastguard Worker       }
290*795d594fSAndroid Build Coastguard Worker     }
291*795d594fSAndroid Build Coastguard Worker   } else {
292*795d594fSAndroid Build Coastguard Worker     // Not the top-most entry.  This creates a hole.  We null out the entry to prevent somebody
293*795d594fSAndroid Build Coastguard Worker     // from deleting it twice and screwing up the hole count.
294*795d594fSAndroid Build Coastguard Worker     if (table_[idx].GetReference()->IsNull()) {
295*795d594fSAndroid Build Coastguard Worker       LOG(INFO) << "--- WEIRD: removing null entry " << idx;
296*795d594fSAndroid Build Coastguard Worker       return false;
297*795d594fSAndroid Build Coastguard Worker     }
298*795d594fSAndroid Build Coastguard Worker     if (!CheckEntry("remove", iref, idx)) {
299*795d594fSAndroid Build Coastguard Worker       return false;
300*795d594fSAndroid Build Coastguard Worker     }
301*795d594fSAndroid Build Coastguard Worker 
302*795d594fSAndroid Build Coastguard Worker     *table_[idx].GetReference() = GcRoot<mirror::Object>(nullptr);
303*795d594fSAndroid Build Coastguard Worker     current_num_holes_++;
304*795d594fSAndroid Build Coastguard Worker     CheckHoleCount(table_, current_num_holes_, top_index_);
305*795d594fSAndroid Build Coastguard Worker     if (kDebugIRT) {
306*795d594fSAndroid Build Coastguard Worker       LOG(INFO) << "+++ left hole at " << idx << ", holes=" << current_num_holes_;
307*795d594fSAndroid Build Coastguard Worker     }
308*795d594fSAndroid Build Coastguard Worker   }
309*795d594fSAndroid Build Coastguard Worker 
310*795d594fSAndroid Build Coastguard Worker   return true;
311*795d594fSAndroid Build Coastguard Worker }
312*795d594fSAndroid Build Coastguard Worker 
Trim()313*795d594fSAndroid Build Coastguard Worker void IndirectReferenceTable::Trim() {
314*795d594fSAndroid Build Coastguard Worker   ScopedTrace trace(__PRETTY_FUNCTION__);
315*795d594fSAndroid Build Coastguard Worker   DCHECK(table_mem_map_.IsValid());
316*795d594fSAndroid Build Coastguard Worker   const size_t top_index = Capacity();
317*795d594fSAndroid Build Coastguard Worker   uint8_t* release_start = AlignUp(reinterpret_cast<uint8_t*>(&table_[top_index]), gPageSize);
318*795d594fSAndroid Build Coastguard Worker   uint8_t* release_end = static_cast<uint8_t*>(table_mem_map_.BaseEnd());
319*795d594fSAndroid Build Coastguard Worker   DCHECK_GE(reinterpret_cast<uintptr_t>(release_end), reinterpret_cast<uintptr_t>(release_start));
320*795d594fSAndroid Build Coastguard Worker   DCHECK_ALIGNED_PARAM(release_end, gPageSize);
321*795d594fSAndroid Build Coastguard Worker   DCHECK_ALIGNED_PARAM(release_end - release_start, gPageSize);
322*795d594fSAndroid Build Coastguard Worker   if (release_start != release_end) {
323*795d594fSAndroid Build Coastguard Worker     madvise(release_start, release_end - release_start, MADV_DONTNEED);
324*795d594fSAndroid Build Coastguard Worker   }
325*795d594fSAndroid Build Coastguard Worker }
326*795d594fSAndroid Build Coastguard Worker 
VisitRoots(RootVisitor * visitor,const RootInfo & root_info)327*795d594fSAndroid Build Coastguard Worker void IndirectReferenceTable::VisitRoots(RootVisitor* visitor, const RootInfo& root_info) {
328*795d594fSAndroid Build Coastguard Worker   BufferedRootVisitor<kDefaultBufferedRootCount> root_visitor(visitor, root_info);
329*795d594fSAndroid Build Coastguard Worker   for (size_t i = 0, capacity = Capacity(); i != capacity; ++i) {
330*795d594fSAndroid Build Coastguard Worker     GcRoot<mirror::Object>* ref = table_[i].GetReference();
331*795d594fSAndroid Build Coastguard Worker     if (!ref->IsNull()) {
332*795d594fSAndroid Build Coastguard Worker       root_visitor.VisitRoot(*ref);
333*795d594fSAndroid Build Coastguard Worker       DCHECK(!ref->IsNull());
334*795d594fSAndroid Build Coastguard Worker     }
335*795d594fSAndroid Build Coastguard Worker   }
336*795d594fSAndroid Build Coastguard Worker }
337*795d594fSAndroid Build Coastguard Worker 
SweepJniWeakGlobals(IsMarkedVisitor * visitor)338*795d594fSAndroid Build Coastguard Worker void IndirectReferenceTable::SweepJniWeakGlobals(IsMarkedVisitor* visitor) {
339*795d594fSAndroid Build Coastguard Worker   CHECK_EQ(kind_, kWeakGlobal);
340*795d594fSAndroid Build Coastguard Worker   MutexLock mu(Thread::Current(), *Locks::jni_weak_globals_lock_);
341*795d594fSAndroid Build Coastguard Worker   Runtime* const runtime = Runtime::Current();
342*795d594fSAndroid Build Coastguard Worker   for (size_t i = 0, capacity = Capacity(); i != capacity; ++i) {
343*795d594fSAndroid Build Coastguard Worker     GcRoot<mirror::Object>* entry = table_[i].GetReference();
344*795d594fSAndroid Build Coastguard Worker     // Need to skip null here to distinguish between null entries and cleared weak ref entries.
345*795d594fSAndroid Build Coastguard Worker     if (!entry->IsNull()) {
346*795d594fSAndroid Build Coastguard Worker       mirror::Object* obj = entry->Read<kWithoutReadBarrier>();
347*795d594fSAndroid Build Coastguard Worker       mirror::Object* new_obj = visitor->IsMarked(obj);
348*795d594fSAndroid Build Coastguard Worker       if (new_obj == nullptr) {
349*795d594fSAndroid Build Coastguard Worker         new_obj = runtime->GetClearedJniWeakGlobal();
350*795d594fSAndroid Build Coastguard Worker       }
351*795d594fSAndroid Build Coastguard Worker       *entry = GcRoot<mirror::Object>(new_obj);
352*795d594fSAndroid Build Coastguard Worker     }
353*795d594fSAndroid Build Coastguard Worker   }
354*795d594fSAndroid Build Coastguard Worker }
355*795d594fSAndroid Build Coastguard Worker 
Dump(std::ostream & os) const356*795d594fSAndroid Build Coastguard Worker void IndirectReferenceTable::Dump(std::ostream& os) const {
357*795d594fSAndroid Build Coastguard Worker   os << kind_ << " table dump:\n";
358*795d594fSAndroid Build Coastguard Worker   ReferenceTable::Table entries;
359*795d594fSAndroid Build Coastguard Worker   for (size_t i = 0; i < Capacity(); ++i) {
360*795d594fSAndroid Build Coastguard Worker     ObjPtr<mirror::Object> obj = table_[i].GetReference()->Read<kWithoutReadBarrier>();
361*795d594fSAndroid Build Coastguard Worker     if (obj != nullptr) {
362*795d594fSAndroid Build Coastguard Worker       obj = table_[i].GetReference()->Read();
363*795d594fSAndroid Build Coastguard Worker       entries.push_back(GcRoot<mirror::Object>(obj));
364*795d594fSAndroid Build Coastguard Worker     }
365*795d594fSAndroid Build Coastguard Worker   }
366*795d594fSAndroid Build Coastguard Worker   ReferenceTable::Dump(os, entries);
367*795d594fSAndroid Build Coastguard Worker }
368*795d594fSAndroid Build Coastguard Worker 
FreeCapacity() const369*795d594fSAndroid Build Coastguard Worker size_t IndirectReferenceTable::FreeCapacity() const {
370*795d594fSAndroid Build Coastguard Worker   return max_entries_ - top_index_;
371*795d594fSAndroid Build Coastguard Worker }
372*795d594fSAndroid Build Coastguard Worker 
373*795d594fSAndroid Build Coastguard Worker }  // namespace art
374