ReferenceTable.cpp revision da2013fc08907c89084d1ff21e51302f871a0796
1f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project/*
2f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * Copyright (C) 2008 The Android Open Source Project
3f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project *
4f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * Licensed under the Apache License, Version 2.0 (the "License");
5f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * you may not use this file except in compliance with the License.
6f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * You may obtain a copy of the License at
7f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project *
8f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project *      http://www.apache.org/licenses/LICENSE-2.0
9f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project *
10f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * Unless required by applicable law or agreed to in writing, software
11f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * distributed under the License is distributed on an "AS IS" BASIS,
12f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * See the License for the specific language governing permissions and
14f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * limitations under the License.
15f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project */
16d5ab726b65d7271be261864c7e224fb90bfe06e0Andy McFadden
17f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project/*
18f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * Reference table management.
19f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project */
20f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project#include "Dalvik.h"
21f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
22f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project/*
23f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * Initialize a ReferenceTable structure.
24f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project */
25f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectbool dvmInitReferenceTable(ReferenceTable* pRef, int initialCount,
26f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    int maxCount)
27f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project{
28f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    assert(initialCount > 0);
29f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    assert(initialCount <= maxCount);
30f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
31f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    pRef->table = (Object**) malloc(initialCount * sizeof(Object*));
32f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    if (pRef->table == NULL)
33f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        return false;
34f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project#ifndef NDEBUG
35f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    memset(pRef->table, 0xdd, initialCount * sizeof(Object*));
36f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project#endif
37f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    pRef->nextEntry = pRef->table;
38f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    pRef->allocEntries = initialCount;
39f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    pRef->maxEntries = maxCount;
40f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
41f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    return true;
42f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project}
43f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
44f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project/*
45f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * Clears out the contents of a ReferenceTable, freeing allocated storage.
46f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project */
47f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectvoid dvmClearReferenceTable(ReferenceTable* pRef)
48f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project{
49f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    free(pRef->table);
50f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    pRef->table = pRef->nextEntry = NULL;
51f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    pRef->allocEntries = pRef->maxEntries = -1;
52f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project}
53f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
54f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project/*
55f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * Add "obj" to "pRef".
56f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project */
57f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectbool dvmAddToReferenceTable(ReferenceTable* pRef, Object* obj)
58f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project{
59f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    assert(dvmIsValidObject(obj));
60f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    assert(obj != NULL);
61f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    assert(pRef->table != NULL);
62734155efc18543eab20b763f9a315ab1a44240acAndy McFadden    assert(pRef->allocEntries <= pRef->maxEntries);
63734155efc18543eab20b763f9a315ab1a44240acAndy McFadden
64734155efc18543eab20b763f9a315ab1a44240acAndy McFadden    if (pRef->nextEntry == pRef->table + pRef->allocEntries) {
65734155efc18543eab20b763f9a315ab1a44240acAndy McFadden        /* reached end of allocated space; did we hit buffer max? */
66734155efc18543eab20b763f9a315ab1a44240acAndy McFadden        if (pRef->nextEntry == pRef->table + pRef->maxEntries) {
67734155efc18543eab20b763f9a315ab1a44240acAndy McFadden            LOGW("ReferenceTable overflow (max=%d)\n", pRef->maxEntries);
68734155efc18543eab20b763f9a315ab1a44240acAndy McFadden            return false;
69734155efc18543eab20b763f9a315ab1a44240acAndy McFadden        }
70f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
71f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        Object** newTable;
72f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        int newSize;
73f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
74f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        newSize = pRef->allocEntries * 2;
75f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        if (newSize > pRef->maxEntries)
76f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            newSize = pRef->maxEntries;
77f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        assert(newSize > pRef->allocEntries);
78f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
79f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        newTable = (Object**) realloc(pRef->table, newSize * sizeof(Object*));
80f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        if (newTable == NULL) {
81f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            LOGE("Unable to expand ref table (from %d to %d %d-byte entries)\n",
82f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                pRef->allocEntries, newSize, sizeof(Object*));
83f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            return false;
84f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
85f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        LOGVV("Growing %p from %d to %d\n", pRef, pRef->allocEntries, newSize);
86f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
87f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        /* update entries; adjust "nextEntry" in case memory moved */
88f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        pRef->nextEntry = newTable + (pRef->nextEntry - pRef->table);
89f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        pRef->table = newTable;
90f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        pRef->allocEntries = newSize;
91f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
92f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
93f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    *pRef->nextEntry++ = obj;
94f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    return true;
95f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project}
96f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
97f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project/*
98f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * Returns NULL if not found.
99f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project */
100d5ab726b65d7271be261864c7e224fb90bfe06e0Andy McFaddenObject** dvmFindInReferenceTable(const ReferenceTable* pRef, Object** bottom,
101f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    Object* obj)
102f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project{
103f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    Object** ptr;
104f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
105f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    ptr = pRef->nextEntry;
106d5ab726b65d7271be261864c7e224fb90bfe06e0Andy McFadden    while (--ptr >= bottom) {
107f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        if (*ptr == obj)
108f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            return ptr;
109f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
110f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    return NULL;
111f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project}
112f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
113f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project/*
114f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * Remove "obj" from "pRef".  We start at the end of the list (where the
115f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * most-recently-added element is), and stop searching for a match after
116d5ab726b65d7271be261864c7e224fb90bfe06e0Andy McFadden * examining the element at "bottom".
117f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project *
118f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * Most of the time "obj" is at or near the end of the list.  If not, we
119f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * compact it down.
120f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project */
121d5ab726b65d7271be261864c7e224fb90bfe06e0Andy McFaddenbool dvmRemoveFromReferenceTable(ReferenceTable* pRef, Object** bottom,
122f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    Object* obj)
123f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project{
124f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    Object** ptr;
125f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
126f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    assert(pRef->table != NULL);
127f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
128f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /*
129d5ab726b65d7271be261864c7e224fb90bfe06e0Andy McFadden     * Scan from the most-recently-added entry up to the bottom entry for
130f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * this frame.
131f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     */
132d5ab726b65d7271be261864c7e224fb90bfe06e0Andy McFadden    ptr = dvmFindInReferenceTable(pRef, bottom, obj);
133f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    if (ptr == NULL)
134f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        return false;
135f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
136f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /*
137f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * Delete the entry.
138f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     */
139f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    pRef->nextEntry--;
140f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    int moveCount = pRef->nextEntry - ptr;
141f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    if (moveCount != 0) {
142f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        /* remove from middle, slide the rest down */
143f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        memmove(ptr, ptr+1, moveCount * sizeof(Object*));
144f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        //LOGV("LREF delete %p, shift %d down\n", obj, moveCount);
145f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    } else {
146f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        /* last entry, falls off the end */
147f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        //LOGV("LREF delete %p from end\n", obj);
148f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
149f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
150f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    return true;
151f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project}
152f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
153f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project/*
154f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * This is a qsort() callback.  We sort Object* by class, allocation size,
155f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * and then by the Object* itself.
156f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project */
157f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectstatic int compareObject(const void* vobj1, const void* vobj2)
158f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project{
159da2013fc08907c89084d1ff21e51302f871a0796Andy McFadden    const Object* obj1 = *((Object* const*) vobj1);
160da2013fc08907c89084d1ff21e51302f871a0796Andy McFadden    const Object* obj2 = *((Object* const*) vobj2);
161f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
162da2013fc08907c89084d1ff21e51302f871a0796Andy McFadden    /* ensure null references appear at the end */
163da2013fc08907c89084d1ff21e51302f871a0796Andy McFadden    if (obj1 == NULL) {
164da2013fc08907c89084d1ff21e51302f871a0796Andy McFadden        if (obj2 == NULL) {
165da2013fc08907c89084d1ff21e51302f871a0796Andy McFadden            return 0;
166da2013fc08907c89084d1ff21e51302f871a0796Andy McFadden        } else {
167da2013fc08907c89084d1ff21e51302f871a0796Andy McFadden            return 1;
168da2013fc08907c89084d1ff21e51302f871a0796Andy McFadden        }
169da2013fc08907c89084d1ff21e51302f871a0796Andy McFadden    } else if (obj2 == NULL) {
170da2013fc08907c89084d1ff21e51302f871a0796Andy McFadden        return -1;
171da2013fc08907c89084d1ff21e51302f871a0796Andy McFadden    }
172f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
173f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    if (obj1->clazz != obj2->clazz) {
174f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        return (u1*)obj1->clazz - (u1*)obj2->clazz;
175f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    } else {
176f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        int size1 = dvmObjectSizeInHeap(obj1);
177f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        int size2 = dvmObjectSizeInHeap(obj2);
178f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        if (size1 != size2) {
179f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            return size1 - size2;
180f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        } else {
181f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            return (u1*)obj1 - (u1*)obj2;
182f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
183f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
184f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project}
185f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
186f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project/*
187f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * Log an object with some additional info.
188f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project *
189f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * Pass in the number of additional elements that are identical to or
190f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * equivalent to the original.
191f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project */
192da2013fc08907c89084d1ff21e51302f871a0796Andy McFaddenstatic void logObject(const Object* obj, int size, int identical, int equiv)
193f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project{
194f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    if (obj == NULL) {
195f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        LOGW("  NULL reference (count=%d)\n", equiv);
196f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        return;
197f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
198f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
199afcd1eb5034dcc3d424297ae282842252162661dAndy McFadden    /* handle "raw" dvmMalloc case */
200afcd1eb5034dcc3d424297ae282842252162661dAndy McFadden    const char* descriptor =
201afcd1eb5034dcc3d424297ae282842252162661dAndy McFadden        (obj->clazz != NULL) ? obj->clazz->descriptor : "(raw)";
202afcd1eb5034dcc3d424297ae282842252162661dAndy McFadden
203f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    if (identical + equiv != 0) {
204f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        LOGW("%5d of %s %dB (%d unique)\n", identical + equiv +1,
205afcd1eb5034dcc3d424297ae282842252162661dAndy McFadden            descriptor, size, equiv +1);
206f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    } else {
207afcd1eb5034dcc3d424297ae282842252162661dAndy McFadden        LOGW("%5d of %s %dB\n", identical + equiv +1, descriptor, size);
208f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
209f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project}
210f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
211f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project/*
212da2013fc08907c89084d1ff21e51302f871a0796Andy McFadden * Dump a summary of an array of references to the log file.
213f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project *
214da2013fc08907c89084d1ff21e51302f871a0796Andy McFadden * This is used to dump the contents of ReferenceTable and IndirectRefTable
215da2013fc08907c89084d1ff21e51302f871a0796Andy McFadden * structs.
216f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project */
217da2013fc08907c89084d1ff21e51302f871a0796Andy McFaddenvoid dvmDumpReferenceTableContents(Object* const* refs, size_t count,
218da2013fc08907c89084d1ff21e51302f871a0796Andy McFadden    const char* descr)
219f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project{
220da2013fc08907c89084d1ff21e51302f871a0796Andy McFadden    const size_t kLast = 10;
221f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
222f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    if (count == 0) {
22392fa476a8802023b443af893817eb14fef18aaeaAndy McFadden        LOGW("%s reference table has no entries\n", descr);
224f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        return;
225f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
226f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    assert(count > 0);
227f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
228f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /*
229f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * Dump the most recent N entries.
230f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     */
231f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    LOGW("Last %d entries in %s reference table:\n", kLast, descr);
232da2013fc08907c89084d1ff21e51302f871a0796Andy McFadden    size_t size, idx;
233f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    int start = count - kLast;
234f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    if (start < 0)
235f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        start = 0;
236f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
237da2013fc08907c89084d1ff21e51302f871a0796Andy McFadden    for (idx = start; idx < count; idx++) {
238da2013fc08907c89084d1ff21e51302f871a0796Andy McFadden        if (refs[idx] == NULL)
239da2013fc08907c89084d1ff21e51302f871a0796Andy McFadden            continue;
240da2013fc08907c89084d1ff21e51302f871a0796Andy McFadden        size = dvmObjectSizeInHeap(refs[idx]);
241da2013fc08907c89084d1ff21e51302f871a0796Andy McFadden        const Object* ref = refs[idx];
242f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        if (ref->clazz == gDvm.classJavaLangClass) {
243f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            ClassObject* clazz = (ClassObject*) ref;
244da2013fc08907c89084d1ff21e51302f871a0796Andy McFadden            LOGW("%5d: %p cls=%s '%s' (%d bytes)\n", idx, ref,
245da2013fc08907c89084d1ff21e51302f871a0796Andy McFadden                (refs[idx] == NULL) ? "-" : ref->clazz->descriptor,
246f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                clazz->descriptor, size);
247afcd1eb5034dcc3d424297ae282842252162661dAndy McFadden        } else if (ref->clazz == NULL) {
248afcd1eb5034dcc3d424297ae282842252162661dAndy McFadden            /* should only be possible right after a plain dvmMalloc() */
249da2013fc08907c89084d1ff21e51302f871a0796Andy McFadden            LOGW("%5d: %p cls=(raw) (%d bytes)\n", idx, ref, size);
250f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        } else {
251da2013fc08907c89084d1ff21e51302f871a0796Andy McFadden            LOGW("%5d: %p cls=%s (%d bytes)\n", idx, ref,
252da2013fc08907c89084d1ff21e51302f871a0796Andy McFadden                (refs[idx] == NULL) ? "-" : ref->clazz->descriptor, size);
253f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
254f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
255f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
256f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /*
257f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * Make a copy of the table, and sort it.
258f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     */
259f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    Object** tableCopy = (Object**)malloc(sizeof(Object*) * count);
260da2013fc08907c89084d1ff21e51302f871a0796Andy McFadden    if (tableCopy == NULL) {
261da2013fc08907c89084d1ff21e51302f871a0796Andy McFadden        LOGE("Unable to copy table with %d elements\n", count);
262da2013fc08907c89084d1ff21e51302f871a0796Andy McFadden        return;
263da2013fc08907c89084d1ff21e51302f871a0796Andy McFadden    }
264da2013fc08907c89084d1ff21e51302f871a0796Andy McFadden    memcpy(tableCopy, refs, sizeof(Object*) * count);
265f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    qsort(tableCopy, count, sizeof(Object*), compareObject);
266f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    refs = tableCopy;       // use sorted list
267f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
268f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /*
269da2013fc08907c89084d1ff21e51302f871a0796Andy McFadden     * Find and remove any "holes" in the list.  The sort moved them all
270da2013fc08907c89084d1ff21e51302f871a0796Andy McFadden     * to the end.
271da2013fc08907c89084d1ff21e51302f871a0796Andy McFadden     *
272da2013fc08907c89084d1ff21e51302f871a0796Andy McFadden     * A table with nothing but NULL entries should have count==0, which
273da2013fc08907c89084d1ff21e51302f871a0796Andy McFadden     * was handled above, so this operation should not leave us with an
274da2013fc08907c89084d1ff21e51302f871a0796Andy McFadden     * empty list.
275da2013fc08907c89084d1ff21e51302f871a0796Andy McFadden     */
276da2013fc08907c89084d1ff21e51302f871a0796Andy McFadden    while (refs[count-1] == NULL) {
277da2013fc08907c89084d1ff21e51302f871a0796Andy McFadden        count--;
278da2013fc08907c89084d1ff21e51302f871a0796Andy McFadden    }
279da2013fc08907c89084d1ff21e51302f871a0796Andy McFadden    assert(count > 0);
280da2013fc08907c89084d1ff21e51302f871a0796Andy McFadden
281da2013fc08907c89084d1ff21e51302f871a0796Andy McFadden    /*
282f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * Dump uniquified table summary.  While we're at it, generate a
283da2013fc08907c89084d1ff21e51302f871a0796Andy McFadden     * cumulative total amount of referenced memory based on the unique
284da2013fc08907c89084d1ff21e51302f871a0796Andy McFadden     * entries.
285f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     */
286f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    LOGW("%s reference table summary (%d entries):\n", descr, count);
287da2013fc08907c89084d1ff21e51302f871a0796Andy McFadden    size_t equiv, identical, total;
288f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    total = equiv = identical = 0;
289da2013fc08907c89084d1ff21e51302f871a0796Andy McFadden    for (idx = 1; idx < count; idx++) {
290da2013fc08907c89084d1ff21e51302f871a0796Andy McFadden        size = dvmObjectSizeInHeap(refs[idx-1]);
291f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
292da2013fc08907c89084d1ff21e51302f871a0796Andy McFadden        if (refs[idx] == refs[idx-1]) {
293f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            /* same reference, added more than once */
294f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            identical++;
295da2013fc08907c89084d1ff21e51302f871a0796Andy McFadden        } else if (refs[idx]->clazz == refs[idx-1]->clazz &&
296da2013fc08907c89084d1ff21e51302f871a0796Andy McFadden            dvmObjectSizeInHeap(refs[idx]) == size)
297f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        {
298f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            /* same class / size, different object */
299f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            total += size;
300f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            equiv++;
301f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        } else {
302f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            /* different class */
303f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            total += size;
304da2013fc08907c89084d1ff21e51302f871a0796Andy McFadden            logObject(refs[idx-1], size, identical, equiv);
305f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            equiv = identical = 0;
306f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
307f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
308f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
309f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /* handle the last entry (everything above outputs refs[i-1]) */
310da2013fc08907c89084d1ff21e51302f871a0796Andy McFadden    size = dvmObjectSizeInHeap(refs[count-1]);
311f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    total += size;
312f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    logObject(refs[count-1], size, identical, equiv);
313f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
314afcd1eb5034dcc3d424297ae282842252162661dAndy McFadden    LOGW("Memory held directly by tracked refs is %d bytes\n", total);
315f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    free(tableCopy);
316f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project}
317da2013fc08907c89084d1ff21e51302f871a0796Andy McFadden
318da2013fc08907c89084d1ff21e51302f871a0796Andy McFadden/*
319da2013fc08907c89084d1ff21e51302f871a0796Andy McFadden * Dump the contents of a ReferenceTable to the log.
320da2013fc08907c89084d1ff21e51302f871a0796Andy McFadden */
321da2013fc08907c89084d1ff21e51302f871a0796Andy McFaddenvoid dvmDumpReferenceTable(const ReferenceTable* pRef, const char* descr)
322da2013fc08907c89084d1ff21e51302f871a0796Andy McFadden{
323da2013fc08907c89084d1ff21e51302f871a0796Andy McFadden    dvmDumpReferenceTableContents(pRef->table, dvmReferenceTableEntries(pRef),
324da2013fc08907c89084d1ff21e51302f871a0796Andy McFadden        descr);
325da2013fc08907c89084d1ff21e51302f871a0796Andy McFadden}
326