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