/* *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; }
/* * 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:从"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; }
/* * Remove "obj" from "pRef". We extract the table offset bits from "iref" * and zap the corresponding entry, leaving a hole if it's not at the top. * * 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. * * Note this is NOT called when a local frame is popped. This is only used * for explicit single removals. * * Returns "false" if nothing was removed. */ bool IndirectRefTable::remove(u4 cookie, IndirectRef iref) { IRTSegmentState prevState; prevState.all = cookie; int topIndex = segmentState.parts.topIndex; int bottomIndex = prevState.parts.topIndex; assert(table_ != NULL); assert(alloc_entries_ <= max_entries_); assert(segmentState.parts.numHoles >= prevState.parts.numHoles); int idx = extractIndex(iref); bool workAroundAppJniBugs = false; if (indirectRefKind(iref) == kIndirectKindInvalid && gDvmJni.workAroundAppJniBugs) { idx = linearScan(iref, bottomIndex, topIndex, table_); workAroundAppJniBugs = true; if (idx == -1) { LOGW("trying to work around app JNI bugs, but didn't find %p in table!", iref); return false; } } if (idx < bottomIndex) { /* wrong segment */ LOGV("Attempt to remove index outside index area (%d vs %d-%d)", idx, bottomIndex, topIndex); return false; } if (idx >= topIndex) { /* bad -- stale reference? */ LOGD("Attempt to remove invalid index %d (bottom=%d top=%d)", idx, bottomIndex, topIndex); return false; } if (idx == topIndex-1) { // Top-most entry. Scan up and consume holes. if (workAroundAppJniBugs == false && !checkEntry("remove", iref, idx)) { return false; } table_[idx] = NULL; int 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, table_[topIndex-1]); if (table_[topIndex-1] != NULL) { break; } LOGV("+++ ate hole at %d", topIndex-1); numHoles--; } segmentState.parts.numHoles = numHoles + prevState.parts.numHoles; segmentState.parts.topIndex = topIndex; } else { segmentState.parts.topIndex = topIndex-1; LOGV("+++ 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. */ if (table_[idx] == NULL) { LOGV("--- WEIRD: removing null entry %d", idx); return false; } if (workAroundAppJniBugs == false && !checkEntry("remove", iref, idx)) { return false; } table_[idx] = NULL; segmentState.parts.numHoles++; LOGV("+++ left hole at %d, holes=%d", idx, segmentState.parts.numHoles); } return true; }