/* Code called from dvmJniStartup() * Initializes the gPolicyTable for fast lookup of taint policy * profiles for methods. */ void dvmTaintPropJniStartup() { TaintPolicy* policy; u4 hash; /* Create the policy table (perfect size) */ gPolicyTable = dvmHashTableCreate( dvmHashSize(TAINT_POLICY_TABLE_SIZE), freeTaintPolicy); for (policy = gDvmJniTaintPolicy; policy->classDescriptor != NULL; policy++) { const TaintProfile *profile; /* Create the method table for this class */ policy->methodTable = dvmHashTableCreate( TAINT_PROFILE_TABLE_SIZE, freeTaintProfile); /* Add all of the methods */ for (profile = &policy->profiles[0]; profile->methodName != NULL; profile++) { hash = dvmComputeUtf8Hash(profile->methodName); dvmHashTableLookup(policy->methodTable, hash,(void *) profile, hashcmpTaintProfile, true); } /* Add this class to gPolicyTable */ hash = dvmComputeUtf8Hash(policy->classDescriptor); dvmHashTableLookup(gPolicyTable, hash, policy, hashcmpTaintPolicy, true); } #ifdef TAINT_JNI_LOG /* JNI logging for debugging purposes */ gJniLogSeen = dvmHashTableCreate(dvmHashSize(50), free); #endif }
/* * Prep string interning. */ bool dvmStringInternStartup() { dvmInitMutex(&gDvm.internLock); gDvm.internedStrings = dvmHashTableCreate(256, NULL); if (gDvm.internedStrings == NULL) return false; gDvm.literalStrings = dvmHashTableCreate(256, NULL); if (gDvm.literalStrings == NULL) return false; return true; }
/* * Initialize the native code loader. */ bool dvmNativeStartup(void) { gDvm.nativeLibs = dvmHashTableCreate(4, freeSharedLibEntry); if (gDvm.nativeLibs == NULL) return false; return true; }
/* *bref:创建一个class的hash表,大小是128. *retval 0:创建成功. *retval !=0:返回错误码. */ int hprofStartup_Class() { gClassHashTable = dvmHashTableCreate(128, NULL); if (gClassHashTable == NULL) { return UNIQUE_ERROR(); } return 0; }
/* * Set up hash values on the class names. */ bool dvmInternalNativeStartup(void) { DalvikNativeClass* classPtr = gDvmNativeMethodSet; while (classPtr->classDescriptor != NULL) { classPtr->classDescriptorHash = dvmComputeUtf8Hash(classPtr->classDescriptor); classPtr++; } gDvm.userDexFiles = dvmHashTableCreate(2, dvmFreeDexOrJar); if (gDvm.userDexFiles == NULL) return false; return true; }
static u4 hprofLookupStackSerialNumber(const StackTraceEntry *stackTrace) { StackTraceEntry *val; u4 hashValue; int serial; /* * Create the hash table on first contact. We can't do this in * hprofStartupStack, because we have to compute stack trace * serial numbers and place them into object headers before the * rest of hprof is triggered by a GC event. */ if (gStackTraceHashTable == NULL) { gStackTraceHashTable = dvmHashTableCreate(512, free); } dvmHashTableLock(gStackTraceHashTable); hashValue = computeStackTraceHash(stackTrace); val = dvmHashTableLookup(gStackTraceHashTable, hashValue, (void *)stackTrace, (HashCompareFunc)stackCmp, false); if (val == NULL) { StackTraceEntry *newStackTrace; newStackTrace = stackDup(stackTrace); newStackTrace->trace.serialNumber = ++gSerialNumber; val = dvmHashTableLookup(gStackTraceHashTable, hashValue, (void *)newStackTrace, (HashCompareFunc)stackCmp, true); assert(val != NULL); } /* Mark the trace as live (in use by an object in the current heap). */ val->live = 1; /* Grab the serial number before unlocking the table. */ serial = val->trace.serialNumber; dvmHashTableUnlock(gStackTraceHashTable); return serial; }
/* * Set up hash values on the class names. */ bool dvmInternalNativeStartup() { #ifndef FASTIVA_NO_DALVIK_INTERNAL_NATIVE DalvikNativeClass* classPtr = gDvmNativeMethodSet; while (classPtr->classDescriptor != NULL) { classPtr->classDescriptorHash = dvmComputeUtf8Hash(classPtr->classDescriptor); #ifdef FASTIVA d2f_registerInternalNativeMethods(classPtr); #endif classPtr++; } #endif gDvm.userDexFiles = dvmHashTableCreate(2, dvmFreeDexOrJar); if (gDvm.userDexFiles == NULL) return false; return true; }
hprof_stack_frame_id hprofLookupStackFrameId(const StackFrameEntry *stackFrameEntry) { StackFrameEntry *val; u4 hashValue; /* * Create the hash table on first contact. We can't do this in * hprofStartupStackFrame, because we have to compute stack trace * serial numbers and place them into object headers before the * rest of hprof is triggered by a GC event. */ if (gStackFrameHashTable == NULL) { gStackFrameHashTable = dvmHashTableCreate(512, free); } dvmHashTableLock(gStackFrameHashTable); hashValue = computeStackFrameHash(stackFrameEntry); val = dvmHashTableLookup(gStackFrameHashTable, hashValue, (void *)stackFrameEntry, (HashCompareFunc)stackFrameCmp, false); if (val == NULL) { const StackFrameEntry *newStackFrameEntry; newStackFrameEntry = stackFrameDup(stackFrameEntry); val = dvmHashTableLookup(gStackFrameHashTable, hashValue, (void *)newStackFrameEntry, (HashCompareFunc)stackFrameCmp, true); assert(val != NULL); } /* Mark the frame as live (in use by an object in the current heap). */ val->live = 1; dvmHashTableUnlock(gStackFrameHashTable); return (hprof_stack_frame_id) val; }
static bool compilerThreadStartup(void) { JitEntry *pJitTable = NULL; unsigned char *pJitProfTable = NULL; JitTraceProfCounters *pJitTraceProfCounters = NULL; unsigned int i; if (!dvmCompilerArchInit()) goto fail; /* * Setup the code cache if we have not inherited a valid code cache * from the zygote. */ if (gDvmJit.codeCache == NULL) { if (!dvmCompilerSetupCodeCache()) goto fail; } /* Allocate the initial arena block */ if (dvmCompilerHeapInit() == false) { goto fail; } /* Cache the thread pointer */ gDvmJit.compilerThread = dvmThreadSelf(); dvmLockMutex(&gDvmJit.compilerLock); /* Track method-level compilation statistics */ gDvmJit.methodStatsTable = dvmHashTableCreate(32, NULL); #if defined(WITH_JIT_TUNING) gDvm.verboseShutdown = true; #endif dvmUnlockMutex(&gDvmJit.compilerLock); /* Set up the JitTable */ /* Power of 2? */ assert(gDvmJit.jitTableSize && !(gDvmJit.jitTableSize & (gDvmJit.jitTableSize - 1))); dvmInitMutex(&gDvmJit.tableLock); dvmLockMutex(&gDvmJit.tableLock); pJitTable = (JitEntry*) calloc(gDvmJit.jitTableSize, sizeof(*pJitTable)); if (!pJitTable) { ALOGE("jit table allocation failed"); dvmUnlockMutex(&gDvmJit.tableLock); goto fail; } /* * NOTE: the profile table must only be allocated once, globally. * Profiling is turned on and off by nulling out gDvm.pJitProfTable * and then restoring its original value. However, this action * is not synchronized for speed so threads may continue to hold * and update the profile table after profiling has been turned * off by null'ng the global pointer. Be aware. */ pJitProfTable = (unsigned char *)malloc(JIT_PROF_SIZE); if (!pJitProfTable) { ALOGE("jit prof table allocation failed"); free(pJitTable); dvmUnlockMutex(&gDvmJit.tableLock); goto fail; } memset(pJitProfTable, gDvmJit.threshold, JIT_PROF_SIZE); for (i=0; i < gDvmJit.jitTableSize; i++) { pJitTable[i].u.info.chain = gDvmJit.jitTableSize; } /* Is chain field wide enough for termination pattern? */ assert(pJitTable[0].u.info.chain == gDvmJit.jitTableSize); /* Allocate the trace profiling structure */ pJitTraceProfCounters = (JitTraceProfCounters*) calloc(1, sizeof(*pJitTraceProfCounters)); if (!pJitTraceProfCounters) { ALOGE("jit trace prof counters allocation failed"); free(pJitTable); free(pJitProfTable); dvmUnlockMutex(&gDvmJit.tableLock); goto fail; } gDvmJit.pJitEntryTable = pJitTable; gDvmJit.jitTableMask = gDvmJit.jitTableSize - 1; gDvmJit.jitTableEntriesUsed = 0; gDvmJit.compilerHighWater = COMPILER_WORK_QUEUE_SIZE - (COMPILER_WORK_QUEUE_SIZE/4); /* * If the VM is launched with wait-on-the-debugger, we will need to hide * the profile table here */ gDvmJit.pProfTable = dvmDebuggerOrProfilerActive() ? NULL : pJitProfTable; gDvmJit.pProfTableCopy = pJitProfTable; gDvmJit.pJitTraceProfCounters = pJitTraceProfCounters; dvmJitUpdateThreadStateAll(); dvmUnlockMutex(&gDvmJit.tableLock); /* Signal running threads to refresh their cached pJitTable pointers */ dvmSuspendAllThreads(SUSPEND_FOR_REFRESH); dvmResumeAllThreads(SUSPEND_FOR_REFRESH); /* Enable signature breakpoints by customizing the following code */ #if defined(SIGNATURE_BREAKPOINT) /* * Suppose one sees the following native crash in the bugreport: * I/DEBUG ( 1638): Build fingerprint: 'unknown' * I/DEBUG ( 1638): pid: 2468, tid: 2507 >>> com.google.android.gallery3d * I/DEBUG ( 1638): signal 11 (SIGSEGV), fault addr 00001400 * I/DEBUG ( 1638): r0 44ea7190 r1 44e4f7b8 r2 44ebc710 r3 00000000 * I/DEBUG ( 1638): r4 00000a00 r5 41862dec r6 4710dc10 r7 00000280 * I/DEBUG ( 1638): r8 ad010f40 r9 46a37a12 10 001116b0 fp 42a78208 * I/DEBUG ( 1638): ip 00000090 sp 4710dbc8 lr ad060e67 pc 46b90682 * cpsr 00000030 * I/DEBUG ( 1638): #00 pc 46b90682 /dev/ashmem/dalvik-jit-code-cache * I/DEBUG ( 1638): #01 pc 00060e62 /system/lib/libdvm.so * * I/DEBUG ( 1638): code around pc: * I/DEBUG ( 1638): 46b90660 6888d01c 34091dcc d2174287 4a186b68 * I/DEBUG ( 1638): 46b90670 d0052800 68006809 28004790 6b68d00e * I/DEBUG ( 1638): 46b90680 512000bc 37016eaf 6ea866af 6f696028 * I/DEBUG ( 1638): 46b90690 682a6069 429a686b e003da08 6df1480b * I/DEBUG ( 1638): 46b906a0 1c2d4788 47806d70 46a378fa 47806d70 * * Clearly it is a JIT bug. To find out which translation contains the * offending code, the content of the memory dump around the faulting PC * can be pasted into the gDvmJit.signatureBreakpoint[] array and next time * when a similar compilation is being created, the JIT compiler replay the * trace in the verbose mode and one can investigate the instruction * sequence in details. * * The length of the signature may need additional experiments to determine. * The rule of thumb is don't include PC-relative instructions in the * signature since it may be affected by the alignment of the compiled code. * However, a signature that's too short might increase the chance of false * positive matches. Using gdbjithelper to disassembly the memory content * first might be a good companion approach. * * For example, if the next 4 words starting from 46b90680 is pasted into * the data structure: */ gDvmJit.signatureBreakpointSize = 4; gDvmJit.signatureBreakpoint = malloc(sizeof(u4) * gDvmJit.signatureBreakpointSize); gDvmJit.signatureBreakpoint[0] = 0x512000bc; gDvmJit.signatureBreakpoint[1] = 0x37016eaf; gDvmJit.signatureBreakpoint[2] = 0x6ea866af; gDvmJit.signatureBreakpoint[3] = 0x6f696028; /* * The following log will be printed when a match is found in subsequent * testings: * * D/dalvikvm( 2468): Signature match starting from offset 0x34 (4 words) * D/dalvikvm( 2468): -------- * D/dalvikvm( 2468): Compiler: Building trace for computeVisibleItems, * offset 0x1f7 * D/dalvikvm( 2468): 0x46a37a12: 0x0090 add-int v42, v5, v26 * D/dalvikvm( 2468): 0x46a37a16: 0x004d aput-object v13, v14, v42 * D/dalvikvm( 2468): 0x46a37a1a: 0x0028 goto, (#0), (#0) * D/dalvikvm( 2468): 0x46a3794e: 0x00d8 add-int/lit8 v26, v26, (#1) * D/dalvikvm( 2468): 0x46a37952: 0x0028 goto, (#0), (#0) * D/dalvikvm( 2468): 0x46a378ee: 0x0002 move/from16 v0, v26, (#0) * D/dalvikvm( 2468): 0x46a378f2: 0x0002 move/from16 v1, v29, (#0) * D/dalvikvm( 2468): 0x46a378f6: 0x0035 if-ge v0, v1, (#10) * D/dalvikvm( 2468): TRACEINFO (554): 0x46a37624 * Lcom/cooliris/media/GridLayer;computeVisibleItems 0x1f7 14 of 934, 8 * blocks * : * : * D/dalvikvm( 2468): 0x20 (0020): ldr r0, [r5, #52] * D/dalvikvm( 2468): 0x22 (0022): ldr r2, [pc, #96] * D/dalvikvm( 2468): 0x24 (0024): cmp r0, #0 * D/dalvikvm( 2468): 0x26 (0026): beq 0x00000034 * D/dalvikvm( 2468): 0x28 (0028): ldr r1, [r1, #0] * D/dalvikvm( 2468): 0x2a (002a): ldr r0, [r0, #0] * D/dalvikvm( 2468): 0x2c (002c): blx r2 * D/dalvikvm( 2468): 0x2e (002e): cmp r0, #0 * D/dalvikvm( 2468): 0x30 (0030): beq 0x00000050 * D/dalvikvm( 2468): 0x32 (0032): ldr r0, [r5, #52] * D/dalvikvm( 2468): 0x34 (0034): lsls r4, r7, #2 * D/dalvikvm( 2468): 0x36 (0036): str r0, [r4, r4] * D/dalvikvm( 2468): -------- dalvik offset: 0x01fb @ goto, (#0), (#0) * D/dalvikvm( 2468): L0x0195: * D/dalvikvm( 2468): -------- dalvik offset: 0x0195 @ add-int/lit8 v26, * v26, (#1) * D/dalvikvm( 2468): 0x38 (0038): ldr r7, [r5, #104] * D/dalvikvm( 2468): 0x3a (003a): adds r7, r7, #1 * D/dalvikvm( 2468): 0x3c (003c): str r7, [r5, #104] * D/dalvikvm( 2468): -------- dalvik offset: 0x0197 @ goto, (#0), (#0) * D/dalvikvm( 2468): L0x0165: * D/dalvikvm( 2468): -------- dalvik offset: 0x0165 @ move/from16 v0, v26, * (#0) * D/dalvikvm( 2468): 0x3e (003e): ldr r0, [r5, #104] * D/dalvikvm( 2468): 0x40 (0040): str r0, [r5, #0] * * The "str r0, [r4, r4]" is indeed the culprit of the native crash. */ #endif return true; fail: return false; }
/* * Some quick hash table tests. */ bool dvmTestHash() { HashTable* pTab; char tmpStr[64]; const char* str; u4 hash; int i; ALOGV("TestHash BEGIN"); pTab = dvmHashTableCreate(dvmHashSize(12), free); if (pTab == NULL) return false; dvmHashTableLock(pTab); /* add some entries */ for (i = 0; i < kNumTestEntries; i++) { sprintf(tmpStr, "entry %d", i); hash = dvmComputeUtf8Hash(tmpStr); dvmHashTableLookup(pTab, hash, strdup(tmpStr), (HashCompareFunc) strcmp, true); } dvmHashTableUnlock(pTab); /* make sure we can find all entries */ for (i = 0; i < kNumTestEntries; i++) { sprintf(tmpStr, "entry %d", i); hash = dvmComputeUtf8Hash(tmpStr); str = (const char*) dvmHashTableLookup(pTab, hash, tmpStr, (HashCompareFunc) strcmp, false); if (str == NULL) { ALOGE("TestHash: failure: could not find '%s'", tmpStr); /* return false */ } } /* make sure it behaves correctly when entry not found and !doAdd */ sprintf(tmpStr, "entry %d", 17); hash = dvmComputeUtf8Hash(tmpStr); str = (const char*) dvmHashTableLookup(pTab, hash, tmpStr, (HashCompareFunc) strcmp, false); if (str == NULL) { /* good */ } else { ALOGE("TestHash found nonexistent string (improper add?)"); } dumpForeach(pTab); dumpIterator(pTab); /* make sure they all get freed */ dvmHashTableFree(pTab); /* * Round 2: verify probing & tombstones. */ pTab = dvmHashTableCreate(dvmHashSize(2), free); if (pTab == NULL) return false; hash = 0; /* two entries, same hash, different values */ const char* str1; str1 = (char*) dvmHashTableLookup(pTab, hash, strdup("one"), (HashCompareFunc) strcmp, true); assert(str1 != NULL); str = (const char*) dvmHashTableLookup(pTab, hash, strdup("two"), (HashCompareFunc) strcmp, true); /* remove the first one */ if (!dvmHashTableRemove(pTab, hash, (void*)str1)) ALOGE("TestHash failed to delete item"); else free((void*)str1); // "Remove" doesn't call the free func /* make sure iterator doesn't included deleted entries */ int count = 0; HashIter iter; for (dvmHashIterBegin(pTab, &iter); !dvmHashIterDone(&iter); dvmHashIterNext(&iter)) { count++; } if (count != 1) { ALOGE("TestHash wrong number of entries (%d)", count); } /* see if we can find them */ str = (const char*) dvmHashTableLookup(pTab, hash, (void*)"one", (HashCompareFunc) strcmp,false); if (str != NULL) ALOGE("TestHash deleted entry has returned!"); str = (const char*) dvmHashTableLookup(pTab, hash, (void*)"two", (HashCompareFunc) strcmp,false); if (str == NULL) ALOGE("TestHash entry vanished"); /* force a table realloc to exercise tombstone removal */ for (i = 0; i < 20; i++) { sprintf(tmpStr, "entry %d", i); str = (const char*) dvmHashTableLookup(pTab, hash, strdup(tmpStr), (HashCompareFunc) strcmp, true); assert(str != NULL); } dvmHashTableFree(pTab); ALOGV("TestHash END"); return true; }