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(obj != NULL);
608bc8bf71a52e17d483021b4c9dc8e735d9bce3edElliott Hughes    assert(dvmIsHeapAddress(obj));
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) {
67e8e1ddccd616e8226b7cc1e4e9fdb327429249e8Steve Block            ALOGW("ReferenceTable overflow (max=%d)", 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) {
81c1a4ab9c313d8a3d12007f2dbef7b5a6fa4ac2efSteve Block            ALOGE("Unable to expand ref table (from %d to %d %d-byte entries)",
82f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                pRef->allocEntries, newSize, sizeof(Object*));
83f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            return false;
84f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
8560fc806b679a3655c228b4093058c59941a49cfeDan Bornstein        LOGVV("Growing %p from %d to %d", 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*));
14492c1f6f1b4249e4e379452ee7b49f027052bf4ceSteve Block        //ALOGV("LREF delete %p, shift %d down", obj, moveCount);
145f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    } else {
146f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        /* last entry, falls off the end */
14792c1f6f1b4249e4e379452ee7b49f027052bf4ceSteve Block        //ALOGV("LREF delete %p from end", 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/*
1544b74b47d2120d4f3fecc47d5dd62ac65708737e5Andy McFadden * If "obj" is an array, return the number of elements in the array.
1554b74b47d2120d4f3fecc47d5dd62ac65708737e5Andy McFadden * Otherwise, return zero.
1564b74b47d2120d4f3fecc47d5dd62ac65708737e5Andy McFadden */
1574b74b47d2120d4f3fecc47d5dd62ac65708737e5Andy McFaddenstatic size_t getElementCount(const Object* obj)
1584b74b47d2120d4f3fecc47d5dd62ac65708737e5Andy McFadden{
1594b74b47d2120d4f3fecc47d5dd62ac65708737e5Andy McFadden    const ArrayObject* arrayObj = (ArrayObject*) obj;
160259a8a5154c63a793ea0ee438d146acda7d990b6Elliott Hughes    if (arrayObj == NULL || arrayObj == kClearedJniWeakGlobal ||
161259a8a5154c63a793ea0ee438d146acda7d990b6Elliott Hughes            arrayObj->clazz == NULL || !dvmIsArray(arrayObj)) {
1624b74b47d2120d4f3fecc47d5dd62ac65708737e5Andy McFadden        return 0;
163259a8a5154c63a793ea0ee438d146acda7d990b6Elliott Hughes    }
1644b74b47d2120d4f3fecc47d5dd62ac65708737e5Andy McFadden    return arrayObj->length;
1654b74b47d2120d4f3fecc47d5dd62ac65708737e5Andy McFadden}
1664b74b47d2120d4f3fecc47d5dd62ac65708737e5Andy McFadden
1674b74b47d2120d4f3fecc47d5dd62ac65708737e5Andy McFadden/*
168f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * This is a qsort() callback.  We sort Object* by class, allocation size,
169f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * and then by the Object* itself.
170f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project */
171f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectstatic int compareObject(const void* vobj1, const void* vobj2)
172f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project{
173da2013fc08907c89084d1ff21e51302f871a0796Andy McFadden    const Object* obj1 = *((Object* const*) vobj1);
174da2013fc08907c89084d1ff21e51302f871a0796Andy McFadden    const Object* obj2 = *((Object* const*) vobj2);
175f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
176259a8a5154c63a793ea0ee438d146acda7d990b6Elliott Hughes    // Ensure null references and cleared jweaks appear at the end.
177da2013fc08907c89084d1ff21e51302f871a0796Andy McFadden    if (obj1 == NULL) {
178da2013fc08907c89084d1ff21e51302f871a0796Andy McFadden        if (obj2 == NULL) {
179da2013fc08907c89084d1ff21e51302f871a0796Andy McFadden            return 0;
180da2013fc08907c89084d1ff21e51302f871a0796Andy McFadden        } else {
181da2013fc08907c89084d1ff21e51302f871a0796Andy McFadden            return 1;
182da2013fc08907c89084d1ff21e51302f871a0796Andy McFadden        }
183da2013fc08907c89084d1ff21e51302f871a0796Andy McFadden    } else if (obj2 == NULL) {
184da2013fc08907c89084d1ff21e51302f871a0796Andy McFadden        return -1;
185da2013fc08907c89084d1ff21e51302f871a0796Andy McFadden    }
186259a8a5154c63a793ea0ee438d146acda7d990b6Elliott Hughes    if (obj1 == kClearedJniWeakGlobal) {
187259a8a5154c63a793ea0ee438d146acda7d990b6Elliott Hughes        if (obj2 == kClearedJniWeakGlobal) {
188259a8a5154c63a793ea0ee438d146acda7d990b6Elliott Hughes            return 0;
189259a8a5154c63a793ea0ee438d146acda7d990b6Elliott Hughes        } else {
190259a8a5154c63a793ea0ee438d146acda7d990b6Elliott Hughes            return 1;
191259a8a5154c63a793ea0ee438d146acda7d990b6Elliott Hughes        }
192259a8a5154c63a793ea0ee438d146acda7d990b6Elliott Hughes    } else if (obj2 == kClearedJniWeakGlobal) {
193259a8a5154c63a793ea0ee438d146acda7d990b6Elliott Hughes        return -1;
194259a8a5154c63a793ea0ee438d146acda7d990b6Elliott Hughes    }
195f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
196f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    if (obj1->clazz != obj2->clazz) {
197f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        return (u1*)obj1->clazz - (u1*)obj2->clazz;
198f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    } else {
1994b74b47d2120d4f3fecc47d5dd62ac65708737e5Andy McFadden        size_t count1 = getElementCount(obj1);
2004b74b47d2120d4f3fecc47d5dd62ac65708737e5Andy McFadden        size_t count2 = getElementCount(obj2);
2014b74b47d2120d4f3fecc47d5dd62ac65708737e5Andy McFadden        if (count1 != count2) {
2024b74b47d2120d4f3fecc47d5dd62ac65708737e5Andy McFadden            return count1 - count2;
203f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        } else {
204f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            return (u1*)obj1 - (u1*)obj2;
205f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
206f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
207f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project}
208f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
209f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project/*
210f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * Log an object with some additional info.
211f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project *
2124b74b47d2120d4f3fecc47d5dd62ac65708737e5Andy McFadden * Pass in the number of elements in the array (or 0 if this is not an
2134b74b47d2120d4f3fecc47d5dd62ac65708737e5Andy McFadden * array object), and the number of additional objects that are identical
2144b74b47d2120d4f3fecc47d5dd62ac65708737e5Andy McFadden * or equivalent to the original.
215f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project */
2167c08071765cb134e4c0b18bf8fd6a7060e145212Elliott Hughesstatic void logSummaryLine(const Object* obj, size_t elems, int identical, int equiv)
217f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project{
218f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    if (obj == NULL) {
219e8e1ddccd616e8226b7cc1e4e9fdb327429249e8Steve Block        ALOGW("    NULL reference (count=%d)", equiv);
220259a8a5154c63a793ea0ee438d146acda7d990b6Elliott Hughes        return;
221259a8a5154c63a793ea0ee438d146acda7d990b6Elliott Hughes    }
222259a8a5154c63a793ea0ee438d146acda7d990b6Elliott Hughes    if (obj == kClearedJniWeakGlobal) {
223e8e1ddccd616e8226b7cc1e4e9fdb327429249e8Steve Block        ALOGW("    cleared jweak (count=%d)", equiv);
224f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        return;
225f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
226f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
2277c08071765cb134e4c0b18bf8fd6a7060e145212Elliott Hughes    std::string className(dvmHumanReadableType(obj));
2287c08071765cb134e4c0b18bf8fd6a7060e145212Elliott Hughes    if (obj->clazz == gDvm.classJavaLangClass) {
2297c08071765cb134e4c0b18bf8fd6a7060e145212Elliott Hughes        // We're summarizing multiple instances, so using the exemplar
2307c08071765cb134e4c0b18bf8fd6a7060e145212Elliott Hughes        // Class' type parameter here would be misleading.
2317c08071765cb134e4c0b18bf8fd6a7060e145212Elliott Hughes        className = "java.lang.Class";
2327c08071765cb134e4c0b18bf8fd6a7060e145212Elliott Hughes    }
2337c08071765cb134e4c0b18bf8fd6a7060e145212Elliott Hughes    if (elems != 0) {
2347c08071765cb134e4c0b18bf8fd6a7060e145212Elliott Hughes        StringAppendF(&className, " (%zd elements)", elems);
2354b74b47d2120d4f3fecc47d5dd62ac65708737e5Andy McFadden    }
2364b74b47d2120d4f3fecc47d5dd62ac65708737e5Andy McFadden
237fe7f2b3920bf5d66eda262e643245b03df3e57c8Elliott Hughes    size_t total = identical + equiv + 1;
238837eabb829417c1542037423c55536649de404b8Elliott Hughes    std::string msg(StringPrintf("%5d of %s", total, className.c_str()));
239f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    if (identical + equiv != 0) {
240837eabb829417c1542037423c55536649de404b8Elliott Hughes        StringAppendF(&msg, " (%d unique instances)", equiv + 1);
241f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
242e8e1ddccd616e8226b7cc1e4e9fdb327429249e8Steve Block    ALOGW("    %s", msg.c_str());
243f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project}
244f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
245f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project/*
246da2013fc08907c89084d1ff21e51302f871a0796Andy McFadden * Dump a summary of an array of references to the log file.
247f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project *
248da2013fc08907c89084d1ff21e51302f871a0796Andy McFadden * This is used to dump the contents of ReferenceTable and IndirectRefTable
249da2013fc08907c89084d1ff21e51302f871a0796Andy McFadden * structs.
250f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project */
251da2013fc08907c89084d1ff21e51302f871a0796Andy McFaddenvoid dvmDumpReferenceTableContents(Object* const* refs, size_t count,
252da2013fc08907c89084d1ff21e51302f871a0796Andy McFadden    const char* descr)
253f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project{
254e8e1ddccd616e8226b7cc1e4e9fdb327429249e8Steve Block    ALOGW("%s reference table (%p) dump:", descr, refs);
255259a8a5154c63a793ea0ee438d146acda7d990b6Elliott Hughes
256f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    if (count == 0) {
257e8e1ddccd616e8226b7cc1e4e9fdb327429249e8Steve Block        ALOGW("  (empty)");
258f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        return;
259f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
260f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
261259a8a5154c63a793ea0ee438d146acda7d990b6Elliott Hughes    // Dump the most recent N entries.
2624b74b47d2120d4f3fecc47d5dd62ac65708737e5Andy McFadden    const size_t kLast = 10;
263fe7f2b3920bf5d66eda262e643245b03df3e57c8Elliott Hughes    int first = count - kLast;
264fe7f2b3920bf5d66eda262e643245b03df3e57c8Elliott Hughes    if (first < 0) {
265fe7f2b3920bf5d66eda262e643245b03df3e57c8Elliott Hughes        first = 0;
266fe7f2b3920bf5d66eda262e643245b03df3e57c8Elliott Hughes    }
267e8e1ddccd616e8226b7cc1e4e9fdb327429249e8Steve Block    ALOGW("  Last %d entries (of %d):", (count - first), count);
268fe7f2b3920bf5d66eda262e643245b03df3e57c8Elliott Hughes    for (int idx = count - 1; idx >= first; --idx) {
269da2013fc08907c89084d1ff21e51302f871a0796Andy McFadden        const Object* ref = refs[idx];
270fe7f2b3920bf5d66eda262e643245b03df3e57c8Elliott Hughes        if (ref == NULL) {
2714b74b47d2120d4f3fecc47d5dd62ac65708737e5Andy McFadden            continue;
272fe7f2b3920bf5d66eda262e643245b03df3e57c8Elliott Hughes        }
273259a8a5154c63a793ea0ee438d146acda7d990b6Elliott Hughes        if (ref == kClearedJniWeakGlobal) {
274e8e1ddccd616e8226b7cc1e4e9fdb327429249e8Steve Block            ALOGW("    %5d: cleared jweak", idx);
275259a8a5154c63a793ea0ee438d146acda7d990b6Elliott Hughes            continue;
276259a8a5154c63a793ea0ee438d146acda7d990b6Elliott Hughes        }
2774b74b47d2120d4f3fecc47d5dd62ac65708737e5Andy McFadden        if (ref->clazz == NULL) {
278259a8a5154c63a793ea0ee438d146acda7d990b6Elliott Hughes            // should only be possible right after a plain dvmMalloc().
2794b74b47d2120d4f3fecc47d5dd62ac65708737e5Andy McFadden            size_t size = dvmObjectSizeInHeap(ref);
280e8e1ddccd616e8226b7cc1e4e9fdb327429249e8Steve Block            ALOGW("    %5d: %p (raw) (%zd bytes)", idx, ref, size);
281fe7f2b3920bf5d66eda262e643245b03df3e57c8Elliott Hughes            continue;
282fe7f2b3920bf5d66eda262e643245b03df3e57c8Elliott Hughes        }
283fe7f2b3920bf5d66eda262e643245b03df3e57c8Elliott Hughes
284fe7f2b3920bf5d66eda262e643245b03df3e57c8Elliott Hughes        std::string className(dvmHumanReadableType(ref));
285fe7f2b3920bf5d66eda262e643245b03df3e57c8Elliott Hughes
286fe7f2b3920bf5d66eda262e643245b03df3e57c8Elliott Hughes        std::string extras;
287fe7f2b3920bf5d66eda262e643245b03df3e57c8Elliott Hughes        size_t elems = getElementCount(ref);
288fe7f2b3920bf5d66eda262e643245b03df3e57c8Elliott Hughes        if (elems != 0) {
289837eabb829417c1542037423c55536649de404b8Elliott Hughes            StringAppendF(&extras, " (%zd elements)", elems);
290fe7f2b3920bf5d66eda262e643245b03df3e57c8Elliott Hughes        } else if (ref->clazz == gDvm.classJavaLangString) {
291fe7f2b3920bf5d66eda262e643245b03df3e57c8Elliott Hughes            const StringObject* str =
292fe7f2b3920bf5d66eda262e643245b03df3e57c8Elliott Hughes                    reinterpret_cast<const StringObject*>(ref);
293fe7f2b3920bf5d66eda262e643245b03df3e57c8Elliott Hughes            extras += " \"";
294fe7f2b3920bf5d66eda262e643245b03df3e57c8Elliott Hughes            size_t count = 0;
295fe7f2b3920bf5d66eda262e643245b03df3e57c8Elliott Hughes            char* s = dvmCreateCstrFromString(str);
296fe7f2b3920bf5d66eda262e643245b03df3e57c8Elliott Hughes            char* p = s;
297fe7f2b3920bf5d66eda262e643245b03df3e57c8Elliott Hughes            for (; *p && count < 16; ++p, ++count) {
298fe7f2b3920bf5d66eda262e643245b03df3e57c8Elliott Hughes                extras += *p;
299fe7f2b3920bf5d66eda262e643245b03df3e57c8Elliott Hughes            }
300fe7f2b3920bf5d66eda262e643245b03df3e57c8Elliott Hughes            if (*p == 0) {
301fe7f2b3920bf5d66eda262e643245b03df3e57c8Elliott Hughes                extras += "\"";
302fe7f2b3920bf5d66eda262e643245b03df3e57c8Elliott Hughes            } else {
303d8a3f9fa1951e552f5f65c2914689083cc0c46c2Elliott Hughes                StringAppendF(&extras, "... (%d chars)", str->length());
304fe7f2b3920bf5d66eda262e643245b03df3e57c8Elliott Hughes            }
305fe7f2b3920bf5d66eda262e643245b03df3e57c8Elliott Hughes            free(s);
306f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
307e8e1ddccd616e8226b7cc1e4e9fdb327429249e8Steve Block        ALOGW("    %5d: %p %s%s", idx, ref, className.c_str(), extras.c_str());
308f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
309f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
310259a8a5154c63a793ea0ee438d146acda7d990b6Elliott Hughes    // Make a copy of the table, and sort it.
311f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    Object** tableCopy = (Object**)malloc(sizeof(Object*) * count);
312da2013fc08907c89084d1ff21e51302f871a0796Andy McFadden    if (tableCopy == NULL) {
313c1a4ab9c313d8a3d12007f2dbef7b5a6fa4ac2efSteve Block        ALOGE("Unable to copy table with %d elements", count);
314da2013fc08907c89084d1ff21e51302f871a0796Andy McFadden        return;
315da2013fc08907c89084d1ff21e51302f871a0796Andy McFadden    }
316da2013fc08907c89084d1ff21e51302f871a0796Andy McFadden    memcpy(tableCopy, refs, sizeof(Object*) * count);
317f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    qsort(tableCopy, count, sizeof(Object*), compareObject);
318f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    refs = tableCopy;       // use sorted list
319f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
320259a8a5154c63a793ea0ee438d146acda7d990b6Elliott Hughes    // Remove any uninteresting stuff from the list. The sort moved them all to the end.
321259a8a5154c63a793ea0ee438d146acda7d990b6Elliott Hughes    while (count > 0 && refs[count-1] == NULL) {
322259a8a5154c63a793ea0ee438d146acda7d990b6Elliott Hughes        --count;
323259a8a5154c63a793ea0ee438d146acda7d990b6Elliott Hughes    }
324259a8a5154c63a793ea0ee438d146acda7d990b6Elliott Hughes    while (count > 0 && refs[count-1] == kClearedJniWeakGlobal) {
325259a8a5154c63a793ea0ee438d146acda7d990b6Elliott Hughes        --count;
326259a8a5154c63a793ea0ee438d146acda7d990b6Elliott Hughes    }
327259a8a5154c63a793ea0ee438d146acda7d990b6Elliott Hughes    if (count == 0) {
328259a8a5154c63a793ea0ee438d146acda7d990b6Elliott Hughes        return;
329da2013fc08907c89084d1ff21e51302f871a0796Andy McFadden    }
330da2013fc08907c89084d1ff21e51302f871a0796Andy McFadden
331259a8a5154c63a793ea0ee438d146acda7d990b6Elliott Hughes    // Dump a summary of the whole table.
332e8e1ddccd616e8226b7cc1e4e9fdb327429249e8Steve Block    ALOGW("  Summary:");
3334b74b47d2120d4f3fecc47d5dd62ac65708737e5Andy McFadden    size_t equiv, identical;
3344b74b47d2120d4f3fecc47d5dd62ac65708737e5Andy McFadden    equiv = identical = 0;
335fe7f2b3920bf5d66eda262e643245b03df3e57c8Elliott Hughes    size_t idx;
336fe7f2b3920bf5d66eda262e643245b03df3e57c8Elliott Hughes    size_t elems;
337da2013fc08907c89084d1ff21e51302f871a0796Andy McFadden    for (idx = 1; idx < count; idx++) {
3384b74b47d2120d4f3fecc47d5dd62ac65708737e5Andy McFadden        elems = getElementCount(refs[idx-1]);
339f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
340da2013fc08907c89084d1ff21e51302f871a0796Andy McFadden        if (refs[idx] == refs[idx-1]) {
341259a8a5154c63a793ea0ee438d146acda7d990b6Elliott Hughes            // same reference, added more than once.
342f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            identical++;
343da2013fc08907c89084d1ff21e51302f871a0796Andy McFadden        } else if (refs[idx]->clazz == refs[idx-1]->clazz &&
3444b74b47d2120d4f3fecc47d5dd62ac65708737e5Andy McFadden            getElementCount(refs[idx]) == elems)
345f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        {
346259a8a5154c63a793ea0ee438d146acda7d990b6Elliott Hughes            // same class / element count, different object.
347f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            equiv++;
348f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        } else {
349259a8a5154c63a793ea0ee438d146acda7d990b6Elliott Hughes            // different class.
3507c08071765cb134e4c0b18bf8fd6a7060e145212Elliott Hughes            logSummaryLine(refs[idx-1], elems, identical, equiv);
351f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            equiv = identical = 0;
352f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
353f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
354f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
355259a8a5154c63a793ea0ee438d146acda7d990b6Elliott Hughes    // Handle the last entry (everything above outputs refs[i-1]).
3564b74b47d2120d4f3fecc47d5dd62ac65708737e5Andy McFadden    elems = getElementCount(refs[idx-1]);
3577c08071765cb134e4c0b18bf8fd6a7060e145212Elliott Hughes    logSummaryLine(refs[count-1], elems, identical, equiv);
358f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
359f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    free(tableCopy);
360f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project}
361da2013fc08907c89084d1ff21e51302f871a0796Andy McFadden
362da2013fc08907c89084d1ff21e51302f871a0796Andy McFadden/*
363da2013fc08907c89084d1ff21e51302f871a0796Andy McFadden * Dump the contents of a ReferenceTable to the log.
364da2013fc08907c89084d1ff21e51302f871a0796Andy McFadden */
365da2013fc08907c89084d1ff21e51302f871a0796Andy McFaddenvoid dvmDumpReferenceTable(const ReferenceTable* pRef, const char* descr)
366da2013fc08907c89084d1ff21e51302f871a0796Andy McFadden{
367da2013fc08907c89084d1ff21e51302f871a0796Andy McFadden    dvmDumpReferenceTableContents(pRef->table, dvmReferenceTableEntries(pRef),
368da2013fc08907c89084d1ff21e51302f871a0796Andy McFadden        descr);
369da2013fc08907c89084d1ff21e51302f871a0796Andy McFadden}
370