summaryrefslogtreecommitdiffstats
path: root/vm/compiler
diff options
context:
space:
mode:
Diffstat (limited to 'vm/compiler')
-rw-r--r--vm/compiler/Compiler.c1
-rw-r--r--vm/compiler/Compiler.h7
-rw-r--r--vm/compiler/CompilerIR.h6
-rw-r--r--vm/compiler/Dataflow.c7
-rw-r--r--vm/compiler/Frontend.c85
-rw-r--r--vm/compiler/InlineTransformation.c103
-rw-r--r--vm/compiler/MethodSSATransformation.c15
-rw-r--r--vm/compiler/codegen/CompilerCodegen.h3
-rw-r--r--vm/compiler/codegen/Optimizer.h1
-rw-r--r--vm/compiler/codegen/arm/ArchFactory.c16
-rw-r--r--vm/compiler/codegen/arm/ArchUtility.c10
-rw-r--r--vm/compiler/codegen/arm/Assemble.c102
-rw-r--r--vm/compiler/codegen/arm/CodegenDriver.c78
-rw-r--r--vm/compiler/codegen/arm/armv5te-vfp/ArchVariant.c4
-rw-r--r--vm/compiler/codegen/arm/armv5te-vfp/Codegen.c3
-rw-r--r--vm/compiler/codegen/arm/armv5te/ArchVariant.c4
-rw-r--r--vm/compiler/codegen/arm/armv5te/Codegen.c3
-rw-r--r--vm/compiler/codegen/arm/armv5te/MethodCodegenDriver.c21
-rw-r--r--vm/compiler/codegen/arm/armv7-a-neon/ArchVariant.c4
-rw-r--r--vm/compiler/codegen/arm/armv7-a-neon/Codegen.c3
-rw-r--r--vm/compiler/codegen/arm/armv7-a-neon/MethodCodegenDriver.c227
-rw-r--r--vm/compiler/codegen/arm/armv7-a/ArchVariant.c4
-rw-r--r--vm/compiler/codegen/arm/armv7-a/Codegen.c3
23 files changed, 584 insertions, 126 deletions
diff --git a/vm/compiler/Compiler.c b/vm/compiler/Compiler.c
index a1e3d0e8d..6cd7eb583 100644
--- a/vm/compiler/Compiler.c
+++ b/vm/compiler/Compiler.c
@@ -644,6 +644,7 @@ static void *compilerThreadStart(void *arg)
work.result.codeAddress) {
dvmJitSetCodeAddr(work.pc, work.result.codeAddress,
work.result.instructionSet,
+ false, /* not method entry */
work.result.profileCodeSize);
}
}
diff --git a/vm/compiler/Compiler.h b/vm/compiler/Compiler.h
index d29520d2e..b0ad7b4a5 100644
--- a/vm/compiler/Compiler.h
+++ b/vm/compiler/Compiler.h
@@ -215,6 +215,7 @@ typedef enum JitMethodAttributes {
kIsThrowFree, /* Method doesn't throw */
kIsGetter, /* Method fits the getter pattern */
kIsSetter, /* Method fits the setter pattern */
+ kCannotCompile, /* Method cannot be compiled */
} JitMethodAttributes;
#define METHOD_IS_CALLEE (1 << kIsCallee)
@@ -224,6 +225,7 @@ typedef enum JitMethodAttributes {
#define METHOD_IS_THROW_FREE (1 << kIsThrowFree)
#define METHOD_IS_GETTER (1 << kIsGetter)
#define METHOD_IS_SETTER (1 << kIsSetter)
+#define METHOD_CANNOT_COMPILE (1 << kCannotCompile)
/* Vectors to provide optimization hints */
typedef enum JitOptimizationHints {
@@ -267,7 +269,7 @@ CompilerMethodStats *dvmCompilerAnalyzeMethodBody(const Method *method,
bool isCallee);
bool dvmCompilerCanIncludeThisInstruction(const Method *method,
const DecodedInstruction *insn);
-bool dvmCompileMethod(const Method *method);
+bool dvmCompileMethod(const Method *method, JitTranslationInfo *info);
bool dvmCompileTrace(JitTraceDescription *trace, int numMaxInsts,
JitTranslationInfo *info, jmp_buf *bailPtr, int optHints);
void dvmCompilerDumpStats(void);
@@ -275,7 +277,8 @@ void dvmCompilerDrainQueue(void);
void dvmJitUnchainAll(void);
void dvmCompilerSortAndPrintTraceProfiles(void);
void dvmCompilerPerformSafePointChecks(void);
-void dvmCompilerInlineMIR(struct CompilationUnit *cUnit);
+void dvmCompilerInlineMIR(struct CompilationUnit *cUnit,
+ JitTranslationInfo *info);
void dvmInitializeSSAConversion(struct CompilationUnit *cUnit);
int dvmConvertSSARegToDalvik(const struct CompilationUnit *cUnit, int ssaReg);
bool dvmCompilerLoopOpt(struct CompilationUnit *cUnit);
diff --git a/vm/compiler/CompilerIR.h b/vm/compiler/CompilerIR.h
index 54d41a5c5..dd1d441bc 100644
--- a/vm/compiler/CompilerIR.h
+++ b/vm/compiler/CompilerIR.h
@@ -99,6 +99,7 @@ typedef enum {
kMIRInlined, // Invoke is inlined (ie dead)
kMIRInlinedPred, // Invoke is inlined via prediction
kMIRCallee, // Instruction is inlined from callee
+ kMIRInvokeMethodJIT, // Callee is JIT'ed as a whole method
} MIROptimizationFlagPositons;
#define MIR_IGNORE_NULL_CHECK (1 << kMIRIgnoreNullCheck)
@@ -108,6 +109,7 @@ typedef enum {
#define MIR_INLINED (1 << kMIRInlined)
#define MIR_INLINED_PRED (1 << kMIRInlinedPred)
#define MIR_CALLEE (1 << kMIRCallee)
+#define MIR_INVOKE_METHOD_JIT (1 << kMIRInvokeMethodJIT)
typedef struct CallsiteInfo {
const ClassObject *clazz;
@@ -209,7 +211,6 @@ typedef struct CompilationUnit {
bool hasLoop; // Contains a loop
bool hasInvoke; // Contains an invoke instruction
bool heapMemOp; // Mark mem ops for self verification
- bool wholeMethod;
int profileCodeSize; // Size of the profile prefix in bytes
int numChainingCells[kChainingCellGap];
LIR *firstChainingLIR[kChainingCellGap];
@@ -243,10 +244,12 @@ typedef struct CompilationUnit {
const u2 *switchOverflowPad;
/* New fields only for method-based compilation */
+ bool methodJitMode;
int numReachableBlocks;
int numDalvikRegisters; // method->registersSize + inlined
BasicBlock *entryBlock;
BasicBlock *exitBlock;
+ BasicBlock *curBlock;
GrowableList dfsOrder;
GrowableList domPostOrderTraversal;
BitVector *tryBlockAddr;
@@ -255,6 +258,7 @@ typedef struct CompilationUnit {
BitVector *tempDalvikRegisterV;
BitVector *tempSSARegisterV; // numSSARegs
bool printSSANames;
+ void *blockLabelList;
} CompilationUnit;
#if defined(WITH_SELF_VERIFICATION)
diff --git a/vm/compiler/Dataflow.c b/vm/compiler/Dataflow.c
index ba1b8fd59..d935fd5f2 100644
--- a/vm/compiler/Dataflow.c
+++ b/vm/compiler/Dataflow.c
@@ -1592,7 +1592,7 @@ char *dvmCompilerGetDalvikDisassembly(const DecodedInstruction *insn,
char buffer[256];
int opcode = insn->opcode;
int dfAttributes = dvmCompilerDataFlowAttributes[opcode];
- int flags = dexGetFlagsFromOpcode(insn->opcode);
+ int flags;
char *ret;
buffer[0] = 0;
@@ -1603,8 +1603,10 @@ char *dvmCompilerGetDalvikDisassembly(const DecodedInstruction *insn,
else {
sprintf(buffer, "Opcode 0x%x", opcode);
}
+ flags = 0;
} else {
strcpy(buffer, dexGetOpcodeName(opcode));
+ flags = dexGetFlagsFromOpcode(insn->opcode);
}
if (note)
@@ -1630,7 +1632,8 @@ char *dvmCompilerGetDalvikDisassembly(const DecodedInstruction *insn,
offset = (int) insn->vA;
break;
default:
- LOGE("Unexpected branch format: %d", dalvikFormat);
+ LOGE("Unexpected branch format %d / opcode %#x", dalvikFormat,
+ opcode);
dvmAbort();
break;
}
diff --git a/vm/compiler/Frontend.c b/vm/compiler/Frontend.c
index 1095225b3..c4dbf2794 100644
--- a/vm/compiler/Frontend.c
+++ b/vm/compiler/Frontend.c
@@ -288,11 +288,12 @@ CompilerMethodStats *dvmCompilerAnalyzeMethodBody(const Method *method,
/* For lookup only */
dummyMethodEntry.method = method;
- realMethodEntry =
- (CompilerMethodStats *) dvmHashTableLookup(gDvmJit.methodStatsTable, hashValue,
- &dummyMethodEntry,
- (HashCompareFunc) compareMethod,
- false);
+ realMethodEntry = (CompilerMethodStats *)
+ dvmHashTableLookup(gDvmJit.methodStatsTable,
+ hashValue,
+ &dummyMethodEntry,
+ (HashCompareFunc) compareMethod,
+ false);
/* This method has never been analyzed before - create an entry */
if (realMethodEntry == NULL) {
@@ -440,7 +441,7 @@ bool dvmCompileTrace(JitTraceDescription *desc, int numMaxInsts,
#endif
/* If we've already compiled this trace, just return success */
- if (dvmJitGetCodeAddr(startCodePtr) && !info->discardResult) {
+ if (dvmJitGetTraceAddr(startCodePtr) && !info->discardResult) {
/*
* Make sure the codeAddress is NULL so that it won't clobber the
* existing entry.
@@ -588,11 +589,12 @@ bool dvmCompileTrace(JitTraceDescription *desc, int numMaxInsts,
int flags = dexGetFlagsFromOpcode(insn->dalvikInsn.opcode);
if (flags & kInstrInvoke) {
+ const Method *calleeMethod = (const Method *) currRun[2].meta;
assert(numInsts == 1);
CallsiteInfo *callsiteInfo =
(CallsiteInfo *)dvmCompilerNew(sizeof(CallsiteInfo), true);
callsiteInfo->clazz = (ClassObject *)currRun[1].meta;
- callsiteInfo->method = (Method *)currRun[2].meta;
+ callsiteInfo->method = calleeMethod;
insn->meta.callsiteInfo = callsiteInfo;
}
@@ -870,7 +872,7 @@ bool dvmCompileTrace(JitTraceDescription *desc, int numMaxInsts,
/* Inline transformation @ the MIR level */
if (cUnit.hasInvoke && !(gDvmJit.disableOpt & (1 << kMethodInlining))) {
- dvmCompilerInlineMIR(&cUnit);
+ dvmCompilerInlineMIR(&cUnit, info);
}
cUnit.numDalvikRegisters = cUnit.method->registersSize;
@@ -921,6 +923,7 @@ bool dvmCompileTrace(JitTraceDescription *desc, int numMaxInsts,
} while (cUnit.assemblerStatus == kRetryAll);
if (cUnit.printMe) {
+ LOGD("Trace Dalvik PC: %p", startCodePtr);
dvmCompilerCodegenDump(&cUnit);
LOGD("End %s%s, %d Dalvik instructions",
desc->method->clazz->descriptor, desc->method->name,
@@ -941,14 +944,6 @@ bool dvmCompileTrace(JitTraceDescription *desc, int numMaxInsts,
methodStats->nativeSize += cUnit.totalSize;
#endif
- /* FIXME - to exercise the method parser, uncomment the following code */
-#if 0
- bool dvmCompileMethod(const Method *method);
- if (desc->trace[0].frag.startOffset == 0) {
- dvmCompileMethod(desc->method);
- }
-#endif
-
return info->codeAddress != NULL;
}
@@ -1671,7 +1666,7 @@ static void processCanThrow(CompilationUnit *cUnit, BasicBlock *curBlock,
* TODO: implementation will be revisited when the trace builder can provide
* whole-method traces.
*/
-bool dvmCompileMethod(const Method *method)
+bool dvmCompileMethod(const Method *method, JitTranslationInfo *info)
{
CompilationUnit cUnit;
const DexCode *dexCode = dvmGetMethodCode(method);
@@ -1680,12 +1675,27 @@ bool dvmCompileMethod(const Method *method)
int numBlocks = 0;
unsigned int curOffset = 0;
+ /* Method already compiled */
+ if (dvmJitGetMethodAddr(codePtr)) {
+ info->codeAddress = NULL;
+ return false;
+ }
+
memset(&cUnit, 0, sizeof(cUnit));
cUnit.method = method;
+ cUnit.methodJitMode = true;
+
/* Initialize the block list */
dvmInitGrowableList(&cUnit.blockList, 4);
+ /*
+ * FIXME - PC reconstruction list won't be needed after the codegen routines
+ * are enhanced to true method mode.
+ */
+ /* Initialize the PC reconstruction list */
+ dvmInitGrowableList(&cUnit.pcReconstructionList, 8);
+
/* Allocate the bit-vector to track the beginning of basic blocks */
BitVector *tryBlockAddr = dvmCompilerAllocBitVector(dexCode->insnsSize,
true /* expandable */);
@@ -1789,6 +1799,10 @@ bool dvmCompileMethod(const Method *method)
}
}
+ if (cUnit.printMe) {
+ dvmCompilerDumpCompilationUnit(&cUnit);
+ }
+
/* Adjust this value accordingly once inlining is performed */
cUnit.numDalvikRegisters = cUnit.method->registersSize;
@@ -1802,10 +1816,41 @@ bool dvmCompileMethod(const Method *method)
/* Perform SSA transformation for the whole method */
dvmCompilerMethodSSATransformation(&cUnit);
- if (cUnit.printMe) dumpCFG(&cUnit, "/data/tombstones/");
+ dvmCompilerInitializeRegAlloc(&cUnit); // Needs to happen after SSA naming
- /* Reset the compiler resource pool */
- dvmCompilerArenaReset();
+ /* Allocate Registers using simple local allocation scheme */
+ dvmCompilerLocalRegAlloc(&cUnit);
+
+ /* Convert MIR to LIR, etc. */
+ dvmCompilerMethodMIR2LIR(&cUnit);
+
+ // Debugging only
+ //dumpCFG(&cUnit, "/data/tombstones/");
+
+ /* Method is not empty */
+ if (cUnit.firstLIRInsn) {
+ /* Convert LIR into machine code. Loop for recoverable retries */
+ do {
+ dvmCompilerAssembleLIR(&cUnit, info);
+ cUnit.assemblerRetries++;
+ if (cUnit.printMe && cUnit.assemblerStatus != kSuccess)
+ LOGD("Assembler abort #%d on %d",cUnit.assemblerRetries,
+ cUnit.assemblerStatus);
+ } while (cUnit.assemblerStatus == kRetryAll);
+
+ if (cUnit.printMe) {
+ dvmCompilerCodegenDump(&cUnit);
+ }
+
+ if (info->codeAddress) {
+ dvmJitSetCodeAddr(dexCode->insns, info->codeAddress,
+ info->instructionSet, true, 0);
+ /*
+ * Clear the codeAddress for the enclosing trace to reuse the info
+ */
+ info->codeAddress = NULL;
+ }
+ }
return false;
}
diff --git a/vm/compiler/InlineTransformation.c b/vm/compiler/InlineTransformation.c
index cab790cac..6cf2d43be 100644
--- a/vm/compiler/InlineTransformation.c
+++ b/vm/compiler/InlineTransformation.c
@@ -34,7 +34,7 @@ static inline u4 convertRegId(const DecodedInstruction *invoke,
}
}
-static void inlineGetter(CompilationUnit *cUnit,
+static bool inlineGetter(CompilationUnit *cUnit,
const Method *calleeMethod,
MIR *invokeMIR,
BasicBlock *invokeBB,
@@ -49,7 +49,7 @@ static void inlineGetter(CompilationUnit *cUnit,
dexDecodeInstruction(calleeMethod->insns, &getterInsn);
if (!dvmCompilerCanIncludeThisInstruction(calleeMethod, &getterInsn))
- return;
+ return false;
/*
* Some getters (especially invoked through interface) are not followed
@@ -59,7 +59,7 @@ static void inlineGetter(CompilationUnit *cUnit,
(moveResultMIR->dalvikInsn.opcode != OP_MOVE_RESULT &&
moveResultMIR->dalvikInsn.opcode != OP_MOVE_RESULT_OBJECT &&
moveResultMIR->dalvikInsn.opcode != OP_MOVE_RESULT_WIDE)) {
- return;
+ return false;
}
int dfFlags = dvmCompilerDataFlowAttributes[getterInsn.opcode];
@@ -124,10 +124,10 @@ static void inlineGetter(CompilationUnit *cUnit,
#endif
}
- return;
+ return true;
}
-static void inlineSetter(CompilationUnit *cUnit,
+static bool inlineSetter(CompilationUnit *cUnit,
const Method *calleeMethod,
MIR *invokeMIR,
BasicBlock *invokeBB,
@@ -140,7 +140,7 @@ static void inlineSetter(CompilationUnit *cUnit,
dexDecodeInstruction(calleeMethod->insns, &setterInsn);
if (!dvmCompilerCanIncludeThisInstruction(calleeMethod, &setterInsn))
- return;
+ return false;
int dfFlags = dvmCompilerDataFlowAttributes[setterInsn.opcode];
@@ -205,17 +205,17 @@ static void inlineSetter(CompilationUnit *cUnit,
#endif
}
- return;
+ return true;
}
-static void tryInlineSingletonCallsite(CompilationUnit *cUnit,
+static bool tryInlineSingletonCallsite(CompilationUnit *cUnit,
const Method *calleeMethod,
MIR *invokeMIR,
BasicBlock *invokeBB,
bool isRange)
{
/* Not a Java method */
- if (dvmIsNativeMethod(calleeMethod)) return;
+ if (dvmIsNativeMethod(calleeMethod)) return false;
CompilerMethodStats *methodStats =
dvmCompilerAnalyzeMethodBody(calleeMethod, true);
@@ -229,19 +229,20 @@ static void tryInlineSingletonCallsite(CompilationUnit *cUnit,
* the PC reconstruction or chaining cell).
*/
invokeBB->needFallThroughBranch = true;
- return;
+ return true;
}
if (methodStats->attributes & METHOD_IS_GETTER) {
- inlineGetter(cUnit, calleeMethod, invokeMIR, invokeBB, false, isRange);
- return;
+ return inlineGetter(cUnit, calleeMethod, invokeMIR, invokeBB, false,
+ isRange);
} else if (methodStats->attributes & METHOD_IS_SETTER) {
- inlineSetter(cUnit, calleeMethod, invokeMIR, invokeBB, false, isRange);
- return;
+ return inlineSetter(cUnit, calleeMethod, invokeMIR, invokeBB, false,
+ isRange);
}
+ return false;
}
-static void inlineEmptyVirtualCallee(CompilationUnit *cUnit,
+static bool inlineEmptyVirtualCallee(CompilationUnit *cUnit,
const Method *calleeMethod,
MIR *invokeMIR,
BasicBlock *invokeBB)
@@ -252,37 +253,39 @@ static void inlineEmptyVirtualCallee(CompilationUnit *cUnit,
dvmCompilerInsertMIRAfter(invokeBB, invokeMIR, invokeMIRSlow);
invokeMIRSlow->OptimizationFlags |= MIR_INLINED_PRED;
+ return true;
}
-static void tryInlineVirtualCallsite(CompilationUnit *cUnit,
+static bool tryInlineVirtualCallsite(CompilationUnit *cUnit,
const Method *calleeMethod,
MIR *invokeMIR,
BasicBlock *invokeBB,
bool isRange)
{
/* Not a Java method */
- if (dvmIsNativeMethod(calleeMethod)) return;
+ if (dvmIsNativeMethod(calleeMethod)) return false;
CompilerMethodStats *methodStats =
dvmCompilerAnalyzeMethodBody(calleeMethod, true);
/* Empty callee - do nothing by checking the clazz pointer */
if (methodStats->attributes & METHOD_IS_EMPTY) {
- inlineEmptyVirtualCallee(cUnit, calleeMethod, invokeMIR, invokeBB);
- return;
+ return inlineEmptyVirtualCallee(cUnit, calleeMethod, invokeMIR,
+ invokeBB);
}
if (methodStats->attributes & METHOD_IS_GETTER) {
- inlineGetter(cUnit, calleeMethod, invokeMIR, invokeBB, true, isRange);
- return;
+ return inlineGetter(cUnit, calleeMethod, invokeMIR, invokeBB, true,
+ isRange);
} else if (methodStats->attributes & METHOD_IS_SETTER) {
- inlineSetter(cUnit, calleeMethod, invokeMIR, invokeBB, true, isRange);
- return;
+ return inlineSetter(cUnit, calleeMethod, invokeMIR, invokeBB, true,
+ isRange);
}
+ return false;
}
-void dvmCompilerInlineMIR(CompilationUnit *cUnit)
+void dvmCompilerInlineMIR(CompilationUnit *cUnit, JitTranslationInfo *info)
{
bool isRange = false;
GrowableListIterator iterator;
@@ -337,8 +340,30 @@ void dvmCompilerInlineMIR(CompilationUnit *cUnit)
}
if (calleeMethod) {
- tryInlineSingletonCallsite(cUnit, calleeMethod, lastMIRInsn, bb,
- isRange);
+ bool inlined = tryInlineSingletonCallsite(cUnit, calleeMethod,
+ lastMIRInsn, bb, isRange);
+ if (!inlined &&
+ !(gDvmJit.disableOpt & (1 << kMethodJit)) &&
+ !dvmIsNativeMethod(calleeMethod)) {
+ CompilerMethodStats *methodStats =
+ dvmCompilerAnalyzeMethodBody(calleeMethod, true);
+ if ((methodStats->attributes & METHOD_IS_LEAF) &&
+ !(methodStats->attributes & METHOD_CANNOT_COMPILE)) {
+ /* Callee has been previously compiled */
+ if (dvmJitGetMethodAddr(calleeMethod->insns)) {
+ lastMIRInsn->OptimizationFlags |= MIR_INVOKE_METHOD_JIT;
+ } else {
+ /* Compile the callee first */
+ dvmCompileMethod(calleeMethod, info);
+ if (dvmJitGetMethodAddr(calleeMethod->insns)) {
+ lastMIRInsn->OptimizationFlags |=
+ MIR_INVOKE_METHOD_JIT;
+ } else {
+ methodStats->attributes |= METHOD_CANNOT_COMPILE;
+ }
+ }
+ }
+ }
return;
}
@@ -360,8 +385,30 @@ void dvmCompilerInlineMIR(CompilationUnit *cUnit)
}
if (calleeMethod) {
- tryInlineVirtualCallsite(cUnit, calleeMethod, lastMIRInsn, bb,
- isRange);
+ bool inlined = tryInlineVirtualCallsite(cUnit, calleeMethod,
+ lastMIRInsn, bb, isRange);
+ if (!inlined &&
+ !(gDvmJit.disableOpt & (1 << kMethodJit)) &&
+ !dvmIsNativeMethod(calleeMethod)) {
+ CompilerMethodStats *methodStats =
+ dvmCompilerAnalyzeMethodBody(calleeMethod, true);
+ if ((methodStats->attributes & METHOD_IS_LEAF) &&
+ !(methodStats->attributes & METHOD_CANNOT_COMPILE)) {
+ /* Callee has been previously compiled */
+ if (dvmJitGetMethodAddr(calleeMethod->insns)) {
+ lastMIRInsn->OptimizationFlags |= MIR_INVOKE_METHOD_JIT;
+ } else {
+ /* Compile the callee first */
+ dvmCompileMethod(calleeMethod, info);
+ if (dvmJitGetMethodAddr(calleeMethod->insns)) {
+ lastMIRInsn->OptimizationFlags |=
+ MIR_INVOKE_METHOD_JIT;
+ } else {
+ methodStats->attributes |= METHOD_CANNOT_COMPILE;
+ }
+ }
+ }
+ }
return;
}
}
diff --git a/vm/compiler/MethodSSATransformation.c b/vm/compiler/MethodSSATransformation.c
index 60eea334a..eaee24ae4 100644
--- a/vm/compiler/MethodSSATransformation.c
+++ b/vm/compiler/MethodSSATransformation.c
@@ -29,8 +29,8 @@ static void recordDFSPreOrder(CompilationUnit *cUnit, BasicBlock *block)
/* Enqueue the block id */
dvmInsertGrowableList(&cUnit->dfsOrder, block->id);
- if (block->taken) recordDFSPreOrder(cUnit, block->taken);
if (block->fallThrough) recordDFSPreOrder(cUnit, block->fallThrough);
+ if (block->taken) recordDFSPreOrder(cUnit, block->taken);
if (block->successorBlockList.blockListType != kNotUsed) {
GrowableListIterator iterator;
dvmGrowableListIteratorInit(&block->successorBlockList.blocks,
@@ -185,13 +185,6 @@ static bool computeDominanceFrontier(CompilationUnit *cUnit, BasicBlock *bb)
}
}
}
- if (cUnit->printMe) {
- char blockName[BLOCK_NAME_LEN];
- dvmGetBlockName(bb, blockName);
- dvmDumpBlockBitVector(blockList, blockName, bb->domFrontier,
- cUnit->numBlocks);
- }
-
return true;
}
@@ -399,11 +392,11 @@ static void insertPhiNodes(CompilationUnit *cUnit)
int dalvikReg;
const GrowableList *blockList = &cUnit->blockList;
BitVector *phiBlocks =
- dvmCompilerAllocBitVector(cUnit->numDalvikRegisters, false);
+ dvmCompilerAllocBitVector(cUnit->numBlocks, false);
BitVector *tmpBlocks =
- dvmCompilerAllocBitVector(cUnit->numDalvikRegisters, false);
+ dvmCompilerAllocBitVector(cUnit->numBlocks, false);
BitVector *inputBlocks =
- dvmCompilerAllocBitVector(cUnit->numDalvikRegisters, false);
+ dvmCompilerAllocBitVector(cUnit->numBlocks, false);
cUnit->tempDalvikRegisterV =
dvmCompilerAllocBitVector(cUnit->numDalvikRegisters, false);
diff --git a/vm/compiler/codegen/CompilerCodegen.h b/vm/compiler/codegen/CompilerCodegen.h
index 70a2bbd64..9cd4847c0 100644
--- a/vm/compiler/codegen/CompilerCodegen.h
+++ b/vm/compiler/codegen/CompilerCodegen.h
@@ -28,6 +28,9 @@ bool dvmCompilerDoWork(CompilerWorkOrder *work);
/* Lower middle-level IR to low-level IR */
void dvmCompilerMIR2LIR(CompilationUnit *cUnit);
+/* Lower middle-level IR to low-level IR for the whole method */
+void dvmCompilerMethodMIR2LIR(CompilationUnit *cUnit);
+
/* Assemble LIR into machine code */
void dvmCompilerAssembleLIR(CompilationUnit *cUnit, JitTranslationInfo *info);
diff --git a/vm/compiler/codegen/Optimizer.h b/vm/compiler/codegen/Optimizer.h
index d42fe8738..2b05476c0 100644
--- a/vm/compiler/codegen/Optimizer.h
+++ b/vm/compiler/codegen/Optimizer.h
@@ -29,6 +29,7 @@ typedef enum optControlVector {
kTrackLiveTemps,
kSuppressLoads,
kMethodInlining,
+ kMethodJit,
} optControlVector;
/* Forward declarations */
diff --git a/vm/compiler/codegen/arm/ArchFactory.c b/vm/compiler/codegen/arm/ArchFactory.c
index 581ba395c..805a6fc48 100644
--- a/vm/compiler/codegen/arm/ArchFactory.c
+++ b/vm/compiler/codegen/arm/ArchFactory.c
@@ -32,7 +32,21 @@ static TGT_LIR *genRegImmCheck(CompilationUnit *cUnit,
TGT_LIR *pcrLabel)
{
TGT_LIR *branch = genCmpImmBranch(cUnit, cond, reg, checkValue);
- return genCheckCommon(cUnit, dOffset, branch, pcrLabel);
+ if (cUnit->methodJitMode) {
+ BasicBlock *bb = cUnit->curBlock;
+ if (bb->taken) {
+ ArmLIR *exceptionLabel = (ArmLIR *) cUnit->blockLabelList;
+ exceptionLabel += bb->taken->id;
+ branch->generic.target = (LIR *) exceptionLabel;
+ return exceptionLabel;
+ } else {
+ LOGE("Catch blocks not handled yet");
+ dvmAbort();
+ return NULL;
+ }
+ } else {
+ return genCheckCommon(cUnit, dOffset, branch, pcrLabel);
+ }
}
/*
diff --git a/vm/compiler/codegen/arm/ArchUtility.c b/vm/compiler/codegen/arm/ArchUtility.c
index 7a4d307b5..5af4f3b5c 100644
--- a/vm/compiler/codegen/arm/ArchUtility.c
+++ b/vm/compiler/codegen/arm/ArchUtility.c
@@ -195,9 +195,10 @@ static void buildInsnString(char *fmt, ArmLIR *lir, char* buf,
}
break;
case 't':
- sprintf(tbuf,"0x%08x",
+ sprintf(tbuf,"0x%08x (L%p)",
(int) baseAddr + lir->generic.offset + 4 +
- (operand << 1));
+ (operand << 1),
+ lir->generic.target);
break;
case 'u': {
int offset_1 = lir->operands[0];
@@ -302,8 +303,6 @@ void dvmDumpLIRInsn(LIR *arg, unsigned char *baseAddr)
case kArmPseudoSSARep:
DUMP_SSA_REP(LOGD("-------- %s\n", (char *) dest));
break;
- case kArmPseudoTargetLabel:
- break;
case kArmPseudoChainingCellBackwardBranch:
LOGD("-------- chaining cell (backward branch): 0x%04x\n", dest);
break;
@@ -344,8 +343,9 @@ void dvmDumpLIRInsn(LIR *arg, unsigned char *baseAddr)
case kArmPseudoEHBlockLabel:
LOGD("Exception_Handling:\n");
break;
+ case kArmPseudoTargetLabel:
case kArmPseudoNormalBlockLabel:
- LOGD("L%#06x:\n", dest);
+ LOGD("L%p:\n", lir);
break;
default:
if (lir->isNop && !dumpNop) {
diff --git a/vm/compiler/codegen/arm/Assemble.c b/vm/compiler/codegen/arm/Assemble.c
index 577f68320..efae8fd37 100644
--- a/vm/compiler/codegen/arm/Assemble.c
+++ b/vm/compiler/codegen/arm/Assemble.c
@@ -1032,6 +1032,17 @@ static AssemblerStatus assembleInstructions(CompilationUnit *cUnit,
lir->operands[0] = (delta >> 12) & 0x7ff;
NEXT_LIR(lir)->operands[0] = (delta>> 1) & 0x7ff;
+ } else if (lir->opcode == kThumbBl1) {
+ assert(NEXT_LIR(lir)->opcode == kThumbBl2);
+ /* Both curPC and target are Thumb */
+ intptr_t curPC = startAddr + lir->generic.offset + 4;
+ intptr_t target = lir->operands[1];
+
+ int delta = target - curPC;
+ assert((delta >= -(1<<22)) && (delta <= ((1<<22)-2)));
+
+ lir->operands[0] = (delta >> 12) & 0x7ff;
+ NEXT_LIR(lir)->operands[0] = (delta>> 1) & 0x7ff;
}
ArmEncodingMap *encoder = &EncodingMap[lir->opcode];
@@ -1213,8 +1224,8 @@ void dvmCompilerAssembleLIR(CompilationUnit *cUnit, JitTranslationInfo *info)
int i;
ChainCellCounts chainCellCounts;
int descSize =
- cUnit->wholeMethod ? 0 : jitTraceDescriptionSize(cUnit->traceDesc);
- int chainingCellGap;
+ cUnit->methodJitMode ? 0 : jitTraceDescriptionSize(cUnit->traceDesc);
+ int chainingCellGap = 0;
info->instructionSet = cUnit->instructionSet;
@@ -1240,30 +1251,34 @@ void dvmCompilerAssembleLIR(CompilationUnit *cUnit, JitTranslationInfo *info)
/* Const values have to be word aligned */
offset = (offset + 3) & ~3;
- /*
- * Get the gap (# of u4) between the offset of chaining cell count and
- * the bottom of real chaining cells. If the translation has chaining
- * cells, the gap is guaranteed to be multiples of 4.
- */
- chainingCellGap = (offset - cUnit->chainingCellBottom->offset) >> 2;
-
- /* Add space for chain cell counts & trace description */
u4 chainCellOffset = offset;
- ArmLIR *chainCellOffsetLIR = (ArmLIR *) cUnit->chainCellOffsetLIR;
- assert(chainCellOffsetLIR);
- assert(chainCellOffset < 0x10000);
- assert(chainCellOffsetLIR->opcode == kArm16BitData &&
- chainCellOffsetLIR->operands[0] == CHAIN_CELL_OFFSET_TAG);
+ ArmLIR *chainCellOffsetLIR = NULL;
- /*
- * Adjust the CHAIN_CELL_OFFSET_TAG LIR's offset to remove the
- * space occupied by the pointer to the trace profiling counter.
- */
- chainCellOffsetLIR->operands[0] = chainCellOffset - 4;
+ if (!cUnit->methodJitMode) {
+ /*
+ * Get the gap (# of u4) between the offset of chaining cell count and
+ * the bottom of real chaining cells. If the translation has chaining
+ * cells, the gap is guaranteed to be multiples of 4.
+ */
+ chainingCellGap = (offset - cUnit->chainingCellBottom->offset) >> 2;
+
+ /* Add space for chain cell counts & trace description */
+ chainCellOffsetLIR = (ArmLIR *) cUnit->chainCellOffsetLIR;
+ assert(chainCellOffsetLIR);
+ assert(chainCellOffset < 0x10000);
+ assert(chainCellOffsetLIR->opcode == kArm16BitData &&
+ chainCellOffsetLIR->operands[0] == CHAIN_CELL_OFFSET_TAG);
- offset += sizeof(chainCellCounts) + descSize;
+ /*
+ * Adjust the CHAIN_CELL_OFFSET_TAG LIR's offset to remove the
+ * space occupied by the pointer to the trace profiling counter.
+ */
+ chainCellOffsetLIR->operands[0] = chainCellOffset - 4;
- assert((offset & 0x3) == 0); /* Should still be word aligned */
+ offset += sizeof(chainCellCounts) + descSize;
+
+ assert((offset & 0x3) == 0); /* Should still be word aligned */
+ }
/* Set up offsets for literals */
cUnit->dataOffset = offset;
@@ -1301,8 +1316,10 @@ void dvmCompilerAssembleLIR(CompilationUnit *cUnit, JitTranslationInfo *info)
break;
case kRetryAll:
if (cUnit->assemblerRetries < MAX_ASSEMBLER_RETRIES) {
- /* Restore pristine chain cell marker on retry */
- chainCellOffsetLIR->operands[0] = CHAIN_CELL_OFFSET_TAG;
+ if (!cUnit->methodJitMode) {
+ /* Restore pristine chain cell marker on retry */
+ chainCellOffsetLIR->operands[0] = CHAIN_CELL_OFFSET_TAG;
+ }
return;
}
/* Too many retries - reset and try cutting the trace in half */
@@ -1351,20 +1368,23 @@ void dvmCompilerAssembleLIR(CompilationUnit *cUnit, JitTranslationInfo *info)
memcpy((char*)cUnit->baseAddr, cUnit->codeBuffer, chainCellOffset);
gDvmJit.numCompilations++;
- /* Install the chaining cell counts */
- for (i=0; i< kChainingCellGap; i++) {
- chainCellCounts.u.count[i] = cUnit->numChainingCells[i];
- }
+ if (!cUnit->methodJitMode) {
+ /* Install the chaining cell counts */
+ for (i=0; i< kChainingCellGap; i++) {
+ chainCellCounts.u.count[i] = cUnit->numChainingCells[i];
+ }
- /* Set the gap number in the chaining cell count structure */
- chainCellCounts.u.count[kChainingCellGap] = chainingCellGap;
+ /* Set the gap number in the chaining cell count structure */
+ chainCellCounts.u.count[kChainingCellGap] = chainingCellGap;
- memcpy((char*)cUnit->baseAddr + chainCellOffset, &chainCellCounts,
- sizeof(chainCellCounts));
+ memcpy((char*)cUnit->baseAddr + chainCellOffset, &chainCellCounts,
+ sizeof(chainCellCounts));
- /* Install the trace description */
- memcpy((char*)cUnit->baseAddr + chainCellOffset + sizeof(chainCellCounts),
- cUnit->traceDesc, descSize);
+ /* Install the trace description */
+ memcpy((char*) cUnit->baseAddr + chainCellOffset +
+ sizeof(chainCellCounts),
+ cUnit->traceDesc, descSize);
+ }
/* Write the literals directly into the code cache */
installDataContent(cUnit);
@@ -1609,7 +1629,7 @@ const Method *dvmJitToPatchPredictedChain(const Method *method,
PROTECT_CODE_CACHE(cell, sizeof(*cell));
goto done;
}
- int tgtAddr = (int) dvmJitGetCodeAddr(method->insns);
+ int tgtAddr = (int) dvmJitGetTraceAddr(method->insns);
/*
* Compilation not made yet for the callee. Reset the counter to a small
@@ -1808,14 +1828,16 @@ void dvmJitUnchainAll()
for (i = 0; i < gDvmJit.jitTableSize; i++) {
if (gDvmJit.pJitEntryTable[i].dPC &&
- gDvmJit.pJitEntryTable[i].codeAddress &&
- (gDvmJit.pJitEntryTable[i].codeAddress !=
- dvmCompilerGetInterpretTemplate())) {
+ !gDvmJit.pJitEntryTable[i].u.info.isMethodEntry &&
+ gDvmJit.pJitEntryTable[i].codeAddress &&
+ (gDvmJit.pJitEntryTable[i].codeAddress !=
+ dvmCompilerGetInterpretTemplate())) {
u4* lastAddress;
lastAddress =
dvmJitUnchain(gDvmJit.pJitEntryTable[i].codeAddress);
if (lowAddress == NULL ||
- (u4*)gDvmJit.pJitEntryTable[i].codeAddress < lowAddress)
+ (u4*)gDvmJit.pJitEntryTable[i].codeAddress <
+ lowAddress)
lowAddress = lastAddress;
if (lastAddress > highAddress)
highAddress = lastAddress;
diff --git a/vm/compiler/codegen/arm/CodegenDriver.c b/vm/compiler/codegen/arm/CodegenDriver.c
index f017b3168..8e1b09c60 100644
--- a/vm/compiler/codegen/arm/CodegenDriver.c
+++ b/vm/compiler/codegen/arm/CodegenDriver.c
@@ -904,24 +904,28 @@ static ArmLIR *genUnconditionalBranch(CompilationUnit *cUnit, ArmLIR *target)
/* Perform the actual operation for OP_RETURN_* */
static void genReturnCommon(CompilationUnit *cUnit, MIR *mir)
{
- genDispatchToHandler(cUnit, gDvmJit.methodTraceSupport ?
- TEMPLATE_RETURN_PROF :
- TEMPLATE_RETURN);
+ if (!cUnit->methodJitMode) {
+ genDispatchToHandler(cUnit, gDvmJit.methodTraceSupport ?
+ TEMPLATE_RETURN_PROF :
+ TEMPLATE_RETURN);
#if defined(WITH_JIT_TUNING)
- gDvmJit.returnOp++;
+ gDvmJit.returnOp++;
#endif
- int dPC = (int) (cUnit->method->insns + mir->offset);
- /* Insert branch, but defer setting of target */
- ArmLIR *branch = genUnconditionalBranch(cUnit, NULL);
- /* Set up the place holder to reconstruct this Dalvik PC */
- ArmLIR *pcrLabel = (ArmLIR *) dvmCompilerNew(sizeof(ArmLIR), true);
- pcrLabel->opcode = kArmPseudoPCReconstructionCell;
- pcrLabel->operands[0] = dPC;
- pcrLabel->operands[1] = mir->offset;
- /* Insert the place holder to the growable list */
- dvmInsertGrowableList(&cUnit->pcReconstructionList, (intptr_t) pcrLabel);
- /* Branch to the PC reconstruction code */
- branch->generic.target = (LIR *) pcrLabel;
+ int dPC = (int) (cUnit->method->insns + mir->offset);
+ /* Insert branch, but defer setting of target */
+ ArmLIR *branch = genUnconditionalBranch(cUnit, NULL);
+ /* Set up the place holder to reconstruct this Dalvik PC */
+ ArmLIR *pcrLabel = (ArmLIR *) dvmCompilerNew(sizeof(ArmLIR), true);
+ pcrLabel->opcode = kArmPseudoPCReconstructionCell;
+ pcrLabel->operands[0] = dPC;
+ pcrLabel->operands[1] = mir->offset;
+ /* Insert the place holder to the growable list */
+ dvmInsertGrowableList(&cUnit->pcReconstructionList,
+ (intptr_t) pcrLabel);
+ /* Branch to the PC reconstruction code */
+ branch->generic.target = (LIR *) pcrLabel;
+ }
+ /* TODO: Move result to InterpState for non-void returns */
}
static void genProcessArgsNoRange(CompilationUnit *cUnit, MIR *mir,
@@ -3197,6 +3201,25 @@ static bool handleFmt35c_3rc_5rc(CompilationUnit *cUnit, MIR *mir,
return false;
}
+/* "this" pointer is already in r0 */
+static void genValidationForMethodCallee(CompilationUnit *cUnit, MIR *mir,
+ ArmLIR **classCheck)
+{
+ CallsiteInfo *callsiteInfo = mir->meta.callsiteInfo;
+ dvmCompilerLockAllTemps(cUnit);
+
+ loadConstant(cUnit, r1, (int) callsiteInfo->clazz);
+
+ loadWordDisp(cUnit, r0, offsetof(Object, clazz), r2);
+ /* Branch to the slow path if classes are not equal */
+ opRegReg(cUnit, kOpCmp, r1, r2);
+ /*
+ * Set the misPredBranchOver target so that it will be generated when the
+ * code for the non-optimized invoke is generated.
+ */
+ *classCheck = opCondBranch(cUnit, kArmCondNe);
+}
+
static bool handleFmt35ms_3rms(CompilationUnit *cUnit, MIR *mir,
BasicBlock *bb, ArmLIR *labelList)
{
@@ -3229,6 +3252,29 @@ static bool handleFmt35ms_3rms(CompilationUnit *cUnit, MIR *mir,
else
genProcessArgsRange(cUnit, mir, dInsn, &pcrLabel);
+
+ if (mir->OptimizationFlags & MIR_INVOKE_METHOD_JIT) {
+ const Method *calleeMethod = mir->meta.callsiteInfo->method;
+ void *calleeAddr = dvmJitGetMethodAddr(calleeMethod->insns);
+ if (calleeAddr) {
+ ArmLIR *classCheck;
+ cUnit->printMe = true;
+ genValidationForMethodCallee(cUnit, mir, &classCheck);
+ newLIR2(cUnit, kThumbBl1, (int) calleeAddr,
+ (int) calleeAddr);
+ newLIR2(cUnit, kThumbBl2, (int) calleeAddr,
+ (int) calleeAddr);
+ genUnconditionalBranch(cUnit, retChainingCell);
+
+ /* Target of slow path */
+ ArmLIR *slowPathLabel = newLIR0(cUnit,
+ kArmPseudoTargetLabel);
+
+ slowPathLabel->defMask = ENCODE_ALL;
+ classCheck->generic.target = (LIR *) slowPathLabel;
+ }
+ }
+
genInvokeVirtualCommon(cUnit, mir, methodIndex,
retChainingCell,
predChainingCell,
diff --git a/vm/compiler/codegen/arm/armv5te-vfp/ArchVariant.c b/vm/compiler/codegen/arm/armv5te-vfp/ArchVariant.c
index f584ce72c..c857fa53b 100644
--- a/vm/compiler/codegen/arm/armv5te-vfp/ArchVariant.c
+++ b/vm/compiler/codegen/arm/armv5te-vfp/ArchVariant.c
@@ -79,6 +79,10 @@ bool dvmCompilerArchVariantInit(void)
LOGE("InterpState.jitToInterpEntries size overflow");
dvmAbort();
}
+
+ /* No method JIT for Thumb backend */
+ gDvmJit.disableOpt |= (1 << kMethodJit);
+
return true;
}
diff --git a/vm/compiler/codegen/arm/armv5te-vfp/Codegen.c b/vm/compiler/codegen/arm/armv5te-vfp/Codegen.c
index d17965d81..a2d77eadb 100644
--- a/vm/compiler/codegen/arm/armv5te-vfp/Codegen.c
+++ b/vm/compiler/codegen/arm/armv5te-vfp/Codegen.c
@@ -49,5 +49,8 @@
/* MIR2LIR dispatcher and architectural independent codegen routines */
#include "../CodegenDriver.c"
+/* Dummy driver for method-based JIT */
+#include "../armv5te/MethodCodegenDriver.c"
+
/* Architecture manifest */
#include "ArchVariant.c"
diff --git a/vm/compiler/codegen/arm/armv5te/ArchVariant.c b/vm/compiler/codegen/arm/armv5te/ArchVariant.c
index cf48d4ef8..0f16839ba 100644
--- a/vm/compiler/codegen/arm/armv5te/ArchVariant.c
+++ b/vm/compiler/codegen/arm/armv5te/ArchVariant.c
@@ -79,6 +79,10 @@ bool dvmCompilerArchVariantInit(void)
LOGE("InterpState.jitToInterpEntries size overflow");
dvmAbort();
}
+
+ /* No method JIT for Thumb backend */
+ gDvmJit.disableOpt |= (1 << kMethodJit);
+
return true;
}
diff --git a/vm/compiler/codegen/arm/armv5te/Codegen.c b/vm/compiler/codegen/arm/armv5te/Codegen.c
index 03c1435fe..f74d968ca 100644
--- a/vm/compiler/codegen/arm/armv5te/Codegen.c
+++ b/vm/compiler/codegen/arm/armv5te/Codegen.c
@@ -49,5 +49,8 @@
/* MIR2LIR dispatcher and architectural independent codegen routines */
#include "../CodegenDriver.c"
+/* Dummy driver for method-based JIT */
+#include "MethodCodegenDriver.c"
+
/* Architecture manifest */
#include "ArchVariant.c"
diff --git a/vm/compiler/codegen/arm/armv5te/MethodCodegenDriver.c b/vm/compiler/codegen/arm/armv5te/MethodCodegenDriver.c
new file mode 100644
index 000000000..20779f3e9
--- /dev/null
+++ b/vm/compiler/codegen/arm/armv5te/MethodCodegenDriver.c
@@ -0,0 +1,21 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+void dvmCompilerMethodMIR2LIR(CompilationUnit *cUnit)
+{
+ LOGE("Method-based JIT not supported for the v5te target");
+ dvmAbort();
+}
diff --git a/vm/compiler/codegen/arm/armv7-a-neon/ArchVariant.c b/vm/compiler/codegen/arm/armv7-a-neon/ArchVariant.c
index 7fcf031cb..3df1095c6 100644
--- a/vm/compiler/codegen/arm/armv7-a-neon/ArchVariant.c
+++ b/vm/compiler/codegen/arm/armv7-a-neon/ArchVariant.c
@@ -74,6 +74,10 @@ bool dvmCompilerArchVariantInit(void)
LOGE("InterpState.jitToInterpEntries size overflow");
dvmAbort();
}
+
+ /* FIXME - comment out the following to enable method-based JIT */
+ gDvmJit.disableOpt |= (1 << kMethodJit);
+
return true;
}
diff --git a/vm/compiler/codegen/arm/armv7-a-neon/Codegen.c b/vm/compiler/codegen/arm/armv7-a-neon/Codegen.c
index f0b772296..439add5ef 100644
--- a/vm/compiler/codegen/arm/armv7-a-neon/Codegen.c
+++ b/vm/compiler/codegen/arm/armv7-a-neon/Codegen.c
@@ -49,5 +49,8 @@
/* MIR2LIR dispatcher and architectural independent codegen routines */
#include "../CodegenDriver.c"
+/* Driver for method-based JIT */
+#include "MethodCodegenDriver.c"
+
/* Architecture manifest */
#include "ArchVariant.c"
diff --git a/vm/compiler/codegen/arm/armv7-a-neon/MethodCodegenDriver.c b/vm/compiler/codegen/arm/armv7-a-neon/MethodCodegenDriver.c
new file mode 100644
index 000000000..c25ab8346
--- /dev/null
+++ b/vm/compiler/codegen/arm/armv7-a-neon/MethodCodegenDriver.c
@@ -0,0 +1,227 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/* Handle the content in each basic block */
+static bool methodBlockCodeGen(CompilationUnit *cUnit, BasicBlock *bb)
+{
+ MIR *mir;
+ ArmLIR *labelList = (ArmLIR *) cUnit->blockLabelList;
+ int blockId = bb->id;
+
+ cUnit->curBlock = bb;
+ labelList[blockId].operands[0] = bb->startOffset;
+
+ /* Insert the block label */
+ labelList[blockId].opcode = kArmPseudoNormalBlockLabel;
+ dvmCompilerAppendLIR(cUnit, (LIR *) &labelList[blockId]);
+
+ dvmCompilerClobberAllRegs(cUnit);
+ dvmCompilerResetNullCheck(cUnit);
+
+ ArmLIR *headLIR = NULL;
+
+ if (bb->blockType == kMethodEntryBlock) {
+ opImm(cUnit, kOpPush, (1 << rlr | 1 << rFP));
+ opRegImm(cUnit, kOpSub, rFP,
+ sizeof(StackSaveArea) + cUnit->method->registersSize * 4);
+
+ } else if (bb->blockType == kMethodExitBlock) {
+ opImm(cUnit, kOpPop, (1 << rpc | 1 << rFP));
+ }
+
+ for (mir = bb->firstMIRInsn; mir; mir = mir->next) {
+
+ dvmCompilerResetRegPool(cUnit);
+ if (gDvmJit.disableOpt & (1 << kTrackLiveTemps)) {
+ dvmCompilerClobberAllRegs(cUnit);
+ }
+
+ if (gDvmJit.disableOpt & (1 << kSuppressLoads)) {
+ dvmCompilerResetDefTracking(cUnit);
+ }
+
+ Opcode dalvikOpcode = mir->dalvikInsn.opcode;
+ InstructionFormat dalvikFormat =
+ dexGetFormatFromOpcode(dalvikOpcode);
+
+ ArmLIR *boundaryLIR;
+
+ /*
+ * Don't generate the boundary LIR unless we are debugging this
+ * trace or we need a scheduling barrier.
+ */
+ if (headLIR == NULL || cUnit->printMe == true) {
+ boundaryLIR =
+ newLIR2(cUnit, kArmPseudoDalvikByteCodeBoundary,
+ mir->offset,
+ (int) dvmCompilerGetDalvikDisassembly(
+ &mir->dalvikInsn, ""));
+ /* Remember the first LIR for this block */
+ if (headLIR == NULL) {
+ headLIR = boundaryLIR;
+ /* Set the first boundaryLIR as a scheduling barrier */
+ headLIR->defMask = ENCODE_ALL;
+ }
+ }
+
+ /* Don't generate the SSA annotation unless verbose mode is on */
+ if (cUnit->printMe && mir->ssaRep) {
+ char *ssaString = dvmCompilerGetSSAString(cUnit, mir->ssaRep);
+ newLIR1(cUnit, kArmPseudoSSARep, (int) ssaString);
+ }
+
+ bool notHandled;
+ switch (dalvikFormat) {
+ case kFmt10t:
+ case kFmt20t:
+ case kFmt30t:
+ notHandled = handleFmt10t_Fmt20t_Fmt30t(cUnit,
+ mir, bb, labelList);
+ break;
+ case kFmt10x:
+ notHandled = handleFmt10x(cUnit, mir);
+ break;
+ case kFmt11n:
+ case kFmt31i:
+ notHandled = handleFmt11n_Fmt31i(cUnit, mir);
+ break;
+ case kFmt11x:
+ notHandled = handleFmt11x(cUnit, mir);
+ break;
+ case kFmt12x:
+ notHandled = handleFmt12x(cUnit, mir);
+ break;
+ case kFmt20bc:
+ case kFmt40sc:
+ notHandled = handleFmt20bc_Fmt40sc(cUnit, mir);
+ break;
+ case kFmt21c:
+ case kFmt31c:
+ case kFmt41c:
+ notHandled = handleFmt21c_Fmt31c_Fmt41c(cUnit, mir);
+ break;
+ case kFmt21h:
+ notHandled = handleFmt21h(cUnit, mir);
+ break;
+ case kFmt21s:
+ notHandled = handleFmt21s(cUnit, mir);
+ break;
+ case kFmt21t:
+ notHandled = handleFmt21t(cUnit, mir, bb, labelList);
+ break;
+ case kFmt22b:
+ case kFmt22s:
+ notHandled = handleFmt22b_Fmt22s(cUnit, mir);
+ break;
+ case kFmt22c:
+ case kFmt52c:
+ notHandled = handleFmt22c_Fmt52c(cUnit, mir);
+ break;
+ case kFmt22cs:
+ notHandled = handleFmt22cs(cUnit, mir);
+ break;
+ case kFmt22t:
+ notHandled = handleFmt22t(cUnit, mir, bb, labelList);
+ break;
+ case kFmt22x:
+ case kFmt32x:
+ notHandled = handleFmt22x_Fmt32x(cUnit, mir);
+ break;
+ case kFmt23x:
+ notHandled = handleFmt23x(cUnit, mir);
+ break;
+ case kFmt31t:
+ notHandled = handleFmt31t(cUnit, mir);
+ break;
+ case kFmt3rc:
+ case kFmt35c:
+ case kFmt5rc:
+ notHandled = handleFmt35c_3rc_5rc(cUnit, mir, bb,
+ labelList);
+ break;
+ case kFmt3rms:
+ case kFmt35ms:
+ notHandled = handleFmt35ms_3rms(cUnit, mir, bb,
+ labelList);
+ break;
+ case kFmt35mi:
+ case kFmt3rmi:
+ notHandled = handleExecuteInline(cUnit, mir);
+ break;
+ case kFmt51l:
+ notHandled = handleFmt51l(cUnit, mir);
+ break;
+ default:
+ notHandled = true;
+ break;
+ }
+
+ /* FIXME - to be implemented */
+ if (notHandled == true && dalvikOpcode >= kNumPackedOpcodes) {
+ notHandled = false;
+ }
+
+ if (notHandled) {
+ LOGE("%#06x: Opcode 0x%x (%s) / Fmt %d not handled\n",
+ mir->offset,
+ dalvikOpcode, dexGetOpcodeName(dalvikOpcode),
+ dalvikFormat);
+ dvmCompilerAbort(cUnit);
+ break;
+ }
+ }
+
+ if (headLIR) {
+ /*
+ * Eliminate redundant loads/stores and delay stores into later
+ * slots
+ */
+ dvmCompilerApplyLocalOptimizations(cUnit, (LIR *) headLIR,
+ cUnit->lastLIRInsn);
+
+ /*
+ * Generate an unconditional branch to the fallthrough block.
+ */
+ if (bb->fallThrough) {
+ genUnconditionalBranch(cUnit,
+ &labelList[bb->fallThrough->id]);
+ }
+ }
+ return false;
+}
+
+void dvmCompilerMethodMIR2LIR(CompilationUnit *cUnit)
+{
+ // FIXME - enable method compilation for selected routines here
+ if (strcmp(cUnit->method->name, "add")) return;
+
+ /* Used to hold the labels of each block */
+ cUnit->blockLabelList =
+ (void *) dvmCompilerNew(sizeof(ArmLIR) * cUnit->numBlocks, true);
+
+ dvmCompilerDataFlowAnalysisDispatcher(cUnit, methodBlockCodeGen,
+ kPreOrderDFSTraversal,
+ false /* isIterative */);
+
+ dvmCompilerApplyGlobalOptimizations(cUnit);
+
+ // FIXME - temporarily enable verbose printing for all methods
+ cUnit->printMe = true;
+
+#if defined(WITH_SELF_VERIFICATION)
+ selfVerificationBranchInsertPass(cUnit);
+#endif
+}
diff --git a/vm/compiler/codegen/arm/armv7-a/ArchVariant.c b/vm/compiler/codegen/arm/armv7-a/ArchVariant.c
index 7fcf031cb..3df1095c6 100644
--- a/vm/compiler/codegen/arm/armv7-a/ArchVariant.c
+++ b/vm/compiler/codegen/arm/armv7-a/ArchVariant.c
@@ -74,6 +74,10 @@ bool dvmCompilerArchVariantInit(void)
LOGE("InterpState.jitToInterpEntries size overflow");
dvmAbort();
}
+
+ /* FIXME - comment out the following to enable method-based JIT */
+ gDvmJit.disableOpt |= (1 << kMethodJit);
+
return true;
}
diff --git a/vm/compiler/codegen/arm/armv7-a/Codegen.c b/vm/compiler/codegen/arm/armv7-a/Codegen.c
index 05dda0c4d..36771ef56 100644
--- a/vm/compiler/codegen/arm/armv7-a/Codegen.c
+++ b/vm/compiler/codegen/arm/armv7-a/Codegen.c
@@ -49,5 +49,8 @@
/* MIR2LIR dispatcher and architectural independent codegen routines */
#include "../CodegenDriver.c"
+/* Driver for method-based JIT */
+#include "../armv7-a-neon/MethodCodegenDriver.c"
+
/* Architecture manifest */
#include "ArchVariant.c"