/* * Check to see if "obj" is NULL. If so, throw an exception. Assumes the * pc has already been exported to the stack. * * Perform additional checks on debug builds. * * Use this to check for NULL when the instruction handler calls into * something that could throw an exception (so we have already called * EXPORT_PC at the top). */ static inline bool checkForNull(Object* obj) { if (obj == NULL) { dvmThrowNullPointerException(NULL); return false; } #ifdef WITH_EXTRA_OBJECT_VALIDATION if (!dvmIsHeapAddress(obj)) { ALOGE("Invalid object %p", obj); dvmAbort(); } #endif #ifndef NDEBUG if (obj->clazz == NULL || ((u4) obj->clazz) <= 65536) { /* probable heap corruption */ ALOGE("Invalid object class %p (in %p)", obj->clazz, obj); dvmAbort(); } #endif return true; }
/* * Add "obj" to "pRef". */ bool dvmAddToReferenceTable(ReferenceTable* pRef, Object* obj) { assert(obj != NULL); assert(dvmIsHeapAddress(obj)); assert(pRef->table != NULL); assert(pRef->allocEntries <= pRef->maxEntries); if (pRef->nextEntry == pRef->table + pRef->allocEntries) { /* reached end of allocated space; did we hit buffer max? */ if (pRef->nextEntry == pRef->table + pRef->maxEntries) { LOGW("ReferenceTable overflow (max=%d)", pRef->maxEntries); return false; } Object** newTable; int newSize; newSize = pRef->allocEntries * 2; if (newSize > pRef->maxEntries) newSize = pRef->maxEntries; assert(newSize > pRef->allocEntries); newTable = (Object**) realloc(pRef->table, newSize * sizeof(Object*)); if (newTable == NULL) { LOGE("Unable to expand ref table (from %d to %d %d-byte entries)", pRef->allocEntries, newSize, sizeof(Object*)); return false; } LOGVV("Growing %p from %d to %d", pRef, pRef->allocEntries, newSize); /* update entries; adjust "nextEntry" in case memory moved */ pRef->nextEntry = newTable + (pRef->nextEntry - pRef->table); pRef->table = newTable; pRef->allocEntries = newSize; } *pRef->nextEntry++ = obj; return true; }
/* * Issue a method call with a variable number of arguments. We process * the contents of "args" by scanning the method signature. * * Pass in NULL for "obj" on calls to static methods. * * We don't need to take the class as an argument because, in Dalvik, * we don't need to worry about static synchronized methods. */ void dvmCallMethodV(Thread* self, const Method* method, Object* obj, bool fromJni, JValue* pResult, va_list args) { //salma //__android_log_print(ANDROID_LOG_DEBUG, "DVM DEBUG", "dvmCallMethodV method name = %s, clazz name: %s", method->name, method->clazz->descriptor); //end salma const char* desc = &(method->shorty[1]); // [0] is the return type. int verifyCount = 0; ClassObject* clazz; u4* ins; clazz = callPrep(self, method, obj, false); if (clazz == NULL) return; /* "ins" for new frame start at frame pointer plus locals */ ins = ((u4*)self->interpSave.curFrame) + (method->registersSize - method->insSize); //ALOGD(" FP is %p, INs live at >= %p", self->interpSave.curFrame, ins); /* put "this" pointer into in0 if appropriate */ if (!dvmIsStaticMethod(method)) { #ifdef WITH_EXTRA_OBJECT_VALIDATION assert(obj != NULL && dvmIsHeapAddress(obj)); #endif *ins++ = (u4) obj; verifyCount++; } while (*desc != '\0') { switch (*(desc++)) { case 'D': case 'J': { u8 val = va_arg(args, u8); memcpy(ins, &val, 8); // EABI prevents direct store ins += 2; verifyCount += 2; break; } case 'F': { /* floats were normalized to doubles; convert back */ float f = (float) va_arg(args, double); *ins++ = dvmFloatToU4(f); verifyCount++; break; } case 'L': { /* 'shorty' descr uses L for all refs, incl array */ void* arg = va_arg(args, void*); assert(obj == NULL || dvmIsHeapAddress(obj)); jobject argObj = reinterpret_cast<jobject>(arg); if (fromJni) *ins++ = (u4) dvmDecodeIndirectRef(self, argObj); else *ins++ = (u4) argObj; verifyCount++; break; } default: { /* Z B C S I -- all passed as 32-bit integers */ *ins++ = va_arg(args, u4); verifyCount++; break; } } } #ifndef NDEBUG if (verifyCount != method->insSize) { ALOGE("Got vfycount=%d insSize=%d for %s.%s", verifyCount, method->insSize, clazz->descriptor, method->name); assert(false); goto bail; } #endif //dvmDumpThreadStack(dvmThreadSelf()); if (dvmIsNativeMethod(method)) { TRACE_METHOD_ENTER(self, method); /* * Because we leave no space for local variables, "curFrame" points * directly at the method arguments. */ (*method->nativeFunc)((u4*)self->interpSave.curFrame, pResult, method, self); TRACE_METHOD_EXIT(self, method); } else { dvmInterpret(self, method, pResult); } #ifndef NDEBUG bail: #endif dvmPopFrame(self); }
/* * Extract the object that is the target of a monitor-enter instruction * in the top stack frame of "thread". * * The other thread might be alive, so this has to work carefully. * * The thread list lock must be held. * * Returns "true" if we successfully recover the object. "*pOwner" will * be NULL if we can't determine the owner for some reason (e.g. race * condition on ownership transfer). */ static bool extractMonitorEnterObject(Thread* thread, Object** pLockObj, Thread** pOwner) { void* framePtr = thread->interpSave.curFrame; if (framePtr == NULL || dvmIsBreakFrame((u4*)framePtr)) return false; const StackSaveArea* saveArea = SAVEAREA_FROM_FP(framePtr); const Method* method = saveArea->method; const u2* currentPc = saveArea->xtra.currentPc; /* check Method* */ if (!dvmLinearAllocContains(method, sizeof(Method))) { ALOGD("ExtrMon: method %p not valid", method); return false; } /* check currentPc */ u4 insnsSize = dvmGetMethodInsnsSize(method); if (currentPc < method->insns || currentPc >= method->insns + insnsSize) { ALOGD("ExtrMon: insns %p not valid (%p - %p)", currentPc, method->insns, method->insns + insnsSize); return false; } /* check the instruction */ if ((*currentPc & 0xff) != OP_MONITOR_ENTER) { ALOGD("ExtrMon: insn at %p is not monitor-enter (0x%02x)", currentPc, *currentPc & 0xff); return false; } /* get and check the register index */ unsigned int reg = *currentPc >> 8; if (reg >= method->registersSize) { ALOGD("ExtrMon: invalid register %d (max %d)", reg, method->registersSize); return false; } /* get and check the object in that register */ u4* fp = (u4*) framePtr; Object* obj = (Object*) fp[reg]; if (obj != NULL && !dvmIsHeapAddress(obj)) { ALOGD("ExtrMon: invalid object %p at %p[%d]", obj, fp, reg); return false; } *pLockObj = obj; /* * Try to determine the object's lock holder; it's okay if this fails. * * We're assuming the thread list lock is already held by this thread. * If it's not, we may be living dangerously if we have to scan through * the thread list to find a match. (The VM will generally be in a * suspended state when executing here, so this is a minor concern * unless we're dumping while threads are running, in which case there's * a good chance of stuff blowing up anyway.) */ *pOwner = dvmGetObjectLockHolder(obj); 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; }
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; }