summaryrefslogtreecommitdiffstats
path: root/vm/ReferenceTable.c
diff options
context:
space:
mode:
authorThe Android Open Source Project <initial-contribution@android.com>2009-03-03 19:28:47 -0800
committerThe Android Open Source Project <initial-contribution@android.com>2009-03-03 19:28:47 -0800
commitf6c387128427e121477c1b32ad35cdcaa5101ba3 (patch)
tree2aa25fa8c8c3a9caeecf98fd8ac4cd9b12717997 /vm/ReferenceTable.c
parentf72d5de56a522ac3be03873bdde26f23a5eeeb3c (diff)
downloadandroid_dalvik-f6c387128427e121477c1b32ad35cdcaa5101ba3.tar.gz
android_dalvik-f6c387128427e121477c1b32ad35cdcaa5101ba3.tar.bz2
android_dalvik-f6c387128427e121477c1b32ad35cdcaa5101ba3.zip
auto import from //depot/cupcake/@135843
Diffstat (limited to 'vm/ReferenceTable.c')
-rw-r--r--vm/ReferenceTable.c283
1 files changed, 283 insertions, 0 deletions
diff --git a/vm/ReferenceTable.c b/vm/ReferenceTable.c
new file mode 100644
index 000000000..c748222a7
--- /dev/null
+++ b/vm/ReferenceTable.c
@@ -0,0 +1,283 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/*
+ * Reference table management.
+ */
+#include "Dalvik.h"
+
+/*
+ * Initialize a ReferenceTable structure.
+ */
+bool dvmInitReferenceTable(ReferenceTable* pRef, int initialCount,
+ int maxCount)
+{
+ assert(initialCount > 0);
+ assert(initialCount <= maxCount);
+
+ pRef->table = (Object**) malloc(initialCount * sizeof(Object*));
+ if (pRef->table == NULL)
+ return false;
+#ifndef NDEBUG
+ memset(pRef->table, 0xdd, initialCount * sizeof(Object*));
+#endif
+ pRef->nextEntry = pRef->table;
+ pRef->allocEntries = initialCount;
+ pRef->maxEntries = maxCount;
+
+ return true;
+}
+
+/*
+ * Clears out the contents of a ReferenceTable, freeing allocated storage.
+ */
+void dvmClearReferenceTable(ReferenceTable* pRef)
+{
+ free(pRef->table);
+ pRef->table = pRef->nextEntry = NULL;
+ pRef->allocEntries = pRef->maxEntries = -1;
+}
+
+/*
+ * Add "obj" to "pRef".
+ */
+bool dvmAddToReferenceTable(ReferenceTable* pRef, Object* obj)
+{
+ assert(dvmIsValidObject(obj));
+ assert(obj != NULL);
+ assert(pRef->table != NULL);
+
+ if (pRef->nextEntry == pRef->table + pRef->maxEntries) {
+ LOGW("ReferenceTable overflow (max=%d)\n", pRef->maxEntries);
+ return false;
+ } else if (pRef->nextEntry == pRef->table + pRef->allocEntries) {
+ Object** newTable;
+ int newSize;
+
+ newSize = pRef->allocEntries * 2;
+ if (newSize > pRef->maxEntries)
+ newSize = pRef->maxEntries;
+ assert(newSize > pRef->allocEntries);
+
+ newTable = (Object**) realloc(pRef->table, newSize * sizeof(Object*));
+ if (newTable == NULL) {
+ LOGE("Unable to expand ref table (from %d to %d %d-byte entries)\n",
+ pRef->allocEntries, newSize, sizeof(Object*));
+ return false;
+ }
+ LOGVV("Growing %p from %d to %d\n", pRef, pRef->allocEntries, newSize);
+
+ /* update entries; adjust "nextEntry" in case memory moved */
+ pRef->nextEntry = newTable + (pRef->nextEntry - pRef->table);
+ pRef->table = newTable;
+ pRef->allocEntries = newSize;
+ }
+
+ *pRef->nextEntry++ = obj;
+ return true;
+}
+
+/*
+ * Returns NULL if not found.
+ */
+Object** dvmFindInReferenceTable(const ReferenceTable* pRef, Object** top,
+ Object* obj)
+{
+ Object** ptr;
+
+ ptr = pRef->nextEntry;
+ while (--ptr >= top) {
+ if (*ptr == obj)
+ return ptr;
+ }
+ return NULL;
+}
+
+/*
+ * Remove "obj" from "pRef". We start at the end of the list (where the
+ * most-recently-added element is), and stop searching for a match after
+ * examining the element at "top".
+ *
+ * Most of the time "obj" is at or near the end of the list. If not, we
+ * compact it down.
+ */
+bool dvmRemoveFromReferenceTable(ReferenceTable* pRef, Object** top,
+ Object* obj)
+{
+ Object** ptr;
+
+ assert(pRef->table != NULL);
+
+ /*
+ * Scan from the most-recently-added entry up to the top entry for
+ * this frame.
+ */
+ ptr = dvmFindInReferenceTable(pRef, top, obj);
+ if (ptr == NULL)
+ return false;
+
+ /*
+ * Delete the entry.
+ */
+ pRef->nextEntry--;
+ int moveCount = pRef->nextEntry - ptr;
+ if (moveCount != 0) {
+ /* remove from middle, slide the rest down */
+ memmove(ptr, ptr+1, moveCount * sizeof(Object*));
+ //LOGV("LREF delete %p, shift %d down\n", obj, moveCount);
+ } else {
+ /* last entry, falls off the end */
+ //LOGV("LREF delete %p from end\n", obj);
+ }
+
+ return true;
+}
+
+/*
+ * This is a qsort() callback. We sort Object* by class, allocation size,
+ * and then by the Object* itself.
+ */
+static int compareObject(const void* vobj1, const void* vobj2)
+{
+ Object* obj1 = *((Object**) vobj1);
+ Object* obj2 = *((Object**) vobj2);
+
+ if (obj1 == NULL || obj2 == NULL)
+ return (u1*)obj1 - (u1*)obj2;
+
+ if (obj1->clazz != obj2->clazz) {
+ return (u1*)obj1->clazz - (u1*)obj2->clazz;
+ } else {
+ int size1 = dvmObjectSizeInHeap(obj1);
+ int size2 = dvmObjectSizeInHeap(obj2);
+ if (size1 != size2) {
+ return size1 - size2;
+ } else {
+ return (u1*)obj1 - (u1*)obj2;
+ }
+ }
+}
+
+/*
+ * Log an object with some additional info.
+ *
+ * Pass in the number of additional elements that are identical to or
+ * equivalent to the original.
+ */
+static void logObject(Object* obj, int size, int identical, int equiv)
+{
+ if (obj == NULL) {
+ LOGW(" NULL reference (count=%d)\n", equiv);
+ return;
+ }
+
+ if (identical + equiv != 0) {
+ LOGW("%5d of %s %dB (%d unique)\n", identical + equiv +1,
+ obj->clazz->descriptor, size, equiv +1);
+ } else {
+ LOGW("%5d of %s %dB\n", identical + equiv +1,
+ obj->clazz->descriptor, size);
+ }
+}
+
+/*
+ * Dump the contents of a ReferenceTable to the log.
+ *
+ * The caller should lock any external sync before calling.
+ *
+ * (This was originally written to be tolerant of null entries in the table.
+ * I don't think that can happen anymore.)
+ */
+void dvmDumpReferenceTable(const ReferenceTable* pRef, const char* descr)
+{
+ const int kLast = 10;
+ int count = dvmReferenceTableEntries(pRef);
+ Object** refs;
+ int i;
+
+ if (count == 0) {
+ LOGW("Reference table has no entries\n");
+ return;
+ }
+ assert(count > 0);
+
+ /*
+ * Dump the most recent N entries.
+ */
+ LOGW("Last %d entries in %s reference table:\n", kLast, descr);
+ refs = pRef->table; // use unsorted list
+ int size;
+ int start = count - kLast;
+ if (start < 0)
+ start = 0;
+
+ for (i = start; i < count; i++) {
+ size = (refs[i] == NULL) ? 0 : dvmObjectSizeInHeap(refs[i]);
+ Object* ref = refs[i];
+ if (ref->clazz == gDvm.classJavaLangClass) {
+ ClassObject* clazz = (ClassObject*) ref;
+ LOGW("%5d: %p cls=%s '%s' (%d bytes)\n", i, ref,
+ (refs[i] == NULL) ? "-" : ref->clazz->descriptor,
+ clazz->descriptor, size);
+ } else {
+ LOGW("%5d: %p cls=%s (%d bytes)\n", i, ref,
+ (refs[i] == NULL) ? "-" : ref->clazz->descriptor, size);
+ }
+ }
+
+ /*
+ * Make a copy of the table, and sort it.
+ */
+ Object** tableCopy = (Object**)malloc(sizeof(Object*) * count);
+ memcpy(tableCopy, pRef->table, sizeof(Object*) * count);
+ qsort(tableCopy, count, sizeof(Object*), compareObject);
+ refs = tableCopy; // use sorted list
+
+ /*
+ * Dump uniquified table summary. While we're at it, generate a
+ * cumulative total amount of pinned memory based on the unique entries.
+ */
+ LOGW("%s reference table summary (%d entries):\n", descr, count);
+ int equiv, identical, total;
+ total = equiv = identical = 0;
+ for (i = 1; i < count; i++) {
+ size = (refs[i-1] == NULL) ? 0 : dvmObjectSizeInHeap(refs[i-1]);
+
+ if (refs[i] == refs[i-1]) {
+ /* same reference, added more than once */
+ identical++;
+ } else if (refs[i]->clazz == refs[i-1]->clazz &&
+ (int) dvmObjectSizeInHeap(refs[i]) == size)
+ {
+ /* same class / size, different object */
+ total += size;
+ equiv++;
+ } else {
+ /* different class */
+ total += size;
+ logObject(refs[i-1], size, identical, equiv);
+ equiv = identical = 0;
+ }
+ }
+
+ /* handle the last entry (everything above outputs refs[i-1]) */
+ size = (refs[count-1] == NULL) ? 0 : dvmObjectSizeInHeap(refs[count-1]);
+ total += size;
+ logObject(refs[count-1], size, identical, equiv);
+
+ LOGW("Memory held directly by native code is %d bytes\n", total);
+ free(tableCopy);
+}
+