/* * Log an object with some additional info. * * Pass in the number of elements in the array (or 0 if this is not an * array object), and the number of additional objects that are identical * or equivalent to the original. */ static void logSummaryLine(const Object* obj, size_t elems, int identical, int equiv) { if (obj == NULL) { LOGW(" NULL reference (count=%d)", equiv); return; } if (obj == kClearedJniWeakGlobal) { LOGW(" cleared jweak (count=%d)", equiv); return; } std::string className(dvmHumanReadableType(obj)); if (obj->clazz == gDvm.classJavaLangClass) { // We're summarizing multiple instances, so using the exemplar // Class' type parameter here would be misleading. className = "java.lang.Class"; } if (elems != 0) { StringAppendF(&className, " (%zd elements)", elems); } size_t total = identical + equiv + 1; std::string msg(StringPrintf("%5d of %s", total, className.c_str())); if (identical + equiv != 0) { StringAppendF(&msg, " (%d unique instances)", equiv + 1); } LOGW(" %s", msg.c_str()); }
static void printWaitMessage(const DebugOutputTarget* target, const char* detail, Object* obj, Thread* thread) { std::string msg(StringPrintf(" - waiting %s <%p> ", detail, obj)); if (obj->clazz != gDvm.classJavaLangClass) { // I(16573) - waiting on <0xf5feda38> (a java.util.LinkedList) // I(16573) - waiting on <0xf5ed54f8> (a java.lang.Class<java.lang.ref.ReferenceQueue>) msg += "(a " + dvmHumanReadableType(obj) + ")"; } if (thread != NULL) { std::string threadName(dvmGetThreadName(thread)); StringAppendF(&msg, " held by tid=%d (%s)", thread->threadId, threadName.c_str()); } dvmPrintDebugMessage(target, "%s\n", msg.c_str()); }
/* * Verify that "obj" is non-null and is an instance of "clazz". * Used to implement reflection on fields and methods. * * Returns "false" and throws an exception if not. */ bool dvmVerifyObjectInClass(Object* obj, ClassObject* clazz) { ClassObject* exceptionClass = NULL; if (obj == NULL) { exceptionClass = gDvm.exNullPointerException; } else if (!dvmInstanceof(obj->clazz, clazz)) { exceptionClass = gDvm.exIllegalArgumentException; } if (exceptionClass == NULL) { return true; } std::string expectedClassName(dvmHumanReadableDescriptor(clazz->descriptor)); std::string actualClassName(dvmHumanReadableType(obj)); dvmThrowExceptionFmt(exceptionClass, "expected receiver of type %s, but got %s", expectedClassName.c_str(), actualClassName.c_str()); return false; }
static void throwArgumentTypeMismatch(int argIndex, ClassObject* expected, DataObject* arg) { std::string expectedClassName(dvmHumanReadableDescriptor(expected->descriptor)); std::string actualClassName = dvmHumanReadableType(arg); dvmThrowExceptionFmt(gDvm.exIllegalArgumentException, "argument %d should have type %s, got %s", argIndex + 1, expectedClassName.c_str(), actualClassName.c_str()); }
/* * Dump a summary of an array of references to the log file. * * This is used to dump the contents of ReferenceTable and IndirectRefTable * structs. */ void dvmDumpReferenceTableContents(Object* const* refs, size_t count, const char* descr) { LOGW("%s reference table (%p) dump:", descr, refs); if (count == 0) { LOGW(" (empty)"); return; } // Dump the most recent N entries. const size_t kLast = 10; int first = count - kLast; if (first < 0) { first = 0; } LOGW(" Last %d entries (of %d):", (count - first), count); for (int idx = count - 1; idx >= first; --idx) { const Object* ref = refs[idx]; if (ref == NULL) { continue; } if (ref == kClearedJniWeakGlobal) { LOGW(" %5d: cleared jweak", idx); continue; } if (ref->clazz == NULL) { // should only be possible right after a plain dvmMalloc(). size_t size = dvmObjectSizeInHeap(ref); LOGW(" %5d: %p (raw) (%zd bytes)", idx, ref, size); continue; } std::string className(dvmHumanReadableType(ref)); std::string extras; size_t elems = getElementCount(ref); if (elems != 0) { StringAppendF(&extras, " (%zd elements)", elems); } else if (ref->clazz == gDvm.classJavaLangString) { const StringObject* str = reinterpret_cast<const StringObject*>(ref); extras += " \""; size_t count = 0; char* s = dvmCreateCstrFromString(str); char* p = s; for (; *p && count < 16; ++p, ++count) { extras += *p; } if (*p == 0) { extras += "\""; } else { StringAppendF(&extras, "... (%d chars)", str->length()); } free(s); } LOGW(" %5d: %p %s%s", idx, ref, className.c_str(), extras.c_str()); } // Make a copy of the table, and sort it. Object** tableCopy = (Object**)malloc(sizeof(Object*) * count); if (tableCopy == NULL) { LOGE("Unable to copy table with %d elements", count); return; } memcpy(tableCopy, refs, sizeof(Object*) * count); qsort(tableCopy, count, sizeof(Object*), compareObject); refs = tableCopy; // use sorted list // Remove any uninteresting stuff from the list. The sort moved them all to the end. while (count > 0 && refs[count-1] == NULL) { --count; } while (count > 0 && refs[count-1] == kClearedJniWeakGlobal) { --count; } if (count == 0) { return; } // Dump a summary of the whole table. LOGW(" Summary:"); size_t equiv, identical; equiv = identical = 0; size_t idx; size_t elems; for (idx = 1; idx < count; idx++) { elems = getElementCount(refs[idx-1]); if (refs[idx] == refs[idx-1]) { // same reference, added more than once. identical++; } else if (refs[idx]->clazz == refs[idx-1]->clazz && getElementCount(refs[idx]) == elems) { // same class / element count, different object. equiv++; } else { // different class. logSummaryLine(refs[idx-1], elems, identical, equiv); equiv = identical = 0; } } // Handle the last entry (everything above outputs refs[i-1]). elems = getElementCount(refs[idx-1]); logSummaryLine(refs[count-1], elems, identical, equiv); free(tableCopy); }