indirect_reference_table.cc revision 73e66f73f5093b64f2b023ebbb85916a13d5c937
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" 215a7a74a042e73a355f5cedffa0d2faf5340028faIan Rogers#include "thread.h" 22cdd1d2d3fee0711b8b11db99f2dfb80113520100Ian Rogers#include "utils.h" 236c1a394b47c85c8d1723fc3b156a3b1b0b29a757Elliott Hughes 246c1a394b47c85c8d1723fc3b156a3b1b0b29a757Elliott Hughes#include <cstdlib> 256c1a394b47c85c8d1723fc3b156a3b1b0b29a757Elliott Hughes 266c1a394b47c85c8d1723fc3b156a3b1b0b29a757Elliott Hughesnamespace art { 276c1a394b47c85c8d1723fc3b156a3b1b0b29a757Elliott Hughes 286c1a394b47c85c8d1723fc3b156a3b1b0b29a757Elliott Hughesstatic void AbortMaybe() { 29a2501990dd0f68baf38ce19251949d7bb3ecfe5aElliott Hughes // If -Xcheck:jni is on, it'll give a more detailed error before aborting. 30a2501990dd0f68baf38ce19251949d7bb3ecfe5aElliott Hughes if (!Runtime::Current()->GetJavaVM()->check_jni) { 31a2501990dd0f68baf38ce19251949d7bb3ecfe5aElliott Hughes // Otherwise, we want to abort rather than hand back a bad reference. 32a2501990dd0f68baf38ce19251949d7bb3ecfe5aElliott Hughes LOG(FATAL) << "JNI ERROR (app bug): see above."; 33a2501990dd0f68baf38ce19251949d7bb3ecfe5aElliott Hughes } 346c1a394b47c85c8d1723fc3b156a3b1b0b29a757Elliott Hughes} 356c1a394b47c85c8d1723fc3b156a3b1b0b29a757Elliott Hughes 366c1a394b47c85c8d1723fc3b156a3b1b0b29a757Elliott HughesIndirectReferenceTable::IndirectReferenceTable(size_t initialCount, 37ba8eee10607a524f43b55a6f33c13924fb16d435Elliott Hughes size_t maxCount, IndirectRefKind desiredKind) { 386c1a394b47c85c8d1723fc3b156a3b1b0b29a757Elliott Hughes CHECK_GT(initialCount, 0U); 396c1a394b47c85c8d1723fc3b156a3b1b0b29a757Elliott Hughes CHECK_LE(initialCount, maxCount); 40408f79aeb676251ba35667a64e86c20638d7cb0bIan Rogers CHECK_NE(desiredKind, kSirtOrInvalid); 416c1a394b47c85c8d1723fc3b156a3b1b0b29a757Elliott Hughes 42cf4c6c41b0084dc4567ff709fb8ce9ebd72b26acElliott Hughes table_ = reinterpret_cast<const Object**>(malloc(initialCount * sizeof(const Object*))); 436c1a394b47c85c8d1723fc3b156a3b1b0b29a757Elliott Hughes CHECK(table_ != NULL); 44cf4c6c41b0084dc4567ff709fb8ce9ebd72b26acElliott Hughes memset(table_, 0xd1, initialCount * sizeof(const Object*)); 456c1a394b47c85c8d1723fc3b156a3b1b0b29a757Elliott Hughes 466c1a394b47c85c8d1723fc3b156a3b1b0b29a757Elliott Hughes slot_data_ = reinterpret_cast<IndirectRefSlot*>(calloc(initialCount, sizeof(IndirectRefSlot))); 476c1a394b47c85c8d1723fc3b156a3b1b0b29a757Elliott Hughes CHECK(slot_data_ != NULL); 486c1a394b47c85c8d1723fc3b156a3b1b0b29a757Elliott Hughes 49dc51b79e65abcdad094ccd5e5a2caf5153433d49Ian Rogers segment_state_.all = IRT_FIRST_SEGMENT; 506c1a394b47c85c8d1723fc3b156a3b1b0b29a757Elliott Hughes alloc_entries_ = initialCount; 516c1a394b47c85c8d1723fc3b156a3b1b0b29a757Elliott Hughes max_entries_ = maxCount; 526c1a394b47c85c8d1723fc3b156a3b1b0b29a757Elliott Hughes kind_ = desiredKind; 536c1a394b47c85c8d1723fc3b156a3b1b0b29a757Elliott Hughes} 546c1a394b47c85c8d1723fc3b156a3b1b0b29a757Elliott Hughes 556c1a394b47c85c8d1723fc3b156a3b1b0b29a757Elliott HughesIndirectReferenceTable::~IndirectReferenceTable() { 566c1a394b47c85c8d1723fc3b156a3b1b0b29a757Elliott Hughes free(table_); 576c1a394b47c85c8d1723fc3b156a3b1b0b29a757Elliott Hughes free(slot_data_); 586c1a394b47c85c8d1723fc3b156a3b1b0b29a757Elliott Hughes table_ = NULL; 596c1a394b47c85c8d1723fc3b156a3b1b0b29a757Elliott Hughes slot_data_ = NULL; 606c1a394b47c85c8d1723fc3b156a3b1b0b29a757Elliott Hughes alloc_entries_ = max_entries_ = -1; 616c1a394b47c85c8d1723fc3b156a3b1b0b29a757Elliott Hughes} 626c1a394b47c85c8d1723fc3b156a3b1b0b29a757Elliott Hughes 6373e66f73f5093b64f2b023ebbb85916a13d5c937Elliott Hughes// Make sure that the entry at "idx" is correctly paired with "iref". 646c1a394b47c85c8d1723fc3b156a3b1b0b29a757Elliott Hughesbool IndirectReferenceTable::CheckEntry(const char* what, IndirectRef iref, int idx) const { 65cf4c6c41b0084dc4567ff709fb8ce9ebd72b26acElliott Hughes const Object* obj = table_[idx]; 666c1a394b47c85c8d1723fc3b156a3b1b0b29a757Elliott Hughes IndirectRef checkRef = ToIndirectRef(obj, idx); 676c1a394b47c85c8d1723fc3b156a3b1b0b29a757Elliott Hughes if (checkRef != iref) { 686c1a394b47c85c8d1723fc3b156a3b1b0b29a757Elliott Hughes LOG(ERROR) << "JNI ERROR (app bug): attempt to " << what 696c1a394b47c85c8d1723fc3b156a3b1b0b29a757Elliott Hughes << " stale " << kind_ << " " << iref 706c1a394b47c85c8d1723fc3b156a3b1b0b29a757Elliott Hughes << " (should be " << checkRef << ")"; 716c1a394b47c85c8d1723fc3b156a3b1b0b29a757Elliott Hughes AbortMaybe(); 726c1a394b47c85c8d1723fc3b156a3b1b0b29a757Elliott Hughes return false; 736c1a394b47c85c8d1723fc3b156a3b1b0b29a757Elliott Hughes } 746c1a394b47c85c8d1723fc3b156a3b1b0b29a757Elliott Hughes return true; 756c1a394b47c85c8d1723fc3b156a3b1b0b29a757Elliott Hughes} 766c1a394b47c85c8d1723fc3b156a3b1b0b29a757Elliott Hughes 77cf4c6c41b0084dc4567ff709fb8ce9ebd72b26acElliott HughesIndirectRef IndirectReferenceTable::Add(uint32_t cookie, const Object* obj) { 786c1a394b47c85c8d1723fc3b156a3b1b0b29a757Elliott Hughes IRTSegmentState prevState; 796c1a394b47c85c8d1723fc3b156a3b1b0b29a757Elliott Hughes prevState.all = cookie; 80dc51b79e65abcdad094ccd5e5a2caf5153433d49Ian Rogers size_t topIndex = segment_state_.parts.topIndex; 816c1a394b47c85c8d1723fc3b156a3b1b0b29a757Elliott Hughes 826c1a394b47c85c8d1723fc3b156a3b1b0b29a757Elliott Hughes DCHECK(obj != NULL); 83cdd1d2d3fee0711b8b11db99f2dfb80113520100Ian Rogers // TODO: stronger sanity check on the object (such as in heap) 84d07986fad0d08cdf05505cf9230714a2cf0dd9aeElliott Hughes DCHECK_ALIGNED(reinterpret_cast<uintptr_t>(obj), 8); 856c1a394b47c85c8d1723fc3b156a3b1b0b29a757Elliott Hughes DCHECK(table_ != NULL); 866c1a394b47c85c8d1723fc3b156a3b1b0b29a757Elliott Hughes DCHECK_LE(alloc_entries_, max_entries_); 87dc51b79e65abcdad094ccd5e5a2caf5153433d49Ian Rogers DCHECK_GE(segment_state_.parts.numHoles, prevState.parts.numHoles); 886c1a394b47c85c8d1723fc3b156a3b1b0b29a757Elliott Hughes 896c1a394b47c85c8d1723fc3b156a3b1b0b29a757Elliott Hughes if (topIndex == alloc_entries_) { 9073e66f73f5093b64f2b023ebbb85916a13d5c937Elliott Hughes // reached end of allocated space; did we hit buffer max? 916c1a394b47c85c8d1723fc3b156a3b1b0b29a757Elliott Hughes if (topIndex == max_entries_) { 9273e66f73f5093b64f2b023ebbb85916a13d5c937Elliott Hughes LOG(FATAL) << "JNI ERROR (app bug): " << kind_ << " table overflow " 9373e66f73f5093b64f2b023ebbb85916a13d5c937Elliott Hughes << "(max=" << max_entries_ << ")\n" 9473e66f73f5093b64f2b023ebbb85916a13d5c937Elliott Hughes << Dumpable<IndirectReferenceTable>(*this); 956c1a394b47c85c8d1723fc3b156a3b1b0b29a757Elliott Hughes } 966c1a394b47c85c8d1723fc3b156a3b1b0b29a757Elliott Hughes 976c1a394b47c85c8d1723fc3b156a3b1b0b29a757Elliott Hughes size_t newSize = alloc_entries_ * 2; 986c1a394b47c85c8d1723fc3b156a3b1b0b29a757Elliott Hughes if (newSize > max_entries_) { 996c1a394b47c85c8d1723fc3b156a3b1b0b29a757Elliott Hughes newSize = max_entries_; 1006c1a394b47c85c8d1723fc3b156a3b1b0b29a757Elliott Hughes } 1016c1a394b47c85c8d1723fc3b156a3b1b0b29a757Elliott Hughes DCHECK_GT(newSize, alloc_entries_); 1026c1a394b47c85c8d1723fc3b156a3b1b0b29a757Elliott Hughes 103ba8eee10607a524f43b55a6f33c13924fb16d435Elliott Hughes table_ = reinterpret_cast<const Object**>(realloc(table_, newSize * sizeof(const Object*))); 104ba8eee10607a524f43b55a6f33c13924fb16d435Elliott Hughes slot_data_ = reinterpret_cast<IndirectRefSlot*>(realloc(slot_data_, newSize * sizeof(IndirectRefSlot))); 1056c1a394b47c85c8d1723fc3b156a3b1b0b29a757Elliott Hughes if (table_ == NULL || slot_data_ == NULL) { 10673e66f73f5093b64f2b023ebbb85916a13d5c937Elliott Hughes LOG(FATAL) << "JNI ERROR (app bug): unable to expand " 1076c1a394b47c85c8d1723fc3b156a3b1b0b29a757Elliott Hughes << kind_ << " table (from " 1086c1a394b47c85c8d1723fc3b156a3b1b0b29a757Elliott Hughes << alloc_entries_ << " to " << newSize 10973e66f73f5093b64f2b023ebbb85916a13d5c937Elliott Hughes << ", max=" << max_entries_ << ")\n" 11073e66f73f5093b64f2b023ebbb85916a13d5c937Elliott Hughes << Dumpable<IndirectReferenceTable>(*this); 1116c1a394b47c85c8d1723fc3b156a3b1b0b29a757Elliott Hughes } 1126c1a394b47c85c8d1723fc3b156a3b1b0b29a757Elliott Hughes 1136c1a394b47c85c8d1723fc3b156a3b1b0b29a757Elliott Hughes // Clear the newly-allocated slot_data_ elements. 1146c1a394b47c85c8d1723fc3b156a3b1b0b29a757Elliott Hughes memset(slot_data_ + alloc_entries_, 0, (newSize - alloc_entries_) * sizeof(IndirectRefSlot)); 1156c1a394b47c85c8d1723fc3b156a3b1b0b29a757Elliott Hughes 1166c1a394b47c85c8d1723fc3b156a3b1b0b29a757Elliott Hughes alloc_entries_ = newSize; 1176c1a394b47c85c8d1723fc3b156a3b1b0b29a757Elliott Hughes } 1186c1a394b47c85c8d1723fc3b156a3b1b0b29a757Elliott Hughes 11973e66f73f5093b64f2b023ebbb85916a13d5c937Elliott Hughes // We know there's enough room in the table. Now we just need to find 12073e66f73f5093b64f2b023ebbb85916a13d5c937Elliott Hughes // the right spot. If there's a hole, find it and fill it; otherwise, 12173e66f73f5093b64f2b023ebbb85916a13d5c937Elliott Hughes // add to the end of the list. 1226c1a394b47c85c8d1723fc3b156a3b1b0b29a757Elliott Hughes IndirectRef result; 123dc51b79e65abcdad094ccd5e5a2caf5153433d49Ian Rogers int numHoles = segment_state_.parts.numHoles - prevState.parts.numHoles; 1246c1a394b47c85c8d1723fc3b156a3b1b0b29a757Elliott Hughes if (numHoles > 0) { 1256c1a394b47c85c8d1723fc3b156a3b1b0b29a757Elliott Hughes DCHECK_GT(topIndex, 1U); 12673e66f73f5093b64f2b023ebbb85916a13d5c937Elliott Hughes // Find the first hole; likely to be near the end of the list. 127cf4c6c41b0084dc4567ff709fb8ce9ebd72b26acElliott Hughes const Object** pScan = &table_[topIndex - 1]; 1286c1a394b47c85c8d1723fc3b156a3b1b0b29a757Elliott Hughes DCHECK(*pScan != NULL); 1296c1a394b47c85c8d1723fc3b156a3b1b0b29a757Elliott Hughes while (*--pScan != NULL) { 1306c1a394b47c85c8d1723fc3b156a3b1b0b29a757Elliott Hughes DCHECK_GE(pScan, table_ + prevState.parts.topIndex); 1316c1a394b47c85c8d1723fc3b156a3b1b0b29a757Elliott Hughes } 1326c1a394b47c85c8d1723fc3b156a3b1b0b29a757Elliott Hughes UpdateSlotAdd(obj, pScan - table_); 1336c1a394b47c85c8d1723fc3b156a3b1b0b29a757Elliott Hughes result = ToIndirectRef(obj, pScan - table_); 1346c1a394b47c85c8d1723fc3b156a3b1b0b29a757Elliott Hughes *pScan = obj; 135dc51b79e65abcdad094ccd5e5a2caf5153433d49Ian Rogers segment_state_.parts.numHoles--; 1366c1a394b47c85c8d1723fc3b156a3b1b0b29a757Elliott Hughes } else { 13773e66f73f5093b64f2b023ebbb85916a13d5c937Elliott Hughes // Add to the end. 1386c1a394b47c85c8d1723fc3b156a3b1b0b29a757Elliott Hughes UpdateSlotAdd(obj, topIndex); 1396c1a394b47c85c8d1723fc3b156a3b1b0b29a757Elliott Hughes result = ToIndirectRef(obj, topIndex); 1406c1a394b47c85c8d1723fc3b156a3b1b0b29a757Elliott Hughes table_[topIndex++] = obj; 141dc51b79e65abcdad094ccd5e5a2caf5153433d49Ian Rogers segment_state_.parts.topIndex = topIndex; 1426c1a394b47c85c8d1723fc3b156a3b1b0b29a757Elliott Hughes } 1435a7a74a042e73a355f5cedffa0d2faf5340028faIan Rogers if (false) { 1445a7a74a042e73a355f5cedffa0d2faf5340028faIan Rogers LOG(INFO) << "+++ added at " << ExtractIndex(result) << " top=" << segment_state_.parts.topIndex 1455a7a74a042e73a355f5cedffa0d2faf5340028faIan Rogers << " holes=" << segment_state_.parts.numHoles; 1465a7a74a042e73a355f5cedffa0d2faf5340028faIan Rogers } 1476c1a394b47c85c8d1723fc3b156a3b1b0b29a757Elliott Hughes 1486c1a394b47c85c8d1723fc3b156a3b1b0b29a757Elliott Hughes DCHECK(result != NULL); 1496c1a394b47c85c8d1723fc3b156a3b1b0b29a757Elliott Hughes return result; 1506c1a394b47c85c8d1723fc3b156a3b1b0b29a757Elliott Hughes} 1516c1a394b47c85c8d1723fc3b156a3b1b0b29a757Elliott Hughes 152726079d3e2e50854cd6ca4c393f4529a796dba58Elliott Hughesvoid IndirectReferenceTable::AssertEmpty() { 153726079d3e2e50854cd6ca4c393f4529a796dba58Elliott Hughes if (begin() != end()) { 15473e66f73f5093b64f2b023ebbb85916a13d5c937Elliott Hughes LOG(FATAL) << "Internal Error: non-empty local reference table\n" 15573e66f73f5093b64f2b023ebbb85916a13d5c937Elliott Hughes << Dumpable<IndirectReferenceTable>(*this); 156726079d3e2e50854cd6ca4c393f4529a796dba58Elliott Hughes } 157726079d3e2e50854cd6ca4c393f4529a796dba58Elliott Hughes} 158726079d3e2e50854cd6ca4c393f4529a796dba58Elliott Hughes 15973e66f73f5093b64f2b023ebbb85916a13d5c937Elliott Hughes// Verifies that the indirect table lookup is valid. 16073e66f73f5093b64f2b023ebbb85916a13d5c937Elliott Hughes// Returns "false" if something looks bad. 1616c1a394b47c85c8d1723fc3b156a3b1b0b29a757Elliott Hughesbool IndirectReferenceTable::GetChecked(IndirectRef iref) const { 1626c1a394b47c85c8d1723fc3b156a3b1b0b29a757Elliott Hughes if (iref == NULL) { 1636c1a394b47c85c8d1723fc3b156a3b1b0b29a757Elliott Hughes LOG(WARNING) << "Attempt to look up NULL " << kind_; 1646c1a394b47c85c8d1723fc3b156a3b1b0b29a757Elliott Hughes return false; 1656c1a394b47c85c8d1723fc3b156a3b1b0b29a757Elliott Hughes } 166408f79aeb676251ba35667a64e86c20638d7cb0bIan Rogers if (GetIndirectRefKind(iref) == kSirtOrInvalid) { 1676c1a394b47c85c8d1723fc3b156a3b1b0b29a757Elliott Hughes LOG(ERROR) << "JNI ERROR (app bug): invalid " << kind_ << " " << iref; 1686c1a394b47c85c8d1723fc3b156a3b1b0b29a757Elliott Hughes AbortMaybe(); 1696c1a394b47c85c8d1723fc3b156a3b1b0b29a757Elliott Hughes return false; 1706c1a394b47c85c8d1723fc3b156a3b1b0b29a757Elliott Hughes } 1716c1a394b47c85c8d1723fc3b156a3b1b0b29a757Elliott Hughes 172dc51b79e65abcdad094ccd5e5a2caf5153433d49Ian Rogers int topIndex = segment_state_.parts.topIndex; 1736c1a394b47c85c8d1723fc3b156a3b1b0b29a757Elliott Hughes int idx = ExtractIndex(iref); 1746c1a394b47c85c8d1723fc3b156a3b1b0b29a757Elliott Hughes if (idx >= topIndex) { 1755a7a74a042e73a355f5cedffa0d2faf5340028faIan Rogers LOG(ERROR) << "JNI ERROR (app bug): accessed stale " << kind_ << " " 1765a7a74a042e73a355f5cedffa0d2faf5340028faIan Rogers << iref << " (index " << idx << " in a table of size " << topIndex << ")"; 1776c1a394b47c85c8d1723fc3b156a3b1b0b29a757Elliott Hughes AbortMaybe(); 1786c1a394b47c85c8d1723fc3b156a3b1b0b29a757Elliott Hughes return false; 1796c1a394b47c85c8d1723fc3b156a3b1b0b29a757Elliott Hughes } 1806c1a394b47c85c8d1723fc3b156a3b1b0b29a757Elliott Hughes 1816c1a394b47c85c8d1723fc3b156a3b1b0b29a757Elliott Hughes if (table_[idx] == NULL) { 1826c1a394b47c85c8d1723fc3b156a3b1b0b29a757Elliott Hughes LOG(ERROR) << "JNI ERROR (app bug): accessed deleted " << kind_ << " " << iref; 1836c1a394b47c85c8d1723fc3b156a3b1b0b29a757Elliott Hughes AbortMaybe(); 1846c1a394b47c85c8d1723fc3b156a3b1b0b29a757Elliott Hughes return false; 1856c1a394b47c85c8d1723fc3b156a3b1b0b29a757Elliott Hughes } 1866c1a394b47c85c8d1723fc3b156a3b1b0b29a757Elliott Hughes 1876c1a394b47c85c8d1723fc3b156a3b1b0b29a757Elliott Hughes if (!CheckEntry("use", iref, idx)) { 1886c1a394b47c85c8d1723fc3b156a3b1b0b29a757Elliott Hughes return false; 1896c1a394b47c85c8d1723fc3b156a3b1b0b29a757Elliott Hughes } 1906c1a394b47c85c8d1723fc3b156a3b1b0b29a757Elliott Hughes 1916c1a394b47c85c8d1723fc3b156a3b1b0b29a757Elliott Hughes return true; 1926c1a394b47c85c8d1723fc3b156a3b1b0b29a757Elliott Hughes} 1936c1a394b47c85c8d1723fc3b156a3b1b0b29a757Elliott Hughes 1942ced6a534157d5d963693346904389c19775d2daElliott Hughesstatic int Find(Object* direct_pointer, int bottomIndex, int topIndex, const Object** table) { 1956c1a394b47c85c8d1723fc3b156a3b1b0b29a757Elliott Hughes for (int i = bottomIndex; i < topIndex; ++i) { 1962ced6a534157d5d963693346904389c19775d2daElliott Hughes if (table[i] == direct_pointer) { 1976c1a394b47c85c8d1723fc3b156a3b1b0b29a757Elliott Hughes return i; 1986c1a394b47c85c8d1723fc3b156a3b1b0b29a757Elliott Hughes } 1996c1a394b47c85c8d1723fc3b156a3b1b0b29a757Elliott Hughes } 2006c1a394b47c85c8d1723fc3b156a3b1b0b29a757Elliott Hughes return -1; 2016c1a394b47c85c8d1723fc3b156a3b1b0b29a757Elliott Hughes} 2026c1a394b47c85c8d1723fc3b156a3b1b0b29a757Elliott Hughes 2032ced6a534157d5d963693346904389c19775d2daElliott Hughesbool IndirectReferenceTable::ContainsDirectPointer(Object* direct_pointer) const { 2042ced6a534157d5d963693346904389c19775d2daElliott Hughes return Find(direct_pointer, 0, segment_state_.parts.topIndex, table_) != -1; 2056c1a394b47c85c8d1723fc3b156a3b1b0b29a757Elliott Hughes} 2066c1a394b47c85c8d1723fc3b156a3b1b0b29a757Elliott Hughes 20773e66f73f5093b64f2b023ebbb85916a13d5c937Elliott Hughes// Removes an object. We extract the table offset bits from "iref" 20873e66f73f5093b64f2b023ebbb85916a13d5c937Elliott Hughes// and zap the corresponding entry, leaving a hole if it's not at the top. 20973e66f73f5093b64f2b023ebbb85916a13d5c937Elliott Hughes// If the entry is not between the current top index and the bottom index 21073e66f73f5093b64f2b023ebbb85916a13d5c937Elliott Hughes// specified by the cookie, we don't remove anything. This is the behavior 21173e66f73f5093b64f2b023ebbb85916a13d5c937Elliott Hughes// required by JNI's DeleteLocalRef function. 21273e66f73f5093b64f2b023ebbb85916a13d5c937Elliott Hughes// This method is not called when a local frame is popped; this is only used 21373e66f73f5093b64f2b023ebbb85916a13d5c937Elliott Hughes// for explicit single removals. 21473e66f73f5093b64f2b023ebbb85916a13d5c937Elliott Hughes// Returns "false" if nothing was removed. 2156c1a394b47c85c8d1723fc3b156a3b1b0b29a757Elliott Hughesbool IndirectReferenceTable::Remove(uint32_t cookie, IndirectRef iref) { 2166c1a394b47c85c8d1723fc3b156a3b1b0b29a757Elliott Hughes IRTSegmentState prevState; 2176c1a394b47c85c8d1723fc3b156a3b1b0b29a757Elliott Hughes prevState.all = cookie; 218dc51b79e65abcdad094ccd5e5a2caf5153433d49Ian Rogers int topIndex = segment_state_.parts.topIndex; 2196c1a394b47c85c8d1723fc3b156a3b1b0b29a757Elliott Hughes int bottomIndex = prevState.parts.topIndex; 2206c1a394b47c85c8d1723fc3b156a3b1b0b29a757Elliott Hughes 2216c1a394b47c85c8d1723fc3b156a3b1b0b29a757Elliott Hughes DCHECK(table_ != NULL); 2226c1a394b47c85c8d1723fc3b156a3b1b0b29a757Elliott Hughes DCHECK_LE(alloc_entries_, max_entries_); 223dc51b79e65abcdad094ccd5e5a2caf5153433d49Ian Rogers DCHECK_GE(segment_state_.parts.numHoles, prevState.parts.numHoles); 2246c1a394b47c85c8d1723fc3b156a3b1b0b29a757Elliott Hughes 2256c1a394b47c85c8d1723fc3b156a3b1b0b29a757Elliott Hughes int idx = ExtractIndex(iref); 2266c1a394b47c85c8d1723fc3b156a3b1b0b29a757Elliott Hughes 227c5bfa8f49d8548d7c685a99b411311ef56bedffaElliott Hughes JavaVMExt* vm = Runtime::Current()->GetJavaVM(); 2285a7a74a042e73a355f5cedffa0d2faf5340028faIan Rogers if (GetIndirectRefKind(iref) == kSirtOrInvalid && 22928f1a147d77ec772db98bed890b50a9ddcff2365TDYa Thread::Current()->StackReferencesContain(reinterpret_cast<jobject>(iref))) { 2305a7a74a042e73a355f5cedffa0d2faf5340028faIan Rogers LOG(WARNING) << "Attempt to remove local SIRT entry from IRT, ignoring"; 2315a7a74a042e73a355f5cedffa0d2faf5340028faIan Rogers return true; 2325a7a74a042e73a355f5cedffa0d2faf5340028faIan Rogers } 233467c9699c3de467f76f03494a9389ebba285cb6cIan Rogers if (GetIndirectRefKind(iref) == kSirtOrInvalid && vm->work_around_app_jni_bugs) { 2342ced6a534157d5d963693346904389c19775d2daElliott Hughes Object* direct_pointer = reinterpret_cast<Object*>(iref); 2352ced6a534157d5d963693346904389c19775d2daElliott Hughes idx = Find(direct_pointer, bottomIndex, topIndex, table_); 2366c1a394b47c85c8d1723fc3b156a3b1b0b29a757Elliott Hughes if (idx == -1) { 2376c1a394b47c85c8d1723fc3b156a3b1b0b29a757Elliott Hughes LOG(WARNING) << "trying to work around app JNI bugs, but didn't find " << iref << " in table!"; 2386c1a394b47c85c8d1723fc3b156a3b1b0b29a757Elliott Hughes return false; 2396c1a394b47c85c8d1723fc3b156a3b1b0b29a757Elliott Hughes } 2406c1a394b47c85c8d1723fc3b156a3b1b0b29a757Elliott Hughes } 2416c1a394b47c85c8d1723fc3b156a3b1b0b29a757Elliott Hughes 2426c1a394b47c85c8d1723fc3b156a3b1b0b29a757Elliott Hughes if (idx < bottomIndex) { 243726079d3e2e50854cd6ca4c393f4529a796dba58Elliott Hughes // Wrong segment. 244726079d3e2e50854cd6ca4c393f4529a796dba58Elliott Hughes LOG(WARNING) << "Attempt to remove index outside index area (" << idx 245726079d3e2e50854cd6ca4c393f4529a796dba58Elliott Hughes << " vs " << bottomIndex << "-" << topIndex << ")"; 2466c1a394b47c85c8d1723fc3b156a3b1b0b29a757Elliott Hughes return false; 2476c1a394b47c85c8d1723fc3b156a3b1b0b29a757Elliott Hughes } 2486c1a394b47c85c8d1723fc3b156a3b1b0b29a757Elliott Hughes if (idx >= topIndex) { 249726079d3e2e50854cd6ca4c393f4529a796dba58Elliott Hughes // Bad --- stale reference? 250726079d3e2e50854cd6ca4c393f4529a796dba58Elliott Hughes LOG(WARNING) << "Attempt to remove invalid index " << idx 251726079d3e2e50854cd6ca4c393f4529a796dba58Elliott Hughes << " (bottom=" << bottomIndex << " top=" << topIndex << ")"; 2526c1a394b47c85c8d1723fc3b156a3b1b0b29a757Elliott Hughes return false; 2536c1a394b47c85c8d1723fc3b156a3b1b0b29a757Elliott Hughes } 2546c1a394b47c85c8d1723fc3b156a3b1b0b29a757Elliott Hughes 2556c1a394b47c85c8d1723fc3b156a3b1b0b29a757Elliott Hughes if (idx == topIndex-1) { 2566c1a394b47c85c8d1723fc3b156a3b1b0b29a757Elliott Hughes // Top-most entry. Scan up and consume holes. 2576c1a394b47c85c8d1723fc3b156a3b1b0b29a757Elliott Hughes 258c5bfa8f49d8548d7c685a99b411311ef56bedffaElliott Hughes if (!vm->work_around_app_jni_bugs && !CheckEntry("remove", iref, idx)) { 2596c1a394b47c85c8d1723fc3b156a3b1b0b29a757Elliott Hughes return false; 2606c1a394b47c85c8d1723fc3b156a3b1b0b29a757Elliott Hughes } 2616c1a394b47c85c8d1723fc3b156a3b1b0b29a757Elliott Hughes 2626c1a394b47c85c8d1723fc3b156a3b1b0b29a757Elliott Hughes table_[idx] = NULL; 263dc51b79e65abcdad094ccd5e5a2caf5153433d49Ian Rogers int numHoles = segment_state_.parts.numHoles - prevState.parts.numHoles; 2646c1a394b47c85c8d1723fc3b156a3b1b0b29a757Elliott Hughes if (numHoles != 0) { 2656c1a394b47c85c8d1723fc3b156a3b1b0b29a757Elliott Hughes while (--topIndex > bottomIndex && numHoles != 0) { 2665a7a74a042e73a355f5cedffa0d2faf5340028faIan Rogers if (false) { 2675a7a74a042e73a355f5cedffa0d2faf5340028faIan Rogers LOG(INFO) << "+++ checking for hole at " << topIndex-1 2685a7a74a042e73a355f5cedffa0d2faf5340028faIan Rogers << " (cookie=" << cookie << ") val=" << table_[topIndex - 1]; 2695a7a74a042e73a355f5cedffa0d2faf5340028faIan Rogers } 2706c1a394b47c85c8d1723fc3b156a3b1b0b29a757Elliott Hughes if (table_[topIndex-1] != NULL) { 2716c1a394b47c85c8d1723fc3b156a3b1b0b29a757Elliott Hughes break; 2726c1a394b47c85c8d1723fc3b156a3b1b0b29a757Elliott Hughes } 2735a7a74a042e73a355f5cedffa0d2faf5340028faIan Rogers if (false) { 2745a7a74a042e73a355f5cedffa0d2faf5340028faIan Rogers LOG(INFO) << "+++ ate hole at " << (topIndex - 1); 2755a7a74a042e73a355f5cedffa0d2faf5340028faIan Rogers } 2766c1a394b47c85c8d1723fc3b156a3b1b0b29a757Elliott Hughes numHoles--; 2776c1a394b47c85c8d1723fc3b156a3b1b0b29a757Elliott Hughes } 278dc51b79e65abcdad094ccd5e5a2caf5153433d49Ian Rogers segment_state_.parts.numHoles = numHoles + prevState.parts.numHoles; 279dc51b79e65abcdad094ccd5e5a2caf5153433d49Ian Rogers segment_state_.parts.topIndex = topIndex; 2806c1a394b47c85c8d1723fc3b156a3b1b0b29a757Elliott Hughes } else { 281dc51b79e65abcdad094ccd5e5a2caf5153433d49Ian Rogers segment_state_.parts.topIndex = topIndex-1; 2825a7a74a042e73a355f5cedffa0d2faf5340028faIan Rogers if (false) { 2835a7a74a042e73a355f5cedffa0d2faf5340028faIan Rogers LOG(INFO) << "+++ ate last entry " << topIndex - 1; 2845a7a74a042e73a355f5cedffa0d2faf5340028faIan Rogers } 2856c1a394b47c85c8d1723fc3b156a3b1b0b29a757Elliott Hughes } 2866c1a394b47c85c8d1723fc3b156a3b1b0b29a757Elliott Hughes } else { 28773e66f73f5093b64f2b023ebbb85916a13d5c937Elliott Hughes // Not the top-most entry. This creates a hole. We NULL out the 28873e66f73f5093b64f2b023ebbb85916a13d5c937Elliott Hughes // entry to prevent somebody from deleting it twice and screwing up 28973e66f73f5093b64f2b023ebbb85916a13d5c937Elliott Hughes // the hole count. 2906c1a394b47c85c8d1723fc3b156a3b1b0b29a757Elliott Hughes if (table_[idx] == NULL) { 2916c1a394b47c85c8d1723fc3b156a3b1b0b29a757Elliott Hughes LOG(INFO) << "--- WEIRD: removing null entry " << idx; 2926c1a394b47c85c8d1723fc3b156a3b1b0b29a757Elliott Hughes return false; 2936c1a394b47c85c8d1723fc3b156a3b1b0b29a757Elliott Hughes } 294c5bfa8f49d8548d7c685a99b411311ef56bedffaElliott Hughes if (!vm->work_around_app_jni_bugs && !CheckEntry("remove", iref, idx)) { 2956c1a394b47c85c8d1723fc3b156a3b1b0b29a757Elliott Hughes return false; 2966c1a394b47c85c8d1723fc3b156a3b1b0b29a757Elliott Hughes } 2976c1a394b47c85c8d1723fc3b156a3b1b0b29a757Elliott Hughes 2986c1a394b47c85c8d1723fc3b156a3b1b0b29a757Elliott Hughes table_[idx] = NULL; 299dc51b79e65abcdad094ccd5e5a2caf5153433d49Ian Rogers segment_state_.parts.numHoles++; 3005a7a74a042e73a355f5cedffa0d2faf5340028faIan Rogers if (false) { 3015a7a74a042e73a355f5cedffa0d2faf5340028faIan Rogers LOG(INFO) << "+++ left hole at " << idx << ", holes=" << segment_state_.parts.numHoles; 3025a7a74a042e73a355f5cedffa0d2faf5340028faIan Rogers } 3036c1a394b47c85c8d1723fc3b156a3b1b0b29a757Elliott Hughes } 3046c1a394b47c85c8d1723fc3b156a3b1b0b29a757Elliott Hughes 3056c1a394b47c85c8d1723fc3b156a3b1b0b29a757Elliott Hughes return true; 3066c1a394b47c85c8d1723fc3b156a3b1b0b29a757Elliott Hughes} 3076c1a394b47c85c8d1723fc3b156a3b1b0b29a757Elliott Hughes 308410c0c876f326e14c176a39ba21fc4dd3f7db8abElliott Hughesvoid IndirectReferenceTable::VisitRoots(Heap::RootVisitor* visitor, void* arg) { 309410c0c876f326e14c176a39ba21fc4dd3f7db8abElliott Hughes typedef IndirectReferenceTable::iterator It; // TODO: C++0x auto 310410c0c876f326e14c176a39ba21fc4dd3f7db8abElliott Hughes for (It it = begin(), end = this->end(); it != end; ++it) { 311410c0c876f326e14c176a39ba21fc4dd3f7db8abElliott Hughes visitor(**it, arg); 312410c0c876f326e14c176a39ba21fc4dd3f7db8abElliott Hughes } 313410c0c876f326e14c176a39ba21fc4dd3f7db8abElliott Hughes} 314410c0c876f326e14c176a39ba21fc4dd3f7db8abElliott Hughes 31573e66f73f5093b64f2b023ebbb85916a13d5c937Elliott Hughesvoid IndirectReferenceTable::Dump(std::ostream& os) const { 31673e66f73f5093b64f2b023ebbb85916a13d5c937Elliott Hughes os << kind_ << " table dump:\n"; 3177577075b147fd8fa37ca41e7a32d1124676776ceElliott Hughes std::vector<const Object*> entries(table_, table_ + Capacity()); 31873e66f73f5093b64f2b023ebbb85916a13d5c937Elliott Hughes ReferenceTable::Dump(os, entries); 3196c1a394b47c85c8d1723fc3b156a3b1b0b29a757Elliott Hughes} 3206c1a394b47c85c8d1723fc3b156a3b1b0b29a757Elliott Hughes 3216c1a394b47c85c8d1723fc3b156a3b1b0b29a757Elliott Hughes} // namespace art 322