1734155efc18543eab20b763f9a315ab1a44240acAndy McFadden/* 2734155efc18543eab20b763f9a315ab1a44240acAndy McFadden * Copyright (C) 2009 The Android Open Source Project 3734155efc18543eab20b763f9a315ab1a44240acAndy McFadden * 4734155efc18543eab20b763f9a315ab1a44240acAndy McFadden * Licensed under the Apache License, Version 2.0 (the "License"); 5734155efc18543eab20b763f9a315ab1a44240acAndy McFadden * you may not use this file except in compliance with the License. 6734155efc18543eab20b763f9a315ab1a44240acAndy McFadden * You may obtain a copy of the License at 7734155efc18543eab20b763f9a315ab1a44240acAndy McFadden * 8734155efc18543eab20b763f9a315ab1a44240acAndy McFadden * http://www.apache.org/licenses/LICENSE-2.0 9734155efc18543eab20b763f9a315ab1a44240acAndy McFadden * 10734155efc18543eab20b763f9a315ab1a44240acAndy McFadden * Unless required by applicable law or agreed to in writing, software 11734155efc18543eab20b763f9a315ab1a44240acAndy McFadden * distributed under the License is distributed on an "AS IS" BASIS, 12734155efc18543eab20b763f9a315ab1a44240acAndy McFadden * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13734155efc18543eab20b763f9a315ab1a44240acAndy McFadden * See the License for the specific language governing permissions and 14734155efc18543eab20b763f9a315ab1a44240acAndy McFadden * limitations under the License. 15734155efc18543eab20b763f9a315ab1a44240acAndy McFadden */ 16734155efc18543eab20b763f9a315ab1a44240acAndy McFadden 17734155efc18543eab20b763f9a315ab1a44240acAndy McFadden/* 18734155efc18543eab20b763f9a315ab1a44240acAndy McFadden * Indirect reference table management. 19734155efc18543eab20b763f9a315ab1a44240acAndy McFadden */ 20734155efc18543eab20b763f9a315ab1a44240acAndy McFadden#include "Dalvik.h" 21734155efc18543eab20b763f9a315ab1a44240acAndy McFadden 2224c57f1d575fccc11239cf71089c7d04270a21c3Elliott Hughesstatic void abortMaybe() { 2324c57f1d575fccc11239cf71089c7d04270a21c3Elliott Hughes // If CheckJNI is on, it'll give a more detailed error before aborting. 2424c57f1d575fccc11239cf71089c7d04270a21c3Elliott Hughes // Otherwise, we want to abort rather than hand back a bad reference. 2524c57f1d575fccc11239cf71089c7d04270a21c3Elliott Hughes if (!gDvmJni.useCheckJni) { 2624c57f1d575fccc11239cf71089c7d04270a21c3Elliott Hughes dvmAbort(); 2724c57f1d575fccc11239cf71089c7d04270a21c3Elliott Hughes } 2824c57f1d575fccc11239cf71089c7d04270a21c3Elliott Hughes} 2924c57f1d575fccc11239cf71089c7d04270a21c3Elliott Hughes 30ce0968340f9ddd54f20e38d4946bfd2ef8f1f343Elliott Hughesbool IndirectRefTable::init(size_t initialCount, 31ce0968340f9ddd54f20e38d4946bfd2ef8f1f343Elliott Hughes size_t maxCount, IndirectRefKind desiredKind) 32734155efc18543eab20b763f9a315ab1a44240acAndy McFadden{ 33734155efc18543eab20b763f9a315ab1a44240acAndy McFadden assert(initialCount > 0); 34734155efc18543eab20b763f9a315ab1a44240acAndy McFadden assert(initialCount <= maxCount); 35b27341588c31ede077762de4c200049abc0417aaElliott Hughes assert(desiredKind != kIndirectKindInvalid); 36734155efc18543eab20b763f9a315ab1a44240acAndy McFadden 375552e62455d486d19e5986a67ae2545411d50fbeJeff Brown table_ = (IndirectRefSlot*) malloc(initialCount * sizeof(IndirectRefSlot)); 38b27341588c31ede077762de4c200049abc0417aaElliott Hughes if (table_ == NULL) { 39734155efc18543eab20b763f9a315ab1a44240acAndy McFadden return false; 40ce0968340f9ddd54f20e38d4946bfd2ef8f1f343Elliott Hughes } 415552e62455d486d19e5986a67ae2545411d50fbeJeff Brown memset(table_, 0xd1, initialCount * sizeof(IndirectRefSlot)); 425d599603ea3d759aabe9a6b274c11b76191d1792Andy McFadden 43ce0968340f9ddd54f20e38d4946bfd2ef8f1f343Elliott Hughes segmentState.all = IRT_FIRST_SEGMENT; 44b27341588c31ede077762de4c200049abc0417aaElliott Hughes alloc_entries_ = initialCount; 45b27341588c31ede077762de4c200049abc0417aaElliott Hughes max_entries_ = maxCount; 46b27341588c31ede077762de4c200049abc0417aaElliott Hughes kind_ = desiredKind; 47734155efc18543eab20b763f9a315ab1a44240acAndy McFadden 48734155efc18543eab20b763f9a315ab1a44240acAndy McFadden return true; 49734155efc18543eab20b763f9a315ab1a44240acAndy McFadden} 50734155efc18543eab20b763f9a315ab1a44240acAndy McFadden 51734155efc18543eab20b763f9a315ab1a44240acAndy McFadden/* 52734155efc18543eab20b763f9a315ab1a44240acAndy McFadden * Clears out the contents of a IndirectRefTable, freeing allocated storage. 53734155efc18543eab20b763f9a315ab1a44240acAndy McFadden */ 54ce0968340f9ddd54f20e38d4946bfd2ef8f1f343Elliott Hughesvoid IndirectRefTable::destroy() 55734155efc18543eab20b763f9a315ab1a44240acAndy McFadden{ 56b27341588c31ede077762de4c200049abc0417aaElliott Hughes free(table_); 57b27341588c31ede077762de4c200049abc0417aaElliott Hughes table_ = NULL; 58b27341588c31ede077762de4c200049abc0417aaElliott Hughes alloc_entries_ = max_entries_ = -1; 59734155efc18543eab20b763f9a315ab1a44240acAndy McFadden} 60734155efc18543eab20b763f9a315ab1a44240acAndy McFadden 61ce0968340f9ddd54f20e38d4946bfd2ef8f1f343Elliott HughesIndirectRef IndirectRefTable::add(u4 cookie, Object* obj) 62734155efc18543eab20b763f9a315ab1a44240acAndy McFadden{ 63734155efc18543eab20b763f9a315ab1a44240acAndy McFadden IRTSegmentState prevState; 64734155efc18543eab20b763f9a315ab1a44240acAndy McFadden prevState.all = cookie; 65ce0968340f9ddd54f20e38d4946bfd2ef8f1f343Elliott Hughes size_t topIndex = segmentState.parts.topIndex; 66734155efc18543eab20b763f9a315ab1a44240acAndy McFadden 67734155efc18543eab20b763f9a315ab1a44240acAndy McFadden assert(obj != NULL); 688bc8bf71a52e17d483021b4c9dc8e735d9bce3edElliott Hughes assert(dvmIsHeapAddress(obj)); 69b27341588c31ede077762de4c200049abc0417aaElliott Hughes assert(table_ != NULL); 70b27341588c31ede077762de4c200049abc0417aaElliott Hughes assert(alloc_entries_ <= max_entries_); 71ce0968340f9ddd54f20e38d4946bfd2ef8f1f343Elliott Hughes assert(segmentState.parts.numHoles >= prevState.parts.numHoles); 72734155efc18543eab20b763f9a315ab1a44240acAndy McFadden 73734155efc18543eab20b763f9a315ab1a44240acAndy McFadden /* 74734155efc18543eab20b763f9a315ab1a44240acAndy McFadden * We know there's enough room in the table. Now we just need to find 75734155efc18543eab20b763f9a315ab1a44240acAndy McFadden * the right spot. If there's a hole, find it and fill it; otherwise, 76734155efc18543eab20b763f9a315ab1a44240acAndy McFadden * add to the end of the list. 77734155efc18543eab20b763f9a315ab1a44240acAndy McFadden */ 78259a8a5154c63a793ea0ee438d146acda7d990b6Elliott Hughes IndirectRef result; 795552e62455d486d19e5986a67ae2545411d50fbeJeff Brown IndirectRefSlot* slot; 80ce0968340f9ddd54f20e38d4946bfd2ef8f1f343Elliott Hughes int numHoles = segmentState.parts.numHoles - prevState.parts.numHoles; 81734155efc18543eab20b763f9a315ab1a44240acAndy McFadden if (numHoles > 0) { 82734155efc18543eab20b763f9a315ab1a44240acAndy McFadden assert(topIndex > 1); 835552e62455d486d19e5986a67ae2545411d50fbeJeff Brown /* find the first hole; likely to be near the end of the list, 845552e62455d486d19e5986a67ae2545411d50fbeJeff Brown * we know the item at the topIndex is not a hole */ 855552e62455d486d19e5986a67ae2545411d50fbeJeff Brown slot = &table_[topIndex - 1]; 865552e62455d486d19e5986a67ae2545411d50fbeJeff Brown assert(slot->obj != NULL); 875552e62455d486d19e5986a67ae2545411d50fbeJeff Brown while ((--slot)->obj != NULL) { 885552e62455d486d19e5986a67ae2545411d50fbeJeff Brown assert(slot >= table_ + prevState.parts.topIndex); 89734155efc18543eab20b763f9a315ab1a44240acAndy McFadden } 90ce0968340f9ddd54f20e38d4946bfd2ef8f1f343Elliott Hughes segmentState.parts.numHoles--; 91734155efc18543eab20b763f9a315ab1a44240acAndy McFadden } else { 925552e62455d486d19e5986a67ae2545411d50fbeJeff Brown /* add to the end, grow if needed */ 935552e62455d486d19e5986a67ae2545411d50fbeJeff Brown if (topIndex == alloc_entries_) { 945552e62455d486d19e5986a67ae2545411d50fbeJeff Brown /* reached end of allocated space; did we hit buffer max? */ 955552e62455d486d19e5986a67ae2545411d50fbeJeff Brown if (topIndex == max_entries_) { 96c1a4ab9c313d8a3d12007f2dbef7b5a6fa4ac2efSteve Block ALOGE("JNI ERROR (app bug): %s reference table overflow (max=%d)", 975552e62455d486d19e5986a67ae2545411d50fbeJeff Brown indirectRefKindToString(kind_), max_entries_); 985552e62455d486d19e5986a67ae2545411d50fbeJeff Brown return NULL; 995552e62455d486d19e5986a67ae2545411d50fbeJeff Brown } 1005552e62455d486d19e5986a67ae2545411d50fbeJeff Brown 1015552e62455d486d19e5986a67ae2545411d50fbeJeff Brown size_t newSize = alloc_entries_ * 2; 1025552e62455d486d19e5986a67ae2545411d50fbeJeff Brown if (newSize > max_entries_) { 1035552e62455d486d19e5986a67ae2545411d50fbeJeff Brown newSize = max_entries_; 1045552e62455d486d19e5986a67ae2545411d50fbeJeff Brown } 1055552e62455d486d19e5986a67ae2545411d50fbeJeff Brown assert(newSize > alloc_entries_); 1065552e62455d486d19e5986a67ae2545411d50fbeJeff Brown 1075552e62455d486d19e5986a67ae2545411d50fbeJeff Brown IndirectRefSlot* newTable = 1085552e62455d486d19e5986a67ae2545411d50fbeJeff Brown (IndirectRefSlot*) realloc(table_, newSize * sizeof(IndirectRefSlot)); 1095552e62455d486d19e5986a67ae2545411d50fbeJeff Brown if (table_ == NULL) { 110c1a4ab9c313d8a3d12007f2dbef7b5a6fa4ac2efSteve Block ALOGE("JNI ERROR (app bug): unable to expand %s reference table " 1115552e62455d486d19e5986a67ae2545411d50fbeJeff Brown "(from %d to %d, max=%d)", 1125552e62455d486d19e5986a67ae2545411d50fbeJeff Brown indirectRefKindToString(kind_), 1135552e62455d486d19e5986a67ae2545411d50fbeJeff Brown alloc_entries_, newSize, max_entries_); 1145552e62455d486d19e5986a67ae2545411d50fbeJeff Brown return NULL; 1155552e62455d486d19e5986a67ae2545411d50fbeJeff Brown } 1165552e62455d486d19e5986a67ae2545411d50fbeJeff Brown 117ee155d4fe47fa751262beb43437a339fde8eabe5Ben Cheng memset(newTable + alloc_entries_, 0xd1, 118ee155d4fe47fa751262beb43437a339fde8eabe5Ben Cheng (newSize - alloc_entries_) * sizeof(IndirectRefSlot)); 119ee155d4fe47fa751262beb43437a339fde8eabe5Ben Cheng 1205552e62455d486d19e5986a67ae2545411d50fbeJeff Brown alloc_entries_ = newSize; 1215552e62455d486d19e5986a67ae2545411d50fbeJeff Brown table_ = newTable; 1225552e62455d486d19e5986a67ae2545411d50fbeJeff Brown } 1235552e62455d486d19e5986a67ae2545411d50fbeJeff Brown slot = &table_[topIndex++]; 124ce0968340f9ddd54f20e38d4946bfd2ef8f1f343Elliott Hughes segmentState.parts.topIndex = topIndex; 125734155efc18543eab20b763f9a315ab1a44240acAndy McFadden } 126734155efc18543eab20b763f9a315ab1a44240acAndy McFadden 1275552e62455d486d19e5986a67ae2545411d50fbeJeff Brown slot->obj = obj; 1285552e62455d486d19e5986a67ae2545411d50fbeJeff Brown slot->serial = nextSerial(slot->serial); 1295552e62455d486d19e5986a67ae2545411d50fbeJeff Brown result = toIndirectRef(slot - table_, slot->serial, kind_); 1305552e62455d486d19e5986a67ae2545411d50fbeJeff Brown 131734155efc18543eab20b763f9a315ab1a44240acAndy McFadden assert(result != NULL); 132734155efc18543eab20b763f9a315ab1a44240acAndy McFadden return result; 133734155efc18543eab20b763f9a315ab1a44240acAndy McFadden} 134734155efc18543eab20b763f9a315ab1a44240acAndy McFadden 135734155efc18543eab20b763f9a315ab1a44240acAndy McFadden/* 1365552e62455d486d19e5986a67ae2545411d50fbeJeff Brown * Get the referent of an indirect ref from the table. 137734155efc18543eab20b763f9a315ab1a44240acAndy McFadden * 1385552e62455d486d19e5986a67ae2545411d50fbeJeff Brown * Returns kInvalidIndirectRefObject if iref is invalid. 139734155efc18543eab20b763f9a315ab1a44240acAndy McFadden */ 1405552e62455d486d19e5986a67ae2545411d50fbeJeff BrownObject* IndirectRefTable::get(IndirectRef iref) const { 1415552e62455d486d19e5986a67ae2545411d50fbeJeff Brown IndirectRefKind kind = indirectRefKind(iref); 1425552e62455d486d19e5986a67ae2545411d50fbeJeff Brown if (kind != kind_) { 1435552e62455d486d19e5986a67ae2545411d50fbeJeff Brown if (iref == NULL) { 144e8e1ddccd616e8226b7cc1e4e9fdb327429249e8Steve Block ALOGW("Attempt to look up NULL %s reference", indirectRefKindToString(kind_)); 1455552e62455d486d19e5986a67ae2545411d50fbeJeff Brown return kInvalidIndirectRefObject; 1465552e62455d486d19e5986a67ae2545411d50fbeJeff Brown } 1475552e62455d486d19e5986a67ae2545411d50fbeJeff Brown if (kind == kIndirectKindInvalid) { 148c1a4ab9c313d8a3d12007f2dbef7b5a6fa4ac2efSteve Block ALOGE("JNI ERROR (app bug): invalid %s reference %p", 1495552e62455d486d19e5986a67ae2545411d50fbeJeff Brown indirectRefKindToString(kind_), iref); 1505552e62455d486d19e5986a67ae2545411d50fbeJeff Brown abortMaybe(); 1515552e62455d486d19e5986a67ae2545411d50fbeJeff Brown return kInvalidIndirectRefObject; 1525552e62455d486d19e5986a67ae2545411d50fbeJeff Brown } 1535552e62455d486d19e5986a67ae2545411d50fbeJeff Brown // References of the requested kind cannot appear within this table. 1545552e62455d486d19e5986a67ae2545411d50fbeJeff Brown return kInvalidIndirectRefObject; 155734155efc18543eab20b763f9a315ab1a44240acAndy McFadden } 156ce0968340f9ddd54f20e38d4946bfd2ef8f1f343Elliott Hughes 1575552e62455d486d19e5986a67ae2545411d50fbeJeff Brown u4 topIndex = segmentState.parts.topIndex; 1585552e62455d486d19e5986a67ae2545411d50fbeJeff Brown u4 index = extractIndex(iref); 1595552e62455d486d19e5986a67ae2545411d50fbeJeff Brown if (index >= topIndex) { 160734155efc18543eab20b763f9a315ab1a44240acAndy McFadden /* bad -- stale reference? */ 161c1a4ab9c313d8a3d12007f2dbef7b5a6fa4ac2efSteve Block ALOGE("JNI ERROR (app bug): accessed stale %s reference %p (index %d in a table of size %d)", 1625552e62455d486d19e5986a67ae2545411d50fbeJeff Brown indirectRefKindToString(kind_), iref, index, topIndex); 163259a8a5154c63a793ea0ee438d146acda7d990b6Elliott Hughes abortMaybe(); 1645552e62455d486d19e5986a67ae2545411d50fbeJeff Brown return kInvalidIndirectRefObject; 165259a8a5154c63a793ea0ee438d146acda7d990b6Elliott Hughes } 166259a8a5154c63a793ea0ee438d146acda7d990b6Elliott Hughes 1675552e62455d486d19e5986a67ae2545411d50fbeJeff Brown Object* obj = table_[index].obj; 1685552e62455d486d19e5986a67ae2545411d50fbeJeff Brown if (obj == NULL) { 1694308417beec548c2b2c06ecec4f7f4a965b09fb2Steve Block ALOGI("JNI ERROR (app bug): accessed deleted %s reference %p", 170b27341588c31ede077762de4c200049abc0417aaElliott Hughes indirectRefKindToString(kind_), iref); 17124c57f1d575fccc11239cf71089c7d04270a21c3Elliott Hughes abortMaybe(); 1725552e62455d486d19e5986a67ae2545411d50fbeJeff Brown return kInvalidIndirectRefObject; 173734155efc18543eab20b763f9a315ab1a44240acAndy McFadden } 174734155efc18543eab20b763f9a315ab1a44240acAndy McFadden 1755552e62455d486d19e5986a67ae2545411d50fbeJeff Brown u4 serial = extractSerial(iref); 1765552e62455d486d19e5986a67ae2545411d50fbeJeff Brown if (serial != table_[index].serial) { 177c1a4ab9c313d8a3d12007f2dbef7b5a6fa4ac2efSteve Block ALOGE("JNI ERROR (app bug): attempt to use stale %s reference %p", 1785552e62455d486d19e5986a67ae2545411d50fbeJeff Brown indirectRefKindToString(kind_), iref); 1795552e62455d486d19e5986a67ae2545411d50fbeJeff Brown abortMaybe(); 1805552e62455d486d19e5986a67ae2545411d50fbeJeff Brown return kInvalidIndirectRefObject; 181ce0968340f9ddd54f20e38d4946bfd2ef8f1f343Elliott Hughes } 182734155efc18543eab20b763f9a315ab1a44240acAndy McFadden 1835552e62455d486d19e5986a67ae2545411d50fbeJeff Brown return obj; 184734155efc18543eab20b763f9a315ab1a44240acAndy McFadden} 185734155efc18543eab20b763f9a315ab1a44240acAndy McFadden 1865552e62455d486d19e5986a67ae2545411d50fbeJeff Brownstatic int findObject(const Object* obj, int bottomIndex, int topIndex, 1875552e62455d486d19e5986a67ae2545411d50fbeJeff Brown const IndirectRefSlot* table) { 188ea333384b92db9c400be1b4c8cb6992d9ba5f14dElliott Hughes for (int i = bottomIndex; i < topIndex; ++i) { 1895552e62455d486d19e5986a67ae2545411d50fbeJeff Brown if (table[i].obj == obj) { 190ea333384b92db9c400be1b4c8cb6992d9ba5f14dElliott Hughes return i; 191ea333384b92db9c400be1b4c8cb6992d9ba5f14dElliott Hughes } 192ea333384b92db9c400be1b4c8cb6992d9ba5f14dElliott Hughes } 193ea333384b92db9c400be1b4c8cb6992d9ba5f14dElliott Hughes return -1; 194ea333384b92db9c400be1b4c8cb6992d9ba5f14dElliott Hughes} 195ea333384b92db9c400be1b4c8cb6992d9ba5f14dElliott Hughes 1965552e62455d486d19e5986a67ae2545411d50fbeJeff Brownbool IndirectRefTable::contains(const Object* obj) const { 1975552e62455d486d19e5986a67ae2545411d50fbeJeff Brown return findObject(obj, 0, segmentState.parts.topIndex, table_) >= 0; 198ea333384b92db9c400be1b4c8cb6992d9ba5f14dElliott Hughes} 199ea333384b92db9c400be1b4c8cb6992d9ba5f14dElliott Hughes 200734155efc18543eab20b763f9a315ab1a44240acAndy McFadden/* 201734155efc18543eab20b763f9a315ab1a44240acAndy McFadden * Remove "obj" from "pRef". We extract the table offset bits from "iref" 202734155efc18543eab20b763f9a315ab1a44240acAndy McFadden * and zap the corresponding entry, leaving a hole if it's not at the top. 203734155efc18543eab20b763f9a315ab1a44240acAndy McFadden * 204734155efc18543eab20b763f9a315ab1a44240acAndy McFadden * If the entry is not between the current top index and the bottom index 205734155efc18543eab20b763f9a315ab1a44240acAndy McFadden * specified by the cookie, we don't remove anything. This is the behavior 206734155efc18543eab20b763f9a315ab1a44240acAndy McFadden * required by JNI's DeleteLocalRef function. 207734155efc18543eab20b763f9a315ab1a44240acAndy McFadden * 2085d599603ea3d759aabe9a6b274c11b76191d1792Andy McFadden * Note this is NOT called when a local frame is popped. This is only used 209ddbd6f44af283415162ea7bb1b4e7ef77c8de492Elliott Hughes * for explicit single removals. 2105d599603ea3d759aabe9a6b274c11b76191d1792Andy McFadden * 211734155efc18543eab20b763f9a315ab1a44240acAndy McFadden * Returns "false" if nothing was removed. 212734155efc18543eab20b763f9a315ab1a44240acAndy McFadden */ 213ce0968340f9ddd54f20e38d4946bfd2ef8f1f343Elliott Hughesbool IndirectRefTable::remove(u4 cookie, IndirectRef iref) 214734155efc18543eab20b763f9a315ab1a44240acAndy McFadden{ 215734155efc18543eab20b763f9a315ab1a44240acAndy McFadden IRTSegmentState prevState; 216734155efc18543eab20b763f9a315ab1a44240acAndy McFadden prevState.all = cookie; 2175552e62455d486d19e5986a67ae2545411d50fbeJeff Brown u4 topIndex = segmentState.parts.topIndex; 2185552e62455d486d19e5986a67ae2545411d50fbeJeff Brown u4 bottomIndex = prevState.parts.topIndex; 219734155efc18543eab20b763f9a315ab1a44240acAndy McFadden 220b27341588c31ede077762de4c200049abc0417aaElliott Hughes assert(table_ != NULL); 221b27341588c31ede077762de4c200049abc0417aaElliott Hughes assert(alloc_entries_ <= max_entries_); 222ce0968340f9ddd54f20e38d4946bfd2ef8f1f343Elliott Hughes assert(segmentState.parts.numHoles >= prevState.parts.numHoles); 223734155efc18543eab20b763f9a315ab1a44240acAndy McFadden 2245552e62455d486d19e5986a67ae2545411d50fbeJeff Brown IndirectRefKind kind = indirectRefKind(iref); 2255552e62455d486d19e5986a67ae2545411d50fbeJeff Brown u4 index; 2265552e62455d486d19e5986a67ae2545411d50fbeJeff Brown if (kind == kind_) { 2275552e62455d486d19e5986a67ae2545411d50fbeJeff Brown index = extractIndex(iref); 2285552e62455d486d19e5986a67ae2545411d50fbeJeff Brown if (index < bottomIndex) { 2295552e62455d486d19e5986a67ae2545411d50fbeJeff Brown /* wrong segment */ 2305552e62455d486d19e5986a67ae2545411d50fbeJeff Brown ALOGV("Attempt to remove index outside index area (%ud vs %ud-%ud)", 2315552e62455d486d19e5986a67ae2545411d50fbeJeff Brown index, bottomIndex, topIndex); 2325552e62455d486d19e5986a67ae2545411d50fbeJeff Brown return false; 2335552e62455d486d19e5986a67ae2545411d50fbeJeff Brown } 2345552e62455d486d19e5986a67ae2545411d50fbeJeff Brown if (index >= topIndex) { 2355552e62455d486d19e5986a67ae2545411d50fbeJeff Brown /* bad -- stale reference? */ 236062bf509a77fce9dfcb7e7b2e401cf2a124d83d5Steve Block ALOGD("Attempt to remove invalid index %ud (bottom=%ud top=%ud)", 2375552e62455d486d19e5986a67ae2545411d50fbeJeff Brown index, bottomIndex, topIndex); 2385552e62455d486d19e5986a67ae2545411d50fbeJeff Brown return false; 2395552e62455d486d19e5986a67ae2545411d50fbeJeff Brown } 2405552e62455d486d19e5986a67ae2545411d50fbeJeff Brown if (table_[index].obj == NULL) { 241062bf509a77fce9dfcb7e7b2e401cf2a124d83d5Steve Block ALOGD("Attempt to remove cleared %s reference %p", 2425552e62455d486d19e5986a67ae2545411d50fbeJeff Brown indirectRefKindToString(kind_), iref); 2435552e62455d486d19e5986a67ae2545411d50fbeJeff Brown return false; 2445552e62455d486d19e5986a67ae2545411d50fbeJeff Brown } 2455552e62455d486d19e5986a67ae2545411d50fbeJeff Brown u4 serial = extractSerial(iref); 2465552e62455d486d19e5986a67ae2545411d50fbeJeff Brown if (table_[index].serial != serial) { 247062bf509a77fce9dfcb7e7b2e401cf2a124d83d5Steve Block ALOGD("Attempt to remove stale %s reference %p", 2485552e62455d486d19e5986a67ae2545411d50fbeJeff Brown indirectRefKindToString(kind_), iref); 2495552e62455d486d19e5986a67ae2545411d50fbeJeff Brown return false; 2505552e62455d486d19e5986a67ae2545411d50fbeJeff Brown } 2515552e62455d486d19e5986a67ae2545411d50fbeJeff Brown } else if (kind == kIndirectKindInvalid && gDvmJni.workAroundAppJniBugs) { 2525552e62455d486d19e5986a67ae2545411d50fbeJeff Brown // reference looks like a pointer, scan the table to find the index 2535552e62455d486d19e5986a67ae2545411d50fbeJeff Brown int i = findObject(reinterpret_cast<Object*>(iref), bottomIndex, topIndex, table_); 2545552e62455d486d19e5986a67ae2545411d50fbeJeff Brown if (i < 0) { 255e8e1ddccd616e8226b7cc1e4e9fdb327429249e8Steve Block ALOGW("trying to work around app JNI bugs, but didn't find %p in table!", iref); 256ea333384b92db9c400be1b4c8cb6992d9ba5f14dElliott Hughes return false; 257ea333384b92db9c400be1b4c8cb6992d9ba5f14dElliott Hughes } 2585552e62455d486d19e5986a67ae2545411d50fbeJeff Brown index = i; 2595552e62455d486d19e5986a67ae2545411d50fbeJeff Brown } else { 2605552e62455d486d19e5986a67ae2545411d50fbeJeff Brown // References of the requested kind cannot appear within this table. 261734155efc18543eab20b763f9a315ab1a44240acAndy McFadden return false; 262734155efc18543eab20b763f9a315ab1a44240acAndy McFadden } 263734155efc18543eab20b763f9a315ab1a44240acAndy McFadden 2645552e62455d486d19e5986a67ae2545411d50fbeJeff Brown if (index == topIndex - 1) { 265259a8a5154c63a793ea0ee438d146acda7d990b6Elliott Hughes // Top-most entry. Scan up and consume holes. 266259a8a5154c63a793ea0ee438d146acda7d990b6Elliott Hughes int numHoles = segmentState.parts.numHoles - prevState.parts.numHoles; 267734155efc18543eab20b763f9a315ab1a44240acAndy McFadden if (numHoles != 0) { 268734155efc18543eab20b763f9a315ab1a44240acAndy McFadden while (--topIndex > bottomIndex && numHoles != 0) { 26992c1f6f1b4249e4e379452ee7b49f027052bf4ceSteve Block ALOGV("+++ checking for hole at %d (cookie=0x%08x) val=%p", 2705552e62455d486d19e5986a67ae2545411d50fbeJeff Brown topIndex-1, cookie, table_[topIndex-1].obj); 2715552e62455d486d19e5986a67ae2545411d50fbeJeff Brown if (table_[topIndex-1].obj != NULL) { 272734155efc18543eab20b763f9a315ab1a44240acAndy McFadden break; 273259a8a5154c63a793ea0ee438d146acda7d990b6Elliott Hughes } 27492c1f6f1b4249e4e379452ee7b49f027052bf4ceSteve Block ALOGV("+++ ate hole at %d", topIndex-1); 275734155efc18543eab20b763f9a315ab1a44240acAndy McFadden numHoles--; 276734155efc18543eab20b763f9a315ab1a44240acAndy McFadden } 277259a8a5154c63a793ea0ee438d146acda7d990b6Elliott Hughes segmentState.parts.numHoles = numHoles + prevState.parts.numHoles; 278ce0968340f9ddd54f20e38d4946bfd2ef8f1f343Elliott Hughes segmentState.parts.topIndex = topIndex; 279734155efc18543eab20b763f9a315ab1a44240acAndy McFadden } else { 280ce0968340f9ddd54f20e38d4946bfd2ef8f1f343Elliott Hughes segmentState.parts.topIndex = topIndex-1; 28192c1f6f1b4249e4e379452ee7b49f027052bf4ceSteve Block ALOGV("+++ ate last entry %d", topIndex-1); 282734155efc18543eab20b763f9a315ab1a44240acAndy McFadden } 283734155efc18543eab20b763f9a315ab1a44240acAndy McFadden } else { 284734155efc18543eab20b763f9a315ab1a44240acAndy McFadden /* 285734155efc18543eab20b763f9a315ab1a44240acAndy McFadden * Not the top-most entry. This creates a hole. We NULL out the 286734155efc18543eab20b763f9a315ab1a44240acAndy McFadden * entry to prevent somebody from deleting it twice and screwing up 287734155efc18543eab20b763f9a315ab1a44240acAndy McFadden * the hole count. 288734155efc18543eab20b763f9a315ab1a44240acAndy McFadden */ 2895552e62455d486d19e5986a67ae2545411d50fbeJeff Brown table_[index].obj = NULL; 290ce0968340f9ddd54f20e38d4946bfd2ef8f1f343Elliott Hughes segmentState.parts.numHoles++; 2915552e62455d486d19e5986a67ae2545411d50fbeJeff Brown ALOGV("+++ left hole at %d, holes=%d", index, segmentState.parts.numHoles); 292734155efc18543eab20b763f9a315ab1a44240acAndy McFadden } 293734155efc18543eab20b763f9a315ab1a44240acAndy McFadden 294734155efc18543eab20b763f9a315ab1a44240acAndy McFadden return true; 295734155efc18543eab20b763f9a315ab1a44240acAndy McFadden} 296734155efc18543eab20b763f9a315ab1a44240acAndy McFadden 297ce0968340f9ddd54f20e38d4946bfd2ef8f1f343Elliott Hughesconst char* indirectRefKindToString(IndirectRefKind kind) 298c759b9f089e8e09df335a030d0555366d9395aebAndy McFadden{ 299ce0968340f9ddd54f20e38d4946bfd2ef8f1f343Elliott Hughes switch (kind) { 300c759b9f089e8e09df335a030d0555366d9395aebAndy McFadden case kIndirectKindInvalid: return "invalid"; 301c759b9f089e8e09df335a030d0555366d9395aebAndy McFadden case kIndirectKindLocal: return "local"; 302c759b9f089e8e09df335a030d0555366d9395aebAndy McFadden case kIndirectKindGlobal: return "global"; 303c759b9f089e8e09df335a030d0555366d9395aebAndy McFadden case kIndirectKindWeakGlobal: return "weak global"; 304c759b9f089e8e09df335a030d0555366d9395aebAndy McFadden default: return "UNKNOWN"; 305c759b9f089e8e09df335a030d0555366d9395aebAndy McFadden } 306c759b9f089e8e09df335a030d0555366d9395aebAndy McFadden} 307c759b9f089e8e09df335a030d0555366d9395aebAndy McFadden 308ce0968340f9ddd54f20e38d4946bfd2ef8f1f343Elliott Hughesvoid IndirectRefTable::dump(const char* descr) const 309734155efc18543eab20b763f9a315ab1a44240acAndy McFadden{ 3105552e62455d486d19e5986a67ae2545411d50fbeJeff Brown size_t count = capacity(); 3115552e62455d486d19e5986a67ae2545411d50fbeJeff Brown Object** copy = new Object*[count]; 3125552e62455d486d19e5986a67ae2545411d50fbeJeff Brown for (size_t i = 0; i < count; i++) { 3135552e62455d486d19e5986a67ae2545411d50fbeJeff Brown copy[i] = table_[i].obj; 3145552e62455d486d19e5986a67ae2545411d50fbeJeff Brown } 3155552e62455d486d19e5986a67ae2545411d50fbeJeff Brown dvmDumpReferenceTableContents(copy, count, descr); 3165552e62455d486d19e5986a67ae2545411d50fbeJeff Brown delete[] copy; 317734155efc18543eab20b763f9a315ab1a44240acAndy McFadden} 318