summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorElliott Hughes <enh@google.com>2011-06-20 17:50:41 -0700
committerElliott Hughes <enh@google.com>2011-06-21 14:54:24 -0700
commitce0968340f9ddd54f20e38d4946bfd2ef8f1f343 (patch)
treeea1f9ab9f0220b3fe1f69febe47d17587ee11782
parent7c08071765cb134e4c0b18bf8fd6a7060e145212 (diff)
downloadandroid_dalvik-ce0968340f9ddd54f20e38d4946bfd2ef8f1f343.tar.gz
android_dalvik-ce0968340f9ddd54f20e38d4946bfd2ef8f1f343.tar.bz2
android_dalvik-ce0968340f9ddd54f20e38d4946bfd2ef8f1f343.zip
Clean up IndirectRefTable a bit.
The main purpose here was to have slightly less unclear warnings for JNI local reference abuse. Change-Id: I2c6378dd0a94d8afb96a8e409f7460205e3cd315
-rw-r--r--vm/CheckJni.cpp19
-rw-r--r--vm/IndirectRefTable.cpp269
-rw-r--r--vm/IndirectRefTable.h313
-rw-r--r--vm/Jni.cpp84
-rw-r--r--vm/Thread.cpp7
-rw-r--r--vm/alloc/MarkSweep.cpp2
-rw-r--r--vm/alloc/Visit.cpp2
-rw-r--r--vm/test/TestIndirectRefTable.cpp322
8 files changed, 364 insertions, 654 deletions
diff --git a/vm/CheckJni.cpp b/vm/CheckJni.cpp
index d1ecd1055..7f3e631ad 100644
--- a/vm/CheckJni.cpp
+++ b/vm/CheckJni.cpp
@@ -264,6 +264,11 @@ private:
#define kFlag_ExcepBad 0x0000 /* raised exceptions are bad */
#define kFlag_ExcepOkay 0x0004 /* ...okay */
+static const char* indirectRefKindName(IndirectRef iref)
+{
+ return indirectRefKindToString(indirectRefKind(iref));
+}
+
class ScopedCheck {
public:
explicit ScopedCheck(JNIEnv* env, int flags, const char* functionName)
@@ -294,7 +299,8 @@ public:
Object* obj = dvmDecodeIndirectRef(mEnv, jarr);
if (!dvmIsValidObject(obj)) {
- LOGW("JNI WARNING: jarray is invalid %s ref (%p)", dvmIndirectRefTypeName(jarr), jarr);
+ LOGW("JNI WARNING: jarray is an invalid %s reference (%p)",
+ indirectRefKindName(jarr), jarr);
printWarn = true;
} else if (obj->clazz->descriptor[0] != '[') {
LOGW("JNI WARNING: jarray arg has wrong type (expected array, got %s)",
@@ -354,8 +360,8 @@ public:
* and valid.
*/
if (obj != NULL && !dvmIsValidObject(obj)) {
- LOGW("JNI WARNING: field operation on invalid %s ref (%p)",
- dvmIndirectRefTypeName(jobj), jobj);
+ LOGW("JNI WARNING: field operation on invalid %s reference (%p)",
+ indirectRefKindName(jobj), jobj);
printWarn = true;
} else {
ClassObject* fieldClass = dvmFindLoadedClass(field->signature);
@@ -458,8 +464,7 @@ public:
bool printWarn = false;
if (dvmGetJNIRefType(mEnv, jobj) == JNIInvalidRefType) {
- LOGW("JNI WARNING: %p is not a valid JNI reference (type=%s)",
- jobj, dvmIndirectRefTypeName(jobj));
+ LOGW("JNI WARNING: %p is not a valid JNI reference", jobj);
printWarn = true;
} else {
Object* obj = dvmDecodeIndirectRef(mEnv, jobj);
@@ -727,8 +732,8 @@ private:
Object* obj = dvmDecodeIndirectRef(mEnv, jobj);
if (!dvmIsValidObject(obj)) {
- LOGW("JNI WARNING: %s is invalid %s ref (%p)",
- argName, dvmIndirectRefTypeName(jobj), jobj);
+ LOGW("JNI WARNING: %s is an invalid %s reference (%p)",
+ argName, indirectRefKindName(jobj), jobj);
printWarn = true;
} else if (obj->clazz != expectedClass) {
LOGW("JNI WARNING: %s arg has wrong type (expected %s, got %s)",
diff --git a/vm/IndirectRefTable.cpp b/vm/IndirectRefTable.cpp
index 225d8c20e..270727ce8 100644
--- a/vm/IndirectRefTable.cpp
+++ b/vm/IndirectRefTable.cpp
@@ -19,32 +19,31 @@
*/
#include "Dalvik.h"
-/*
- * Initialize an IndirectRefTable structure.
- */
-bool dvmInitIndirectRefTable(IndirectRefTable* pRef, int initialCount,
- int maxCount, IndirectRefKind kind)
+bool IndirectRefTable::init(size_t initialCount,
+ size_t maxCount, IndirectRefKind desiredKind)
{
assert(initialCount > 0);
assert(initialCount <= maxCount);
assert(kind != kIndirectKindInvalid);
- pRef->table = (Object**) malloc(initialCount * sizeof(Object*));
- if (pRef->table == NULL)
+ table = (Object**) malloc(initialCount * sizeof(Object*));
+ if (table == NULL) {
return false;
+ }
#ifndef NDEBUG
- memset(pRef->table, 0xd1, initialCount * sizeof(Object*));
+ memset(table, 0xd1, initialCount * sizeof(Object*));
#endif
- pRef->slotData =
+ slotData =
(IndirectRefSlot*) calloc(maxCount, sizeof(IndirectRefSlot));
- if (pRef->slotData == NULL)
+ if (slotData == NULL) {
return false;
+ }
- pRef->segmentState.all = IRT_FIRST_SEGMENT;
- pRef->allocEntries = initialCount;
- pRef->maxEntries = maxCount;
- pRef->kind = kind;
+ segmentState.all = IRT_FIRST_SEGMENT;
+ allocEntries = initialCount;
+ maxEntries = maxCount;
+ kind = desiredKind;
return true;
}
@@ -52,133 +51,69 @@ bool dvmInitIndirectRefTable(IndirectRefTable* pRef, int initialCount,
/*
* Clears out the contents of a IndirectRefTable, freeing allocated storage.
*/
-void dvmClearIndirectRefTable(IndirectRefTable* pRef)
+void IndirectRefTable::destroy()
{
- free(pRef->table);
- free(pRef->slotData);
- pRef->table = NULL;
- pRef->allocEntries = pRef->maxEntries = -1;
-}
-
-/*
- * Remove one or more segments from the top. The table entry identified
- * by "cookie" becomes the new top-most entry.
- *
- * Returns false if "cookie" is invalid or the table has only one segment.
- */
-bool dvmPopIndirectRefTableSegmentCheck(IndirectRefTable* pRef, u4 cookie)
-{
- IRTSegmentState sst;
-
- /*
- * The new value for "top" must be <= the current value. Otherwise
- * this would represent an expansion of the table.
- */
- sst.all = cookie;
- if (sst.parts.topIndex > pRef->segmentState.parts.topIndex) {
- LOGE("Attempt to expand table with segment pop (%d to %d)",
- pRef->segmentState.parts.topIndex, sst.parts.topIndex);
- return false;
- }
- if (sst.parts.numHoles >= sst.parts.topIndex) {
- LOGE("Absurd numHoles in cookie (%d bi=%d)",
- sst.parts.numHoles, sst.parts.topIndex);
- return false;
- }
-
- LOGV("IRT %p[%d]: pop, top=%d holes=%d",
- pRef, pRef->kind, sst.parts.topIndex, sst.parts.numHoles);
-
- return true;
+ free(table);
+ free(slotData);
+ table = NULL;
+ allocEntries = maxEntries = -1;
}
/*
* Make sure that the entry at "idx" is correctly paired with "iref".
*/
-static bool checkEntry(IndirectRefTable* pRef, IndirectRef iref, int idx)
+bool IndirectRefTable::checkEntry(IndirectRef iref, int idx) const
{
- Object* obj = pRef->table[idx];
- IndirectRef checkRef = dvmObjectToIndirectRef(pRef, obj, idx, pRef->kind);
+ Object* obj = table[idx];
+ IndirectRef checkRef = toIndirectRef(obj, idx);
if (checkRef != iref) {
- LOGW("IRT %p[%d]: iref mismatch (req=%p vs cur=%p)",
- pRef, pRef->kind, iref, checkRef);
+ LOGE("Attempt to use stale %s reference (req=%p vs cur=%p; table=%p)",
+ indirectRefKindToString(kind), iref, checkRef, this);
return false;
}
return true;
}
-/*
- * Update extended debug info when an entry is added.
- *
- * We advance the serial number, invalidating any outstanding references to
- * this slot.
- */
-static inline void updateSlotAdd(IndirectRefTable* pRef, Object* obj, int slot)
-{
- if (pRef->slotData != NULL) {
- IndirectRefSlot* pSlot = &pRef->slotData[slot];
- pSlot->serial++;
- //LOGI("+++ add [%d] slot %d (%p->%p), serial=%d",
- // pRef->kind, slot, obj, iref, pSlot->serial);
- pSlot->previous[pSlot->serial % kIRTPrevCount] = obj;
- }
-}
-
-/*
- * Update extended debug info when an entry is removed.
- */
-static inline void updateSlotRemove(IndirectRefTable* pRef, int slot)
-{
- if (pRef->slotData != NULL) {
- //IndirectRefSlot* pSlot = &pRef->slotData[slot];
- //LOGI("+++ remove [%d] slot %d, serial now %d",
- // pRef->kind, slot, pSlot->serial);
- }
-}
-
-/*
- * Add "obj" to "pRef".
- */
-IndirectRef dvmAddToIndirectRefTable(IndirectRefTable* pRef, u4 cookie,
- Object* obj)
+IndirectRef IndirectRefTable::add(u4 cookie, Object* obj)
{
IRTSegmentState prevState;
prevState.all = cookie;
- int topIndex = pRef->segmentState.parts.topIndex;
+ size_t topIndex = segmentState.parts.topIndex;
assert(obj != NULL);
assert(dvmIsValidObject(obj));
- assert(pRef->table != NULL);
- assert(pRef->allocEntries <= pRef->maxEntries);
- assert(pRef->segmentState.parts.numHoles >= prevState.parts.numHoles);
+ assert(table != NULL);
+ assert(allocEntries <= maxEntries);
+ assert(segmentState.parts.numHoles >= prevState.parts.numHoles);
- if (topIndex == pRef->allocEntries) {
+ if (topIndex == allocEntries) {
/* reached end of allocated space; did we hit buffer max? */
- if (topIndex == pRef->maxEntries) {
- LOGW("IndirectRefTable overflow (max=%d)", pRef->maxEntries);
+ if (topIndex == maxEntries) {
+ LOGW("%s reference table overflow (max=%d)",
+ indirectRefKindToString(kind), maxEntries);
return NULL;
}
- Object** newTable;
- int newSize;
-
- newSize = pRef->allocEntries * 2;
- if (newSize > pRef->maxEntries)
- newSize = pRef->maxEntries;
- assert(newSize > pRef->allocEntries);
+ size_t newSize = allocEntries * 2;
+ if (newSize > maxEntries) {
+ newSize = maxEntries;
+ }
+ assert(newSize > allocEntries);
- newTable = (Object**) realloc(pRef->table, newSize * sizeof(Object*));
+ Object** newTable = (Object**) realloc(table, newSize * sizeof(Object*));
if (newTable == NULL) {
- LOGE("Unable to expand iref table (from %d to %d, max=%d)",
- pRef->allocEntries, newSize, pRef->maxEntries);
+ LOGE("Unable to expand %s reference table from %d to %d (max=%d)",
+ indirectRefKindToString(kind), allocEntries,
+ newSize, maxEntries);
return false;
}
- LOGV("Growing ireftab %p from %d to %d (max=%d)",
- pRef, pRef->allocEntries, newSize, pRef->maxEntries);
+ LOGV("Growing %s reference table %p from %d to %d (max=%d)",
+ indirectRefKindToString(kind), this,
+ allocEntries, newSize, maxEntries);
/* update entries; adjust "nextEntry" in case memory moved */
- pRef->table = newTable;
- pRef->allocEntries = newSize;
+ table = newTable;
+ allocEntries = newSize;
}
IndirectRef result;
@@ -188,26 +123,25 @@ IndirectRef dvmAddToIndirectRefTable(IndirectRefTable* pRef, u4 cookie,
* the right spot. If there's a hole, find it and fill it; otherwise,
* add to the end of the list.
*/
- int numHoles = pRef->segmentState.parts.numHoles - prevState.parts.numHoles;
+ int numHoles = segmentState.parts.numHoles - prevState.parts.numHoles;
if (numHoles > 0) {
assert(topIndex > 1);
/* find the first hole; likely to be near the end of the list */
- Object** pScan = &pRef->table[topIndex - 1];
+ Object** pScan = &table[topIndex - 1];
assert(*pScan != NULL);
while (*--pScan != NULL) {
- assert(pScan >= pRef->table + prevState.parts.topIndex);
+ assert(pScan >= table + prevState.parts.topIndex);
}
- updateSlotAdd(pRef, obj, pScan - pRef->table);
- result = dvmObjectToIndirectRef(pRef, obj, pScan - pRef->table,
- pRef->kind);
+ updateSlotAdd(obj, pScan - table);
+ result = toIndirectRef(obj, pScan - table);
*pScan = obj;
- pRef->segmentState.parts.numHoles--;
+ segmentState.parts.numHoles--;
} else {
/* add to the end */
- updateSlotAdd(pRef, obj, topIndex);
- result = dvmObjectToIndirectRef(pRef, obj, topIndex, pRef->kind);
- pRef->table[topIndex++] = obj;
- pRef->segmentState.parts.topIndex = topIndex;
+ updateSlotAdd(obj, topIndex);
+ result = toIndirectRef(obj, topIndex);
+ table[topIndex++] = obj;
+ segmentState.parts.topIndex = topIndex;
}
assert(result != NULL);
@@ -219,34 +153,37 @@ IndirectRef dvmAddToIndirectRefTable(IndirectRefTable* pRef, u4 cookie,
*
* Returns "false" if something looks bad.
*/
-bool dvmGetFromIndirectRefTableCheck(IndirectRefTable* pRef, IndirectRef iref)
+bool IndirectRefTable::getChecked(IndirectRef iref) const
{
- if (dvmGetIndirectRefType(iref) == kIndirectKindInvalid) {
- LOGW("Invalid indirect reference 0x%08x", (u4) iref);
+ if (iref == NULL) {
+ LOGW("Attempt to look up NULL %s reference",
+ indirectRefKindToString(kind));
return false;
}
-
- int topIndex = pRef->segmentState.parts.topIndex;
- int idx = dvmIndirectRefToIndex(iref);
-
- if (iref == NULL) {
- LOGD("Attempt to look up NULL iref");
+ if (indirectRefKind(iref) == kIndirectKindInvalid) {
+ LOGW("Invalid %s reference %p",
+ indirectRefKindToString(kind), iref);
return false;
}
+
+ int topIndex = segmentState.parts.topIndex;
+ int idx = extractIndex(iref);
if (idx >= topIndex) {
/* bad -- stale reference? */
- LOGD("Attempt to access invalid index %d (top=%d)",
- idx, topIndex);
+ LOGW("Attempt to access stale %s reference at index %d (top=%d)",
+ indirectRefKindToString(kind), idx, topIndex);
return false;
}
- Object* obj = pRef->table[idx];
+ Object* obj = table[idx];
if (obj == NULL) {
- LOGD("Attempt to read from hole, iref=%p", iref);
+ LOGW("Attempt to access deleted %s reference (%p)",
+ indirectRefKindToString(kind), iref);
return false;
}
- if (!checkEntry(pRef, iref, idx))
+ if (!checkEntry(iref, idx)) {
return false;
+ }
return true;
}
@@ -264,19 +201,18 @@ bool dvmGetFromIndirectRefTableCheck(IndirectRefTable* pRef, IndirectRef iref)
*
* Returns "false" if nothing was removed.
*/
-bool dvmRemoveFromIndirectRefTable(IndirectRefTable* pRef, u4 cookie,
- IndirectRef iref)
+bool IndirectRefTable::remove(u4 cookie, IndirectRef iref)
{
IRTSegmentState prevState;
prevState.all = cookie;
- int topIndex = pRef->segmentState.parts.topIndex;
+ int topIndex = segmentState.parts.topIndex;
int bottomIndex = prevState.parts.topIndex;
- assert(pRef->table != NULL);
- assert(pRef->allocEntries <= pRef->maxEntries);
- assert(pRef->segmentState.parts.numHoles >= prevState.parts.numHoles);
+ assert(table != NULL);
+ assert(allocEntries <= maxEntries);
+ assert(segmentState.parts.numHoles >= prevState.parts.numHoles);
- int idx = dvmIndirectRefToIndex(iref);
+ int idx = extractIndex(iref);
if (idx < bottomIndex) {
/* wrong segment */
LOGV("Attempt to remove index outside index area (%d vs %d-%d)",
@@ -295,30 +231,31 @@ bool dvmRemoveFromIndirectRefTable(IndirectRefTable* pRef, u4 cookie,
* Top-most entry. Scan up and consume holes. No need to NULL
* out the entry, since the test vs. topIndex will catch it.
*/
- if (!checkEntry(pRef, iref, idx))
+ if (!checkEntry(iref, idx)) {
return false;
- updateSlotRemove(pRef, idx);
+ }
+ updateSlotRemove(idx);
#ifndef NDEBUG
- pRef->table[idx] = (Object*)0xd3d3d3d3;
+ table[idx] = (Object*)0xd3d3d3d3;
#endif
int numHoles =
- pRef->segmentState.parts.numHoles - prevState.parts.numHoles;
+ segmentState.parts.numHoles - prevState.parts.numHoles;
if (numHoles != 0) {
while (--topIndex > bottomIndex && numHoles != 0) {
LOGV("+++ checking for hole at %d (cookie=0x%08x) val=%p",
- topIndex-1, cookie, pRef->table[topIndex-1]);
- if (pRef->table[topIndex-1] != NULL)
+ topIndex-1, cookie, table[topIndex-1]);
+ if (table[topIndex-1] != NULL)
break;
LOGV("+++ ate hole at %d", topIndex-1);
numHoles--;
}
- pRef->segmentState.parts.numHoles =
+ segmentState.parts.numHoles =
numHoles + prevState.parts.numHoles;
- pRef->segmentState.parts.topIndex = topIndex;
+ segmentState.parts.topIndex = topIndex;
} else {
- pRef->segmentState.parts.topIndex = topIndex-1;
+ segmentState.parts.topIndex = topIndex-1;
LOGV("+++ ate last entry %d", topIndex-1);
}
} else {
@@ -327,29 +264,27 @@ bool dvmRemoveFromIndirectRefTable(IndirectRefTable* pRef, u4 cookie,
* entry to prevent somebody from deleting it twice and screwing up
* the hole count.
*/
- if (pRef->table[idx] == NULL) {
+ if (table[idx] == NULL) {
LOGV("--- WEIRD: removing null entry %d", idx);
return false;
}
- if (!checkEntry(pRef, iref, idx))
+ if (!checkEntry(iref, idx)) {
return false;
- updateSlotRemove(pRef, idx);
+ }
+ updateSlotRemove(idx);
- pRef->table[idx] = NULL;
- pRef->segmentState.parts.numHoles++;
+ table[idx] = NULL;
+ segmentState.parts.numHoles++;
LOGV("+++ left hole at %d, holes=%d",
- idx, pRef->segmentState.parts.numHoles);
+ idx, segmentState.parts.numHoles);
}
return true;
}
-/*
- * Return a type name, useful for debugging.
- */
-const char* dvmIndirectRefTypeName(IndirectRef iref)
+const char* indirectRefKindToString(IndirectRefKind kind)
{
- switch (dvmGetIndirectRefType(iref)) {
+ switch (kind) {
case kIndirectKindInvalid: return "invalid";
case kIndirectKindLocal: return "local";
case kIndirectKindGlobal: return "global";
@@ -358,11 +293,7 @@ const char* dvmIndirectRefTypeName(IndirectRef iref)
}
}
-/*
- * Dump the contents of a IndirectRefTable to the log.
- */
-void dvmDumpIndirectRefTable(const IndirectRefTable* pRef, const char* descr)
+void IndirectRefTable::dump(const char* descr) const
{
- dvmDumpReferenceTableContents(pRef->table, dvmIndirectRefTableEntries(pRef),
- descr);
+ dvmDumpReferenceTableContents(table, capacity(), descr);
}
diff --git a/vm/IndirectRefTable.h b/vm/IndirectRefTable.h
index 8b8f4d7ea..4b91c88d4 100644
--- a/vm/IndirectRefTable.h
+++ b/vm/IndirectRefTable.h
@@ -85,6 +85,9 @@
*/
typedef void* IndirectRef;
+/* magic failure value; must not pass dvmIsValidObject() */
+#define kInvalidIndirectRefObject ((Object*)0xdead4321)
+
/*
* Indirect reference kind, used as the two low bits of IndirectRef.
*
@@ -96,6 +99,15 @@ enum IndirectRefKind {
kIndirectKindGlobal = 2,
kIndirectKindWeakGlobal = 3
};
+const char* indirectRefKindToString(IndirectRefKind kind);
+
+/*
+ * Determine what kind of indirect reference this is.
+ */
+INLINE IndirectRefKind indirectRefKind(IndirectRef iref)
+{
+ return (IndirectRefKind)((u4) iref & 0x03);
+}
/*
* Extended debugging structure. We keep a parallel array of these, one
@@ -107,6 +119,9 @@ struct IndirectRefSlot {
Object* previous[kIRTPrevCount];
};
+/* use as initial value for "cookie", and when table has only one segment */
+#define IRT_FIRST_SEGMENT 0
+
/*
* Table definition.
*
@@ -188,205 +203,137 @@ struct IndirectRefTable {
/* semi-public - read-only during GC scan; pointer must not be kept */
Object** table; /* bottom of the stack */
- /* private */
- IndirectRefSlot* slotData; /* extended debugging info */
- int allocEntries; /* #of entries we have space for */
- int maxEntries; /* max #of entries allowed */
+ /*
+ * private:
+ *
+ * TODO: we can't make these private as long as the interpreter
+ * uses offsetof, since private member data makes us non-POD.
+ */
IndirectRefKind kind; /* bit mask, ORed into all irefs */
+ IndirectRefSlot* slotData; /* extended debugging info */
+ size_t allocEntries; /* #of entries we have space for */
+ size_t maxEntries; /* max #of entries allowed */
// TODO: want hole-filling stats (#of holes filled, total entries scanned)
// for performance evaluation.
-};
-
-/* use as initial value for "cookie", and when table has only one segment */
-#define IRT_FIRST_SEGMENT 0
-
-/*
- * (This is PRIVATE, but we want it inside other inlines in this header.)
- *
- * Indirectify the object.
- *
- * The object pointer itself is subject to relocation in some GC
- * implementations, so we shouldn't really be using it here.
- */
-INLINE IndirectRef dvmObjectToIndirectRef(IndirectRefTable* pRef,
- Object* obj, u4 tableIndex, IndirectRefKind kind)
-{
- assert(tableIndex < 65536);
- //u4 objChunk = (((u4) obj >> 3) ^ ((u4) obj >> 19)) & 0x3fff;
- //u4 uref = objChunk << 18 | (tableIndex << 2) | kind;
- u4 serialChunk = pRef->slotData[tableIndex].serial;
- u4 uref = serialChunk << 20 | (tableIndex << 2) | kind;
- return (IndirectRef) uref;
-}
-
-/*
- * (This is PRIVATE, but we want it inside other inlines in this header.)
- *
- * Extract the table index from an indirect reference.
- */
-INLINE u4 dvmIndirectRefToIndex(IndirectRef iref)
-{
- u4 uref = (u4) iref;
- return (uref >> 2) & 0xffff;
-}
-
-/*
- * Determine what kind of indirect reference this is.
- */
-INLINE IndirectRefKind dvmGetIndirectRefType(IndirectRef iref)
-{
- return (IndirectRefKind)((u4) iref & 0x03);
-}
-
-/*
- * Return a string constant describing the indirect ref type.
- */
-const char* dvmIndirectRefTypeName(IndirectRef iref);
-
-/*
- * Initialize an IndirectRefTable.
- *
- * If "initialCount" != "maxCount", the table will expand as required.
- *
- * "kind" should be Local or Global. The Global table may also hold
- * WeakGlobal refs.
- *
- * Returns "false" if table allocation fails.
- */
-bool dvmInitIndirectRefTable(IndirectRefTable* pRef, int initialCount,
- int maxCount, IndirectRefKind kind);
-
-/*
- * Clear out the contents, freeing allocated storage. Does not free "pRef".
- *
- * You must call dvmInitReferenceTable() before you can re-use this table.
- */
-void dvmClearIndirectRefTable(IndirectRefTable* pRef);
-/*
- * Start a new segment at the top of the table.
- *
- * Returns an opaque 32-bit value that must be provided when the segment
- * is to be removed.
- *
- * IMPORTANT: this is implemented as a single instruction in mterp, rather
- * than a call here. You can add debugging aids for the C-language
- * interpreters, but the basic implementation may not change.
- */
-INLINE u4 dvmPushIndirectRefTableSegment(IndirectRefTable* pRef)
-{
- return pRef->segmentState.all;
-}
+ /*
+ * Add a new entry. "obj" must be a valid non-NULL object reference
+ * (though it's okay if it's not fully-formed, e.g. the result from
+ * dvmMalloc doesn't have obj->clazz set).
+ *
+ * Returns NULL if the table is full (max entries reached, or alloc
+ * failed during expansion).
+ */
+ IndirectRef add(u4 cookie, Object* obj);
-/* extra debugging checks */
-bool dvmPopIndirectRefTableSegmentCheck(IndirectRefTable* pRef, u4 cookie);
+ /*
+ * Given an IndirectRef in the table, return the Object it refers to.
+ *
+ * Returns kInvalidIndirectRefObject if iref is invalid.
+ */
+ Object* get(IndirectRef iref) const {
+ if (!getChecked(iref)) {
+ return kInvalidIndirectRefObject;
+ }
+ return table[extractIndex(iref)];
+ }
-/*
- * Remove one or more segments from the top. The table entry identified
- * by "cookie" becomes the new top-most entry.
- *
- * IMPORTANT: this is implemented as a single instruction in mterp, rather
- * than a call here. You can add debugging aids for the C-language
- * interpreters, but the basic implementation must not change.
- */
-INLINE void dvmPopIndirectRefTableSegment(IndirectRefTable* pRef, u4 cookie)
-{
- dvmPopIndirectRefTableSegmentCheck(pRef, cookie);
- pRef->segmentState.all = cookie;
-}
+ /*
+ * Remove an existing entry.
+ *
+ * If the entry is not between the current top index and the bottom index
+ * specified by the cookie, we don't remove anything. This is the behavior
+ * required by JNI's DeleteLocalRef function.
+ *
+ * Returns "false" if nothing was removed.
+ */
+ bool remove(u4 cookie, IndirectRef iref);
-/*
- * Return the #of entries in the entire table. This includes holes, and
- * so may be larger than the actual number of "live" entries.
- */
-INLINE size_t dvmIndirectRefTableEntries(const IndirectRefTable* pRef)
-{
- return pRef->segmentState.parts.topIndex;
-}
+ /*
+ * Initialize an IndirectRefTable.
+ *
+ * If "initialCount" != "maxCount", the table will expand as required.
+ *
+ * "kind" should be Local or Global. The Global table may also hold
+ * WeakGlobal refs.
+ *
+ * Returns "false" if table allocation fails.
+ */
+ bool init(size_t initialCount, size_t maxCount, IndirectRefKind kind);
-/*
- * Returns "true" if the table is full. The table is considered full if
- * we would need to expand it to add another entry to the current segment.
- */
-INLINE size_t dvmIsIndirectRefTableFull(const IndirectRefTable* pRef)
-{
- return dvmIndirectRefTableEntries(pRef) == (size_t)pRef->allocEntries;
-}
+ /*
+ * Clear out the contents, freeing allocated storage.
+ *
+ * You must call dvmInitReferenceTable() before you can re-use this table.
+ *
+ * TODO: this should be a destructor.
+ */
+ void destroy();
-/*
- * Add a new entry. "obj" must be a valid non-NULL object reference
- * (though it's okay if it's not fully-formed, e.g. the result from
- * dvmMalloc doesn't have obj->clazz set).
- *
- * Returns NULL if the table is full (max entries reached, or alloc
- * failed during expansion).
- */
-IndirectRef dvmAddToIndirectRefTable(IndirectRefTable* pRef, u4 cookie,
- Object* obj);
+ /*
+ * Dump the contents of a reference table to the log file.
+ *
+ * The caller should lock any external sync before calling.
+ *
+ * TODO: we should name the table in a constructor and remove
+ * the argument here.
+ */
+ void dump(const char* descr) const;
-/*
- * Add a new entry at the end. Similar to Add but does not usually attempt
- * to fill in holes. This is only appropriate to use right after a new
- * segment has been pushed.
- *
- * (This is intended for use when calling into a native JNI method, so
- * performance is critical.)
- */
-INLINE IndirectRef dvmAppendToIndirectRefTable(IndirectRefTable* pRef,
- u4 cookie, Object* obj)
-{
- int topIndex = pRef->segmentState.parts.topIndex;
- if (topIndex == pRef->allocEntries) {
- /* up against alloc or max limit, call the fancy version */
- return dvmAddToIndirectRefTable(pRef, cookie, obj);
- } else {
- IndirectRef result = dvmObjectToIndirectRef(pRef, obj, topIndex,
- pRef->kind);
- pRef->table[topIndex++] = obj;
- pRef->segmentState.parts.topIndex = topIndex;
- return result;
+ /*
+ * Return the #of entries in the entire table. This includes holes, and
+ * so may be larger than the actual number of "live" entries.
+ */
+ size_t capacity() const {
+ return segmentState.parts.topIndex;
}
-}
-
-/* extra debugging checks */
-bool dvmGetFromIndirectRefTableCheck(IndirectRefTable* pRef, IndirectRef iref);
-/* magic failure value; must not pass dvmIsValidObject() */
-#define kInvalidIndirectRefObject ((Object*)0xdead4321)
+private:
+ /*
+ * Extract the table index from an indirect reference.
+ */
+ static u4 extractIndex(IndirectRef iref) {
+ u4 uref = (u4) iref;
+ return (uref >> 2) & 0xffff;
+ }
-/*
- * Given an IndirectRef in the table, return the Object it refers to.
- *
- * Returns kInvalidIndirectRefObject if iref is invalid.
- */
-INLINE Object* dvmGetFromIndirectRefTable(IndirectRefTable* pRef,
- IndirectRef iref)
-{
- if (!dvmGetFromIndirectRefTableCheck(pRef, iref))
- return kInvalidIndirectRefObject;
+ /*
+ * The object pointer itself is subject to relocation in some GC
+ * implementations, so we shouldn't really be using it here.
+ */
+ IndirectRef toIndirectRef(Object* obj, u4 tableIndex) const {
+ assert(tableIndex < 65536);
+ //u4 objChunk = (((u4) obj >> 3) ^ ((u4) obj >> 19)) & 0x3fff;
+ //u4 uref = objChunk << 18 | (tableIndex << 2) | kind;
+ u4 serialChunk = slotData[tableIndex].serial;
+ u4 uref = serialChunk << 20 | (tableIndex << 2) | kind;
+ return (IndirectRef) uref;
+ }
- int idx = dvmIndirectRefToIndex(iref);
- return pRef->table[idx];
-}
+ /*
+ * Update extended debug info when an entry is added.
+ *
+ * We advance the serial number, invalidating any outstanding references to
+ * this slot.
+ */
+ void updateSlotAdd(Object* obj, int slot) {
+ if (slotData != NULL) {
+ IndirectRefSlot* pSlot = &slotData[slot];
+ pSlot->serial++;
+ pSlot->previous[pSlot->serial % kIRTPrevCount] = obj;
+ }
+ }
-/*
- * Remove an existing entry.
- *
- * If the entry is not between the current top index and the bottom index
- * specified by the cookie, we don't remove anything. This is the behavior
- * required by JNI's DeleteLocalRef function.
- *
- * Returns "false" if nothing was removed.
- */
-bool dvmRemoveFromIndirectRefTable(IndirectRefTable* pRef, u4 cookie,
- IndirectRef iref);
+ /*
+ * Update extended debug info when an entry is removed.
+ */
+ void updateSlotRemove(int slot) {
+ }
-/*
- * Dump the contents of a reference table to the log file.
- *
- * The caller should lock any external sync before calling.
- */
-void dvmDumpIndirectRefTable(const IndirectRefTable* pRef, const char* descr);
+ /* extra debugging checks */
+ bool getChecked(IndirectRef) const;
+ bool checkEntry(IndirectRef, int) const;
+};
#endif // DALVIK_INDIRECTREFTABLE_H_
diff --git a/vm/Jni.cpp b/vm/Jni.cpp
index 49a2c8ad9..474dba78a 100644
--- a/vm/Jni.cpp
+++ b/vm/Jni.cpp
@@ -241,14 +241,12 @@ private:
#define kPinComplainThreshold 10
bool dvmJniStartup() {
- if (!dvmInitIndirectRefTable(&gDvm.jniGlobalRefTable,
- kGlobalRefsTableInitialSize,
+ if (!gDvm.jniGlobalRefTable.init(kGlobalRefsTableInitialSize,
kGlobalRefsTableMaxSize,
kIndirectKindGlobal)) {
return false;
}
- if (!dvmInitIndirectRefTable(&gDvm.jniWeakGlobalRefTable,
- kWeakGlobalRefsTableInitialSize,
+ if (!gDvm.jniWeakGlobalRefTable.init(kWeakGlobalRefsTableInitialSize,
kGlobalRefsTableMaxSize,
kIndirectKindWeakGlobal)) {
return false;
@@ -269,8 +267,8 @@ bool dvmJniStartup() {
}
void dvmJniShutdown() {
- dvmClearIndirectRefTable(&gDvm.jniGlobalRefTable);
- dvmClearIndirectRefTable(&gDvm.jniWeakGlobalRefTable);
+ gDvm.jniGlobalRefTable.destroy();
+ gDvm.jniWeakGlobalRefTable.destroy();
dvmClearReferenceTable(&gDvm.jniPinRefTable);
}
@@ -311,30 +309,24 @@ Object* dvmDecodeIndirectRef(JNIEnv* env, jobject jobj) {
return NULL;
}
- Object* result;
-
- switch (dvmGetIndirectRefType(jobj)) {
+ switch (indirectRefKind(jobj)) {
case kIndirectKindLocal:
- {
- IndirectRefTable* pRefTable = getLocalRefTable(env);
- result = dvmGetFromIndirectRefTable(pRefTable, jobj);
- }
- break;
+ return getLocalRefTable(env)->get(jobj);
case kIndirectKindGlobal:
{
// TODO: find a way to avoid the mutex activity here
IndirectRefTable* pRefTable = &gDvm.jniGlobalRefTable;
ScopedPthreadMutexLock lock(&gDvm.jniGlobalRefLock);
- result = dvmGetFromIndirectRefTable(pRefTable, jobj);
+ return pRefTable->get(jobj);
}
- break;
case kIndirectKindWeakGlobal:
{
- // TODO: find a way to avoid the mutex activity here
- IndirectRefTable* pRefTable = &gDvm.jniWeakGlobalRefTable;
+ Object* result;
{
+ // TODO: find a way to avoid the mutex activity here
+ IndirectRefTable* pRefTable = &gDvm.jniWeakGlobalRefTable;
ScopedPthreadMutexLock lock(&gDvm.jniWeakGlobalRefLock);
- result = dvmGetFromIndirectRefTable(pRefTable, jobj);
+ result = pRefTable->get(jobj);
}
/*
* TODO: this is a temporary workaround for broken weak global
@@ -348,17 +340,14 @@ Object* dvmDecodeIndirectRef(JNIEnv* env, jobject jobj) {
LOGW("Warning: used weak global ref hack");
result = NULL;
}
+ return result;
}
- break;
case kIndirectKindInvalid:
default:
LOGW("Invalid indirect reference %p in decodeIndirectRef", jobj);
dvmAbort();
- result = kInvalidIndirectRefObject;
- break;
+ return kInvalidIndirectRefObject;
}
-
- return result;
}
/*
@@ -381,19 +370,19 @@ static jobject addLocalReference(JNIEnv* env, Object* obj) {
IndirectRefTable* pRefTable = getLocalRefTable(env);
void* curFrame = ((JNIEnvExt*)env)->self->interpSave.curFrame;
u4 cookie = SAVEAREA_FROM_FP(curFrame)->xtra.localRefCookie;
- jobject jobj = (jobject) dvmAddToIndirectRefTable(pRefTable, cookie, obj);
+ jobject jobj = (jobject) pRefTable->add(cookie, obj);
if (jobj == NULL) {
- dvmDumpIndirectRefTable(pRefTable, "JNI local");
- LOGE("Failed adding to JNI local ref table (has %d entries)",
- (int) dvmIndirectRefTableEntries(pRefTable));
+ pRefTable->dump("JNI local");
+ LOGE("Failed adding to JNI local ref table (has %zd entries)",
+ pRefTable->capacity());
dvmDumpThread(dvmThreadSelf(), false);
dvmAbort(); // spec says call FatalError; this is equivalent
} else {
if (false) {
- LOGI("LREF add %p (%s.%s) (ent=%d)", obj,
+ LOGI("LREF add %p (%s.%s) (ent=%zd)", obj,
dvmGetCurrentJNIMethod()->clazz->descriptor,
dvmGetCurrentJNIMethod()->name,
- (int) dvmIndirectRefTableEntries(pRefTable));
+ pRefTable->capacity());
}
}
@@ -406,7 +395,7 @@ static jobject addLocalReference(JNIEnv* env, Object* obj) {
*/
static bool ensureLocalCapacity(JNIEnv* env, int capacity) {
IndirectRefTable* pRefTable = getLocalRefTable(env);
- int numEntries = dvmIndirectRefTableEntries(pRefTable);
+ int numEntries = pRefTable->capacity();
// TODO: this isn't quite right, since "numEntries" includes holes
return ((kJniLocalRefMax - numEntries) >= capacity);
}
@@ -424,7 +413,7 @@ static void deleteLocalReference(JNIEnv* env, jobject jobj) {
u4 cookie =
SAVEAREA_FROM_FP(self->interpSave.curFrame)->xtra.localRefCookie;
- if (!dvmRemoveFromIndirectRefTable(pRefTable, cookie, jobj)) {
+ if (!pRefTable->remove(cookie, jobj)) {
/*
* Attempting to delete a local reference that is not in the
* topmost local reference frame is a no-op. DeleteLocalRef returns
@@ -489,12 +478,11 @@ static jobject addGlobalReference(Object* obj) {
* we're either leaking global ref table entries or we're going to
* run out of space in the GC heap.
*/
- jobject jobj = (jobject) dvmAddToIndirectRefTable(&gDvm.jniGlobalRefTable, IRT_FIRST_SEGMENT,
- obj);
+ jobject jobj = (jobject) gDvm.jniGlobalRefTable.add(IRT_FIRST_SEGMENT, obj);
if (jobj == NULL) {
- dvmDumpIndirectRefTable(&gDvm.jniGlobalRefTable, "JNI global");
- LOGE("Failed adding to JNI global ref table (%d entries)",
- (int) dvmIndirectRefTableEntries(&gDvm.jniGlobalRefTable));
+ gDvm.jniGlobalRefTable.dump("JNI global");
+ LOGE("Failed adding to JNI global ref table (%zd entries)",
+ gDvm.jniGlobalRefTable.capacity());
dvmAbort();
}
@@ -504,7 +492,7 @@ static jobject addGlobalReference(Object* obj) {
/* GREF usage tracking; should probably be disabled for production env */
if (kTrackGrefUsage && gDvm.jniGrefLimit != 0) {
- int count = dvmIndirectRefTableEntries(&gDvm.jniGlobalRefTable);
+ int count = gDvm.jniGlobalRefTable.capacity();
// TODO: adjust for "holes"
if (count > gDvm.jniGlobalRefHiMark) {
LOGD("GREF has increased to %d", count);
@@ -516,7 +504,7 @@ static jobject addGlobalReference(Object* obj) {
if (gDvmJni.warnOnly) {
LOGW("Excessive JNI global references (%d)", count);
} else {
- dvmDumpIndirectRefTable(&gDvm.jniGlobalRefTable, "JNI global");
+ gDvm.jniGlobalRefTable.dump("JNI global");
LOGE("Excessive JNI global references (%d)", count);
dvmAbort();
}
@@ -533,11 +521,11 @@ static jobject addWeakGlobalReference(Object* obj) {
ScopedPthreadMutexLock lock(&gDvm.jniWeakGlobalRefLock);
IndirectRefTable *table = &gDvm.jniWeakGlobalRefTable;
- jobject jobj = (jobject) dvmAddToIndirectRefTable(table, IRT_FIRST_SEGMENT, obj);
+ jobject jobj = (jobject) table->add(IRT_FIRST_SEGMENT, obj);
if (jobj == NULL) {
- dvmDumpIndirectRefTable(table, "JNI weak global");
+ table->dump("JNI weak global");
LOGE("Failed adding to JNI weak global ref table (%zd entries)",
- dvmIndirectRefTableEntries(table));
+ table->capacity());
}
return jobj;
}
@@ -549,7 +537,7 @@ static void deleteWeakGlobalReference(jobject jobj) {
ScopedPthreadMutexLock lock(&gDvm.jniWeakGlobalRefLock);
IndirectRefTable *table = &gDvm.jniWeakGlobalRefTable;
- if (!dvmRemoveFromIndirectRefTable(table, IRT_FIRST_SEGMENT, jobj)) {
+ if (!table->remove(IRT_FIRST_SEGMENT, jobj)) {
LOGW("JNI: DeleteWeakGlobalRef(%p) failed to find entry", jobj);
}
}
@@ -567,13 +555,13 @@ static void deleteGlobalReference(jobject jobj) {
}
ScopedPthreadMutexLock lock(&gDvm.jniGlobalRefLock);
- if (!dvmRemoveFromIndirectRefTable(&gDvm.jniGlobalRefTable, IRT_FIRST_SEGMENT, jobj)) {
+ if (!gDvm.jniGlobalRefTable.remove(IRT_FIRST_SEGMENT, jobj)) {
LOGW("JNI: DeleteGlobalRef(%p) failed to find entry", jobj);
return;
}
if (kTrackGrefUsage && gDvm.jniGrefLimit != 0) {
- int count = dvmIndirectRefTableEntries(&gDvm.jniGlobalRefTable);
+ int count = gDvm.jniGlobalRefTable.capacity();
// TODO: not quite right, need to subtract holes
if (count < gDvm.jniGlobalRefLoMark) {
LOGD("GREF has decreased to %d", count);
@@ -656,8 +644,8 @@ void dvmDumpJniReferenceTables() {
Thread* self = dvmThreadSelf();
JNIEnv* env = self->jniEnv;
IndirectRefTable* pLocalRefs = getLocalRefTable(env);
- dvmDumpIndirectRefTable(pLocalRefs, "JNI local");
- dvmDumpIndirectRefTable(&gDvm.jniGlobalRefTable, "JNI global");
+ pLocalRefs->dump("JNI local");
+ gDvm.jniGlobalRefTable.dump("JNI global");
dvmDumpReferenceTable(&gDvm.jniPinRefTable, "JNI pinned array");
}
@@ -686,7 +674,7 @@ jobjectRefType dvmGetJNIRefType(JNIEnv* env, jobject jobj) {
if (obj == kInvalidIndirectRefObject) {
return JNIInvalidRefType;
} else {
- return (jobjectRefType) dvmGetIndirectRefType(jobj);
+ return (jobjectRefType) indirectRefKind(jobj);
}
}
diff --git a/vm/Thread.cpp b/vm/Thread.cpp
index 3844b25e6..5122adfad 100644
--- a/vm/Thread.cpp
+++ b/vm/Thread.cpp
@@ -922,9 +922,10 @@ static bool prepareThread(Thread* thread)
* Most threads won't use jniMonitorRefTable, so we clear out the
* structure but don't call the init function (which allocs storage).
*/
- if (!dvmInitIndirectRefTable(&thread->jniLocalRefTable,
- kJniLocalRefMin, kJniLocalRefMax, kIndirectKindLocal))
+ if (!thread->jniLocalRefTable.init(kJniLocalRefMin,
+ kJniLocalRefMax, kIndirectKindLocal)) {
return false;
+ }
if (!dvmInitReferenceTable(&thread->internalLocalRefTable,
kInternalRefDefault, kInternalRefMax))
return false;
@@ -984,7 +985,7 @@ static void freeThread(Thread* thread)
#endif
}
- dvmClearIndirectRefTable(&thread->jniLocalRefTable);
+ thread->jniLocalRefTable.destroy();
dvmClearReferenceTable(&thread->internalLocalRefTable);
if (&thread->jniMonitorRefTable.table != NULL)
dvmClearReferenceTable(&thread->jniMonitorRefTable);
diff --git a/vm/alloc/MarkSweep.cpp b/vm/alloc/MarkSweep.cpp
index 309bd03c7..19fadc13e 100644
--- a/vm/alloc/MarkSweep.cpp
+++ b/vm/alloc/MarkSweep.cpp
@@ -1001,7 +1001,7 @@ void sweepWeakJniGlobals()
IndirectRefTable *table = &gDvm.jniWeakGlobalRefTable;
Object **entry = table->table;
GcMarkContext *ctx = &gDvm.gcHeap->markContext;
- int numEntries = dvmIndirectRefTableEntries(table);
+ int numEntries = table->capacity();
for (int i = 0; i < numEntries; ++i) {
if (entry[i] != NULL && !isMarked(entry[i], ctx)) {
entry[i] = NULL;
diff --git a/vm/alloc/Visit.cpp b/vm/alloc/Visit.cpp
index 7f949f671..a869418af 100644
--- a/vm/alloc/Visit.cpp
+++ b/vm/alloc/Visit.cpp
@@ -71,7 +71,7 @@ static void visitIndirectRefTable(RootVisitor *visitor, IndirectRefTable *table,
assert(visitor != NULL);
assert(table != NULL);
Object **entry = table->table;
- int numEntries = dvmIndirectRefTableEntries(table);
+ int numEntries = table->capacity();
for (int i = 0; i < numEntries; ++i) {
(*visitor)(&entry[i], threadId, type, arg);
}
diff --git a/vm/test/TestIndirectRefTable.cpp b/vm/test/TestIndirectRefTable.cpp
index de68c20a5..1e462e74f 100644
--- a/vm/test/TestIndirectRefTable.cpp
+++ b/vm/test/TestIndirectRefTable.cpp
@@ -23,7 +23,7 @@
#ifndef NDEBUG
-#define DBUG_MSG LOGV
+#define DBUG_MSG LOGI
/*
* Basic add/get/delete tests in an unsegmented table.
@@ -42,14 +42,12 @@ static bool basicTest()
const u4 cookie = IRT_FIRST_SEGMENT;
bool result = false;
- if (!dvmInitIndirectRefTable(&irt, kTableMax/2, kTableMax,
- kIndirectKindGlobal))
- {
+ if (!irt.init(kTableMax/2, kTableMax, kIndirectKindGlobal)) {
return false;
}
iref0 = (IndirectRef) 0x11110;
- if (dvmRemoveFromIndirectRefTable(&irt, cookie, iref0)) {
+ if (irt.remove(cookie, iref0)) {
LOGE("unexpectedly successful removal");
goto bail;
}
@@ -58,44 +56,41 @@ static bool basicTest()
* Add three, check, remove in the order in which they were added.
*/
DBUG_MSG("+++ START fifo\n");
- iref0 = dvmAddToIndirectRefTable(&irt, cookie, obj0);
- iref1 = dvmAddToIndirectRefTable(&irt, cookie, obj1);
- iref2 = dvmAddToIndirectRefTable(&irt, cookie, obj2);
+ iref0 = irt.add(cookie, obj0);
+ iref1 = irt.add(cookie, obj1);
+ iref2 = irt.add(cookie, obj2);
if (iref0 == NULL || iref1 == NULL || iref2 == NULL) {
LOGE("trivial add1 failed");
goto bail;
}
- if (dvmGetFromIndirectRefTable(&irt, iref0) != obj0 ||
- dvmGetFromIndirectRefTable(&irt, iref1) != obj1 ||
- dvmGetFromIndirectRefTable(&irt, iref2) != obj2)
- {
+ if (irt.get(iref0) != obj0 ||
+ irt.get(iref1) != obj1 ||
+ irt.get(iref2) != obj2) {
LOGE("objects don't match expected values %p %p %p vs. %p %p %p",
- dvmGetFromIndirectRefTable(&irt, iref0),
- dvmGetFromIndirectRefTable(&irt, iref1),
- dvmGetFromIndirectRefTable(&irt, iref2),
- obj0, obj1, obj2);
+ irt.get(iref0), irt.get(iref1), irt.get(iref2),
+ obj0, obj1, obj2);
goto bail;
} else {
DBUG_MSG("+++ obj1=%p --> iref1=%p\n", obj1, iref1);
}
- if (!dvmRemoveFromIndirectRefTable(&irt, cookie, iref0) ||
- !dvmRemoveFromIndirectRefTable(&irt, cookie, iref1) ||
- !dvmRemoveFromIndirectRefTable(&irt, cookie, iref2))
+ if (!irt.remove(cookie, iref0) ||
+ !irt.remove(cookie, iref1) ||
+ !irt.remove(cookie, iref2))
{
LOGE("fifo deletion failed");
goto bail;
}
/* table should be empty now */
- if (dvmIndirectRefTableEntries(&irt) != 0) {
+ if (irt.capacity() != 0) {
LOGE("fifo del not empty");
goto bail;
}
/* get invalid entry (off the end of the list) */
- if (dvmGetFromIndirectRefTable(&irt, iref0) != kInvalidIndirectRefObject) {
+ if (irt.get(iref0) != kInvalidIndirectRefObject) {
LOGE("stale entry get succeeded unexpectedly");
goto bail;
}
@@ -104,24 +99,24 @@ static bool basicTest()
* Add three, remove in the opposite order.
*/
DBUG_MSG("+++ START lifo\n");
- iref0 = dvmAddToIndirectRefTable(&irt, cookie, obj0);
- iref1 = dvmAddToIndirectRefTable(&irt, cookie, obj1);
- iref2 = dvmAddToIndirectRefTable(&irt, cookie, obj2);
+ iref0 = irt.add(cookie, obj0);
+ iref1 = irt.add(cookie, obj1);
+ iref2 = irt.add(cookie, obj2);
if (iref0 == NULL || iref1 == NULL || iref2 == NULL) {
LOGE("trivial add2 failed");
goto bail;
}
- if (!dvmRemoveFromIndirectRefTable(&irt, cookie, iref2) ||
- !dvmRemoveFromIndirectRefTable(&irt, cookie, iref1) ||
- !dvmRemoveFromIndirectRefTable(&irt, cookie, iref0))
+ if (!irt.remove(cookie, iref2) ||
+ !irt.remove(cookie, iref1) ||
+ !irt.remove(cookie, iref0))
{
LOGE("lifo deletion failed");
goto bail;
}
/* table should be empty now */
- if (dvmIndirectRefTableEntries(&irt) != 0) {
+ if (irt.capacity() != 0) {
LOGE("lifo del not empty");
goto bail;
}
@@ -131,42 +126,37 @@ static bool basicTest()
* to remove middle should fail.)
*/
DBUG_MSG("+++ START unorder\n");
- iref0 = dvmAddToIndirectRefTable(&irt, cookie, obj0);
- iref1 = dvmAddToIndirectRefTable(&irt, cookie, obj1);
- iref2 = dvmAddToIndirectRefTable(&irt, cookie, obj2);
+ iref0 = irt.add(cookie, obj0);
+ iref1 = irt.add(cookie, obj1);
+ iref2 = irt.add(cookie, obj2);
if (iref0 == NULL || iref1 == NULL || iref2 == NULL) {
LOGE("trivial add3 failed");
goto bail;
}
- if (dvmIndirectRefTableEntries(&irt) != 3) {
- LOGE("expected 3 entries, found %d",
- dvmIndirectRefTableEntries(&irt));
+ if (irt.capacity() != 3) {
+ LOGE("expected 3 entries, found %d", irt.capacity());
goto bail;
}
- if (!dvmRemoveFromIndirectRefTable(&irt, cookie, iref1) ||
- dvmRemoveFromIndirectRefTable(&irt, cookie, iref1))
- {
+ if (!irt.remove(cookie, iref1) || irt.remove(cookie, iref1)) {
LOGE("unorder deletion1 failed");
goto bail;
}
/* get invalid entry (from hole) */
- if (dvmGetFromIndirectRefTable(&irt, iref1) != kInvalidIndirectRefObject) {
+ if (irt.get(iref1) != kInvalidIndirectRefObject) {
LOGE("hole get succeeded unexpectedly");
goto bail;
}
- if (!dvmRemoveFromIndirectRefTable(&irt, cookie, iref2) ||
- !dvmRemoveFromIndirectRefTable(&irt, cookie, iref0))
- {
+ if (!irt.remove(cookie, iref2) || !irt.remove(cookie, iref0)) {
LOGE("unorder deletion2 failed");
goto bail;
}
/* table should be empty now */
- if (dvmIndirectRefTableEntries(&irt) != 0) {
+ if (irt.capacity() != 0) {
LOGE("unorder del not empty");
goto bail;
}
@@ -177,40 +167,36 @@ static bool basicTest()
* that we delete one and don't hole-compact the other.
*/
DBUG_MSG("+++ START hole fill\n");
- iref0 = dvmAddToIndirectRefTable(&irt, cookie, obj0);
- iref1 = dvmAddToIndirectRefTable(&irt, cookie, obj1);
- iref2 = dvmAddToIndirectRefTable(&irt, cookie, obj2);
- iref3 = dvmAddToIndirectRefTable(&irt, cookie, obj3);
+ iref0 = irt.add(cookie, obj0);
+ iref1 = irt.add(cookie, obj1);
+ iref2 = irt.add(cookie, obj2);
+ iref3 = irt.add(cookie, obj3);
if (iref0 == NULL || iref1 == NULL || iref2 == NULL || iref3 == NULL) {
LOGE("trivial add4 failed");
goto bail;
}
- if (!dvmRemoveFromIndirectRefTable(&irt, cookie, iref1)) {
+ if (!irt.remove(cookie, iref1)) {
LOGE("remove 1 of 4 failed");
goto bail;
}
- iref1 = dvmAddToIndirectRefTable(&irt, cookie, obj1);
- if (dvmIndirectRefTableEntries(&irt) != 4) {
+ iref1 = irt.add(cookie, obj1);
+ if (irt.capacity() != 4) {
LOGE("hole not filled");
goto bail;
}
- if (!dvmRemoveFromIndirectRefTable(&irt, cookie, iref1) ||
- !dvmRemoveFromIndirectRefTable(&irt, cookie, iref3))
- {
+ if (!irt.remove(cookie, iref1) || !irt.remove(cookie, iref3)) {
LOGE("remove 1/3 failed");
goto bail;
}
- if (dvmIndirectRefTableEntries(&irt) != 3) {
+ if (irt.capacity() != 3) {
LOGE("should be 3 after two deletions");
goto bail;
}
- if (!dvmRemoveFromIndirectRefTable(&irt, cookie, iref2) ||
- !dvmRemoveFromIndirectRefTable(&irt, cookie, iref0))
- {
+ if (!irt.remove(cookie, iref2) || !irt.remove(cookie, iref0)) {
LOGE("remove 2/0 failed");
goto bail;
}
- if (dvmIndirectRefTableEntries(&irt) != 0) {
+ if (irt.capacity() != 0) {
LOGE("not empty after split remove");
goto bail;
}
@@ -221,18 +207,18 @@ static bool basicTest()
* With the extended checks in place, this should fail.
*/
DBUG_MSG("+++ START switched\n");
- iref0 = dvmAddToIndirectRefTable(&irt, cookie, obj0);
- dvmRemoveFromIndirectRefTable(&irt, cookie, iref0);
- iref1 = dvmAddToIndirectRefTable(&irt, cookie, obj1);
- if (dvmRemoveFromIndirectRefTable(&irt, cookie, iref0)) {
+ iref0 = irt.add(cookie, obj0);
+ irt.remove(cookie, iref0);
+ iref1 = irt.add(cookie, obj1);
+ if (irt.remove(cookie, iref0)) {
LOGE("mismatched del succeeded (%p vs %p)", iref0, iref1);
goto bail;
}
- if (!dvmRemoveFromIndirectRefTable(&irt, cookie, iref1)) {
+ if (!irt.remove(cookie, iref1)) {
LOGE("switched del failed");
goto bail;
}
- if (dvmIndirectRefTableEntries(&irt) != 0) {
+ if (irt.capacity() != 0) {
LOGE("switching del not empty");
goto bail;
}
@@ -241,63 +227,77 @@ static bool basicTest()
* Same as above, but with the same object. A more rigorous checker
* (e.g. with slot serialization) will catch this.
*/
- iref0 = dvmAddToIndirectRefTable(&irt, cookie, obj0);
- dvmRemoveFromIndirectRefTable(&irt, cookie, iref0);
- iref1 = dvmAddToIndirectRefTable(&irt, cookie, obj0);
+ DBUG_MSG("+++ START switched same object\n");
+ iref0 = irt.add(cookie, obj0);
+ irt.remove(cookie, iref0);
+ iref1 = irt.add(cookie, obj0);
if (iref0 != iref1) {
/* try 0, should not work */
- if (dvmRemoveFromIndirectRefTable(&irt, cookie, iref0)) {
+ if (irt.remove(cookie, iref0)) {
LOGE("temporal del succeeded (%p vs %p)", iref0, iref1);
goto bail;
}
}
- if (!dvmRemoveFromIndirectRefTable(&irt, cookie, iref1)) {
+ if (!irt.remove(cookie, iref1)) {
LOGE("temporal cleanup failed");
goto bail;
}
- if (dvmIndirectRefTableEntries(&irt) != 0) {
+ if (irt.capacity() != 0) {
LOGE("temporal del not empty");
goto bail;
}
+ DBUG_MSG("+++ START null lookup\n");
+ if (irt.get(NULL) != kInvalidIndirectRefObject) {
+ LOGE("null lookup succeeded");
+ goto bail;
+ }
+
+ DBUG_MSG("+++ START stale lookup\n");
+ iref0 = irt.add(cookie, obj0);
+ irt.remove(cookie, iref0);
+ if (irt.get(iref0) != kInvalidIndirectRefObject) {
+ LOGE("stale lookup succeeded");
+ goto bail;
+ }
+
/*
* Test table overflow.
*/
DBUG_MSG("+++ START overflow\n");
int i;
for (i = 0; i < kTableMax; i++) {
- manyRefs[i] = dvmAddToIndirectRefTable(&irt, cookie, obj0);
+ manyRefs[i] = irt.add(cookie, obj0);
if (manyRefs[i] == NULL) {
LOGE("Failed adding %d of %d", i, kTableMax);
goto bail;
}
}
- if (dvmAddToIndirectRefTable(&irt, cookie, obj0) != NULL) {
+ if (irt.add(cookie, obj0) != NULL) {
LOGE("Table overflow succeeded");
goto bail;
}
- if (dvmIndirectRefTableEntries(&irt) != (size_t)kTableMax) {
- LOGE("Expected %d entries, found %d",
- kTableMax, dvmIndirectRefTableEntries(&irt));
+ if (irt.capacity() != (size_t)kTableMax) {
+ LOGE("Expected %d entries, found %d", kTableMax, irt.capacity());
goto bail;
}
for (i = 0; i < kTableMax-1; i++) {
- if (!dvmRemoveFromIndirectRefTable(&irt, cookie, manyRefs[i])) {
+ if (!irt.remove(cookie, manyRefs[i])) {
LOGE("multi-remove failed at %d", i);
goto bail;
}
}
/* because of removal order, should have 20 entries, 19 of them holes */
- if (dvmIndirectRefTableEntries(&irt) != (size_t)kTableMax) {
+ if (irt.capacity() != (size_t)kTableMax) {
LOGE("Expected %d entries (with holes), found %d",
- kTableMax, dvmIndirectRefTableEntries(&irt));
+ kTableMax, irt.capacity());
goto bail;
}
- if (!dvmRemoveFromIndirectRefTable(&irt, cookie, manyRefs[kTableMax-1])) {
+ if (!irt.remove(cookie, manyRefs[kTableMax-1])) {
LOGE("multi-remove final failed");
goto bail;
}
- if (dvmIndirectRefTableEntries(&irt) != 0) {
+ if (irt.capacity() != 0) {
LOGE("multi-del not empty");
goto bail;
}
@@ -306,168 +306,10 @@ static bool basicTest()
result = true;
bail:
- dvmClearIndirectRefTable(&irt);
- return result;
-}
-
-/*
- * Test operations on a segmented table.
- */
-static bool segmentTest()
-{
- static const int kTableMax = 20;
- IndirectRefTable irt;
- IndirectRef iref0, iref1, iref2, iref3;
- ClassObject* clazz = dvmFindClass("Ljava/lang/Object;", NULL);
- Object* obj0 = dvmAllocObject(clazz, ALLOC_DONT_TRACK);
- Object* obj1 = dvmAllocObject(clazz, ALLOC_DONT_TRACK);
- Object* obj2 = dvmAllocObject(clazz, ALLOC_DONT_TRACK);
- Object* obj3 = dvmAllocObject(clazz, ALLOC_DONT_TRACK);
- u4 cookie;
- u4 segmentState[4];
- bool result = false;
-
- if (!dvmInitIndirectRefTable(&irt, kTableMax, kTableMax,
- kIndirectKindLocal))
- {
- return false;
- }
- cookie = segmentState[0] = IRT_FIRST_SEGMENT;
- DBUG_MSG("+++ objs %p %p %p %p\n", obj0, obj1, obj2, obj3);
-
- /*
- * Push two, create new segment, push two more, try to get all four,
- * try to delete all 4. All four should be accessible, but only the
- * last two should be deletable.
- */
- DBUG_MSG("+++ START basic segment\n");
- iref0 = dvmAddToIndirectRefTable(&irt, cookie, obj0);
- iref1 = dvmAddToIndirectRefTable(&irt, cookie, obj1);
- cookie = segmentState[1] = dvmPushIndirectRefTableSegment(&irt);
- DBUG_MSG("+++ pushed, cookie is 0x%08x\n", cookie);
- iref2 = dvmAddToIndirectRefTable(&irt, cookie, obj2);
- iref3 = dvmAddToIndirectRefTable(&irt, cookie, obj3);
-
- if (dvmRemoveFromIndirectRefTable(&irt, cookie, iref0) ||
- dvmRemoveFromIndirectRefTable(&irt, cookie, iref1))
- {
- LOGE("removed values from earlier segment");
- goto bail;
- }
- if (!dvmRemoveFromIndirectRefTable(&irt, cookie, iref2) ||
- !dvmRemoveFromIndirectRefTable(&irt, cookie, iref3))
- {
- LOGE("unable to remove values from current segment");
- goto bail;
- }
- if (dvmIndirectRefTableEntries(&irt) != 2) {
- LOGE("wrong total entries");
- goto bail;
- }
- dvmPopIndirectRefTableSegment(&irt, segmentState[1]);
- cookie = segmentState[0];
- if (!dvmRemoveFromIndirectRefTable(&irt, cookie, iref0) ||
- !dvmRemoveFromIndirectRefTable(&irt, cookie, iref1))
- {
- LOGE("unable to remove values from first segment");
- goto bail;
- }
- if (dvmIndirectRefTableEntries(&irt) != 0) {
- LOGE("basic push/pop not empty");
- goto bail;
- }
-
- /*
- * Push two, delete first, segment, push two more, pop segment, verify
- * the last two are no longer present and hole count is right. The
- * adds after the segment pop should not be filling in the hole.
- */
- DBUG_MSG("+++ START segment pop\n");
- iref0 = dvmAddToIndirectRefTable(&irt, cookie, obj0);
- iref1 = dvmAddToIndirectRefTable(&irt, cookie, obj1);
- dvmRemoveFromIndirectRefTable(&irt, cookie, iref0);
- cookie = segmentState[1] = dvmPushIndirectRefTableSegment(&irt);
- iref2 = dvmAddToIndirectRefTable(&irt, cookie, obj2);
- iref3 = dvmAddToIndirectRefTable(&irt, cookie, obj3);
- dvmPopIndirectRefTableSegment(&irt, segmentState[1]);
- cookie = segmentState[0];
- if (dvmIndirectRefTableEntries(&irt) != 2) {
- LOGE("wrong total entries after pop");
- goto bail;
- }
- dvmRemoveFromIndirectRefTable(&irt, cookie, iref1);
- if (dvmIndirectRefTableEntries(&irt) != 0) {
- LOGE("not back to zero after pop + del");
- goto bail;
- }
-
- /*
- * Multiple segments, some empty.
- */
- DBUG_MSG("+++ START multiseg\n");
- iref0 = dvmAppendToIndirectRefTable(&irt, cookie, obj0);
- iref1 = dvmAppendToIndirectRefTable(&irt, cookie, obj1);
- cookie = segmentState[1] = dvmPushIndirectRefTableSegment(&irt);
- cookie = segmentState[2] = dvmPushIndirectRefTableSegment(&irt);
- iref3 = dvmAppendToIndirectRefTable(&irt, cookie, obj3);
- iref2 = dvmAppendToIndirectRefTable(&irt, cookie, obj2);
- dvmRemoveFromIndirectRefTable(&irt, cookie, iref3);
- cookie = segmentState[3] = dvmPushIndirectRefTableSegment(&irt);
- iref3 = dvmAppendToIndirectRefTable(&irt, cookie, obj3);
-
- if (dvmGetFromIndirectRefTable(&irt, iref0) != obj0 ||
- dvmGetFromIndirectRefTable(&irt, iref1) != obj1 ||
- dvmGetFromIndirectRefTable(&irt, iref2) != obj2 ||
- dvmGetFromIndirectRefTable(&irt, iref3) != obj3)
- {
- LOGE("Unable to retrieve all multiseg objects");
- goto bail;
- }
-
- dvmDumpIndirectRefTable(&irt, "test");
-
- //int i;
- //for (i = 0; i < sizeof(segmentState) / sizeof(segmentState[0]); i++) {
- // DBUG_MSG("+++ segment %d = 0x%08x\n", i, segmentState[i]);
- //}
-
- dvmRemoveFromIndirectRefTable(&irt, cookie, iref3);
- if (dvmRemoveFromIndirectRefTable(&irt, cookie, iref2)) {
- LOGE("multiseg del2 worked");
- goto bail;
- }
- dvmPopIndirectRefTableSegment(&irt, segmentState[3]);
- cookie = segmentState[2];
- if (!dvmRemoveFromIndirectRefTable(&irt, cookie, iref2)) {
- LOGE("multiseg del2b failed (cookie=0x%08x ref=%p)", cookie, iref2);
- goto bail;
- }
- iref2 = dvmAddToIndirectRefTable(&irt, cookie, obj2);
-
- /* pop two off at once */
- dvmPopIndirectRefTableSegment(&irt, segmentState[1]);
- cookie = segmentState[0];
-
- if (dvmIndirectRefTableEntries(&irt) != 2) {
- LOGE("Unexpected entry count in multiseg");
- goto bail;
- }
- dvmRemoveFromIndirectRefTable(&irt, cookie, iref0);
- dvmRemoveFromIndirectRefTable(&irt, cookie, iref1);
- if (dvmIndirectRefTableEntries(&irt) != 0) {
- LOGE("Unexpected entry count at multiseg end");
- goto bail;
- }
-
- DBUG_MSG("+++ segment test complete\n");
- result = true;
-
-bail:
- dvmClearIndirectRefTable(&irt);
+ irt.destroy();
return result;
}
-
/*
* Some quick tests.
*/
@@ -477,10 +319,6 @@ bool dvmTestIndirectRefTable()
LOGE("IRT basic test failed");
return false;
}
- if (!segmentTest()) {
- LOGE("IRT segment test failed");
- return false;
- }
return true;
}