indirect_reference_table.cc revision cd2cfff09c916c9e72a7cfeb0686b441847dc62e
16c1a394b47c85c8d1723fc3b156a3b1b0b29a757Elliott Hughes/* 26c1a394b47c85c8d1723fc3b156a3b1b0b29a757Elliott Hughes * Copyright (C) 2009 The Android Open Source Project 36c1a394b47c85c8d1723fc3b156a3b1b0b29a757Elliott Hughes * 46c1a394b47c85c8d1723fc3b156a3b1b0b29a757Elliott Hughes * Licensed under the Apache License, Version 2.0 (the "License"); 56c1a394b47c85c8d1723fc3b156a3b1b0b29a757Elliott Hughes * you may not use this file except in compliance with the License. 66c1a394b47c85c8d1723fc3b156a3b1b0b29a757Elliott Hughes * You may obtain a copy of the License at 76c1a394b47c85c8d1723fc3b156a3b1b0b29a757Elliott Hughes * 86c1a394b47c85c8d1723fc3b156a3b1b0b29a757Elliott Hughes * http://www.apache.org/licenses/LICENSE-2.0 96c1a394b47c85c8d1723fc3b156a3b1b0b29a757Elliott Hughes * 106c1a394b47c85c8d1723fc3b156a3b1b0b29a757Elliott Hughes * Unless required by applicable law or agreed to in writing, software 116c1a394b47c85c8d1723fc3b156a3b1b0b29a757Elliott Hughes * distributed under the License is distributed on an "AS IS" BASIS, 126c1a394b47c85c8d1723fc3b156a3b1b0b29a757Elliott Hughes * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 136c1a394b47c85c8d1723fc3b156a3b1b0b29a757Elliott Hughes * See the License for the specific language governing permissions and 146c1a394b47c85c8d1723fc3b156a3b1b0b29a757Elliott Hughes * limitations under the License. 156c1a394b47c85c8d1723fc3b156a3b1b0b29a757Elliott Hughes */ 166c1a394b47c85c8d1723fc3b156a3b1b0b29a757Elliott Hughes 176c1a394b47c85c8d1723fc3b156a3b1b0b29a757Elliott Hughes#include "indirect_reference_table.h" 18a2501990dd0f68baf38ce19251949d7bb3ecfe5aElliott Hughes#include "jni_internal.h" 196c1a394b47c85c8d1723fc3b156a3b1b0b29a757Elliott Hughes#include "reference_table.h" 20a2501990dd0f68baf38ce19251949d7bb3ecfe5aElliott Hughes#include "runtime.h" 2100f7d0eaa6bd93d33bf0c1429bf4ba0b3f28abacIan Rogers#include "scoped_thread_state_change.h" 225a7a74a042e73a355f5cedffa0d2faf5340028faIan Rogers#include "thread.h" 23cdd1d2d3fee0711b8b11db99f2dfb80113520100Ian Rogers#include "utils.h" 246c1a394b47c85c8d1723fc3b156a3b1b0b29a757Elliott Hughes 256c1a394b47c85c8d1723fc3b156a3b1b0b29a757Elliott Hughes#include <cstdlib> 266c1a394b47c85c8d1723fc3b156a3b1b0b29a757Elliott Hughes 276c1a394b47c85c8d1723fc3b156a3b1b0b29a757Elliott Hughesnamespace art { 286c1a394b47c85c8d1723fc3b156a3b1b0b29a757Elliott Hughes 296c1a394b47c85c8d1723fc3b156a3b1b0b29a757Elliott Hughesstatic void AbortMaybe() { 30a2501990dd0f68baf38ce19251949d7bb3ecfe5aElliott Hughes // If -Xcheck:jni is on, it'll give a more detailed error before aborting. 31a2501990dd0f68baf38ce19251949d7bb3ecfe5aElliott Hughes if (!Runtime::Current()->GetJavaVM()->check_jni) { 32a2501990dd0f68baf38ce19251949d7bb3ecfe5aElliott Hughes // Otherwise, we want to abort rather than hand back a bad reference. 33a2501990dd0f68baf38ce19251949d7bb3ecfe5aElliott Hughes LOG(FATAL) << "JNI ERROR (app bug): see above."; 34a2501990dd0f68baf38ce19251949d7bb3ecfe5aElliott Hughes } 356c1a394b47c85c8d1723fc3b156a3b1b0b29a757Elliott Hughes} 366c1a394b47c85c8d1723fc3b156a3b1b0b29a757Elliott Hughes 376c1a394b47c85c8d1723fc3b156a3b1b0b29a757Elliott HughesIndirectReferenceTable::IndirectReferenceTable(size_t initialCount, 38ba8eee10607a524f43b55a6f33c13924fb16d435Elliott Hughes size_t maxCount, IndirectRefKind desiredKind) { 396c1a394b47c85c8d1723fc3b156a3b1b0b29a757Elliott Hughes CHECK_GT(initialCount, 0U); 406c1a394b47c85c8d1723fc3b156a3b1b0b29a757Elliott Hughes CHECK_LE(initialCount, maxCount); 41408f79aeb676251ba35667a64e86c20638d7cb0bIan Rogers CHECK_NE(desiredKind, kSirtOrInvalid); 426c1a394b47c85c8d1723fc3b156a3b1b0b29a757Elliott Hughes 43423d2a3dcbb260b020efb5da59f784c9f02accbfMathieu Chartier table_ = reinterpret_cast<mirror::Object**>(malloc(initialCount * sizeof(const mirror::Object*))); 446c1a394b47c85c8d1723fc3b156a3b1b0b29a757Elliott Hughes CHECK(table_ != NULL); 452dd0e2cea360bc9206eb88ecc40d259e796c239dIan Rogers memset(table_, 0xd1, initialCount * sizeof(const mirror::Object*)); 466c1a394b47c85c8d1723fc3b156a3b1b0b29a757Elliott Hughes 476c1a394b47c85c8d1723fc3b156a3b1b0b29a757Elliott Hughes slot_data_ = reinterpret_cast<IndirectRefSlot*>(calloc(initialCount, sizeof(IndirectRefSlot))); 486c1a394b47c85c8d1723fc3b156a3b1b0b29a757Elliott Hughes CHECK(slot_data_ != NULL); 496c1a394b47c85c8d1723fc3b156a3b1b0b29a757Elliott Hughes 50dc51b79e65abcdad094ccd5e5a2caf5153433d49Ian Rogers segment_state_.all = IRT_FIRST_SEGMENT; 516c1a394b47c85c8d1723fc3b156a3b1b0b29a757Elliott Hughes alloc_entries_ = initialCount; 526c1a394b47c85c8d1723fc3b156a3b1b0b29a757Elliott Hughes max_entries_ = maxCount; 536c1a394b47c85c8d1723fc3b156a3b1b0b29a757Elliott Hughes kind_ = desiredKind; 546c1a394b47c85c8d1723fc3b156a3b1b0b29a757Elliott Hughes} 556c1a394b47c85c8d1723fc3b156a3b1b0b29a757Elliott Hughes 566c1a394b47c85c8d1723fc3b156a3b1b0b29a757Elliott HughesIndirectReferenceTable::~IndirectReferenceTable() { 576c1a394b47c85c8d1723fc3b156a3b1b0b29a757Elliott Hughes free(table_); 586c1a394b47c85c8d1723fc3b156a3b1b0b29a757Elliott Hughes free(slot_data_); 596c1a394b47c85c8d1723fc3b156a3b1b0b29a757Elliott Hughes table_ = NULL; 606c1a394b47c85c8d1723fc3b156a3b1b0b29a757Elliott Hughes slot_data_ = NULL; 616c1a394b47c85c8d1723fc3b156a3b1b0b29a757Elliott Hughes alloc_entries_ = max_entries_ = -1; 626c1a394b47c85c8d1723fc3b156a3b1b0b29a757Elliott Hughes} 636c1a394b47c85c8d1723fc3b156a3b1b0b29a757Elliott Hughes 6473e66f73f5093b64f2b023ebbb85916a13d5c937Elliott Hughes// Make sure that the entry at "idx" is correctly paired with "iref". 656c1a394b47c85c8d1723fc3b156a3b1b0b29a757Elliott Hughesbool IndirectReferenceTable::CheckEntry(const char* what, IndirectRef iref, int idx) const { 662dd0e2cea360bc9206eb88ecc40d259e796c239dIan Rogers const mirror::Object* obj = table_[idx]; 676c1a394b47c85c8d1723fc3b156a3b1b0b29a757Elliott Hughes IndirectRef checkRef = ToIndirectRef(obj, idx); 684f6ad8ab428038129b2d0d6c40b7fd625cca15e1Ian Rogers if (UNLIKELY(checkRef != iref)) { 696c1a394b47c85c8d1723fc3b156a3b1b0b29a757Elliott Hughes LOG(ERROR) << "JNI ERROR (app bug): attempt to " << what 706c1a394b47c85c8d1723fc3b156a3b1b0b29a757Elliott Hughes << " stale " << kind_ << " " << iref 716c1a394b47c85c8d1723fc3b156a3b1b0b29a757Elliott Hughes << " (should be " << checkRef << ")"; 726c1a394b47c85c8d1723fc3b156a3b1b0b29a757Elliott Hughes AbortMaybe(); 736c1a394b47c85c8d1723fc3b156a3b1b0b29a757Elliott Hughes return false; 746c1a394b47c85c8d1723fc3b156a3b1b0b29a757Elliott Hughes } 756c1a394b47c85c8d1723fc3b156a3b1b0b29a757Elliott Hughes return true; 766c1a394b47c85c8d1723fc3b156a3b1b0b29a757Elliott Hughes} 776c1a394b47c85c8d1723fc3b156a3b1b0b29a757Elliott Hughes 78423d2a3dcbb260b020efb5da59f784c9f02accbfMathieu ChartierIndirectRef IndirectReferenceTable::Add(uint32_t cookie, mirror::Object* obj) { 796c1a394b47c85c8d1723fc3b156a3b1b0b29a757Elliott Hughes IRTSegmentState prevState; 806c1a394b47c85c8d1723fc3b156a3b1b0b29a757Elliott Hughes prevState.all = cookie; 81dc51b79e65abcdad094ccd5e5a2caf5153433d49Ian Rogers size_t topIndex = segment_state_.parts.topIndex; 826c1a394b47c85c8d1723fc3b156a3b1b0b29a757Elliott Hughes 83cd2cfff09c916c9e72a7cfeb0686b441847dc62eMathieu Chartier CHECK(obj != NULL); 84cdd1d2d3fee0711b8b11db99f2dfb80113520100Ian Rogers // TODO: stronger sanity check on the object (such as in heap) 85d07986fad0d08cdf05505cf9230714a2cf0dd9aeElliott Hughes DCHECK_ALIGNED(reinterpret_cast<uintptr_t>(obj), 8); 866c1a394b47c85c8d1723fc3b156a3b1b0b29a757Elliott Hughes DCHECK(table_ != NULL); 876c1a394b47c85c8d1723fc3b156a3b1b0b29a757Elliott Hughes DCHECK_LE(alloc_entries_, max_entries_); 88dc51b79e65abcdad094ccd5e5a2caf5153433d49Ian Rogers DCHECK_GE(segment_state_.parts.numHoles, prevState.parts.numHoles); 896c1a394b47c85c8d1723fc3b156a3b1b0b29a757Elliott Hughes 906c1a394b47c85c8d1723fc3b156a3b1b0b29a757Elliott Hughes if (topIndex == alloc_entries_) { 9173e66f73f5093b64f2b023ebbb85916a13d5c937Elliott Hughes // reached end of allocated space; did we hit buffer max? 926c1a394b47c85c8d1723fc3b156a3b1b0b29a757Elliott Hughes if (topIndex == max_entries_) { 9373e66f73f5093b64f2b023ebbb85916a13d5c937Elliott Hughes LOG(FATAL) << "JNI ERROR (app bug): " << kind_ << " table overflow " 9473e66f73f5093b64f2b023ebbb85916a13d5c937Elliott Hughes << "(max=" << max_entries_ << ")\n" 9500f7d0eaa6bd93d33bf0c1429bf4ba0b3f28abacIan Rogers << MutatorLockedDumpable<IndirectReferenceTable>(*this); 966c1a394b47c85c8d1723fc3b156a3b1b0b29a757Elliott Hughes } 976c1a394b47c85c8d1723fc3b156a3b1b0b29a757Elliott Hughes 986c1a394b47c85c8d1723fc3b156a3b1b0b29a757Elliott Hughes size_t newSize = alloc_entries_ * 2; 996c1a394b47c85c8d1723fc3b156a3b1b0b29a757Elliott Hughes if (newSize > max_entries_) { 1006c1a394b47c85c8d1723fc3b156a3b1b0b29a757Elliott Hughes newSize = max_entries_; 1016c1a394b47c85c8d1723fc3b156a3b1b0b29a757Elliott Hughes } 1026c1a394b47c85c8d1723fc3b156a3b1b0b29a757Elliott Hughes DCHECK_GT(newSize, alloc_entries_); 1036c1a394b47c85c8d1723fc3b156a3b1b0b29a757Elliott Hughes 104423d2a3dcbb260b020efb5da59f784c9f02accbfMathieu Chartier table_ = reinterpret_cast<mirror::Object**>(realloc(table_, newSize * sizeof(mirror::Object*))); 10500f7d0eaa6bd93d33bf0c1429bf4ba0b3f28abacIan Rogers slot_data_ = reinterpret_cast<IndirectRefSlot*>(realloc(slot_data_, 10600f7d0eaa6bd93d33bf0c1429bf4ba0b3f28abacIan Rogers newSize * sizeof(IndirectRefSlot))); 1076c1a394b47c85c8d1723fc3b156a3b1b0b29a757Elliott Hughes if (table_ == NULL || slot_data_ == NULL) { 10873e66f73f5093b64f2b023ebbb85916a13d5c937Elliott Hughes LOG(FATAL) << "JNI ERROR (app bug): unable to expand " 1096c1a394b47c85c8d1723fc3b156a3b1b0b29a757Elliott Hughes << kind_ << " table (from " 1106c1a394b47c85c8d1723fc3b156a3b1b0b29a757Elliott Hughes << alloc_entries_ << " to " << newSize 11173e66f73f5093b64f2b023ebbb85916a13d5c937Elliott Hughes << ", max=" << max_entries_ << ")\n" 11200f7d0eaa6bd93d33bf0c1429bf4ba0b3f28abacIan Rogers << MutatorLockedDumpable<IndirectReferenceTable>(*this); 1136c1a394b47c85c8d1723fc3b156a3b1b0b29a757Elliott Hughes } 1146c1a394b47c85c8d1723fc3b156a3b1b0b29a757Elliott Hughes 1156c1a394b47c85c8d1723fc3b156a3b1b0b29a757Elliott Hughes // Clear the newly-allocated slot_data_ elements. 1166c1a394b47c85c8d1723fc3b156a3b1b0b29a757Elliott Hughes memset(slot_data_ + alloc_entries_, 0, (newSize - alloc_entries_) * sizeof(IndirectRefSlot)); 1176c1a394b47c85c8d1723fc3b156a3b1b0b29a757Elliott Hughes 1186c1a394b47c85c8d1723fc3b156a3b1b0b29a757Elliott Hughes alloc_entries_ = newSize; 1196c1a394b47c85c8d1723fc3b156a3b1b0b29a757Elliott Hughes } 1206c1a394b47c85c8d1723fc3b156a3b1b0b29a757Elliott Hughes 12173e66f73f5093b64f2b023ebbb85916a13d5c937Elliott Hughes // We know there's enough room in the table. Now we just need to find 12273e66f73f5093b64f2b023ebbb85916a13d5c937Elliott Hughes // the right spot. If there's a hole, find it and fill it; otherwise, 12373e66f73f5093b64f2b023ebbb85916a13d5c937Elliott Hughes // add to the end of the list. 1246c1a394b47c85c8d1723fc3b156a3b1b0b29a757Elliott Hughes IndirectRef result; 125dc51b79e65abcdad094ccd5e5a2caf5153433d49Ian Rogers int numHoles = segment_state_.parts.numHoles - prevState.parts.numHoles; 1266c1a394b47c85c8d1723fc3b156a3b1b0b29a757Elliott Hughes if (numHoles > 0) { 1276c1a394b47c85c8d1723fc3b156a3b1b0b29a757Elliott Hughes DCHECK_GT(topIndex, 1U); 12873e66f73f5093b64f2b023ebbb85916a13d5c937Elliott Hughes // Find the first hole; likely to be near the end of the list. 129423d2a3dcbb260b020efb5da59f784c9f02accbfMathieu Chartier mirror::Object** pScan = &table_[topIndex - 1]; 1306c1a394b47c85c8d1723fc3b156a3b1b0b29a757Elliott Hughes DCHECK(*pScan != NULL); 1316c1a394b47c85c8d1723fc3b156a3b1b0b29a757Elliott Hughes while (*--pScan != NULL) { 1326c1a394b47c85c8d1723fc3b156a3b1b0b29a757Elliott Hughes DCHECK_GE(pScan, table_ + prevState.parts.topIndex); 1336c1a394b47c85c8d1723fc3b156a3b1b0b29a757Elliott Hughes } 1346c1a394b47c85c8d1723fc3b156a3b1b0b29a757Elliott Hughes UpdateSlotAdd(obj, pScan - table_); 1356c1a394b47c85c8d1723fc3b156a3b1b0b29a757Elliott Hughes result = ToIndirectRef(obj, pScan - table_); 1366c1a394b47c85c8d1723fc3b156a3b1b0b29a757Elliott Hughes *pScan = obj; 137dc51b79e65abcdad094ccd5e5a2caf5153433d49Ian Rogers segment_state_.parts.numHoles--; 1386c1a394b47c85c8d1723fc3b156a3b1b0b29a757Elliott Hughes } else { 13973e66f73f5093b64f2b023ebbb85916a13d5c937Elliott Hughes // Add to the end. 1406c1a394b47c85c8d1723fc3b156a3b1b0b29a757Elliott Hughes UpdateSlotAdd(obj, topIndex); 1416c1a394b47c85c8d1723fc3b156a3b1b0b29a757Elliott Hughes result = ToIndirectRef(obj, topIndex); 1426c1a394b47c85c8d1723fc3b156a3b1b0b29a757Elliott Hughes table_[topIndex++] = obj; 143dc51b79e65abcdad094ccd5e5a2caf5153433d49Ian Rogers segment_state_.parts.topIndex = topIndex; 1446c1a394b47c85c8d1723fc3b156a3b1b0b29a757Elliott Hughes } 1455a7a74a042e73a355f5cedffa0d2faf5340028faIan Rogers if (false) { 1465a7a74a042e73a355f5cedffa0d2faf5340028faIan Rogers LOG(INFO) << "+++ added at " << ExtractIndex(result) << " top=" << segment_state_.parts.topIndex 1475a7a74a042e73a355f5cedffa0d2faf5340028faIan Rogers << " holes=" << segment_state_.parts.numHoles; 1485a7a74a042e73a355f5cedffa0d2faf5340028faIan Rogers } 1496c1a394b47c85c8d1723fc3b156a3b1b0b29a757Elliott Hughes 1506c1a394b47c85c8d1723fc3b156a3b1b0b29a757Elliott Hughes DCHECK(result != NULL); 1516c1a394b47c85c8d1723fc3b156a3b1b0b29a757Elliott Hughes return result; 1526c1a394b47c85c8d1723fc3b156a3b1b0b29a757Elliott Hughes} 1536c1a394b47c85c8d1723fc3b156a3b1b0b29a757Elliott Hughes 154726079d3e2e50854cd6ca4c393f4529a796dba58Elliott Hughesvoid IndirectReferenceTable::AssertEmpty() { 15500f7d0eaa6bd93d33bf0c1429bf4ba0b3f28abacIan Rogers if (UNLIKELY(begin() != end())) { 15600f7d0eaa6bd93d33bf0c1429bf4ba0b3f28abacIan Rogers ScopedObjectAccess soa(Thread::Current()); 15773e66f73f5093b64f2b023ebbb85916a13d5c937Elliott Hughes LOG(FATAL) << "Internal Error: non-empty local reference table\n" 15800f7d0eaa6bd93d33bf0c1429bf4ba0b3f28abacIan Rogers << MutatorLockedDumpable<IndirectReferenceTable>(*this); 159726079d3e2e50854cd6ca4c393f4529a796dba58Elliott Hughes } 160726079d3e2e50854cd6ca4c393f4529a796dba58Elliott Hughes} 161726079d3e2e50854cd6ca4c393f4529a796dba58Elliott Hughes 16273e66f73f5093b64f2b023ebbb85916a13d5c937Elliott Hughes// Verifies that the indirect table lookup is valid. 16373e66f73f5093b64f2b023ebbb85916a13d5c937Elliott Hughes// Returns "false" if something looks bad. 1646c1a394b47c85c8d1723fc3b156a3b1b0b29a757Elliott Hughesbool IndirectReferenceTable::GetChecked(IndirectRef iref) const { 1654f6ad8ab428038129b2d0d6c40b7fd625cca15e1Ian Rogers if (UNLIKELY(iref == NULL)) { 1666c1a394b47c85c8d1723fc3b156a3b1b0b29a757Elliott Hughes LOG(WARNING) << "Attempt to look up NULL " << kind_; 1676c1a394b47c85c8d1723fc3b156a3b1b0b29a757Elliott Hughes return false; 1686c1a394b47c85c8d1723fc3b156a3b1b0b29a757Elliott Hughes } 1694f6ad8ab428038129b2d0d6c40b7fd625cca15e1Ian Rogers if (UNLIKELY(GetIndirectRefKind(iref) == kSirtOrInvalid)) { 1706c1a394b47c85c8d1723fc3b156a3b1b0b29a757Elliott Hughes LOG(ERROR) << "JNI ERROR (app bug): invalid " << kind_ << " " << iref; 1716c1a394b47c85c8d1723fc3b156a3b1b0b29a757Elliott Hughes AbortMaybe(); 1726c1a394b47c85c8d1723fc3b156a3b1b0b29a757Elliott Hughes return false; 1736c1a394b47c85c8d1723fc3b156a3b1b0b29a757Elliott Hughes } 1746c1a394b47c85c8d1723fc3b156a3b1b0b29a757Elliott Hughes 175dc51b79e65abcdad094ccd5e5a2caf5153433d49Ian Rogers int topIndex = segment_state_.parts.topIndex; 1766c1a394b47c85c8d1723fc3b156a3b1b0b29a757Elliott Hughes int idx = ExtractIndex(iref); 1774f6ad8ab428038129b2d0d6c40b7fd625cca15e1Ian Rogers if (UNLIKELY(idx >= topIndex)) { 1785a7a74a042e73a355f5cedffa0d2faf5340028faIan Rogers LOG(ERROR) << "JNI ERROR (app bug): accessed stale " << kind_ << " " 1795a7a74a042e73a355f5cedffa0d2faf5340028faIan Rogers << iref << " (index " << idx << " in a table of size " << topIndex << ")"; 1806c1a394b47c85c8d1723fc3b156a3b1b0b29a757Elliott Hughes AbortMaybe(); 1816c1a394b47c85c8d1723fc3b156a3b1b0b29a757Elliott Hughes return false; 1826c1a394b47c85c8d1723fc3b156a3b1b0b29a757Elliott Hughes } 1836c1a394b47c85c8d1723fc3b156a3b1b0b29a757Elliott Hughes 1844f6ad8ab428038129b2d0d6c40b7fd625cca15e1Ian Rogers if (UNLIKELY(table_[idx] == NULL)) { 1856c1a394b47c85c8d1723fc3b156a3b1b0b29a757Elliott Hughes LOG(ERROR) << "JNI ERROR (app bug): accessed deleted " << kind_ << " " << iref; 1866c1a394b47c85c8d1723fc3b156a3b1b0b29a757Elliott Hughes AbortMaybe(); 1876c1a394b47c85c8d1723fc3b156a3b1b0b29a757Elliott Hughes return false; 1886c1a394b47c85c8d1723fc3b156a3b1b0b29a757Elliott Hughes } 1896c1a394b47c85c8d1723fc3b156a3b1b0b29a757Elliott Hughes 1904f6ad8ab428038129b2d0d6c40b7fd625cca15e1Ian Rogers if (UNLIKELY(!CheckEntry("use", iref, idx))) { 1916c1a394b47c85c8d1723fc3b156a3b1b0b29a757Elliott Hughes return false; 1926c1a394b47c85c8d1723fc3b156a3b1b0b29a757Elliott Hughes } 1936c1a394b47c85c8d1723fc3b156a3b1b0b29a757Elliott Hughes 1946c1a394b47c85c8d1723fc3b156a3b1b0b29a757Elliott Hughes return true; 1956c1a394b47c85c8d1723fc3b156a3b1b0b29a757Elliott Hughes} 1966c1a394b47c85c8d1723fc3b156a3b1b0b29a757Elliott Hughes 197423d2a3dcbb260b020efb5da59f784c9f02accbfMathieu Chartierstatic int Find(mirror::Object* direct_pointer, int bottomIndex, int topIndex, 198423d2a3dcbb260b020efb5da59f784c9f02accbfMathieu Chartier mirror::Object** table) { 1996c1a394b47c85c8d1723fc3b156a3b1b0b29a757Elliott Hughes for (int i = bottomIndex; i < topIndex; ++i) { 2002ced6a534157d5d963693346904389c19775d2daElliott Hughes if (table[i] == direct_pointer) { 2016c1a394b47c85c8d1723fc3b156a3b1b0b29a757Elliott Hughes return i; 2026c1a394b47c85c8d1723fc3b156a3b1b0b29a757Elliott Hughes } 2036c1a394b47c85c8d1723fc3b156a3b1b0b29a757Elliott Hughes } 2046c1a394b47c85c8d1723fc3b156a3b1b0b29a757Elliott Hughes return -1; 2056c1a394b47c85c8d1723fc3b156a3b1b0b29a757Elliott Hughes} 2066c1a394b47c85c8d1723fc3b156a3b1b0b29a757Elliott Hughes 2072dd0e2cea360bc9206eb88ecc40d259e796c239dIan Rogersbool IndirectReferenceTable::ContainsDirectPointer(mirror::Object* direct_pointer) const { 2082ced6a534157d5d963693346904389c19775d2daElliott Hughes return Find(direct_pointer, 0, segment_state_.parts.topIndex, table_) != -1; 2096c1a394b47c85c8d1723fc3b156a3b1b0b29a757Elliott Hughes} 2106c1a394b47c85c8d1723fc3b156a3b1b0b29a757Elliott Hughes 21173e66f73f5093b64f2b023ebbb85916a13d5c937Elliott Hughes// Removes an object. We extract the table offset bits from "iref" 21273e66f73f5093b64f2b023ebbb85916a13d5c937Elliott Hughes// and zap the corresponding entry, leaving a hole if it's not at the top. 21373e66f73f5093b64f2b023ebbb85916a13d5c937Elliott Hughes// If the entry is not between the current top index and the bottom index 21473e66f73f5093b64f2b023ebbb85916a13d5c937Elliott Hughes// specified by the cookie, we don't remove anything. This is the behavior 21573e66f73f5093b64f2b023ebbb85916a13d5c937Elliott Hughes// required by JNI's DeleteLocalRef function. 21673e66f73f5093b64f2b023ebbb85916a13d5c937Elliott Hughes// This method is not called when a local frame is popped; this is only used 21773e66f73f5093b64f2b023ebbb85916a13d5c937Elliott Hughes// for explicit single removals. 21873e66f73f5093b64f2b023ebbb85916a13d5c937Elliott Hughes// Returns "false" if nothing was removed. 2196c1a394b47c85c8d1723fc3b156a3b1b0b29a757Elliott Hughesbool IndirectReferenceTable::Remove(uint32_t cookie, IndirectRef iref) { 2206c1a394b47c85c8d1723fc3b156a3b1b0b29a757Elliott Hughes IRTSegmentState prevState; 2216c1a394b47c85c8d1723fc3b156a3b1b0b29a757Elliott Hughes prevState.all = cookie; 222dc51b79e65abcdad094ccd5e5a2caf5153433d49Ian Rogers int topIndex = segment_state_.parts.topIndex; 2236c1a394b47c85c8d1723fc3b156a3b1b0b29a757Elliott Hughes int bottomIndex = prevState.parts.topIndex; 2246c1a394b47c85c8d1723fc3b156a3b1b0b29a757Elliott Hughes 2256c1a394b47c85c8d1723fc3b156a3b1b0b29a757Elliott Hughes DCHECK(table_ != NULL); 2266c1a394b47c85c8d1723fc3b156a3b1b0b29a757Elliott Hughes DCHECK_LE(alloc_entries_, max_entries_); 227dc51b79e65abcdad094ccd5e5a2caf5153433d49Ian Rogers DCHECK_GE(segment_state_.parts.numHoles, prevState.parts.numHoles); 2286c1a394b47c85c8d1723fc3b156a3b1b0b29a757Elliott Hughes 2296c1a394b47c85c8d1723fc3b156a3b1b0b29a757Elliott Hughes int idx = ExtractIndex(iref); 2306c1a394b47c85c8d1723fc3b156a3b1b0b29a757Elliott Hughes 231c5bfa8f49d8548d7c685a99b411311ef56bedffaElliott Hughes JavaVMExt* vm = Runtime::Current()->GetJavaVM(); 2325a7a74a042e73a355f5cedffa0d2faf5340028faIan Rogers if (GetIndirectRefKind(iref) == kSirtOrInvalid && 2330399dde18753aa9bd2bd0d7cf60beef154d164a4Ian Rogers Thread::Current()->SirtContains(reinterpret_cast<jobject>(iref))) { 2345a7a74a042e73a355f5cedffa0d2faf5340028faIan Rogers LOG(WARNING) << "Attempt to remove local SIRT entry from IRT, ignoring"; 2355a7a74a042e73a355f5cedffa0d2faf5340028faIan Rogers return true; 2365a7a74a042e73a355f5cedffa0d2faf5340028faIan Rogers } 237467c9699c3de467f76f03494a9389ebba285cb6cIan Rogers if (GetIndirectRefKind(iref) == kSirtOrInvalid && vm->work_around_app_jni_bugs) { 2382dd0e2cea360bc9206eb88ecc40d259e796c239dIan Rogers mirror::Object* direct_pointer = reinterpret_cast<mirror::Object*>(iref); 2392ced6a534157d5d963693346904389c19775d2daElliott Hughes idx = Find(direct_pointer, bottomIndex, topIndex, table_); 2406c1a394b47c85c8d1723fc3b156a3b1b0b29a757Elliott Hughes if (idx == -1) { 2419dcd45c60c691524bd8ef7d6f65075d9ee3e5554Elliott Hughes LOG(WARNING) << "Trying to work around app JNI bugs, but didn't find " << iref << " in table!"; 2426c1a394b47c85c8d1723fc3b156a3b1b0b29a757Elliott Hughes return false; 2436c1a394b47c85c8d1723fc3b156a3b1b0b29a757Elliott Hughes } 2446c1a394b47c85c8d1723fc3b156a3b1b0b29a757Elliott Hughes } 2456c1a394b47c85c8d1723fc3b156a3b1b0b29a757Elliott Hughes 2466c1a394b47c85c8d1723fc3b156a3b1b0b29a757Elliott Hughes if (idx < bottomIndex) { 247726079d3e2e50854cd6ca4c393f4529a796dba58Elliott Hughes // Wrong segment. 248726079d3e2e50854cd6ca4c393f4529a796dba58Elliott Hughes LOG(WARNING) << "Attempt to remove index outside index area (" << idx 249726079d3e2e50854cd6ca4c393f4529a796dba58Elliott Hughes << " vs " << bottomIndex << "-" << topIndex << ")"; 2506c1a394b47c85c8d1723fc3b156a3b1b0b29a757Elliott Hughes return false; 2516c1a394b47c85c8d1723fc3b156a3b1b0b29a757Elliott Hughes } 2526c1a394b47c85c8d1723fc3b156a3b1b0b29a757Elliott Hughes if (idx >= topIndex) { 253726079d3e2e50854cd6ca4c393f4529a796dba58Elliott Hughes // Bad --- stale reference? 254726079d3e2e50854cd6ca4c393f4529a796dba58Elliott Hughes LOG(WARNING) << "Attempt to remove invalid index " << idx 255726079d3e2e50854cd6ca4c393f4529a796dba58Elliott Hughes << " (bottom=" << bottomIndex << " top=" << topIndex << ")"; 2566c1a394b47c85c8d1723fc3b156a3b1b0b29a757Elliott Hughes return false; 2576c1a394b47c85c8d1723fc3b156a3b1b0b29a757Elliott Hughes } 2586c1a394b47c85c8d1723fc3b156a3b1b0b29a757Elliott Hughes 2596c1a394b47c85c8d1723fc3b156a3b1b0b29a757Elliott Hughes if (idx == topIndex-1) { 2606c1a394b47c85c8d1723fc3b156a3b1b0b29a757Elliott Hughes // Top-most entry. Scan up and consume holes. 2616c1a394b47c85c8d1723fc3b156a3b1b0b29a757Elliott Hughes 262c5bfa8f49d8548d7c685a99b411311ef56bedffaElliott Hughes if (!vm->work_around_app_jni_bugs && !CheckEntry("remove", iref, idx)) { 2636c1a394b47c85c8d1723fc3b156a3b1b0b29a757Elliott Hughes return false; 2646c1a394b47c85c8d1723fc3b156a3b1b0b29a757Elliott Hughes } 2656c1a394b47c85c8d1723fc3b156a3b1b0b29a757Elliott Hughes 2666c1a394b47c85c8d1723fc3b156a3b1b0b29a757Elliott Hughes table_[idx] = NULL; 267dc51b79e65abcdad094ccd5e5a2caf5153433d49Ian Rogers int numHoles = segment_state_.parts.numHoles - prevState.parts.numHoles; 2686c1a394b47c85c8d1723fc3b156a3b1b0b29a757Elliott Hughes if (numHoles != 0) { 2696c1a394b47c85c8d1723fc3b156a3b1b0b29a757Elliott Hughes while (--topIndex > bottomIndex && numHoles != 0) { 2705a7a74a042e73a355f5cedffa0d2faf5340028faIan Rogers if (false) { 2715a7a74a042e73a355f5cedffa0d2faf5340028faIan Rogers LOG(INFO) << "+++ checking for hole at " << topIndex-1 2725a7a74a042e73a355f5cedffa0d2faf5340028faIan Rogers << " (cookie=" << cookie << ") val=" << table_[topIndex - 1]; 2735a7a74a042e73a355f5cedffa0d2faf5340028faIan Rogers } 2746c1a394b47c85c8d1723fc3b156a3b1b0b29a757Elliott Hughes if (table_[topIndex-1] != NULL) { 2756c1a394b47c85c8d1723fc3b156a3b1b0b29a757Elliott Hughes break; 2766c1a394b47c85c8d1723fc3b156a3b1b0b29a757Elliott Hughes } 2775a7a74a042e73a355f5cedffa0d2faf5340028faIan Rogers if (false) { 2785a7a74a042e73a355f5cedffa0d2faf5340028faIan Rogers LOG(INFO) << "+++ ate hole at " << (topIndex - 1); 2795a7a74a042e73a355f5cedffa0d2faf5340028faIan Rogers } 2806c1a394b47c85c8d1723fc3b156a3b1b0b29a757Elliott Hughes numHoles--; 2816c1a394b47c85c8d1723fc3b156a3b1b0b29a757Elliott Hughes } 282dc51b79e65abcdad094ccd5e5a2caf5153433d49Ian Rogers segment_state_.parts.numHoles = numHoles + prevState.parts.numHoles; 283dc51b79e65abcdad094ccd5e5a2caf5153433d49Ian Rogers segment_state_.parts.topIndex = topIndex; 2846c1a394b47c85c8d1723fc3b156a3b1b0b29a757Elliott Hughes } else { 285dc51b79e65abcdad094ccd5e5a2caf5153433d49Ian Rogers segment_state_.parts.topIndex = topIndex-1; 2865a7a74a042e73a355f5cedffa0d2faf5340028faIan Rogers if (false) { 2875a7a74a042e73a355f5cedffa0d2faf5340028faIan Rogers LOG(INFO) << "+++ ate last entry " << topIndex - 1; 2885a7a74a042e73a355f5cedffa0d2faf5340028faIan Rogers } 2896c1a394b47c85c8d1723fc3b156a3b1b0b29a757Elliott Hughes } 2906c1a394b47c85c8d1723fc3b156a3b1b0b29a757Elliott Hughes } else { 29173e66f73f5093b64f2b023ebbb85916a13d5c937Elliott Hughes // Not the top-most entry. This creates a hole. We NULL out the 29273e66f73f5093b64f2b023ebbb85916a13d5c937Elliott Hughes // entry to prevent somebody from deleting it twice and screwing up 29373e66f73f5093b64f2b023ebbb85916a13d5c937Elliott Hughes // the hole count. 2946c1a394b47c85c8d1723fc3b156a3b1b0b29a757Elliott Hughes if (table_[idx] == NULL) { 2956c1a394b47c85c8d1723fc3b156a3b1b0b29a757Elliott Hughes LOG(INFO) << "--- WEIRD: removing null entry " << idx; 2966c1a394b47c85c8d1723fc3b156a3b1b0b29a757Elliott Hughes return false; 2976c1a394b47c85c8d1723fc3b156a3b1b0b29a757Elliott Hughes } 298c5bfa8f49d8548d7c685a99b411311ef56bedffaElliott Hughes if (!vm->work_around_app_jni_bugs && !CheckEntry("remove", iref, idx)) { 2996c1a394b47c85c8d1723fc3b156a3b1b0b29a757Elliott Hughes return false; 3006c1a394b47c85c8d1723fc3b156a3b1b0b29a757Elliott Hughes } 3016c1a394b47c85c8d1723fc3b156a3b1b0b29a757Elliott Hughes 3026c1a394b47c85c8d1723fc3b156a3b1b0b29a757Elliott Hughes table_[idx] = NULL; 303dc51b79e65abcdad094ccd5e5a2caf5153433d49Ian Rogers segment_state_.parts.numHoles++; 3045a7a74a042e73a355f5cedffa0d2faf5340028faIan Rogers if (false) { 3055a7a74a042e73a355f5cedffa0d2faf5340028faIan Rogers LOG(INFO) << "+++ left hole at " << idx << ", holes=" << segment_state_.parts.numHoles; 3065a7a74a042e73a355f5cedffa0d2faf5340028faIan Rogers } 3076c1a394b47c85c8d1723fc3b156a3b1b0b29a757Elliott Hughes } 3086c1a394b47c85c8d1723fc3b156a3b1b0b29a757Elliott Hughes 3096c1a394b47c85c8d1723fc3b156a3b1b0b29a757Elliott Hughes return true; 3106c1a394b47c85c8d1723fc3b156a3b1b0b29a757Elliott Hughes} 3116c1a394b47c85c8d1723fc3b156a3b1b0b29a757Elliott Hughes 3122dd0e2cea360bc9206eb88ecc40d259e796c239dIan Rogersvoid IndirectReferenceTable::VisitRoots(RootVisitor* visitor, void* arg) { 31302e25119b15a6f619f17db99f5d05124a5807ff3Mathieu Chartier for (auto ref : *this) { 314423d2a3dcbb260b020efb5da59f784c9f02accbfMathieu Chartier *ref = visitor(const_cast<mirror::Object*>(*ref), arg); 315423d2a3dcbb260b020efb5da59f784c9f02accbfMathieu Chartier DCHECK(*ref != nullptr); 316410c0c876f326e14c176a39ba21fc4dd3f7db8abElliott Hughes } 317410c0c876f326e14c176a39ba21fc4dd3f7db8abElliott Hughes} 318410c0c876f326e14c176a39ba21fc4dd3f7db8abElliott Hughes 31973e66f73f5093b64f2b023ebbb85916a13d5c937Elliott Hughesvoid IndirectReferenceTable::Dump(std::ostream& os) const { 32073e66f73f5093b64f2b023ebbb85916a13d5c937Elliott Hughes os << kind_ << " table dump:\n"; 321423d2a3dcbb260b020efb5da59f784c9f02accbfMathieu Chartier ReferenceTable::Table entries(table_, table_ + Capacity()); 32263818dc8b06af4a1e65c41b453f1a42166c22728Ian Rogers // Remove NULLs. 32363818dc8b06af4a1e65c41b453f1a42166c22728Ian Rogers for (int i = entries.size() - 1; i >= 0; --i) { 32463818dc8b06af4a1e65c41b453f1a42166c22728Ian Rogers if (entries[i] == NULL) { 32563818dc8b06af4a1e65c41b453f1a42166c22728Ian Rogers entries.erase(entries.begin() + i); 32663818dc8b06af4a1e65c41b453f1a42166c22728Ian Rogers } 32763818dc8b06af4a1e65c41b453f1a42166c22728Ian Rogers } 32873e66f73f5093b64f2b023ebbb85916a13d5c937Elliott Hughes ReferenceTable::Dump(os, entries); 3296c1a394b47c85c8d1723fc3b156a3b1b0b29a757Elliott Hughes} 3306c1a394b47c85c8d1723fc3b156a3b1b0b29a757Elliott Hughes 3316c1a394b47c85c8d1723fc3b156a3b1b0b29a757Elliott Hughes} // namespace art 332