diff options
author | Elliott Hughes <enh@google.com> | 2011-06-20 17:50:41 -0700 |
---|---|---|
committer | Elliott Hughes <enh@google.com> | 2011-06-21 14:54:24 -0700 |
commit | ce0968340f9ddd54f20e38d4946bfd2ef8f1f343 (patch) | |
tree | ea1f9ab9f0220b3fe1f69febe47d17587ee11782 | |
parent | 7c08071765cb134e4c0b18bf8fd6a7060e145212 (diff) | |
download | android_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.cpp | 19 | ||||
-rw-r--r-- | vm/IndirectRefTable.cpp | 269 | ||||
-rw-r--r-- | vm/IndirectRefTable.h | 313 | ||||
-rw-r--r-- | vm/Jni.cpp | 84 | ||||
-rw-r--r-- | vm/Thread.cpp | 7 | ||||
-rw-r--r-- | vm/alloc/MarkSweep.cpp | 2 | ||||
-rw-r--r-- | vm/alloc/Visit.cpp | 2 | ||||
-rw-r--r-- | vm/test/TestIndirectRefTable.cpp | 322 |
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; } |