diff options
author | Ben Cheng <bccheng@android.com> | 2011-03-10 11:17:04 -0800 |
---|---|---|
committer | Android (Google) Code Review <android-gerrit@google.com> | 2011-03-10 11:17:04 -0800 |
commit | 6d59d5584b793e597e94300bf95dea8ee8335ccf (patch) | |
tree | c78bf70af11ad28b43d715671dbf1cc23997ac42 /vm/compiler/codegen | |
parent | 9ea32b0a0fa0eb4c4bfcd73f0c7fe15ddb0f9ce2 (diff) | |
parent | 385828e36ea70effe9aa18a954d008b1f7dc1d63 (diff) | |
download | android_dalvik-6d59d5584b793e597e94300bf95dea8ee8335ccf.tar.gz android_dalvik-6d59d5584b793e597e94300bf95dea8ee8335ccf.tar.bz2 android_dalvik-6d59d5584b793e597e94300bf95dea8ee8335ccf.zip |
Merge "Handle relocatable class objects in JIT'ed code." into dalvik-dev
Diffstat (limited to 'vm/compiler/codegen')
-rw-r--r-- | vm/compiler/codegen/CodegenFactory.c | 30 | ||||
-rw-r--r-- | vm/compiler/codegen/CompilerCodegen.h | 7 | ||||
-rw-r--r-- | vm/compiler/codegen/arm/ArchUtility.c | 9 | ||||
-rw-r--r-- | vm/compiler/codegen/arm/Assemble.c | 480 | ||||
-rw-r--r-- | vm/compiler/codegen/arm/CodegenCommon.c | 13 | ||||
-rw-r--r-- | vm/compiler/codegen/arm/CodegenDriver.c | 20 | ||||
-rw-r--r-- | vm/compiler/codegen/arm/Thumb/Factory.c | 4 | ||||
-rw-r--r-- | vm/compiler/codegen/arm/Thumb2/Factory.c | 8 | ||||
-rw-r--r-- | vm/compiler/codegen/x86/Assemble.c | 4 |
9 files changed, 409 insertions, 166 deletions
diff --git a/vm/compiler/codegen/CodegenFactory.c b/vm/compiler/codegen/CodegenFactory.c index 61e29d7d1..ef7a0a976 100644 --- a/vm/compiler/codegen/CodegenFactory.c +++ b/vm/compiler/codegen/CodegenFactory.c @@ -263,3 +263,33 @@ static void storeValueWide(CompilationUnit *cUnit, RegLocation rlDest, } } } + +/* + * Load a class pointer value into a fixed or temp register. Target + * register is clobbered, and marked inUse. + */ +static ArmLIR *loadClassPointer(CompilationUnit *cUnit, int rDest, int value) +{ + ArmLIR *res; + cUnit->hasClassLiterals = true; + if (dvmCompilerIsTemp(cUnit, rDest)) { + dvmCompilerClobber(cUnit, rDest); + dvmCompilerMarkInUse(cUnit, rDest); + } + ArmLIR *dataTarget = scanLiteralPool(cUnit->classPointerList, value, 0); + if (dataTarget == NULL) { + dataTarget = addWordData(cUnit, &cUnit->classPointerList, value); + /* Counts the number of class pointers in this translation */ + cUnit->numClassPointers++; + } + ArmLIR *loadPcRel = (ArmLIR *) dvmCompilerNew(sizeof(ArmLIR), true); + loadPcRel->opcode = kThumb2LdrPcRel12; + loadPcRel->generic.target = (LIR *) dataTarget; + loadPcRel->operands[0] = rDest; + setupResourceMasks(loadPcRel); + setMemRefType(loadPcRel, true, kLiteral); + loadPcRel->aliasInfo = dataTarget->operands[0]; + res = loadPcRel; + dvmCompilerAppendLIR(cUnit, (LIR *) loadPcRel); + return res; +} diff --git a/vm/compiler/codegen/CompilerCodegen.h b/vm/compiler/codegen/CompilerCodegen.h index 9cd4847c0..efa913f90 100644 --- a/vm/compiler/codegen/CompilerCodegen.h +++ b/vm/compiler/codegen/CompilerCodegen.h @@ -34,6 +34,10 @@ void dvmCompilerMethodMIR2LIR(CompilationUnit *cUnit); /* Assemble LIR into machine code */ void dvmCompilerAssembleLIR(CompilationUnit *cUnit, JitTranslationInfo *info); +/* Install class objects in the literal pool */ +void dvmJitInstallClassObjectPointers(CompilationUnit *cUnit, + char *codeAddress); + /* Patch inline cache content for polymorphic callsites */ bool dvmJitPatchInlineCache(void *cellPtr, void *contentPtr); @@ -41,9 +45,6 @@ bool dvmJitPatchInlineCache(void *cellPtr, void *contentPtr); void dvmCompilerCodegenDump(CompilationUnit *cUnit); /* Implemented in the codegen/<target>/Assembler.c */ -void* dvmJitChain(void *tgtAddr, u4* branchAddr); -u4* dvmJitUnchain(void *codeAddr); -void dvmJitUnchainAll(void); void dvmCompilerPatchInlineCache(void); /* Implemented in codegen/<target>/Ralloc.c */ diff --git a/vm/compiler/codegen/arm/ArchUtility.c b/vm/compiler/codegen/arm/ArchUtility.c index 02a02fa1f..d94b1a7e1 100644 --- a/vm/compiler/codegen/arm/ArchUtility.c +++ b/vm/compiler/codegen/arm/ArchUtility.c @@ -395,7 +395,14 @@ void dvmCompilerCodegenDump(CompilationUnit *cUnit) for (lirInsn = cUnit->firstLIRInsn; lirInsn; lirInsn = lirInsn->next) { dvmDumpLIRInsn(lirInsn, (unsigned char *) cUnit->baseAddr); } - for (lirInsn = cUnit->wordList; lirInsn; lirInsn = lirInsn->next) { + for (lirInsn = cUnit->classPointerList; lirInsn; lirInsn = lirInsn->next) { + armLIR = (ArmLIR *) lirInsn; + LOGD("%p (%04x): .class (%s)\n", + (char*)cUnit->baseAddr + armLIR->generic.offset, + armLIR->generic.offset, + ((CallsiteInfo *) armLIR->operands[0])->classDescriptor); + } + for (lirInsn = cUnit->literalList; lirInsn; lirInsn = lirInsn->next) { armLIR = (ArmLIR *) lirInsn; LOGD("%p (%04x): .word (0x%x)\n", (char*)cUnit->baseAddr + armLIR->generic.offset, diff --git a/vm/compiler/codegen/arm/Assemble.c b/vm/compiler/codegen/arm/Assemble.c index 8fc1add35..9b24b7588 100644 --- a/vm/compiler/codegen/arm/Assemble.c +++ b/vm/compiler/codegen/arm/Assemble.c @@ -897,28 +897,26 @@ ArmEncodingMap EncodingMap[kArmLast] = { #define UPDATE_CODE_CACHE_PATCHES() #endif -/* Write the numbers in the literal pool to the codegen stream */ -static void installDataContent(CompilationUnit *cUnit) +/* Write the numbers in the constant and class pool to the output stream */ +static void installLiteralPools(CompilationUnit *cUnit) { int *dataPtr = (int *) ((char *) cUnit->baseAddr + cUnit->dataOffset); - ArmLIR *dataLIR = (ArmLIR *) cUnit->wordList; + /* Install number of class pointer literals */ + *dataPtr++ = cUnit->numClassPointers; + ArmLIR *dataLIR = (ArmLIR *) cUnit->classPointerList; while (dataLIR) { + /* + * Install the callsiteinfo pointers into the cells for now. They will + * be converted into real pointers in dvmJitInstallClassObjectPointers. + */ *dataPtr++ = dataLIR->operands[0]; dataLIR = NEXT_LIR(dataLIR); } -} - -/* Returns the size of a Jit trace description */ -static int jitTraceDescriptionSize(const JitTraceDescription *desc) -{ - int runCount; - /* Trace end is always of non-meta type (ie isCode == true) */ - for (runCount = 0; ; runCount++) { - if (desc->trace[runCount].frag.isCode && - desc->trace[runCount].frag.runEnd) - break; + dataLIR = (ArmLIR *) cUnit->literalList; + while (dataLIR) { + *dataPtr++ = dataLIR->operands[0]; + dataLIR = NEXT_LIR(dataLIR); } - return sizeof(JitTraceDescription) + ((runCount+1) * sizeof(JitTraceRun)); } /* @@ -1146,35 +1144,24 @@ static AssemblerStatus assembleInstructions(CompilationUnit *cUnit, return kSuccess; } -#if defined(SIGNATURE_BREAKPOINT) -/* Inspect the assembled instruction stream to find potential matches */ -static void matchSignatureBreakpoint(const CompilationUnit *cUnit, - unsigned int size) +static int assignLiteralOffsetCommon(LIR *lir, int offset) { - unsigned int i, j; - u4 *ptr = (u4 *) cUnit->codeBuffer; - - for (i = 0; i < size - gDvmJit.signatureBreakpointSize + 1; i++) { - if (ptr[i] == gDvmJit.signatureBreakpoint[0]) { - for (j = 1; j < gDvmJit.signatureBreakpointSize; j++) { - if (ptr[i+j] != gDvmJit.signatureBreakpoint[j]) { - break; - } - } - if (j == gDvmJit.signatureBreakpointSize) { - LOGD("Signature match starting from offset %#x (%d words)", - i*4, gDvmJit.signatureBreakpointSize); - int descSize = jitTraceDescriptionSize(cUnit->traceDesc); - JitTraceDescription *newCopy = - (JitTraceDescription *) malloc(descSize); - memcpy(newCopy, cUnit->traceDesc, descSize); - dvmCompilerWorkEnqueue(NULL, kWorkOrderTraceDebug, newCopy); - break; - } - } + for (;lir != NULL; lir = lir->next) { + lir->offset = offset; + offset += 4; } + return offset; +} + +/* Determine the offset of each literal field */ +static int assignLiteralOffset(CompilationUnit *cUnit, int offset) +{ + /* Reserved for the size field of class pointer pool */ + offset += 4; + offset = assignLiteralOffsetCommon(cUnit->classPointerList, offset); + offset = assignLiteralOffsetCommon(cUnit->literalList, offset); + return offset; } -#endif /* * Translation layout in the code cache. Note that the codeAddress pointer @@ -1183,9 +1170,9 @@ static void matchSignatureBreakpoint(const CompilationUnit *cUnit, * counter is at codeAddress - 6. * * +----------------------------+ - * | Trace Profile Counter addr | -> 4 bytes + * | Trace Profile Counter addr | -> 4 bytes (PROF_COUNTER_ADDR_SIZE) * +----------------------------+ - * +--| Offset to chain cell counts| -> 2 bytes + * +--| Offset to chain cell counts| -> 2 bytes (CHAIN_CELL_OFFSET_SIZE) * | +----------------------------+ * | | Trace profile code | <- entry point when profiling * | . - - - - - - - . @@ -1206,25 +1193,151 @@ static void matchSignatureBreakpoint(const CompilationUnit *cUnit, * . . * | | * +----------------------------+ + * | # Class pointer pool size | -> 4 bytes + * +----------------------------+ + * | Class pointer pool | -> 4-byte aligned, variable size + * . . + * . . + * | | + * +----------------------------+ * | Literal pool | -> 4-byte aligned, variable size * . . * . . * | | * +----------------------------+ * + */ + +#define PROF_COUNTER_ADDR_SIZE 4 +#define CHAIN_CELL_OFFSET_SIZE 2 + +/* + * Utility functions to navigate various parts in a trace. If we change the + * layout/offset in the future, we just modify these functions and we don't need + * to propagate the changes to all the use cases. + */ +static inline char *getTraceBase(const JitEntry *p) +{ + return (char*)p->codeAddress - + (PROF_COUNTER_ADDR_SIZE + CHAIN_CELL_OFFSET_SIZE + + (p->u.info.instructionSet == DALVIK_JIT_ARM ? 0 : 1)); +} + +/* Handy function to retrieve the profile count */ +static inline JitTraceCounter_t getProfileCount(const JitEntry *entry) +{ + if (entry->dPC == 0 || entry->codeAddress == 0 || + entry->codeAddress == dvmCompilerGetInterpretTemplate()) + return 0; + + JitTraceCounter_t **p = (JitTraceCounter_t **) getTraceBase(entry); + + return **p; +} + +/* Handy function to reset the profile count */ +static inline void resetProfileCount(const JitEntry *entry) +{ + if (entry->dPC == 0 || entry->codeAddress == 0 || + entry->codeAddress == dvmCompilerGetInterpretTemplate()) + return; + + JitTraceCounter_t **p = (JitTraceCounter_t **) getTraceBase(entry); + + **p = 0; +} + +/* Get the pointer of the chain cell count */ +static inline ChainCellCounts* getChainCellCountsPointer(const char *base) +{ + /* 4 is the size of the profile count */ + u2 *chainCellOffsetP = (u2 *) (base + PROF_COUNTER_ADDR_SIZE); + u2 chainCellOffset = *chainCellOffsetP; + return (ChainCellCounts *) ((char *) chainCellOffsetP + chainCellOffset); +} + +/* Get the size of all chaining cells */ +static inline u4 getChainCellSize(const ChainCellCounts* pChainCellCounts) +{ + int cellSize = 0; + int i; + + /* Get total count of chain cells */ + for (i = 0; i < kChainingCellGap; i++) { + if (i != kChainingCellInvokePredicted) { + cellSize += pChainCellCounts->u.count[i] * + (CHAIN_CELL_NORMAL_SIZE >> 2); + } else { + cellSize += pChainCellCounts->u.count[i] * + (CHAIN_CELL_PREDICTED_SIZE >> 2); + } + } + return cellSize; +} + +/* Get the starting pointer of the trace description section */ +static JitTraceDescription* getTraceDescriptionPointer(const char *base) +{ + ChainCellCounts* pCellCounts = getChainCellCountsPointer(base); + return (JitTraceDescription*) ((char*)pCellCounts + sizeof(*pCellCounts)); +} + +/* Get the size of a trace description */ +static int getTraceDescriptionSize(const JitTraceDescription *desc) +{ + int runCount; + /* Trace end is always of non-meta type (ie isCode == true) */ + for (runCount = 0; ; runCount++) { + if (desc->trace[runCount].isCode && + desc->trace[runCount].info.frag.runEnd) + break; + } + return sizeof(JitTraceDescription) + ((runCount+1) * sizeof(JitTraceRun)); +} + +#if defined(SIGNATURE_BREAKPOINT) +/* Inspect the assembled instruction stream to find potential matches */ +static void matchSignatureBreakpoint(const CompilationUnit *cUnit, + unsigned int size) +{ + unsigned int i, j; + u4 *ptr = (u4 *) cUnit->codeBuffer; + + for (i = 0; i < size - gDvmJit.signatureBreakpointSize + 1; i++) { + if (ptr[i] == gDvmJit.signatureBreakpoint[0]) { + for (j = 1; j < gDvmJit.signatureBreakpointSize; j++) { + if (ptr[i+j] != gDvmJit.signatureBreakpoint[j]) { + break; + } + } + if (j == gDvmJit.signatureBreakpointSize) { + LOGD("Signature match starting from offset %#x (%d words)", + i*4, gDvmJit.signatureBreakpointSize); + int descSize = getTraceDescriptionSize(cUnit->traceDesc); + JitTraceDescription *newCopy = + (JitTraceDescription *) malloc(descSize); + memcpy(newCopy, cUnit->traceDesc, descSize); + dvmCompilerWorkEnqueue(NULL, kWorkOrderTraceDebug, newCopy); + break; + } + } + } +} +#endif + +/* * Go over each instruction in the list and calculate the offset from the top * before sending them off to the assembler. If out-of-range branch distance is * seen rearrange the instructions a bit to correct it. */ void dvmCompilerAssembleLIR(CompilationUnit *cUnit, JitTranslationInfo *info) { - LIR *lir; ArmLIR *armLIR; int offset = 0; int i; ChainCellCounts chainCellCounts; int descSize = - cUnit->methodJitMode ? 0 : jitTraceDescriptionSize(cUnit->traceDesc); + cUnit->methodJitMode ? 0 : getTraceDescriptionSize(cUnit->traceDesc); int chainingCellGap = 0; info->instructionSet = cUnit->instructionSet; @@ -1283,10 +1396,11 @@ void dvmCompilerAssembleLIR(CompilationUnit *cUnit, JitTranslationInfo *info) /* Set up offsets for literals */ cUnit->dataOffset = offset; - for (lir = cUnit->wordList; lir; lir = lir->next) { - lir->offset = offset; - offset += 4; - } + /* + * Assign each class pointer/constant an offset from the beginning of the + * compilation unit. + */ + offset = assignLiteralOffset(cUnit, offset); cUnit->totalSize = offset; @@ -1387,8 +1501,7 @@ void dvmCompilerAssembleLIR(CompilationUnit *cUnit, JitTranslationInfo *info) } /* Write the literals directly into the code cache */ - installDataContent(cUnit); - + installLiteralPools(cUnit); /* Flush dcache and invalidate the icache to maintain coherence */ dvmCompilerCacheFlush((long)cUnit->baseAddr, @@ -1575,8 +1688,14 @@ static void inlineCachePatchEnqueue(PredictedChainingCell *cellAddr, */ } else if (gDvmJit.compilerICPatchIndex < COMPILER_IC_PATCH_QUEUE_SIZE) { int index = gDvmJit.compilerICPatchIndex++; + const ClassObject *clazz = newContent->clazz; + gDvmJit.compilerICPatchQueue[index].cellAddr = cellAddr; gDvmJit.compilerICPatchQueue[index].cellContent = *newContent; + gDvmJit.compilerICPatchQueue[index].classDescriptor = clazz->descriptor; + gDvmJit.compilerICPatchQueue[index].classLoader = clazz->classLoader; + /* For verification purpose only */ + gDvmJit.compilerICPatchQueue[index].serialNumber = clazz->serialNumber; #if defined(WITH_JIT_TUNING) gDvmJit.icPatchQueued++; #endif @@ -1700,10 +1819,16 @@ void dvmCompilerPatchInlineCache(void) maxAddr = (PredictedChainingCell *) gDvmJit.codeCache; for (i = 0; i < gDvmJit.compilerICPatchIndex; i++) { - PredictedChainingCell *cellAddr = - gDvmJit.compilerICPatchQueue[i].cellAddr; - PredictedChainingCell *cellContent = - &gDvmJit.compilerICPatchQueue[i].cellContent; + ICPatchWorkOrder *workOrder = &gDvmJit.compilerICPatchQueue[i]; + PredictedChainingCell *cellAddr = workOrder->cellAddr; + PredictedChainingCell *cellContent = &workOrder->cellContent; + ClassObject *clazz = dvmFindClassNoInit(workOrder->classDescriptor, + workOrder->classLoader); + + assert(clazz->serialNumber == workOrder->serialNumber); + + /* Use the newly resolved clazz pointer */ + cellContent->clazz = clazz; COMPILER_TRACE_CHAINING( LOGD("Jit Runtime: predicted chain %p from %s to %s (%s) " @@ -1736,35 +1861,22 @@ void dvmCompilerPatchInlineCache(void) * the incoming codeAddr is a thumb code address, and therefore has * the low bit set. */ -u4* dvmJitUnchain(void* codeAddr) +static u4* unchainSingle(JitEntry *trace) { - u2* pChainCellOffset = (u2*)((char*)codeAddr - 3); - u2 chainCellOffset = *pChainCellOffset; - ChainCellCounts *pChainCellCounts = - (ChainCellCounts*)((char*)codeAddr + chainCellOffset - 3); - int cellSize; + const char *base = getTraceBase(trace); + ChainCellCounts *pChainCellCounts = getChainCellCountsPointer(base); + int cellSize = getChainCellSize(pChainCellCounts); u4* pChainCells; - u4* pStart; u4 newInst; int i,j; PredictedChainingCell *predChainCell; - /* Get total count of chain cells */ - for (i = 0, cellSize = 0; i < kChainingCellGap; i++) { - if (i != kChainingCellInvokePredicted) { - cellSize += pChainCellCounts->u.count[i] * (CHAIN_CELL_NORMAL_SIZE >> 2); - } else { - cellSize += pChainCellCounts->u.count[i] * - (CHAIN_CELL_PREDICTED_SIZE >> 2); - } - } - if (cellSize == 0) return (u4 *) pChainCellCounts; /* Locate the beginning of the chain cell region */ - pStart = pChainCells = ((u4 *) pChainCellCounts) - cellSize - - pChainCellCounts->u.count[kChainingCellGap]; + pChainCells = ((u4 *) pChainCellCounts) - cellSize - + pChainCellCounts->u.count[kChainingCellGap]; /* The cells are sorted in order - walk through them and reset */ for (i = 0; i < kChainingCellGap; i++) { @@ -1833,8 +1945,7 @@ void dvmJitUnchainAll() (gDvmJit.pJitEntryTable[i].codeAddress != dvmCompilerGetInterpretTemplate())) { u4* lastAddress; - lastAddress = - dvmJitUnchain(gDvmJit.pJitEntryTable[i].codeAddress); + lastAddress = unchainSingle(&gDvmJit.pJitEntryTable[i]); if (lowAddress == NULL || (u4*)gDvmJit.pJitEntryTable[i].codeAddress < lowAddress) @@ -1872,73 +1983,33 @@ static int addrToLineCb (void *cnxt, u4 bytecodeOffset, u4 lineNum) return 0; } -static char *getTraceBase(const JitEntry *p) -{ - return (char*)p->codeAddress - - (6 + (p->u.info.instructionSet == DALVIK_JIT_ARM ? 0 : 1)); -} - -/* Handy function to retrieve the profile count */ -static inline JitTraceCounter_t getProfileCount(const JitEntry *entry) -{ - if (entry->dPC == 0 || entry->codeAddress == 0 || - entry->codeAddress == dvmCompilerGetInterpretTemplate()) - return 0; - - JitTraceCounter_t **p = (JitTraceCounter_t **) getTraceBase(entry); - - return **p; -} - -/* Handy function to reset the profile count */ -static inline void resetProfileCount(const JitEntry *entry) -{ - if (entry->dPC == 0 || entry->codeAddress == 0 || - entry->codeAddress == dvmCompilerGetInterpretTemplate()) - return; - - JitTraceCounter_t **p = (JitTraceCounter_t **) getTraceBase(entry); - - **p = 0; -} - /* Dumps profile info for a single trace */ static int dumpTraceProfile(JitEntry *p, bool silent, bool reset, unsigned long sum) { - ChainCellCounts* pCellCounts; - char* traceBase; - JitTraceCounter_t count; - u2* pCellOffset; - JitTraceDescription *desc; - const Method* method; int idx; - traceBase = getTraceBase(p); - if (p->codeAddress == NULL) { if (!silent) - LOGD("TRACEPROFILE 0x%08x 0 NULL 0 0", (int)traceBase); + LOGD("TRACEPROFILE NULL"); return 0; } if (p->codeAddress == dvmCompilerGetInterpretTemplate()) { if (!silent) - LOGD("TRACEPROFILE 0x%08x 0 INTERPRET_ONLY 0 0", (int)traceBase); + LOGD("TRACEPROFILE INTERPRET_ONLY"); return 0; } - count = getProfileCount(p); + JitTraceCounter_t count = getProfileCount(p); if (reset) { resetProfileCount(p); } if (silent) { return count; } - pCellOffset = (u2*) (traceBase + 4); - pCellCounts = (ChainCellCounts*) ((char *)pCellOffset + *pCellOffset); - desc = (JitTraceDescription*) ((char*)pCellCounts + sizeof(*pCellCounts)); - method = desc->method; + JitTraceDescription *desc = getTraceDescriptionPointer(getTraceBase(p)); + const Method *method = desc->method; char *methodDesc = dexProtoCopyMethodDescriptor(&method->prototype); - jitProfileAddrToLine addrToLine = {0, desc->trace[0].frag.startOffset}; + jitProfileAddrToLine addrToLine = {0, desc->trace[0].info.frag.startOffset}; /* * We may end up decoding the debug information for the same method @@ -1955,18 +2026,18 @@ static int dumpTraceProfile(JitEntry *p, bool silent, bool reset, addrToLineCb, NULL, &addrToLine); LOGD("TRACEPROFILE 0x%08x % 10d %5.2f%% [%#x(+%d), %d] %s%s;%s", - (int)traceBase, + (int) getTraceBase(p), count, ((float ) count) / sum * 100.0, - desc->trace[0].frag.startOffset, - desc->trace[0].frag.numInsts, + desc->trace[0].info.frag.startOffset, + desc->trace[0].info.frag.numInsts, addrToLine.lineNum, method->clazz->descriptor, method->name, methodDesc); free(methodDesc); /* Find the last fragment (ie runEnd is set) */ for (idx = 0; - desc->trace[idx].frag.isCode && !desc->trace[idx].frag.runEnd; + desc->trace[idx].isCode && !desc->trace[idx].info.frag.runEnd; idx++) { } @@ -1974,8 +2045,9 @@ static int dumpTraceProfile(JitEntry *p, bool silent, bool reset, * runEnd must comes with a JitCodeDesc frag. If isCode is false it must * be a meta info field (only used by callsite info for now). */ - if (!desc->trace[idx].frag.isCode) { - const Method *method = (const Method *)desc->trace[idx+1].meta; + if (!desc->trace[idx].isCode) { + const Method *method = (const Method *) + desc->trace[idx+JIT_TRACE_CUR_METHOD-1].info.meta; char *methodDesc = dexProtoCopyMethodDescriptor(&method->prototype); /* Print the callee info in the trace */ LOGD(" -> %s%s;%s", method->clazz->descriptor, method->name, @@ -1994,20 +2066,11 @@ JitTraceDescription *dvmCopyTraceDescriptor(const u2 *pc, if ((jitEntry == NULL) || (jitEntry->codeAddress == 0)) return NULL; - /* Find out the startint point */ - char *traceBase = getTraceBase(jitEntry); - - /* Then find out the starting point of the chaining cell */ - u2 *pCellOffset = (u2*) (traceBase + 4); - ChainCellCounts *pCellCounts = - (ChainCellCounts*) ((char *)pCellOffset + *pCellOffset); - - /* From there we can find out the starting point of the trace descriptor */ JitTraceDescription *desc = - (JitTraceDescription*) ((char*)pCellCounts + sizeof(*pCellCounts)); + getTraceDescriptionPointer(getTraceBase(jitEntry)); /* Now make a copy and return */ - int descSize = jitTraceDescriptionSize(desc); + int descSize = getTraceDescriptionSize(desc); JitTraceDescription *newCopy = (JitTraceDescription *) malloc(descSize); memcpy(newCopy, desc, descSize); return newCopy; @@ -2091,6 +2154,145 @@ done: return; } +static void findClassPointersSingleTrace(char *base, void (*callback)(void *)) +{ + unsigned int chainTypeIdx, chainIdx; + ChainCellCounts *pChainCellCounts = getChainCellCountsPointer(base); + int cellSize = getChainCellSize(pChainCellCounts); + /* Scan the chaining cells */ + if (cellSize) { + /* Locate the beginning of the chain cell region */ + u4 *pChainCells = ((u4 *) pChainCellCounts) - cellSize - + pChainCellCounts->u.count[kChainingCellGap]; + /* The cells are sorted in order - walk through them */ + for (chainTypeIdx = 0; chainTypeIdx < kChainingCellGap; + chainTypeIdx++) { + if (chainTypeIdx != kChainingCellInvokePredicted) { + /* In 32-bit words */ + pChainCells += (CHAIN_CELL_NORMAL_SIZE >> 2) * + pChainCellCounts->u.count[chainTypeIdx]; + continue; + } + for (chainIdx = 0; + chainIdx < pChainCellCounts->u.count[chainTypeIdx]; + chainIdx++) { + PredictedChainingCell *cell = + (PredictedChainingCell *) pChainCells; + /* + * Report the cell if it contains a sane class + * pointer. + */ + if (cell->clazz != NULL && + cell->clazz != + (ClassObject *) PREDICTED_CHAIN_FAKE_CLAZZ) { + callback(&cell->clazz); + } + pChainCells += CHAIN_CELL_PREDICTED_SIZE >> 2; + } + } + } + + /* Scan the class pointer pool */ + JitTraceDescription *desc = getTraceDescriptionPointer(base); + int descSize = getTraceDescriptionSize(desc); + int *classPointerP = (int *) ((char *) desc + descSize); + int numClassPointers = *classPointerP++; + for (; numClassPointers; numClassPointers--, classPointerP++) { + callback(classPointerP); + } +} + +/* + * Scan class pointers in each translation and pass its address to the callback + * function. Currently such a pointers can be found in the pointer pool and the + * clazz field in the predicted chaining cells. + */ +void dvmJitScanAllClassPointers(void (*callback)(void *)) +{ + UNPROTECT_CODE_CACHE(gDvmJit.codeCache, gDvmJit.codeCacheByteUsed); + + /* Handle the inflight compilation first */ + if (gDvmJit.inflightBaseAddr) + findClassPointersSingleTrace((char *) gDvmJit.inflightBaseAddr, + callback); + + if (gDvmJit.pJitEntryTable != NULL) { + unsigned int traceIdx; + dvmLockMutex(&gDvmJit.tableLock); + for (traceIdx = 0; traceIdx < gDvmJit.jitTableSize; traceIdx++) { + const JitEntry *entry = &gDvmJit.pJitEntryTable[traceIdx]; + if (entry->dPC && + !entry->u.info.isMethodEntry && + entry->codeAddress && + (entry->codeAddress != dvmCompilerGetInterpretTemplate())) { + char *base = getTraceBase(entry); + findClassPointersSingleTrace(base, callback); + } + } + dvmUnlockMutex(&gDvmJit.tableLock); + } + UPDATE_CODE_CACHE_PATCHES(); + + PROTECT_CODE_CACHE(gDvmJit.codeCache, gDvmJit.codeCacheByteUsed); +} + +/* + * Provide the final touch on the class object pointer pool to install the + * actual pointers. The thread has to be in the running state. + */ +void dvmJitInstallClassObjectPointers(CompilationUnit *cUnit, char *codeAddress) +{ + char *base = codeAddress - cUnit->headerSize - + (cUnit->instructionSet == DALVIK_JIT_ARM ? 0 : 1); + + /* Scan the class pointer pool */ + JitTraceDescription *desc = getTraceDescriptionPointer(base); + int descSize = getTraceDescriptionSize(desc); + intptr_t *classPointerP = (int *) ((char *) desc + descSize); + int numClassPointers = *(int *)classPointerP++; + intptr_t *startClassPointerP = classPointerP; + + UNPROTECT_CODE_CACHE(startClassPointerP, + numClassPointers * sizeof(intptr_t)); + /* + * Change the thread state to VM_RUNNING so that GC won't be happening + * when the assembler looks up the class pointers. + */ + dvmChangeStatus(gDvmJit.compilerThread, THREAD_RUNNING); +#if defined(WITH_JIT_TUNING) + u8 startTime = dvmGetRelativeTimeUsec(); +#endif + for (;numClassPointers; numClassPointers--) { + CallsiteInfo *callsiteInfo = (CallsiteInfo *) *classPointerP; + ClassObject *clazz = dvmFindClassNoInit( + callsiteInfo->classDescriptor, callsiteInfo->classLoader); + assert(!strcmp(clazz->descriptor, callsiteInfo->classDescriptor)); + *classPointerP++ = (intptr_t) clazz; + } + + /* + * Register the base address so that if GC kicks in after the thread state + * has been changed to VMWAIT and before the compiled code is registered + * in the JIT table, its content can be patched if class objects are + * moved. + */ + gDvmJit.inflightBaseAddr = base; + +#if defined(WITH_JIT_TUNING) + u8 blockTime = dvmGetRelativeTimeUsec() - startTime; + gDvmJit.compilerThreadBlockGCTime += blockTime; + if (blockTime > gDvmJit.maxCompilerThreadBlockGCTime) + gDvmJit.maxCompilerThreadBlockGCTime = blockTime; + gDvmJit.numCompilerThreadBlockGC++; +#endif + /* Change the thread state back to VMWAIT */ + dvmChangeStatus(gDvmJit.compilerThread, THREAD_VMWAIT); + + UPDATE_CODE_CACHE_PATCHES(); + + PROTECT_CODE_CACHE(startClassPointerP, numClassPointers * sizeof(intptr_t)); +} + #if defined(WITH_SELF_VERIFICATION) /* * The following are used to keep compiled loads and stores from modifying diff --git a/vm/compiler/codegen/arm/CodegenCommon.c b/vm/compiler/codegen/arm/CodegenCommon.c index 2555a8dbc..ae41fe9af 100644 --- a/vm/compiler/codegen/arm/CodegenCommon.c +++ b/vm/compiler/codegen/arm/CodegenCommon.c @@ -357,10 +357,8 @@ static RegLocation inlinedTarget(CompilationUnit *cUnit, MIR *mir, * Search the existing constants in the literal pool for an exact or close match * within specified delta (greater or equal to 0). */ -static ArmLIR *scanLiteralPool(CompilationUnit *cUnit, int value, - unsigned int delta) +static ArmLIR *scanLiteralPool(LIR *dataTarget, int value, unsigned int delta) { - LIR *dataTarget = cUnit->wordList; while (dataTarget) { if (((unsigned) (value - ((ArmLIR *) dataTarget)->operands[0])) <= delta) @@ -376,14 +374,15 @@ static ArmLIR *scanLiteralPool(CompilationUnit *cUnit, int value, */ /* Add a 32-bit constant either in the constant pool or mixed with code */ -static ArmLIR *addWordData(CompilationUnit *cUnit, int value, bool inPlace) +static ArmLIR *addWordData(CompilationUnit *cUnit, LIR **constantListP, + int value) { /* Add the constant to the literal pool */ - if (!inPlace) { + if (constantListP) { ArmLIR *newValue = (ArmLIR *) dvmCompilerNew(sizeof(ArmLIR), true); newValue->operands[0] = value; - newValue->generic.next = cUnit->wordList; - cUnit->wordList = (LIR *) newValue; + newValue->generic.next = *constantListP; + *constantListP = (LIR *) newValue; return newValue; } else { /* Add the constant in the middle of code stream */ diff --git a/vm/compiler/codegen/arm/CodegenDriver.c b/vm/compiler/codegen/arm/CodegenDriver.c index cc81d1da8..55c06476f 100644 --- a/vm/compiler/codegen/arm/CodegenDriver.c +++ b/vm/compiler/codegen/arm/CodegenDriver.c @@ -1285,7 +1285,7 @@ static void genInvokeVirtualWholeMethod(CompilationUnit *cUnit, CallsiteInfo *callsiteInfo = mir->meta.callsiteInfo; dvmCompilerLockAllTemps(cUnit); - loadConstant(cUnit, r1, (int) callsiteInfo->clazz); + loadClassPointer(cUnit, r1, (int) callsiteInfo); loadWordDisp(cUnit, r0, offsetof(Object, clazz), r2); /* Branch to the slow path if classes are not equal */ @@ -3741,7 +3741,7 @@ static void handleNormalChainingCell(CompilationUnit *cUnit, offsetof(Thread, jitToInterpEntries.dvmJitToInterpNormal) >> 2); newLIR1(cUnit, kThumbBlxR, r0); - addWordData(cUnit, (int) (cUnit->method->insns + offset), true); + addWordData(cUnit, NULL, (int) (cUnit->method->insns + offset)); } /* @@ -3760,7 +3760,7 @@ static void handleHotChainingCell(CompilationUnit *cUnit, offsetof(Thread, jitToInterpEntries.dvmJitToInterpTraceSelect) >> 2); newLIR1(cUnit, kThumbBlxR, r0); - addWordData(cUnit, (int) (cUnit->method->insns + offset), true); + addWordData(cUnit, NULL, (int) (cUnit->method->insns + offset)); } /* Chaining cell for branches that branch back into the same basic block */ @@ -3781,7 +3781,7 @@ static void handleBackwardBranchChainingCell(CompilationUnit *cUnit, offsetof(Thread, jitToInterpEntries.dvmJitToInterpNormal) >> 2); #endif newLIR1(cUnit, kThumbBlxR, r0); - addWordData(cUnit, (int) (cUnit->method->insns + offset), true); + addWordData(cUnit, NULL, (int) (cUnit->method->insns + offset)); } /* Chaining cell for monomorphic method invocations. */ @@ -3797,7 +3797,7 @@ static void handleInvokeSingletonChainingCell(CompilationUnit *cUnit, offsetof(Thread, jitToInterpEntries.dvmJitToInterpTraceSelect) >> 2); newLIR1(cUnit, kThumbBlxR, r0); - addWordData(cUnit, (int) (callee->insns), true); + addWordData(cUnit, NULL, (int) (callee->insns)); } /* Chaining cell for monomorphic method invocations. */ @@ -3805,16 +3805,16 @@ static void handleInvokePredictedChainingCell(CompilationUnit *cUnit) { /* Should not be executed in the initial state */ - addWordData(cUnit, PREDICTED_CHAIN_BX_PAIR_INIT, true); + addWordData(cUnit, NULL, PREDICTED_CHAIN_BX_PAIR_INIT); /* To be filled: class */ - addWordData(cUnit, PREDICTED_CHAIN_CLAZZ_INIT, true); + addWordData(cUnit, NULL, PREDICTED_CHAIN_CLAZZ_INIT); /* To be filled: method */ - addWordData(cUnit, PREDICTED_CHAIN_METHOD_INIT, true); + addWordData(cUnit, NULL, PREDICTED_CHAIN_METHOD_INIT); /* * Rechain count. The initial value of 0 here will trigger chaining upon * the first invocation of this callsite. */ - addWordData(cUnit, PREDICTED_CHAIN_COUNTER_INIT, true); + addWordData(cUnit, NULL, PREDICTED_CHAIN_COUNTER_INIT); } /* Load the Dalvik PC into r0 and jump to the specified target */ @@ -4042,7 +4042,7 @@ static void genValidationForPredictedInline(CompilationUnit *cUnit, MIR *mir) rlThis = loadValue(cUnit, rlThis, kCoreReg); int regPredictedClass = dvmCompilerAllocTemp(cUnit); - loadConstant(cUnit, regPredictedClass, (int) callsiteInfo->clazz); + loadClassPointer(cUnit, regPredictedClass, (int) callsiteInfo); genNullCheck(cUnit, rlThis.sRegLow, rlThis.lowReg, mir->offset, NULL);/* null object? */ int regActualClass = dvmCompilerAllocTemp(cUnit); diff --git a/vm/compiler/codegen/arm/Thumb/Factory.c b/vm/compiler/codegen/arm/Thumb/Factory.c index bd84a2896..7b51df160 100644 --- a/vm/compiler/codegen/arm/Thumb/Factory.c +++ b/vm/compiler/codegen/arm/Thumb/Factory.c @@ -69,9 +69,9 @@ static ArmLIR *loadConstantNoClobber(CompilationUnit *cUnit, int rDest, return res; } /* No shortcut - go ahead and use literal pool */ - ArmLIR *dataTarget = scanLiteralPool(cUnit, value, 255); + ArmLIR *dataTarget = scanLiteralPool(cUnit->literalList, value, 255); if (dataTarget == NULL) { - dataTarget = addWordData(cUnit, value, false); + dataTarget = addWordData(cUnit, &cUnit->literalList, value); } ArmLIR *loadPcRel = (ArmLIR *) dvmCompilerNew(sizeof(ArmLIR), true); loadPcRel->opcode = kThumbLdrPcRel; diff --git a/vm/compiler/codegen/arm/Thumb2/Factory.c b/vm/compiler/codegen/arm/Thumb2/Factory.c index e5adcadaa..80454508f 100644 --- a/vm/compiler/codegen/arm/Thumb2/Factory.c +++ b/vm/compiler/codegen/arm/Thumb2/Factory.c @@ -56,9 +56,9 @@ static ArmLIR *loadFPConstantValue(CompilationUnit *cUnit, int rDest, if (encodedImm >= 0) { return newLIR2(cUnit, kThumb2Vmovs_IMM8, rDest, encodedImm); } - ArmLIR *dataTarget = scanLiteralPool(cUnit, value, 0); + ArmLIR *dataTarget = scanLiteralPool(cUnit->literalList, value, 0); if (dataTarget == NULL) { - dataTarget = addWordData(cUnit, value, false); + dataTarget = addWordData(cUnit, &cUnit->literalList, value); } ArmLIR *loadPcRel = (ArmLIR *) dvmCompilerNew(sizeof(ArmLIR), true); loadPcRel->opcode = kThumb2Vldrs; @@ -164,9 +164,9 @@ static ArmLIR *loadConstantNoClobber(CompilationUnit *cUnit, int rDest, return res; } /* No shortcut - go ahead and use literal pool */ - ArmLIR *dataTarget = scanLiteralPool(cUnit, value, 0); + ArmLIR *dataTarget = scanLiteralPool(cUnit->literalList, value, 0); if (dataTarget == NULL) { - dataTarget = addWordData(cUnit, value, false); + dataTarget = addWordData(cUnit, &cUnit->literalList, value); } ArmLIR *loadPcRel = (ArmLIR *) dvmCompilerNew(sizeof(ArmLIR), true); loadPcRel->opcode = kThumb2LdrPcRel12; diff --git a/vm/compiler/codegen/x86/Assemble.c b/vm/compiler/codegen/x86/Assemble.c index d583001e9..03edbf109 100644 --- a/vm/compiler/codegen/x86/Assemble.c +++ b/vm/compiler/codegen/x86/Assemble.c @@ -142,3 +142,7 @@ JitTraceDescription *dvmCopyTraceDescriptor(const u2 *pc, void dvmCompilerSortAndPrintTraceProfiles() { } + +void dvmJitScanAllClassPointers(void (*callback)(void *)) +{ +} |