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
22734155efc18543eab20b763f9a315ab1a44240acAndy McFadden/*
23734155efc18543eab20b763f9a315ab1a44240acAndy McFadden * Initialize an IndirectRefTable structure.
24734155efc18543eab20b763f9a315ab1a44240acAndy McFadden */
25734155efc18543eab20b763f9a315ab1a44240acAndy McFaddenbool dvmInitIndirectRefTable(IndirectRefTable* pRef, int initialCount,
26734155efc18543eab20b763f9a315ab1a44240acAndy McFadden    int maxCount, IndirectRefKind kind)
27734155efc18543eab20b763f9a315ab1a44240acAndy McFadden{
28734155efc18543eab20b763f9a315ab1a44240acAndy McFadden    assert(initialCount > 0);
29734155efc18543eab20b763f9a315ab1a44240acAndy McFadden    assert(initialCount <= maxCount);
30734155efc18543eab20b763f9a315ab1a44240acAndy McFadden    assert(kind == kIndirectKindLocal || kind == kIndirectKindGlobal);
31734155efc18543eab20b763f9a315ab1a44240acAndy McFadden
32734155efc18543eab20b763f9a315ab1a44240acAndy McFadden    pRef->table = (Object**) malloc(initialCount * sizeof(Object*));
33734155efc18543eab20b763f9a315ab1a44240acAndy McFadden    if (pRef->table == NULL)
34734155efc18543eab20b763f9a315ab1a44240acAndy McFadden        return false;
35734155efc18543eab20b763f9a315ab1a44240acAndy McFadden#ifndef NDEBUG
36734155efc18543eab20b763f9a315ab1a44240acAndy McFadden    memset(pRef->table, 0xd1, initialCount * sizeof(Object*));
37734155efc18543eab20b763f9a315ab1a44240acAndy McFadden#endif
385d599603ea3d759aabe9a6b274c11b76191d1792Andy McFadden
395d599603ea3d759aabe9a6b274c11b76191d1792Andy McFadden    pRef->slotData =
405d599603ea3d759aabe9a6b274c11b76191d1792Andy McFadden        (IndirectRefSlot*) calloc(maxCount, sizeof(IndirectRefSlot));
415d599603ea3d759aabe9a6b274c11b76191d1792Andy McFadden    if (pRef->slotData == NULL)
425d599603ea3d759aabe9a6b274c11b76191d1792Andy McFadden        return false;
435d599603ea3d759aabe9a6b274c11b76191d1792Andy McFadden
44ab00d455ea67fbf4090567bb09ead8017896ea61Andy McFadden    pRef->segmentState.all = IRT_FIRST_SEGMENT;
45734155efc18543eab20b763f9a315ab1a44240acAndy McFadden    pRef->allocEntries = initialCount;
46734155efc18543eab20b763f9a315ab1a44240acAndy McFadden    pRef->maxEntries = maxCount;
47734155efc18543eab20b763f9a315ab1a44240acAndy McFadden    pRef->kind = kind;
48734155efc18543eab20b763f9a315ab1a44240acAndy McFadden
49734155efc18543eab20b763f9a315ab1a44240acAndy McFadden    return true;
50734155efc18543eab20b763f9a315ab1a44240acAndy McFadden}
51734155efc18543eab20b763f9a315ab1a44240acAndy McFadden
52734155efc18543eab20b763f9a315ab1a44240acAndy McFadden/*
53734155efc18543eab20b763f9a315ab1a44240acAndy McFadden * Clears out the contents of a IndirectRefTable, freeing allocated storage.
54734155efc18543eab20b763f9a315ab1a44240acAndy McFadden */
55734155efc18543eab20b763f9a315ab1a44240acAndy McFaddenvoid dvmClearIndirectRefTable(IndirectRefTable* pRef)
56734155efc18543eab20b763f9a315ab1a44240acAndy McFadden{
57734155efc18543eab20b763f9a315ab1a44240acAndy McFadden    free(pRef->table);
58734155efc18543eab20b763f9a315ab1a44240acAndy McFadden    pRef->table = NULL;
59734155efc18543eab20b763f9a315ab1a44240acAndy McFadden    pRef->allocEntries = pRef->maxEntries = -1;
60734155efc18543eab20b763f9a315ab1a44240acAndy McFadden}
61734155efc18543eab20b763f9a315ab1a44240acAndy McFadden
62734155efc18543eab20b763f9a315ab1a44240acAndy McFadden/*
63734155efc18543eab20b763f9a315ab1a44240acAndy McFadden * Remove one or more segments from the top.  The table entry identified
64734155efc18543eab20b763f9a315ab1a44240acAndy McFadden * by "cookie" becomes the new top-most entry.
65734155efc18543eab20b763f9a315ab1a44240acAndy McFadden *
66734155efc18543eab20b763f9a315ab1a44240acAndy McFadden * Returns false if "cookie" is invalid or the table has only one segment.
67734155efc18543eab20b763f9a315ab1a44240acAndy McFadden */
68734155efc18543eab20b763f9a315ab1a44240acAndy McFaddenbool dvmPopIndirectRefTableSegmentCheck(IndirectRefTable* pRef, u4 cookie)
69734155efc18543eab20b763f9a315ab1a44240acAndy McFadden{
70734155efc18543eab20b763f9a315ab1a44240acAndy McFadden    IRTSegmentState sst;
71734155efc18543eab20b763f9a315ab1a44240acAndy McFadden
72734155efc18543eab20b763f9a315ab1a44240acAndy McFadden    /*
73734155efc18543eab20b763f9a315ab1a44240acAndy McFadden     * The new value for "top" must be <= the current value.  Otherwise
74734155efc18543eab20b763f9a315ab1a44240acAndy McFadden     * this would represent an expansion of the table.
75734155efc18543eab20b763f9a315ab1a44240acAndy McFadden     */
76734155efc18543eab20b763f9a315ab1a44240acAndy McFadden    sst.all = cookie;
77734155efc18543eab20b763f9a315ab1a44240acAndy McFadden    if (sst.parts.topIndex > pRef->segmentState.parts.topIndex) {
78734155efc18543eab20b763f9a315ab1a44240acAndy McFadden        LOGE("Attempt to expand table with segment pop (%d to %d)\n",
79734155efc18543eab20b763f9a315ab1a44240acAndy McFadden            pRef->segmentState.parts.topIndex, sst.parts.topIndex);
80734155efc18543eab20b763f9a315ab1a44240acAndy McFadden        return false;
81734155efc18543eab20b763f9a315ab1a44240acAndy McFadden    }
82734155efc18543eab20b763f9a315ab1a44240acAndy McFadden    if (sst.parts.numHoles >= sst.parts.topIndex) {
83734155efc18543eab20b763f9a315ab1a44240acAndy McFadden        LOGE("Absurd numHoles in cookie (%d bi=%d)\n",
84734155efc18543eab20b763f9a315ab1a44240acAndy McFadden            sst.parts.numHoles, sst.parts.topIndex);
85734155efc18543eab20b763f9a315ab1a44240acAndy McFadden        return false;
86734155efc18543eab20b763f9a315ab1a44240acAndy McFadden    }
87734155efc18543eab20b763f9a315ab1a44240acAndy McFadden
885d599603ea3d759aabe9a6b274c11b76191d1792Andy McFadden    LOGV("IRT %p[%d]: pop, top=%d holes=%d\n",
895d599603ea3d759aabe9a6b274c11b76191d1792Andy McFadden        pRef, pRef->kind, sst.parts.topIndex, sst.parts.numHoles);
90734155efc18543eab20b763f9a315ab1a44240acAndy McFadden
91734155efc18543eab20b763f9a315ab1a44240acAndy McFadden    return true;
92734155efc18543eab20b763f9a315ab1a44240acAndy McFadden}
93734155efc18543eab20b763f9a315ab1a44240acAndy McFadden
94734155efc18543eab20b763f9a315ab1a44240acAndy McFadden/*
95734155efc18543eab20b763f9a315ab1a44240acAndy McFadden * Make sure that the entry at "idx" is correctly paired with "iref".
96734155efc18543eab20b763f9a315ab1a44240acAndy McFadden */
97734155efc18543eab20b763f9a315ab1a44240acAndy McFaddenstatic bool checkEntry(IndirectRefTable* pRef, IndirectRef iref, int idx)
98734155efc18543eab20b763f9a315ab1a44240acAndy McFadden{
99734155efc18543eab20b763f9a315ab1a44240acAndy McFadden    Object* obj = pRef->table[idx];
1005d599603ea3d759aabe9a6b274c11b76191d1792Andy McFadden    IndirectRef checkRef = dvmObjectToIndirectRef(pRef, obj, idx, pRef->kind);
101734155efc18543eab20b763f9a315ab1a44240acAndy McFadden    if (checkRef != iref) {
1025d599603ea3d759aabe9a6b274c11b76191d1792Andy McFadden        LOGW("IRT %p[%d]: iref mismatch (req=%p vs cur=%p)\n",
1035d599603ea3d759aabe9a6b274c11b76191d1792Andy McFadden            pRef, pRef->kind, iref, checkRef);
104734155efc18543eab20b763f9a315ab1a44240acAndy McFadden        return false;
105734155efc18543eab20b763f9a315ab1a44240acAndy McFadden    }
106734155efc18543eab20b763f9a315ab1a44240acAndy McFadden    return true;
107734155efc18543eab20b763f9a315ab1a44240acAndy McFadden}
108734155efc18543eab20b763f9a315ab1a44240acAndy McFadden
109734155efc18543eab20b763f9a315ab1a44240acAndy McFadden/*
1105d599603ea3d759aabe9a6b274c11b76191d1792Andy McFadden * Update extended debug info when an entry is added.
1115d599603ea3d759aabe9a6b274c11b76191d1792Andy McFadden *
1125d599603ea3d759aabe9a6b274c11b76191d1792Andy McFadden * We advance the serial number, invalidating any outstanding references to
1135d599603ea3d759aabe9a6b274c11b76191d1792Andy McFadden * this slot.
1145d599603ea3d759aabe9a6b274c11b76191d1792Andy McFadden */
1155d599603ea3d759aabe9a6b274c11b76191d1792Andy McFaddenstatic inline void updateSlotAdd(IndirectRefTable* pRef, Object* obj, int slot)
1165d599603ea3d759aabe9a6b274c11b76191d1792Andy McFadden{
1175d599603ea3d759aabe9a6b274c11b76191d1792Andy McFadden    if (pRef->slotData != NULL) {
1185d599603ea3d759aabe9a6b274c11b76191d1792Andy McFadden        IndirectRefSlot* pSlot = &pRef->slotData[slot];
1195d599603ea3d759aabe9a6b274c11b76191d1792Andy McFadden        pSlot->serial++;
1205d599603ea3d759aabe9a6b274c11b76191d1792Andy McFadden        //LOGI("+++ add [%d] slot %d (%p->%p), serial=%d\n",
1215d599603ea3d759aabe9a6b274c11b76191d1792Andy McFadden        //    pRef->kind, slot, obj, iref, pSlot->serial);
1225d599603ea3d759aabe9a6b274c11b76191d1792Andy McFadden        pSlot->previous[pSlot->serial % kIRTPrevCount] = obj;
1235d599603ea3d759aabe9a6b274c11b76191d1792Andy McFadden    }
1245d599603ea3d759aabe9a6b274c11b76191d1792Andy McFadden}
1255d599603ea3d759aabe9a6b274c11b76191d1792Andy McFadden
1265d599603ea3d759aabe9a6b274c11b76191d1792Andy McFadden/*
1275d599603ea3d759aabe9a6b274c11b76191d1792Andy McFadden * Update extended debug info when an entry is removed.
1285d599603ea3d759aabe9a6b274c11b76191d1792Andy McFadden */
1295d599603ea3d759aabe9a6b274c11b76191d1792Andy McFaddenstatic inline void updateSlotRemove(IndirectRefTable* pRef, int slot)
1305d599603ea3d759aabe9a6b274c11b76191d1792Andy McFadden{
1315d599603ea3d759aabe9a6b274c11b76191d1792Andy McFadden    if (pRef->slotData != NULL) {
1325d599603ea3d759aabe9a6b274c11b76191d1792Andy McFadden        IndirectRefSlot* pSlot = &pRef->slotData[slot];
1335d599603ea3d759aabe9a6b274c11b76191d1792Andy McFadden        //LOGI("+++ remove [%d] slot %d, serial now %d\n",
1345d599603ea3d759aabe9a6b274c11b76191d1792Andy McFadden        //    pRef->kind, slot, pSlot->serial);
1355d599603ea3d759aabe9a6b274c11b76191d1792Andy McFadden    }
1365d599603ea3d759aabe9a6b274c11b76191d1792Andy McFadden}
1375d599603ea3d759aabe9a6b274c11b76191d1792Andy McFadden
1385d599603ea3d759aabe9a6b274c11b76191d1792Andy McFadden/*
139734155efc18543eab20b763f9a315ab1a44240acAndy McFadden * Add "obj" to "pRef".
140734155efc18543eab20b763f9a315ab1a44240acAndy McFadden */
141734155efc18543eab20b763f9a315ab1a44240acAndy McFaddenIndirectRef dvmAddToIndirectRefTable(IndirectRefTable* pRef, u4 cookie,
142734155efc18543eab20b763f9a315ab1a44240acAndy McFadden    Object* obj)
143734155efc18543eab20b763f9a315ab1a44240acAndy McFadden{
144734155efc18543eab20b763f9a315ab1a44240acAndy McFadden    IRTSegmentState prevState;
145734155efc18543eab20b763f9a315ab1a44240acAndy McFadden    prevState.all = cookie;
146734155efc18543eab20b763f9a315ab1a44240acAndy McFadden    int topIndex = pRef->segmentState.parts.topIndex;
147734155efc18543eab20b763f9a315ab1a44240acAndy McFadden    int bottomIndex = prevState.parts.topIndex;
148734155efc18543eab20b763f9a315ab1a44240acAndy McFadden
149734155efc18543eab20b763f9a315ab1a44240acAndy McFadden    assert(obj != NULL);
150734155efc18543eab20b763f9a315ab1a44240acAndy McFadden    assert(dvmIsValidObject(obj));
151734155efc18543eab20b763f9a315ab1a44240acAndy McFadden    assert(pRef->table != NULL);
152734155efc18543eab20b763f9a315ab1a44240acAndy McFadden    assert(pRef->allocEntries <= pRef->maxEntries);
153734155efc18543eab20b763f9a315ab1a44240acAndy McFadden    assert(pRef->segmentState.parts.numHoles >= prevState.parts.numHoles);
154734155efc18543eab20b763f9a315ab1a44240acAndy McFadden
155734155efc18543eab20b763f9a315ab1a44240acAndy McFadden    if (topIndex == pRef->allocEntries) {
156734155efc18543eab20b763f9a315ab1a44240acAndy McFadden        /* reached end of allocated space; did we hit buffer max? */
157734155efc18543eab20b763f9a315ab1a44240acAndy McFadden        if (topIndex == pRef->maxEntries) {
1580423f0e813a3807168fe5524405eb96675532097Andy McFadden            LOGW("IndirectRefTable overflow (max=%d)\n", pRef->maxEntries);
159734155efc18543eab20b763f9a315ab1a44240acAndy McFadden            return NULL;
160734155efc18543eab20b763f9a315ab1a44240acAndy McFadden        }
161734155efc18543eab20b763f9a315ab1a44240acAndy McFadden
162734155efc18543eab20b763f9a315ab1a44240acAndy McFadden        Object** newTable;
163734155efc18543eab20b763f9a315ab1a44240acAndy McFadden        int newSize;
164734155efc18543eab20b763f9a315ab1a44240acAndy McFadden
165734155efc18543eab20b763f9a315ab1a44240acAndy McFadden        newSize = pRef->allocEntries * 2;
166734155efc18543eab20b763f9a315ab1a44240acAndy McFadden        if (newSize > pRef->maxEntries)
167734155efc18543eab20b763f9a315ab1a44240acAndy McFadden            newSize = pRef->maxEntries;
168734155efc18543eab20b763f9a315ab1a44240acAndy McFadden        assert(newSize > pRef->allocEntries);
169734155efc18543eab20b763f9a315ab1a44240acAndy McFadden
170734155efc18543eab20b763f9a315ab1a44240acAndy McFadden        newTable = (Object**) realloc(pRef->table, newSize * sizeof(Object*));
171734155efc18543eab20b763f9a315ab1a44240acAndy McFadden        if (newTable == NULL) {
1720423f0e813a3807168fe5524405eb96675532097Andy McFadden            LOGE("Unable to expand iref table (from %d to %d, max=%d)\n",
1730423f0e813a3807168fe5524405eb96675532097Andy McFadden                pRef->allocEntries, newSize, pRef->maxEntries);
174734155efc18543eab20b763f9a315ab1a44240acAndy McFadden            return false;
175734155efc18543eab20b763f9a315ab1a44240acAndy McFadden        }
1760423f0e813a3807168fe5524405eb96675532097Andy McFadden        LOGI("Growing ireftab %p from %d to %d (max=%d)\n",
1770423f0e813a3807168fe5524405eb96675532097Andy McFadden            pRef, pRef->allocEntries, newSize, pRef->maxEntries);
178734155efc18543eab20b763f9a315ab1a44240acAndy McFadden
179734155efc18543eab20b763f9a315ab1a44240acAndy McFadden        /* update entries; adjust "nextEntry" in case memory moved */
180734155efc18543eab20b763f9a315ab1a44240acAndy McFadden        pRef->table = newTable;
181734155efc18543eab20b763f9a315ab1a44240acAndy McFadden        pRef->allocEntries = newSize;
182734155efc18543eab20b763f9a315ab1a44240acAndy McFadden    }
183734155efc18543eab20b763f9a315ab1a44240acAndy McFadden
184734155efc18543eab20b763f9a315ab1a44240acAndy McFadden    IndirectRef result;
185734155efc18543eab20b763f9a315ab1a44240acAndy McFadden
186734155efc18543eab20b763f9a315ab1a44240acAndy McFadden    /*
187734155efc18543eab20b763f9a315ab1a44240acAndy McFadden     * We know there's enough room in the table.  Now we just need to find
188734155efc18543eab20b763f9a315ab1a44240acAndy McFadden     * the right spot.  If there's a hole, find it and fill it; otherwise,
189734155efc18543eab20b763f9a315ab1a44240acAndy McFadden     * add to the end of the list.
190734155efc18543eab20b763f9a315ab1a44240acAndy McFadden     */
191734155efc18543eab20b763f9a315ab1a44240acAndy McFadden    int numHoles = pRef->segmentState.parts.numHoles - prevState.parts.numHoles;
192734155efc18543eab20b763f9a315ab1a44240acAndy McFadden    if (numHoles > 0) {
193734155efc18543eab20b763f9a315ab1a44240acAndy McFadden        assert(topIndex > 1);
194734155efc18543eab20b763f9a315ab1a44240acAndy McFadden        /* find the first hole; likely to be near the end of the list */
195734155efc18543eab20b763f9a315ab1a44240acAndy McFadden        Object** pScan = &pRef->table[topIndex - 1];
196734155efc18543eab20b763f9a315ab1a44240acAndy McFadden        assert(*pScan != NULL);
197734155efc18543eab20b763f9a315ab1a44240acAndy McFadden        while (*--pScan != NULL) {
198734155efc18543eab20b763f9a315ab1a44240acAndy McFadden            assert(pScan >= pRef->table + bottomIndex);
199734155efc18543eab20b763f9a315ab1a44240acAndy McFadden        }
2005d599603ea3d759aabe9a6b274c11b76191d1792Andy McFadden        updateSlotAdd(pRef, obj, pScan - pRef->table);
2015d599603ea3d759aabe9a6b274c11b76191d1792Andy McFadden        result = dvmObjectToIndirectRef(pRef, obj, pScan - pRef->table,
2025d599603ea3d759aabe9a6b274c11b76191d1792Andy McFadden            pRef->kind);
203734155efc18543eab20b763f9a315ab1a44240acAndy McFadden        *pScan = obj;
204734155efc18543eab20b763f9a315ab1a44240acAndy McFadden        pRef->segmentState.parts.numHoles--;
205734155efc18543eab20b763f9a315ab1a44240acAndy McFadden    } else {
206734155efc18543eab20b763f9a315ab1a44240acAndy McFadden        /* add to the end */
2075d599603ea3d759aabe9a6b274c11b76191d1792Andy McFadden        updateSlotAdd(pRef, obj, topIndex);
2085d599603ea3d759aabe9a6b274c11b76191d1792Andy McFadden        result = dvmObjectToIndirectRef(pRef, obj, topIndex, pRef->kind);
209734155efc18543eab20b763f9a315ab1a44240acAndy McFadden        pRef->table[topIndex++] = obj;
210734155efc18543eab20b763f9a315ab1a44240acAndy McFadden        pRef->segmentState.parts.topIndex = topIndex;
211734155efc18543eab20b763f9a315ab1a44240acAndy McFadden    }
212734155efc18543eab20b763f9a315ab1a44240acAndy McFadden
213734155efc18543eab20b763f9a315ab1a44240acAndy McFadden    assert(result != NULL);
214734155efc18543eab20b763f9a315ab1a44240acAndy McFadden    return result;
215734155efc18543eab20b763f9a315ab1a44240acAndy McFadden}
216734155efc18543eab20b763f9a315ab1a44240acAndy McFadden
217734155efc18543eab20b763f9a315ab1a44240acAndy McFadden/*
218734155efc18543eab20b763f9a315ab1a44240acAndy McFadden * Verify that the indirect table lookup is valid.
219734155efc18543eab20b763f9a315ab1a44240acAndy McFadden *
220734155efc18543eab20b763f9a315ab1a44240acAndy McFadden * Returns "false" if something looks bad.
221734155efc18543eab20b763f9a315ab1a44240acAndy McFadden */
222734155efc18543eab20b763f9a315ab1a44240acAndy McFaddenbool dvmGetFromIndirectRefTableCheck(IndirectRefTable* pRef, IndirectRef iref)
223734155efc18543eab20b763f9a315ab1a44240acAndy McFadden{
224ab00d455ea67fbf4090567bb09ead8017896ea61Andy McFadden    if (dvmGetIndirectRefType(iref) == kIndirectKindInvalid) {
225ab00d455ea67fbf4090567bb09ead8017896ea61Andy McFadden        LOGW("Invalid indirect reference 0x%08x\n", (u4) iref);
226ab00d455ea67fbf4090567bb09ead8017896ea61Andy McFadden        return false;
227ab00d455ea67fbf4090567bb09ead8017896ea61Andy McFadden    }
228ab00d455ea67fbf4090567bb09ead8017896ea61Andy McFadden
229734155efc18543eab20b763f9a315ab1a44240acAndy McFadden    int topIndex = pRef->segmentState.parts.topIndex;
230734155efc18543eab20b763f9a315ab1a44240acAndy McFadden    int idx = dvmIndirectRefToIndex(iref);
231734155efc18543eab20b763f9a315ab1a44240acAndy McFadden
232734155efc18543eab20b763f9a315ab1a44240acAndy McFadden    if (iref == NULL) {
233734155efc18543eab20b763f9a315ab1a44240acAndy McFadden        LOGI("--- lookup on NULL iref\n");
234734155efc18543eab20b763f9a315ab1a44240acAndy McFadden        return false;
235734155efc18543eab20b763f9a315ab1a44240acAndy McFadden    }
236734155efc18543eab20b763f9a315ab1a44240acAndy McFadden    if (idx >= topIndex) {
237734155efc18543eab20b763f9a315ab1a44240acAndy McFadden        /* bad -- stale reference? */
238734155efc18543eab20b763f9a315ab1a44240acAndy McFadden        LOGI("Attempt to access invalid index %d (top=%d)\n",
239734155efc18543eab20b763f9a315ab1a44240acAndy McFadden            idx, topIndex);
240734155efc18543eab20b763f9a315ab1a44240acAndy McFadden        return false;
241734155efc18543eab20b763f9a315ab1a44240acAndy McFadden    }
242734155efc18543eab20b763f9a315ab1a44240acAndy McFadden
243734155efc18543eab20b763f9a315ab1a44240acAndy McFadden    Object* obj = pRef->table[idx];
244734155efc18543eab20b763f9a315ab1a44240acAndy McFadden    if (obj == NULL) {
245734155efc18543eab20b763f9a315ab1a44240acAndy McFadden        LOGI("Attempt to read from hole, iref=%p\n", iref);
246734155efc18543eab20b763f9a315ab1a44240acAndy McFadden        return false;
247734155efc18543eab20b763f9a315ab1a44240acAndy McFadden    }
248734155efc18543eab20b763f9a315ab1a44240acAndy McFadden    if (!checkEntry(pRef, iref, idx))
249734155efc18543eab20b763f9a315ab1a44240acAndy McFadden        return false;
250734155efc18543eab20b763f9a315ab1a44240acAndy McFadden
251734155efc18543eab20b763f9a315ab1a44240acAndy McFadden    return true;
252734155efc18543eab20b763f9a315ab1a44240acAndy McFadden}
253734155efc18543eab20b763f9a315ab1a44240acAndy McFadden
254734155efc18543eab20b763f9a315ab1a44240acAndy McFadden/*
255734155efc18543eab20b763f9a315ab1a44240acAndy McFadden * Remove "obj" from "pRef".  We extract the table offset bits from "iref"
256734155efc18543eab20b763f9a315ab1a44240acAndy McFadden * and zap the corresponding entry, leaving a hole if it's not at the top.
257734155efc18543eab20b763f9a315ab1a44240acAndy McFadden *
258734155efc18543eab20b763f9a315ab1a44240acAndy McFadden * If the entry is not between the current top index and the bottom index
259734155efc18543eab20b763f9a315ab1a44240acAndy McFadden * specified by the cookie, we don't remove anything.  This is the behavior
260734155efc18543eab20b763f9a315ab1a44240acAndy McFadden * required by JNI's DeleteLocalRef function.
261734155efc18543eab20b763f9a315ab1a44240acAndy McFadden *
2625d599603ea3d759aabe9a6b274c11b76191d1792Andy McFadden * Note this is NOT called when a local frame is popped.  This is only used
2635d599603ea3d759aabe9a6b274c11b76191d1792Andy McFadden * for explict single removals.
2645d599603ea3d759aabe9a6b274c11b76191d1792Andy McFadden *
265734155efc18543eab20b763f9a315ab1a44240acAndy McFadden * Returns "false" if nothing was removed.
266734155efc18543eab20b763f9a315ab1a44240acAndy McFadden */
267734155efc18543eab20b763f9a315ab1a44240acAndy McFaddenbool dvmRemoveFromIndirectRefTable(IndirectRefTable* pRef, u4 cookie,
268734155efc18543eab20b763f9a315ab1a44240acAndy McFadden    IndirectRef iref)
269734155efc18543eab20b763f9a315ab1a44240acAndy McFadden{
270734155efc18543eab20b763f9a315ab1a44240acAndy McFadden    IRTSegmentState prevState;
271734155efc18543eab20b763f9a315ab1a44240acAndy McFadden    prevState.all = cookie;
272734155efc18543eab20b763f9a315ab1a44240acAndy McFadden    int topIndex = pRef->segmentState.parts.topIndex;
273734155efc18543eab20b763f9a315ab1a44240acAndy McFadden    int bottomIndex = prevState.parts.topIndex;
274734155efc18543eab20b763f9a315ab1a44240acAndy McFadden
275734155efc18543eab20b763f9a315ab1a44240acAndy McFadden    assert(pRef->table != NULL);
276734155efc18543eab20b763f9a315ab1a44240acAndy McFadden    assert(pRef->allocEntries <= pRef->maxEntries);
277734155efc18543eab20b763f9a315ab1a44240acAndy McFadden    assert(pRef->segmentState.parts.numHoles >= prevState.parts.numHoles);
278734155efc18543eab20b763f9a315ab1a44240acAndy McFadden
279734155efc18543eab20b763f9a315ab1a44240acAndy McFadden    int idx = dvmIndirectRefToIndex(iref);
280734155efc18543eab20b763f9a315ab1a44240acAndy McFadden    if (idx < bottomIndex) {
281734155efc18543eab20b763f9a315ab1a44240acAndy McFadden        /* wrong segment */
282734155efc18543eab20b763f9a315ab1a44240acAndy McFadden        LOGV("Attempt to remove index outside index area (%d vs %d-%d)\n",
283734155efc18543eab20b763f9a315ab1a44240acAndy McFadden            idx, bottomIndex, topIndex);
284734155efc18543eab20b763f9a315ab1a44240acAndy McFadden        return false;
285734155efc18543eab20b763f9a315ab1a44240acAndy McFadden    }
286734155efc18543eab20b763f9a315ab1a44240acAndy McFadden    if (idx >= topIndex) {
287734155efc18543eab20b763f9a315ab1a44240acAndy McFadden        /* bad -- stale reference? */
288734155efc18543eab20b763f9a315ab1a44240acAndy McFadden        LOGI("Attempt to remove invalid index %d (bottom=%d top=%d)\n",
289734155efc18543eab20b763f9a315ab1a44240acAndy McFadden            idx, bottomIndex, topIndex);
290734155efc18543eab20b763f9a315ab1a44240acAndy McFadden        return false;
291734155efc18543eab20b763f9a315ab1a44240acAndy McFadden    }
292734155efc18543eab20b763f9a315ab1a44240acAndy McFadden
293734155efc18543eab20b763f9a315ab1a44240acAndy McFadden    if (idx == topIndex-1) {
294734155efc18543eab20b763f9a315ab1a44240acAndy McFadden        /*
295734155efc18543eab20b763f9a315ab1a44240acAndy McFadden         * Top-most entry.  Scan up and consume holes.  No need to NULL
296734155efc18543eab20b763f9a315ab1a44240acAndy McFadden         * out the entry, since the test vs. topIndex will catch it.
297734155efc18543eab20b763f9a315ab1a44240acAndy McFadden         */
298734155efc18543eab20b763f9a315ab1a44240acAndy McFadden        if (!checkEntry(pRef, iref, idx))
299734155efc18543eab20b763f9a315ab1a44240acAndy McFadden            return false;
3005d599603ea3d759aabe9a6b274c11b76191d1792Andy McFadden        updateSlotRemove(pRef, idx);
301734155efc18543eab20b763f9a315ab1a44240acAndy McFadden
302734155efc18543eab20b763f9a315ab1a44240acAndy McFadden#ifndef NDEBUG
303734155efc18543eab20b763f9a315ab1a44240acAndy McFadden        pRef->table[idx] = (IndirectRef) 0xd3d3d3d3;
304734155efc18543eab20b763f9a315ab1a44240acAndy McFadden#endif
305734155efc18543eab20b763f9a315ab1a44240acAndy McFadden
306734155efc18543eab20b763f9a315ab1a44240acAndy McFadden        int numHoles =
307734155efc18543eab20b763f9a315ab1a44240acAndy McFadden            pRef->segmentState.parts.numHoles - prevState.parts.numHoles;
308734155efc18543eab20b763f9a315ab1a44240acAndy McFadden        if (numHoles != 0) {
309734155efc18543eab20b763f9a315ab1a44240acAndy McFadden            while (--topIndex > bottomIndex && numHoles != 0) {
310734155efc18543eab20b763f9a315ab1a44240acAndy McFadden                LOGV("+++ checking for hole at %d (cookie=0x%08x) val=%p\n",
311734155efc18543eab20b763f9a315ab1a44240acAndy McFadden                    topIndex-1, cookie, pRef->table[topIndex-1]);
312734155efc18543eab20b763f9a315ab1a44240acAndy McFadden                if (pRef->table[topIndex-1] != NULL)
313734155efc18543eab20b763f9a315ab1a44240acAndy McFadden                    break;
314734155efc18543eab20b763f9a315ab1a44240acAndy McFadden                LOGV("+++ ate hole at %d\n", topIndex-1);
315734155efc18543eab20b763f9a315ab1a44240acAndy McFadden                numHoles--;
316734155efc18543eab20b763f9a315ab1a44240acAndy McFadden            }
317734155efc18543eab20b763f9a315ab1a44240acAndy McFadden            pRef->segmentState.parts.numHoles =
318734155efc18543eab20b763f9a315ab1a44240acAndy McFadden                numHoles + prevState.parts.numHoles;
319734155efc18543eab20b763f9a315ab1a44240acAndy McFadden            pRef->segmentState.parts.topIndex = topIndex;
320734155efc18543eab20b763f9a315ab1a44240acAndy McFadden        } else {
321734155efc18543eab20b763f9a315ab1a44240acAndy McFadden            pRef->segmentState.parts.topIndex = topIndex-1;
322734155efc18543eab20b763f9a315ab1a44240acAndy McFadden            LOGV("+++ ate last entry %d\n", topIndex-1);
323734155efc18543eab20b763f9a315ab1a44240acAndy McFadden        }
324734155efc18543eab20b763f9a315ab1a44240acAndy McFadden    } else {
325734155efc18543eab20b763f9a315ab1a44240acAndy McFadden        /*
326734155efc18543eab20b763f9a315ab1a44240acAndy McFadden         * Not the top-most entry.  This creates a hole.  We NULL out the
327734155efc18543eab20b763f9a315ab1a44240acAndy McFadden         * entry to prevent somebody from deleting it twice and screwing up
328734155efc18543eab20b763f9a315ab1a44240acAndy McFadden         * the hole count.
329734155efc18543eab20b763f9a315ab1a44240acAndy McFadden         */
330734155efc18543eab20b763f9a315ab1a44240acAndy McFadden        if (pRef->table[idx] == NULL) {
331734155efc18543eab20b763f9a315ab1a44240acAndy McFadden            LOGV("--- WEIRD: removing null entry %d\n", idx);
332734155efc18543eab20b763f9a315ab1a44240acAndy McFadden            return false;
333734155efc18543eab20b763f9a315ab1a44240acAndy McFadden        }
334734155efc18543eab20b763f9a315ab1a44240acAndy McFadden        if (!checkEntry(pRef, iref, idx))
335734155efc18543eab20b763f9a315ab1a44240acAndy McFadden            return false;
3365d599603ea3d759aabe9a6b274c11b76191d1792Andy McFadden        updateSlotRemove(pRef, idx);
337734155efc18543eab20b763f9a315ab1a44240acAndy McFadden
338734155efc18543eab20b763f9a315ab1a44240acAndy McFadden        pRef->table[idx] = NULL;
339734155efc18543eab20b763f9a315ab1a44240acAndy McFadden        pRef->segmentState.parts.numHoles++;
340734155efc18543eab20b763f9a315ab1a44240acAndy McFadden        LOGV("+++ left hole at %d, holes=%d\n",
341734155efc18543eab20b763f9a315ab1a44240acAndy McFadden            idx, pRef->segmentState.parts.numHoles);
342734155efc18543eab20b763f9a315ab1a44240acAndy McFadden    }
343734155efc18543eab20b763f9a315ab1a44240acAndy McFadden
344734155efc18543eab20b763f9a315ab1a44240acAndy McFadden    return true;
345734155efc18543eab20b763f9a315ab1a44240acAndy McFadden}
346734155efc18543eab20b763f9a315ab1a44240acAndy McFadden
347734155efc18543eab20b763f9a315ab1a44240acAndy McFadden/*
348734155efc18543eab20b763f9a315ab1a44240acAndy McFadden * This is a qsort() callback.  We sort Object* by class, allocation size,
349734155efc18543eab20b763f9a315ab1a44240acAndy McFadden * and then by the Object* itself.
350734155efc18543eab20b763f9a315ab1a44240acAndy McFadden */
351734155efc18543eab20b763f9a315ab1a44240acAndy McFaddenstatic int compareObject(const void* vobj1, const void* vobj2)
352734155efc18543eab20b763f9a315ab1a44240acAndy McFadden{
353734155efc18543eab20b763f9a315ab1a44240acAndy McFadden    Object* obj1 = *((Object**) vobj1);
354734155efc18543eab20b763f9a315ab1a44240acAndy McFadden    Object* obj2 = *((Object**) vobj2);
355734155efc18543eab20b763f9a315ab1a44240acAndy McFadden
356734155efc18543eab20b763f9a315ab1a44240acAndy McFadden    /* ensure null references appear at the end */
357734155efc18543eab20b763f9a315ab1a44240acAndy McFadden    if (obj1 == NULL) {
358734155efc18543eab20b763f9a315ab1a44240acAndy McFadden        if (obj2 == NULL) {
359734155efc18543eab20b763f9a315ab1a44240acAndy McFadden            return 0;
360734155efc18543eab20b763f9a315ab1a44240acAndy McFadden        } else {
361734155efc18543eab20b763f9a315ab1a44240acAndy McFadden            return 1;
362734155efc18543eab20b763f9a315ab1a44240acAndy McFadden        }
363734155efc18543eab20b763f9a315ab1a44240acAndy McFadden    } else if (obj2 == NULL) {
364734155efc18543eab20b763f9a315ab1a44240acAndy McFadden        return -1;
365734155efc18543eab20b763f9a315ab1a44240acAndy McFadden    }
366734155efc18543eab20b763f9a315ab1a44240acAndy McFadden
367734155efc18543eab20b763f9a315ab1a44240acAndy McFadden    if (obj1->clazz != obj2->clazz) {
368734155efc18543eab20b763f9a315ab1a44240acAndy McFadden        return (u1*)obj1->clazz - (u1*)obj2->clazz;
369734155efc18543eab20b763f9a315ab1a44240acAndy McFadden    } else {
370734155efc18543eab20b763f9a315ab1a44240acAndy McFadden        int size1 = dvmObjectSizeInHeap(obj1);
371734155efc18543eab20b763f9a315ab1a44240acAndy McFadden        int size2 = dvmObjectSizeInHeap(obj2);
372734155efc18543eab20b763f9a315ab1a44240acAndy McFadden        if (size1 != size2) {
373734155efc18543eab20b763f9a315ab1a44240acAndy McFadden            return size1 - size2;
374734155efc18543eab20b763f9a315ab1a44240acAndy McFadden        } else {
375734155efc18543eab20b763f9a315ab1a44240acAndy McFadden            return (u1*)obj1 - (u1*)obj2;
376734155efc18543eab20b763f9a315ab1a44240acAndy McFadden        }
377734155efc18543eab20b763f9a315ab1a44240acAndy McFadden    }
378734155efc18543eab20b763f9a315ab1a44240acAndy McFadden}
379734155efc18543eab20b763f9a315ab1a44240acAndy McFadden
380734155efc18543eab20b763f9a315ab1a44240acAndy McFadden/*
381734155efc18543eab20b763f9a315ab1a44240acAndy McFadden * Log an object with some additional info.
382734155efc18543eab20b763f9a315ab1a44240acAndy McFadden *
383734155efc18543eab20b763f9a315ab1a44240acAndy McFadden * Pass in the number of additional elements that are identical to or
384734155efc18543eab20b763f9a315ab1a44240acAndy McFadden * equivalent to the original.
385734155efc18543eab20b763f9a315ab1a44240acAndy McFadden */
386734155efc18543eab20b763f9a315ab1a44240acAndy McFaddenstatic void logObject(Object* obj, int size, int identical, int equiv)
387734155efc18543eab20b763f9a315ab1a44240acAndy McFadden{
388734155efc18543eab20b763f9a315ab1a44240acAndy McFadden    if (obj == NULL) {
389734155efc18543eab20b763f9a315ab1a44240acAndy McFadden        LOGW("  NULL reference (count=%d)\n", equiv);
390734155efc18543eab20b763f9a315ab1a44240acAndy McFadden        return;
391734155efc18543eab20b763f9a315ab1a44240acAndy McFadden    }
392734155efc18543eab20b763f9a315ab1a44240acAndy McFadden
393734155efc18543eab20b763f9a315ab1a44240acAndy McFadden    if (identical + equiv != 0) {
394734155efc18543eab20b763f9a315ab1a44240acAndy McFadden        LOGW("%5d of %s %dB (%d unique)\n", identical + equiv +1,
395734155efc18543eab20b763f9a315ab1a44240acAndy McFadden            obj->clazz->descriptor, size, equiv +1);
396734155efc18543eab20b763f9a315ab1a44240acAndy McFadden    } else {
397734155efc18543eab20b763f9a315ab1a44240acAndy McFadden        LOGW("%5d of %s %dB\n", identical + equiv +1,
398734155efc18543eab20b763f9a315ab1a44240acAndy McFadden            obj->clazz->descriptor, size);
399734155efc18543eab20b763f9a315ab1a44240acAndy McFadden    }
400734155efc18543eab20b763f9a315ab1a44240acAndy McFadden}
401734155efc18543eab20b763f9a315ab1a44240acAndy McFadden
402734155efc18543eab20b763f9a315ab1a44240acAndy McFadden/*
403734155efc18543eab20b763f9a315ab1a44240acAndy McFadden * Dump the contents of a IndirectRefTable to the log.
404734155efc18543eab20b763f9a315ab1a44240acAndy McFadden */
405734155efc18543eab20b763f9a315ab1a44240acAndy McFaddenvoid dvmDumpIndirectRefTable(const IndirectRefTable* pRef, const char* descr)
406734155efc18543eab20b763f9a315ab1a44240acAndy McFadden{
407734155efc18543eab20b763f9a315ab1a44240acAndy McFadden    const int kLast = 10;
408734155efc18543eab20b763f9a315ab1a44240acAndy McFadden    int count = dvmIndirectRefTableEntries(pRef);
409734155efc18543eab20b763f9a315ab1a44240acAndy McFadden    Object** refs;
410734155efc18543eab20b763f9a315ab1a44240acAndy McFadden    int i;
411734155efc18543eab20b763f9a315ab1a44240acAndy McFadden
412734155efc18543eab20b763f9a315ab1a44240acAndy McFadden    if (count == 0) {
413734155efc18543eab20b763f9a315ab1a44240acAndy McFadden        LOGW("Reference table has no entries\n");
414734155efc18543eab20b763f9a315ab1a44240acAndy McFadden        return;
415734155efc18543eab20b763f9a315ab1a44240acAndy McFadden    }
416734155efc18543eab20b763f9a315ab1a44240acAndy McFadden    assert(count > 0);
417734155efc18543eab20b763f9a315ab1a44240acAndy McFadden
418734155efc18543eab20b763f9a315ab1a44240acAndy McFadden    /*
419734155efc18543eab20b763f9a315ab1a44240acAndy McFadden     * Dump the most recent N entries.  If there are holes, we will show
420734155efc18543eab20b763f9a315ab1a44240acAndy McFadden     * fewer than N.
421734155efc18543eab20b763f9a315ab1a44240acAndy McFadden     */
422734155efc18543eab20b763f9a315ab1a44240acAndy McFadden    LOGW("Last %d entries in %s reference table:\n", kLast, descr);
423734155efc18543eab20b763f9a315ab1a44240acAndy McFadden    refs = pRef->table;         // use unsorted list
424734155efc18543eab20b763f9a315ab1a44240acAndy McFadden    int size;
425734155efc18543eab20b763f9a315ab1a44240acAndy McFadden    int start = count - kLast;
426734155efc18543eab20b763f9a315ab1a44240acAndy McFadden    if (start < 0)
427734155efc18543eab20b763f9a315ab1a44240acAndy McFadden        start = 0;
428734155efc18543eab20b763f9a315ab1a44240acAndy McFadden
429734155efc18543eab20b763f9a315ab1a44240acAndy McFadden    for (i = start; i < count; i++) {
430734155efc18543eab20b763f9a315ab1a44240acAndy McFadden        if (refs[i] == NULL)
431734155efc18543eab20b763f9a315ab1a44240acAndy McFadden            continue;
432734155efc18543eab20b763f9a315ab1a44240acAndy McFadden        size = dvmObjectSizeInHeap(refs[i]);
433734155efc18543eab20b763f9a315ab1a44240acAndy McFadden        Object* ref = refs[i];
434734155efc18543eab20b763f9a315ab1a44240acAndy McFadden        if (ref->clazz == gDvm.classJavaLangClass) {
435734155efc18543eab20b763f9a315ab1a44240acAndy McFadden            ClassObject* clazz = (ClassObject*) ref;
436734155efc18543eab20b763f9a315ab1a44240acAndy McFadden            LOGW("%5d: %p cls=%s '%s' (%d bytes)\n", i, ref,
437734155efc18543eab20b763f9a315ab1a44240acAndy McFadden                (refs[i] == NULL) ? "-" : ref->clazz->descriptor,
438734155efc18543eab20b763f9a315ab1a44240acAndy McFadden                clazz->descriptor, size);
439734155efc18543eab20b763f9a315ab1a44240acAndy McFadden        } else {
440734155efc18543eab20b763f9a315ab1a44240acAndy McFadden            LOGW("%5d: %p cls=%s (%d bytes)\n", i, ref,
441734155efc18543eab20b763f9a315ab1a44240acAndy McFadden                (refs[i] == NULL) ? "-" : ref->clazz->descriptor, size);
442734155efc18543eab20b763f9a315ab1a44240acAndy McFadden        }
443734155efc18543eab20b763f9a315ab1a44240acAndy McFadden    }
444734155efc18543eab20b763f9a315ab1a44240acAndy McFadden
445734155efc18543eab20b763f9a315ab1a44240acAndy McFadden    /*
446734155efc18543eab20b763f9a315ab1a44240acAndy McFadden     * Make a copy of the table, and sort it.
447734155efc18543eab20b763f9a315ab1a44240acAndy McFadden     *
448734155efc18543eab20b763f9a315ab1a44240acAndy McFadden     * The NULL "holes" wind up at the end, so we can strip them off easily.
449734155efc18543eab20b763f9a315ab1a44240acAndy McFadden     */
450734155efc18543eab20b763f9a315ab1a44240acAndy McFadden    Object** tableCopy = (Object**)malloc(sizeof(Object*) * count);
451734155efc18543eab20b763f9a315ab1a44240acAndy McFadden    memcpy(tableCopy, pRef->table, sizeof(Object*) * count);
452734155efc18543eab20b763f9a315ab1a44240acAndy McFadden    qsort(tableCopy, count, sizeof(Object*), compareObject);
453734155efc18543eab20b763f9a315ab1a44240acAndy McFadden    refs = tableCopy;       // use sorted list
454734155efc18543eab20b763f9a315ab1a44240acAndy McFadden
4555d599603ea3d759aabe9a6b274c11b76191d1792Andy McFadden    if (false) {
456734155efc18543eab20b763f9a315ab1a44240acAndy McFadden        int q;
457734155efc18543eab20b763f9a315ab1a44240acAndy McFadden        for (q = 0; q < count; q++)
458734155efc18543eab20b763f9a315ab1a44240acAndy McFadden            LOGI("%d %p\n", q, refs[q]);
459734155efc18543eab20b763f9a315ab1a44240acAndy McFadden    }
460734155efc18543eab20b763f9a315ab1a44240acAndy McFadden
461734155efc18543eab20b763f9a315ab1a44240acAndy McFadden    int holes = 0;
462734155efc18543eab20b763f9a315ab1a44240acAndy McFadden    while (refs[count-1] == NULL) {
463734155efc18543eab20b763f9a315ab1a44240acAndy McFadden        count--;
464734155efc18543eab20b763f9a315ab1a44240acAndy McFadden        holes++;
465734155efc18543eab20b763f9a315ab1a44240acAndy McFadden    }
466734155efc18543eab20b763f9a315ab1a44240acAndy McFadden
467734155efc18543eab20b763f9a315ab1a44240acAndy McFadden    /*
468734155efc18543eab20b763f9a315ab1a44240acAndy McFadden     * Dump uniquified table summary.  While we're at it, generate a
469734155efc18543eab20b763f9a315ab1a44240acAndy McFadden     * cumulative total amount of pinned memory based on the unique entries.
470734155efc18543eab20b763f9a315ab1a44240acAndy McFadden     */
471734155efc18543eab20b763f9a315ab1a44240acAndy McFadden    LOGW("%s reference table summary (%d entries / %d holes):\n",
472734155efc18543eab20b763f9a315ab1a44240acAndy McFadden        descr, count, holes);
473734155efc18543eab20b763f9a315ab1a44240acAndy McFadden    int equiv, identical, total;
474734155efc18543eab20b763f9a315ab1a44240acAndy McFadden    total = equiv = identical = 0;
475734155efc18543eab20b763f9a315ab1a44240acAndy McFadden    for (i = 1; i < count; i++) {
476734155efc18543eab20b763f9a315ab1a44240acAndy McFadden        size = dvmObjectSizeInHeap(refs[i-1]);
477734155efc18543eab20b763f9a315ab1a44240acAndy McFadden
478734155efc18543eab20b763f9a315ab1a44240acAndy McFadden        if (refs[i] == refs[i-1]) {
479734155efc18543eab20b763f9a315ab1a44240acAndy McFadden            /* same reference, added more than once */
480734155efc18543eab20b763f9a315ab1a44240acAndy McFadden            identical++;
481734155efc18543eab20b763f9a315ab1a44240acAndy McFadden        } else if (refs[i]->clazz == refs[i-1]->clazz &&
482734155efc18543eab20b763f9a315ab1a44240acAndy McFadden            (int) dvmObjectSizeInHeap(refs[i]) == size)
483734155efc18543eab20b763f9a315ab1a44240acAndy McFadden        {
484734155efc18543eab20b763f9a315ab1a44240acAndy McFadden            /* same class / size, different object */
485734155efc18543eab20b763f9a315ab1a44240acAndy McFadden            total += size;
486734155efc18543eab20b763f9a315ab1a44240acAndy McFadden            equiv++;
487734155efc18543eab20b763f9a315ab1a44240acAndy McFadden        } else {
488734155efc18543eab20b763f9a315ab1a44240acAndy McFadden            /* different class */
489734155efc18543eab20b763f9a315ab1a44240acAndy McFadden            total += size;
490734155efc18543eab20b763f9a315ab1a44240acAndy McFadden            logObject(refs[i-1], size, identical, equiv);
491734155efc18543eab20b763f9a315ab1a44240acAndy McFadden            equiv = identical = 0;
492734155efc18543eab20b763f9a315ab1a44240acAndy McFadden        }
493734155efc18543eab20b763f9a315ab1a44240acAndy McFadden    }
494734155efc18543eab20b763f9a315ab1a44240acAndy McFadden
495734155efc18543eab20b763f9a315ab1a44240acAndy McFadden    /* handle the last entry (everything above outputs refs[i-1]) */
496734155efc18543eab20b763f9a315ab1a44240acAndy McFadden    size = (refs[count-1] == NULL) ? 0 : dvmObjectSizeInHeap(refs[count-1]);
497734155efc18543eab20b763f9a315ab1a44240acAndy McFadden    total += size;
498734155efc18543eab20b763f9a315ab1a44240acAndy McFadden    logObject(refs[count-1], size, identical, equiv);
499734155efc18543eab20b763f9a315ab1a44240acAndy McFadden
500734155efc18543eab20b763f9a315ab1a44240acAndy McFadden    LOGW("Memory held directly by native code is %d bytes\n", total);
501734155efc18543eab20b763f9a315ab1a44240acAndy McFadden    free(tableCopy);
502734155efc18543eab20b763f9a315ab1a44240acAndy McFadden}
503734155efc18543eab20b763f9a315ab1a44240acAndy McFadden
504