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