/* *breif:获取表的间接引用对象. *param[iref]:间接引用表. */ Object* IndirectRefTable::get(IndirectRef iref) const { IndirectRefKind kind = indirectRefKind(iref); if (kind != kind_) { if (iref == NULL) { ALOGW("Attempt to look up NULL %s reference", indirectRefKindToString(kind_)); return kInvalidIndirectRefObject; } if (kind == kIndirectKindInvalid) { ALOGE("JNI ERROR (app bug): invalid %s reference %p", indirectRefKindToString(kind_), iref); abortMaybe(); return kInvalidIndirectRefObject; } // References of the requested kind cannot appear within this table. return kInvalidIndirectRefObject; } u4 topIndex = segmentState.parts.topIndex; u4 index = extractIndex(iref); if (index >= topIndex) { /* bad -- stale reference? */ ALOGE("JNI ERROR (app bug): accessed stale %s reference %p (index %d in a table of size %d)", indirectRefKindToString(kind_), iref, index, topIndex); abortMaybe(); return kInvalidIndirectRefObject; } Object* obj = table_[index].obj; if (obj == NULL) { ALOGI("JNI ERROR (app bug): accessed deleted %s reference %p", indirectRefKindToString(kind_), iref); abortMaybe(); return kInvalidIndirectRefObject; } u4 serial = extractSerial(iref); if (serial != table_[index].serial) { ALOGE("JNI ERROR (app bug): attempt to use stale %s reference %p", indirectRefKindToString(kind_), iref); abortMaybe(); return kInvalidIndirectRefObject; } return obj; }
/* * Make sure that the entry at "idx" is correctly paired with "iref". */ bool IndirectRefTable::checkEntry(const char* what, IndirectRef iref, int idx) const { Object* obj = table_[idx]; IndirectRef checkRef = toIndirectRef(obj, idx); if (checkRef != iref) { LOGE("JNI ERROR (app bug): attempt to %s stale %s reference %p (should be %p)", what, indirectRefKindToString(kind_), iref, checkRef); abortMaybe(); return false; } return true; }
/* * Verify that the indirect table lookup is valid. * * Returns "false" if something looks bad. */ bool IndirectRefTable::getChecked(IndirectRef iref) const { if (iref == NULL) { LOGW("Attempt to look up NULL %s reference", indirectRefKindToString(kind_)); return false; } if (indirectRefKind(iref) == kIndirectKindInvalid) { LOGE("JNI ERROR (app bug): invalid %s reference %p", indirectRefKindToString(kind_), iref); abortMaybe(); return false; } int topIndex = segmentState.parts.topIndex; int idx = extractIndex(iref); if (idx >= topIndex) { /* bad -- stale reference? */ LOGE("JNI ERROR (app bug): accessed stale %s reference %p (index %d in a table of size %d)", indirectRefKindToString(kind_), iref, idx, topIndex); abortMaybe(); return false; } if (table_[idx] == NULL) { LOGI("JNI ERROR (app bug): accessed deleted %s reference %p", indirectRefKindToString(kind_), iref); abortMaybe(); return false; } if (!checkEntry("use", iref, idx)) { return false; } return true; }
/* *breif:添加一个新的条目.重新调整表大小. *param[cookie]: *param[obj]:要添加的条目. */ IndirectRef IndirectRefTable::add(u4 cookie, Object* obj) { IRTSegmentState prevState; prevState.all = cookie; size_t topIndex = segmentState.parts.topIndex; assert(obj != NULL); assert(dvmIsHeapAddress(obj)); assert(table_ != NULL); assert(alloc_entries_ <= max_entries_); assert(segmentState.parts.numHoles >= prevState.parts.numHoles); /* * We know there's enough room in the table. Now we just need to find * the right spot. If there's a hole, find it and fill it; otherwise, * add to the end of the list. */ IndirectRef result; IndirectRefSlot* slot; 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, * we know the item at the topIndex is not a hole */ slot = &table_[topIndex - 1]; assert(slot->obj != NULL); while ((--slot)->obj != NULL) { assert(slot >= table_ + prevState.parts.topIndex); } segmentState.parts.numHoles--; } else { /* add to the end, grow if needed */ if (topIndex == alloc_entries_) { /* reached end of allocated space; did we hit buffer max? */ if (topIndex == max_entries_) { ALOGE("JNI ERROR (app bug): %s reference table overflow (max=%d)", indirectRefKindToString(kind_), max_entries_); return NULL; } size_t newSize = alloc_entries_ * 2; if (newSize > max_entries_) { newSize = max_entries_; } assert(newSize > alloc_entries_); IndirectRefSlot* newTable = (IndirectRefSlot*) realloc(table_, newSize * sizeof(IndirectRefSlot)); if (table_ == NULL) { ALOGE("JNI ERROR (app bug): unable to expand %s reference table " "(from %d to %d, max=%d)", indirectRefKindToString(kind_), alloc_entries_, newSize, max_entries_); return NULL; } memset(newTable + alloc_entries_, 0xd1, (newSize - alloc_entries_) * sizeof(IndirectRefSlot)); alloc_entries_ = newSize; table_ = newTable; } slot = &table_[topIndex++]; segmentState.parts.topIndex = topIndex; } slot->obj = obj; slot->serial = nextSerial(slot->serial); result = toIndirectRef(slot - table_, slot->serial, kind_); assert(result != NULL); return result; }
/* *breif:从"pRef"删除 "obj". */ bool IndirectRefTable::remove(u4 cookie, IndirectRef iref) { IRTSegmentState prevState; prevState.all = cookie; u4 topIndex = segmentState.parts.topIndex; u4 bottomIndex = prevState.parts.topIndex; assert(table_ != NULL); assert(alloc_entries_ <= max_entries_); assert(segmentState.parts.numHoles >= prevState.parts.numHoles); IndirectRefKind kind = indirectRefKind(iref); u4 index; if (kind == kind_) { index = extractIndex(iref); if (index < bottomIndex) { /* wrong segment */ ALOGV("Attempt to remove index outside index area (%ud vs %ud-%ud)", index, bottomIndex, topIndex); return false; } if (index >= topIndex) { /* bad -- stale reference? */ ALOGD("Attempt to remove invalid index %ud (bottom=%ud top=%ud)", index, bottomIndex, topIndex); return false; } if (table_[index].obj == NULL) { ALOGD("Attempt to remove cleared %s reference %p", indirectRefKindToString(kind_), iref); return false; } u4 serial = extractSerial(iref); if (table_[index].serial != serial) { ALOGD("Attempt to remove stale %s reference %p", indirectRefKindToString(kind_), iref); return false; } } else if (kind == kIndirectKindInvalid && gDvmJni.workAroundAppJniBugs) { // reference looks like a pointer, scan the table to find the index int i = findObject(reinterpret_cast<Object*>(iref), bottomIndex, topIndex, table_); if (i < 0) { ALOGW("trying to work around app JNI bugs, but didn't find %p in table!", iref); return false; } index = i; } else { // References of the requested kind cannot appear within this table. return false; } if (index == topIndex - 1) { // Top-most entry. Scan up and consume holes. int numHoles = segmentState.parts.numHoles - prevState.parts.numHoles; if (numHoles != 0) { while (--topIndex > bottomIndex && numHoles != 0) { ALOGV("+++ checking for hole at %d (cookie=0x%08x) val=%p", topIndex-1, cookie, table_[topIndex-1].obj); if (table_[topIndex-1].obj != NULL) { break; } ALOGV("+++ ate hole at %d", topIndex-1); numHoles--; } segmentState.parts.numHoles = numHoles + prevState.parts.numHoles; segmentState.parts.topIndex = topIndex; } else { segmentState.parts.topIndex = topIndex-1; ALOGV("+++ ate last entry %d", topIndex-1); } } else { /* * Not the top-most entry. This creates a hole. We NULL out the * entry to prevent somebody from deleting it twice and screwing up * the hole count. */ table_[index].obj = NULL; segmentState.parts.numHoles++; ALOGV("+++ left hole at %d, holes=%d", index, segmentState.parts.numHoles); } return true; }
IndirectRef IndirectRefTable::add(u4 cookie, Object* obj) { IRTSegmentState prevState; prevState.all = cookie; size_t topIndex = segmentState.parts.topIndex; assert(obj != NULL); assert(dvmIsHeapAddress(obj)); assert(table_ != NULL); assert(alloc_entries_ <= max_entries_); assert(segmentState.parts.numHoles >= prevState.parts.numHoles); if (topIndex == alloc_entries_) { /* reached end of allocated space; did we hit buffer max? */ if (topIndex == max_entries_) { LOGE("JNI ERROR (app bug): %s reference table overflow (max=%d)", indirectRefKindToString(kind_), max_entries_); dump(indirectRefKindToString(kind_)); dvmAbort(); } size_t newSize = alloc_entries_ * 2; if (newSize > max_entries_) { newSize = max_entries_; } assert(newSize > alloc_entries_); table_ = (Object**) realloc(table_, newSize * sizeof(Object*)); slot_data_ = (IndirectRefSlot*) realloc(slot_data_, newSize * sizeof(IndirectRefSlot)); if (table_ == NULL || slot_data_ == NULL) { LOGE("JNI ERROR (app bug): unable to expand %s reference table (from %d to %d, max=%d)", indirectRefKindToString(kind_), alloc_entries_, newSize, max_entries_); dump(indirectRefKindToString(kind_)); dvmAbort(); } // Clear the newly-allocated slot_data_ elements. memset(slot_data_ + alloc_entries_, 0, (newSize - alloc_entries_) * sizeof(IndirectRefSlot)); alloc_entries_ = newSize; } /* * We know there's enough room in the table. Now we just need to find * the right spot. If there's a hole, find it and fill it; otherwise, * add to the end of the list. */ IndirectRef result; 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 = &table_[topIndex - 1]; assert(*pScan != NULL); while (*--pScan != NULL) { assert(pScan >= table_ + prevState.parts.topIndex); } updateSlotAdd(obj, pScan - table_); result = toIndirectRef(obj, pScan - table_); *pScan = obj; segmentState.parts.numHoles--; } else { /* add to the end */ updateSlotAdd(obj, topIndex); result = toIndirectRef(obj, topIndex); table_[topIndex++] = obj; segmentState.parts.topIndex = topIndex; } assert(result != NULL); return result; }