summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBen Cheng <bccheng@android.com>2010-06-07 13:44:23 -0700
committerBen Cheng <bccheng@android.com>2010-08-02 14:52:10 -0700
commit7a2697d327936e20ef5484f7819e2e4bf91c891f (patch)
tree1a98a82d12e5aecc3c7b790abfd9963c1583b4a8
parent7b11fa96c361bf029cb465a19b23134d85267430 (diff)
downloadandroid_dalvik-7a2697d327936e20ef5484f7819e2e4bf91c891f.tar.gz
android_dalvik-7a2697d327936e20ef5484f7819e2e4bf91c891f.tar.bz2
android_dalvik-7a2697d327936e20ef5484f7819e2e4bf91c891f.zip
Implement method inlining for getters/setters
Changes include: 1) Force the trace that ends with an invoke instruction to include the next instruction if it is a move-result (because both need to be turned into no-ops if callee is inlined). 2) Interpreter entry point/trace builder changes so that return target won't automatically be considered as trace starting points (to avoid duplicate traces that include the move result instructions). 3) Codegen changes to handle getters/setters invoked from both monomorphic and polymorphic callsites. 4) Extend/fix self-verification to form identical trace regions and handle traces with inlined callees. 5) Apply touchups to the method based parsing - still not in use. Change-Id: I116b934df01bf9ada6d5a25187510e352bccd13c
-rw-r--r--vm/Dvm.mk1
-rw-r--r--vm/Globals.h4
-rw-r--r--vm/Thread.h9
-rw-r--r--vm/compiler/Compiler.c10
-rw-r--r--vm/compiler/Compiler.h84
-rw-r--r--vm/compiler/CompilerIR.h32
-rw-r--r--vm/compiler/CompilerUtility.h1
-rw-r--r--vm/compiler/Dataflow.c130
-rw-r--r--vm/compiler/Dataflow.h5
-rw-r--r--vm/compiler/Frontend.c446
-rw-r--r--vm/compiler/InlineTransformation.c349
-rw-r--r--vm/compiler/IntermediateRep.c16
-rw-r--r--vm/compiler/Loop.c4
-rw-r--r--vm/compiler/Ralloc.c4
-rw-r--r--vm/compiler/Utility.c48
-rw-r--r--vm/compiler/codegen/Optimizer.h1
-rw-r--r--vm/compiler/codegen/arm/ArchUtility.c3
-rw-r--r--vm/compiler/codegen/arm/Assemble.c9
-rw-r--r--vm/compiler/codegen/arm/CodegenDriver.c286
-rw-r--r--vm/compiler/template/armv5te/TEMPLATE_RETURN.S2
-rw-r--r--vm/compiler/template/armv5te/footer.S2
-rw-r--r--vm/compiler/template/out/CompilerTemplateAsm-armv5te-vfp.S18
-rw-r--r--vm/compiler/template/out/CompilerTemplateAsm-armv5te.S23
-rw-r--r--vm/compiler/template/out/CompilerTemplateAsm-armv7-a-neon.S18
-rw-r--r--vm/compiler/template/out/CompilerTemplateAsm-armv7-a.S18
-rw-r--r--vm/interp/Interp.c8
-rw-r--r--vm/interp/Jit.c85
-rw-r--r--vm/interp/Jit.h6
-rw-r--r--vm/mterp/armv5te/entry.S23
-rw-r--r--vm/mterp/armv5te/footer.S52
-rw-r--r--vm/mterp/c/gotoTargets.c12
-rw-r--r--vm/mterp/common/asm-constants.h26
-rw-r--r--vm/mterp/out/InterpAsm-armv4t.S75
-rw-r--r--vm/mterp/out/InterpAsm-armv5te-vfp.S75
-rw-r--r--vm/mterp/out/InterpAsm-armv5te.S75
-rw-r--r--vm/mterp/out/InterpAsm-armv7-a-neon.S75
-rw-r--r--vm/mterp/out/InterpAsm-armv7-a.S75
-rw-r--r--vm/mterp/out/InterpC-allstubs.c12
-rw-r--r--vm/mterp/out/InterpC-portdbg.c26
-rw-r--r--vm/mterp/out/InterpC-portstd.c20
-rw-r--r--vm/mterp/out/InterpC-x86-atom.c12
-rw-r--r--vm/mterp/out/InterpC-x86.c12
-rw-r--r--vm/mterp/portable/entry.c8
-rw-r--r--vm/mterp/portable/portdbg.c6
44 files changed, 1813 insertions, 393 deletions
diff --git a/vm/Dvm.mk b/vm/Dvm.mk
index 862637519..c624258b7 100644
--- a/vm/Dvm.mk
+++ b/vm/Dvm.mk
@@ -220,6 +220,7 @@ ifeq ($(WITH_JIT),true)
compiler/Compiler.c \
compiler/Frontend.c \
compiler/Utility.c \
+ compiler/InlineTransformation.c \
compiler/IntermediateRep.c \
compiler/Dataflow.c \
compiler/Loop.c \
diff --git a/vm/Globals.h b/vm/Globals.h
index 7bed2e3df..5341d262a 100644
--- a/vm/Globals.h
+++ b/vm/Globals.h
@@ -840,6 +840,10 @@ struct DvmJitGlobals {
int invokeMonomorphic;
int invokePolymorphic;
int invokeNative;
+ int invokeMonoGetterInlined;
+ int invokeMonoSetterInlined;
+ int invokePolyGetterInlined;
+ int invokePolySetterInlined;
int returnOp;
int icPatchInit;
int icPatchLockFree;
diff --git a/vm/Thread.h b/vm/Thread.h
index f00b0dfac..204135a05 100644
--- a/vm/Thread.h
+++ b/vm/Thread.h
@@ -171,6 +171,10 @@ typedef struct Thread {
* matter)
*/
void* inJitCodeCache;
+#if defined(WITH_SELF_VERIFICATION)
+ /* Buffer for register state during self verification */
+ struct ShadowSpace* shadowSpace;
+#endif
#endif
/* JNI local reference tracking */
@@ -248,11 +252,6 @@ typedef struct Thread {
const u2* currentPc2;
#endif
-#if defined(WITH_SELF_VERIFICATION)
- /* Buffer for register state during self verification */
- struct ShadowSpace* shadowSpace;
-#endif
-
/* system thread state */
SystemThread* systemThread;
} Thread;
diff --git a/vm/compiler/Compiler.c b/vm/compiler/Compiler.c
index 2368daea7..2b0ad5236 100644
--- a/vm/compiler/Compiler.c
+++ b/vm/compiler/Compiler.c
@@ -95,6 +95,7 @@ bool dvmCompilerWorkEnqueue(const u2 *pc, WorkOrderKind kind, void* info)
newOrder->pc = pc;
newOrder->kind = kind;
newOrder->info = info;
+ newOrder->result.methodCompilationAborted = NULL;
newOrder->result.codeAddress = NULL;
newOrder->result.discardResult =
(kind == kWorkOrderTraceDebug) ? true : false;
@@ -351,9 +352,10 @@ bool compilerThreadStartup(void)
dvmLockMutex(&gDvmJit.compilerLock);
-#if defined(WITH_JIT_TUNING)
/* Track method-level compilation statistics */
gDvmJit.methodStatsTable = dvmHashTableCreate(32, NULL);
+
+#if defined(WITH_JIT_TUNING)
gDvm.verboseShutdown = true;
#endif
@@ -626,8 +628,10 @@ static void *compilerThreadStart(void *arg)
}
if (aborted || !compileOK) {
dvmCompilerArenaReset();
- work.result.codeAddress = dvmCompilerGetInterpretTemplate();
- } else if (!work.result.discardResult) {
+ } else if (!work.result.discardResult &&
+ work.result.codeAddress) {
+ /* Make sure that proper code addr is installed */
+ assert(work.result.codeAddress != NULL);
dvmJitSetCodeAddr(work.pc, work.result.codeAddress,
work.result.instructionSet);
}
diff --git a/vm/compiler/Compiler.h b/vm/compiler/Compiler.h
index dae46fc88..1d074f229 100644
--- a/vm/compiler/Compiler.h
+++ b/vm/compiler/Compiler.h
@@ -87,6 +87,7 @@ typedef struct JitTranslationInfo {
void *codeAddress;
JitInstructionSetType instructionSet;
bool discardResult; // Used for debugging divergence and IC patching
+ bool methodCompilationAborted; // Cannot compile the whole method
Thread *requestingThread; // For debugging purpose
} JitTranslationInfo;
@@ -141,8 +142,8 @@ typedef enum SelfVerificationState {
kSVSStart = 1, // Shadow space set up, running compiled code
kSVSPunt = 2, // Exiting compiled code by punting
kSVSSingleStep = 3, // Exiting compiled code by single stepping
- kSVSTraceSelectNoChain = 4,// Exiting compiled code by trace select no chain
- kSVSTraceSelect = 5, // Exiting compiled code by trace select
+ kSVSNoProfile = 4, // Exiting compiled code and don't collect profiles
+ kSVSTraceSelect = 5, // Exiting compiled code and compile the next pc
kSVSNormal = 6, // Exiting compiled code normally
kSVSNoChain = 7, // Exiting compiled code by no chain
kSVSBackwardBranch = 8, // Exiting compiled code with backward branch trace
@@ -158,21 +159,41 @@ typedef enum JitHint {
} jitHint;
/*
- * Element of a Jit trace description. Describes a contiguous
- * sequence of Dalvik byte codes, the last of which can be
- * associated with a hint.
- * Dalvik byte code
+ * Element of a Jit trace description. If the isCode bit is set, it describes
+ * a contiguous sequence of Dalvik byte codes.
*/
typedef struct {
- u2 startOffset; // Starting offset for trace run
+ unsigned isCode:1; // If set denotes code fragments
unsigned numInsts:8; // Number of Byte codes in run
unsigned runEnd:1; // Run ends with last byte code
- jitHint hint:7; // Hint to apply to final code of run
+ jitHint hint:6; // Hint to apply to final code of run
+ u2 startOffset; // Starting offset for trace run
} JitCodeDesc;
+/*
+ * A complete list of trace runs passed to the compiler looks like the
+ * following:
+ * frag1
+ * frag2
+ * frag3
+ * meta1
+ * meta2
+ * frag4
+ *
+ * frags 1-4 have the "isCode" field set, and metas 1-2 are plain pointers or
+ * pointers to auxiliary data structures as long as the LSB is null.
+ * The meaning of the meta content is loosely defined. It is usually the code
+ * fragment right before the first meta field (frag3 in this case) to
+ * understand and parse them. Frag4 could be a dummy one with 0 "numInsts" but
+ * the "runEnd" field set.
+ *
+ * For example, if a trace run contains a method inlining target, the class
+ * type of "this" and the currently resolved method pointer are two instances
+ * of meta information stored there.
+ */
typedef union {
JitCodeDesc frag;
- void* hint;
+ void* meta;
} JitTraceRun;
/*
@@ -183,16 +204,42 @@ typedef union {
*/
typedef struct {
const Method* method;
- JitTraceRun trace[];
+ JitTraceRun trace[0]; // Variable-length trace descriptors
} JitTraceDescription;
+typedef enum JitMethodAttributes {
+ kIsCallee = 0, /* Code is part of a callee (invoked by a hot trace) */
+ kIsHot, /* Code is part of a hot trace */
+ kIsLeaf, /* Method is leaf */
+ kIsEmpty, /* Method is empty */
+ kIsThrowFree, /* Method doesn't throw */
+ kIsGetter, /* Method fits the getter pattern */
+ kIsSetter, /* Method fits the setter pattern */
+} JitMethodAttributes;
+
+#define METHOD_IS_CALLEE (1 << kIsCallee)
+#define METHOD_IS_HOT (1 << kIsHot)
+#define METHOD_IS_LEAF (1 << kIsLeaf)
+#define METHOD_IS_EMPTY (1 << kIsEmpty)
+#define METHOD_IS_THROW_FREE (1 << kIsThrowFree)
+#define METHOD_IS_GETTER (1 << kIsGetter)
+#define METHOD_IS_SETTER (1 << kIsSetter)
+
typedef struct CompilerMethodStats {
const Method *method; // Used as hash entry signature
int dalvikSize; // # of bytes for dalvik bytecodes
int compiledDalvikSize; // # of compiled dalvik bytecodes
int nativeSize; // # of bytes for produced native code
+ int attributes; // attribute vector
} CompilerMethodStats;
+struct CompilationUnit;
+struct BasicBlock;
+struct SSARepresentation;
+struct GrowableList;
+struct JitEntry;
+struct MIR;
+
bool dvmCompilerSetupCodeCache(void);
bool dvmCompilerArchInit(void);
void dvmCompilerArchDump(void);
@@ -200,7 +247,12 @@ bool dvmCompilerStartup(void);
void dvmCompilerShutdown(void);
bool dvmCompilerWorkEnqueue(const u2* pc, WorkOrderKind kind, void* info);
void *dvmCheckCodeCache(void *method);
-bool dvmCompileMethod(const Method *method, JitTranslationInfo *info);
+CompilerMethodStats *dvmCompilerAnalyzeMethodBody(const Method *method,
+ bool isCallee);
+bool dvmCompilerCanIncludeThisInstruction(const Method *method,
+ const DecodedInstruction *insn);
+bool dvmCompileMethod(struct CompilationUnit *cUnit, const Method *method,
+ JitTranslationInfo *info);
bool dvmCompileTrace(JitTraceDescription *trace, int numMaxInsts,
JitTranslationInfo *info, jmp_buf *bailPtr);
void dvmCompilerDumpStats(void);
@@ -208,13 +260,7 @@ void dvmCompilerDrainQueue(void);
void dvmJitUnchainAll(void);
void dvmCompilerSortAndPrintTraceProfiles(void);
void dvmCompilerPerformSafePointChecks(void);
-
-struct CompilationUnit;
-struct BasicBlock;
-struct SSARepresentation;
-struct GrowableList;
-struct JitEntry;
-
+void dvmCompilerInlineMIR(struct CompilationUnit *cUnit);
void dvmInitializeSSAConversion(struct CompilationUnit *cUnit);
int dvmConvertSSARegToDalvik(struct CompilationUnit *cUnit, int ssaReg);
void dvmCompilerLoopOpt(struct CompilationUnit *cUnit);
@@ -227,7 +273,7 @@ void dvmCompilerDoConstantPropagation(struct CompilationUnit *cUnit,
struct BasicBlock *bb);
void dvmCompilerFindInductionVariables(struct CompilationUnit *cUnit,
struct BasicBlock *bb);
-char *dvmCompilerGetDalvikDisassembly(DecodedInstruction *insn);
+char *dvmCompilerGetDalvikDisassembly(DecodedInstruction *insn, char *note);
char *dvmCompilerGetSSAString(struct CompilationUnit *cUnit,
struct SSARepresentation *ssaRep);
void dvmCompilerDataFlowAnalysisDispatcher(struct CompilationUnit *cUnit,
diff --git a/vm/compiler/CompilerIR.h b/vm/compiler/CompilerIR.h
index 2bf243d6e..21aadec3a 100644
--- a/vm/compiler/CompilerIR.h
+++ b/vm/compiler/CompilerIR.h
@@ -54,9 +54,11 @@ typedef enum BBType {
kChainingCellGap,
/* Don't insert new fields between Gap and Last */
kChainingCellLast = kChainingCellGap + 1,
- kEntryBlock,
+ kMethodEntryBlock,
+ kTraceEntryBlock,
kDalvikByteCode,
- kExitBlock,
+ kTraceExitBlock,
+ kMethodExitBlock,
kPCReconstruction,
kExceptionHandling,
} BBType;
@@ -82,6 +84,7 @@ enum ExtendedMIROpcode {
kMirOpNullNRangeDownCheck,
kMirOpLowerBound,
kMirOpPunt,
+ kMirOpCheckInlinePrediction, // Gen checks for predicted inlining
kMirOpLast,
};
@@ -92,12 +95,24 @@ typedef enum {
kMIRNullCheckOnly,
kMIRIgnoreRangeCheck,
kMIRRangeCheckOnly,
+ kMIRInlined, // Invoke is inlined (ie dead)
+ kMIRInlinedPred, // Invoke is inlined via prediction
+ kMIRCallee, // Instruction is inlined from callee
} MIROptimizationFlagPositons;
#define MIR_IGNORE_NULL_CHECK (1 << kMIRIgnoreNullCheck)
#define MIR_NULL_CHECK_ONLY (1 << kMIRNullCheckOnly)
#define MIR_IGNORE_RANGE_CHECK (1 << kMIRIgnoreRangeCheck)
#define MIR_RANGE_CHECK_ONLY (1 << kMIRRangeCheckOnly)
+#define MIR_INLINED (1 << kMIRInlined)
+#define MIR_INLINED_PRED (1 << kMIRInlinedPred)
+#define MIR_CALLEE (1 << kMIRCallee)
+
+typedef struct CallsiteInfo {
+ const ClassObject *clazz;
+ const Method *method;
+ LIR *misPredBranchOver;
+} CallsiteInfo;
typedef struct MIR {
DecodedInstruction dalvikInsn;
@@ -108,6 +123,12 @@ typedef struct MIR {
struct SSARepresentation *ssaRep;
int OptimizationFlags;
int seqNum;
+ union {
+ // Used by the inlined insn from the callee to find the mother method
+ const Method *calleeMethod;
+ // Used by the inlined invoke to find the class and method pointers
+ CallsiteInfo *callsiteInfo;
+ } meta;
} MIR;
struct BasicBlockDataFlow;
@@ -119,6 +140,7 @@ typedef struct BasicBlock {
const Method *containingMethod; // For blocks from the callee
BBType blockType;
bool needFallThroughBranch; // For blocks ended due to length limit
+ bool isFallThroughFromInvoke; // True means the block needs alignment
MIR *firstMIRInsn;
MIR *lastMIRInsn;
struct BasicBlock *fallThrough;
@@ -150,8 +172,10 @@ typedef struct CompilationUnit {
bool allSingleStep;
bool halveInstCount;
bool executionCount; // Add code to count trace executions
- bool hasLoop;
+ bool hasLoop; // Contains a loop
+ bool hasInvoke; // Contains an invoke instruction
bool heapMemOp; // Mark mem ops for self verification
+ bool wholeMethod;
int numChainingCells[kChainingCellGap];
LIR *firstChainingLIR[kChainingCellGap];
LIR *chainingCellBottom;
@@ -196,6 +220,8 @@ void dvmCompilerAppendMIR(BasicBlock *bb, MIR *mir);
void dvmCompilerPrependMIR(BasicBlock *bb, MIR *mir);
+void dvmCompilerInsertMIRAfter(BasicBlock *bb, MIR *currentMIR, MIR *newMIR);
+
void dvmCompilerAppendLIR(CompilationUnit *cUnit, LIR *lir);
void dvmCompilerInsertLIRBefore(LIR *currentLIR, LIR *newLIR);
diff --git a/vm/compiler/CompilerUtility.h b/vm/compiler/CompilerUtility.h
index 8bb5b4bbe..551edb8ab 100644
--- a/vm/compiler/CompilerUtility.h
+++ b/vm/compiler/CompilerUtility.h
@@ -26,6 +26,7 @@
bool dvmCompilerHeapInit(void);
typedef struct ArenaMemBlock {
+ size_t blockSize;
size_t bytesAllocated;
struct ArenaMemBlock *next;
char ptr[0];
diff --git a/vm/compiler/Dataflow.c b/vm/compiler/Dataflow.c
index e68e174d0..89c5b354e 100644
--- a/vm/compiler/Dataflow.c
+++ b/vm/compiler/Dataflow.c
@@ -234,130 +234,130 @@ int dvmCompilerDataFlowAttributes[kMirOpLast] = {
DF_NOP,
// 44 OP_AGET vAA, vBB, vCC
- DF_DA | DF_UB | DF_UC | DF_NULL_N_RANGE_CHECK_0,
+ DF_DA | DF_UB | DF_UC | DF_NULL_N_RANGE_CHECK_0 | DF_IS_GETTER,
// 45 OP_AGET_WIDE vAA, vBB, vCC
- DF_DA_WIDE | DF_UB | DF_UC | DF_NULL_N_RANGE_CHECK_0,
+ DF_DA_WIDE | DF_UB | DF_UC | DF_NULL_N_RANGE_CHECK_0 | DF_IS_GETTER,
// 46 OP_AGET_OBJECT vAA, vBB, vCC
- DF_DA | DF_UB | DF_UC | DF_NULL_N_RANGE_CHECK_0,
+ DF_DA | DF_UB | DF_UC | DF_NULL_N_RANGE_CHECK_0 | DF_IS_GETTER,
// 47 OP_AGET_BOOLEAN vAA, vBB, vCC
- DF_DA | DF_UB | DF_UC | DF_NULL_N_RANGE_CHECK_0,
+ DF_DA | DF_UB | DF_UC | DF_NULL_N_RANGE_CHECK_0 | DF_IS_GETTER,
// 48 OP_AGET_BYTE vAA, vBB, vCC
- DF_DA | DF_UB | DF_UC | DF_NULL_N_RANGE_CHECK_0,
+ DF_DA | DF_UB | DF_UC | DF_NULL_N_RANGE_CHECK_0 | DF_IS_GETTER,
// 49 OP_AGET_CHAR vAA, vBB, vCC
- DF_DA | DF_UB | DF_UC | DF_NULL_N_RANGE_CHECK_0,
+ DF_DA | DF_UB | DF_UC | DF_NULL_N_RANGE_CHECK_0 | DF_IS_GETTER,
// 4A OP_AGET_SHORT vAA, vBB, vCC
- DF_DA | DF_UB | DF_UC | DF_NULL_N_RANGE_CHECK_0,
+ DF_DA | DF_UB | DF_UC | DF_NULL_N_RANGE_CHECK_0 | DF_IS_GETTER,
// 4B OP_APUT vAA, vBB, vCC
- DF_UA | DF_UB | DF_UC | DF_NULL_N_RANGE_CHECK_1,
+ DF_UA | DF_UB | DF_UC | DF_NULL_N_RANGE_CHECK_1 | DF_IS_SETTER,
// 4C OP_APUT_WIDE vAA, vBB, vCC
- DF_UA_WIDE | DF_UB | DF_UC | DF_NULL_N_RANGE_CHECK_2,
+ DF_UA_WIDE | DF_UB | DF_UC | DF_NULL_N_RANGE_CHECK_2 | DF_IS_SETTER,
// 4D OP_APUT_OBJECT vAA, vBB, vCC
- DF_UA | DF_UB | DF_UC | DF_NULL_N_RANGE_CHECK_1,
+ DF_UA | DF_UB | DF_UC | DF_NULL_N_RANGE_CHECK_1 | DF_IS_SETTER,
// 4E OP_APUT_BOOLEAN vAA, vBB, vCC
- DF_UA | DF_UB | DF_UC | DF_NULL_N_RANGE_CHECK_1,
+ DF_UA | DF_UB | DF_UC | DF_NULL_N_RANGE_CHECK_1 | DF_IS_SETTER,
// 4F OP_APUT_BYTE vAA, vBB, vCC
- DF_UA | DF_UB | DF_UC | DF_NULL_N_RANGE_CHECK_1,
+ DF_UA | DF_UB | DF_UC | DF_NULL_N_RANGE_CHECK_1 | DF_IS_SETTER,
// 50 OP_APUT_CHAR vAA, vBB, vCC
- DF_UA | DF_UB | DF_UC | DF_NULL_N_RANGE_CHECK_1,
+ DF_UA | DF_UB | DF_UC | DF_NULL_N_RANGE_CHECK_1 | DF_IS_SETTER,
// 51 OP_APUT_SHORT vAA, vBB, vCC
- DF_UA | DF_UB | DF_UC | DF_NULL_N_RANGE_CHECK_1,
+ DF_UA | DF_UB | DF_UC | DF_NULL_N_RANGE_CHECK_1 | DF_IS_SETTER,
// 52 OP_IGET vA, vB, field@CCCC
- DF_DA | DF_UB,
+ DF_DA | DF_UB | DF_IS_GETTER,
// 53 OP_IGET_WIDE vA, vB, field@CCCC
- DF_DA_WIDE | DF_UB,
+ DF_DA_WIDE | DF_UB | DF_IS_GETTER,
// 54 OP_IGET_OBJECT vA, vB, field@CCCC
- DF_DA | DF_UB,
+ DF_DA | DF_UB | DF_IS_GETTER,
// 55 OP_IGET_BOOLEAN vA, vB, field@CCCC
- DF_DA | DF_UB,
+ DF_DA | DF_UB | DF_IS_GETTER,
// 56 OP_IGET_BYTE vA, vB, field@CCCC
- DF_DA | DF_UB,
+ DF_DA | DF_UB | DF_IS_GETTER,
// 57 OP_IGET_CHAR vA, vB, field@CCCC
- DF_DA | DF_UB,
+ DF_DA | DF_UB | DF_IS_GETTER,
// 58 OP_IGET_SHORT vA, vB, field@CCCC
- DF_DA | DF_UB,
+ DF_DA | DF_UB | DF_IS_GETTER,
// 59 OP_IPUT vA, vB, field@CCCC
- DF_UA | DF_UB,
+ DF_UA | DF_UB | DF_IS_SETTER,
// 5A OP_IPUT_WIDE vA, vB, field@CCCC
- DF_UA_WIDE | DF_UB,
+ DF_UA_WIDE | DF_UB | DF_IS_SETTER,
// 5B OP_IPUT_OBJECT vA, vB, field@CCCC
- DF_UA | DF_UB,
+ DF_UA | DF_UB | DF_IS_SETTER,
// 5C OP_IPUT_BOOLEAN vA, vB, field@CCCC
- DF_UA | DF_UB,
+ DF_UA | DF_UB | DF_IS_SETTER,
// 5D OP_IPUT_BYTE vA, vB, field@CCCC
- DF_UA | DF_UB,
+ DF_UA | DF_UB | DF_IS_SETTER,
// 5E OP_IPUT_CHAR vA, vB, field@CCCC
- DF_UA | DF_UB,
+ DF_UA | DF_UB | DF_IS_SETTER,
// 5F OP_IPUT_SHORT vA, vB, field@CCCC
- DF_UA | DF_UB,
+ DF_UA | DF_UB | DF_IS_SETTER,
// 60 OP_SGET vAA, field@BBBB
- DF_DA,
+ DF_DA | DF_IS_GETTER,
// 61 OP_SGET_WIDE vAA, field@BBBB
- DF_DA_WIDE,
+ DF_DA_WIDE | DF_IS_GETTER,
// 62 OP_SGET_OBJECT vAA, field@BBBB
- DF_DA,
+ DF_DA | DF_IS_GETTER,
// 63 OP_SGET_BOOLEAN vAA, field@BBBB
- DF_DA,
+ DF_DA | DF_IS_GETTER,
// 64 OP_SGET_BYTE vAA, field@BBBB
- DF_DA,
+ DF_DA | DF_IS_GETTER,
// 65 OP_SGET_CHAR vAA, field@BBBB
- DF_DA,
+ DF_DA | DF_IS_GETTER,
// 66 OP_SGET_SHORT vAA, field@BBBB
- DF_DA,
+ DF_DA | DF_IS_GETTER,
// 67 OP_SPUT vAA, field@BBBB
- DF_UA,
+ DF_UA | DF_IS_SETTER,
// 68 OP_SPUT_WIDE vAA, field@BBBB
- DF_UA_WIDE,
+ DF_UA_WIDE | DF_IS_SETTER,
// 69 OP_SPUT_OBJECT vAA, field@BBBB
- DF_UA,
+ DF_UA | DF_IS_SETTER,
// 6A OP_SPUT_BOOLEAN vAA, field@BBBB
- DF_UA,
+ DF_UA | DF_IS_SETTER,
// 6B OP_SPUT_BYTE vAA, field@BBBB
- DF_UA,
+ DF_UA | DF_IS_SETTER,
// 6C OP_SPUT_CHAR vAA, field@BBBB
- DF_UA,
+ DF_UA | DF_IS_SETTER,
// 6D OP_SPUT_SHORT vAA, field@BBBB
- DF_UA,
+ DF_UA | DF_IS_SETTER,
// 6E OP_INVOKE_VIRTUAL {vD, vE, vF, vG, vA}
DF_FORMAT_35C,
@@ -756,22 +756,22 @@ int dvmCompilerDataFlowAttributes[kMirOpLast] = {
DF_NOP,
// F2 OP_IGET_QUICK
- DF_DA | DF_UB,
+ DF_DA | DF_UB | DF_IS_GETTER,
// F3 OP_IGET_WIDE_QUICK
- DF_DA_WIDE | DF_UB,
+ DF_DA_WIDE | DF_UB | DF_IS_GETTER,
// F4 OP_IGET_OBJECT_QUICK
- DF_DA | DF_UB,
+ DF_DA | DF_UB | DF_IS_GETTER,
// F5 OP_IPUT_QUICK
- DF_UA | DF_UB,
+ DF_UA | DF_UB | DF_IS_SETTER,
// F6 OP_IPUT_WIDE_QUICK
- DF_UA_WIDE | DF_UB,
+ DF_UA_WIDE | DF_UB | DF_IS_SETTER,
// F7 OP_IPUT_OBJECT_QUICK
- DF_UA | DF_UB,
+ DF_UA | DF_UB | DF_IS_SETTER,
// F8 OP_INVOKE_VIRTUAL_QUICK
DF_FORMAT_35C,
@@ -818,7 +818,8 @@ int dvmConvertSSARegToDalvik(CompilationUnit *cUnit, int ssaReg)
* and subscript pair. Each SSA register can be used to index the
* ssaToDalvikMap list to get the subscript[31..16]/dalvik_reg[15..0] mapping.
*/
-char *dvmCompilerGetDalvikDisassembly(DecodedInstruction *insn)
+char *dvmCompilerGetDalvikDisassembly(DecodedInstruction *insn,
+ char *note)
{
char buffer[256];
int opcode = insn->opCode;
@@ -828,36 +829,35 @@ char *dvmCompilerGetDalvikDisassembly(DecodedInstruction *insn)
buffer[0] = 0;
strcpy(buffer, dexGetOpcodeName(opcode));
+ if (note)
+ strcat(buffer, note);
+
if (dfAttributes & DF_FORMAT_35C) {
unsigned int i;
for (i = 0; i < insn->vA; i++) {
if (i != 0) strcat(buffer, ",");
- sprintf(buffer + strlen(buffer), " v%d", insn->arg[i]);
+ snprintf(buffer + strlen(buffer), 256, " v%d", insn->arg[i]);
}
}
else if (dfAttributes & DF_FORMAT_3RC) {
- sprintf(buffer + strlen(buffer),
- " v%d..v%d", insn->vC, insn->vC + insn->vA - 1);
+ snprintf(buffer + strlen(buffer), 256,
+ " v%d..v%d", insn->vC, insn->vC + insn->vA - 1);
}
else {
if (dfAttributes & DF_A_IS_REG) {
- sprintf(buffer + strlen(buffer), " v%d", insn->vA);
+ snprintf(buffer + strlen(buffer), 256, " v%d", insn->vA);
}
if (dfAttributes & DF_B_IS_REG) {
- sprintf(buffer + strlen(buffer),
- ", v%d", insn->vB);
+ snprintf(buffer + strlen(buffer), 256, ", v%d", insn->vB);
}
else {
- sprintf(buffer + strlen(buffer),
- ", (#%d)", insn->vB);
+ snprintf(buffer + strlen(buffer), 256, ", (#%d)", insn->vB);
}
if (dfAttributes & DF_C_IS_REG) {
- sprintf(buffer + strlen(buffer),
- ", v%d", insn->vC);
+ snprintf(buffer + strlen(buffer), 256, ", v%d", insn->vC);
}
else {
- sprintf(buffer + strlen(buffer),
- ", (#%d)", insn->vC);
+ snprintf(buffer + strlen(buffer), 256, ", (#%d)", insn->vC);
}
}
int length = strlen(buffer) + 1;
@@ -934,7 +934,7 @@ void dvmCompilerFindLiveIn(CompilationUnit *cUnit, BasicBlock *bb)
BitVector *useV, *defV, *liveInV;
if (bb->blockType != kDalvikByteCode &&
- bb->blockType != kEntryBlock) {
+ bb->blockType != kTraceEntryBlock) {
return;
}
@@ -1041,7 +1041,7 @@ void dvmCompilerDoSSAConversion(CompilationUnit *cUnit, BasicBlock *bb)
{
MIR *mir;
- if (bb->blockType != kDalvikByteCode && bb->blockType != kEntryBlock) {
+ if (bb->blockType != kDalvikByteCode && bb->blockType != kTraceEntryBlock) {
return;
}
@@ -1240,7 +1240,7 @@ void dvmCompilerFindInductionVariables(struct CompilationUnit *cUnit,
MIR *mir;
if (bb->blockType != kDalvikByteCode &&
- bb->blockType != kEntryBlock) {
+ bb->blockType != kTraceEntryBlock) {
return;
}
@@ -1436,7 +1436,7 @@ void dvmInitializeSSAConversion(CompilationUnit *cUnit)
for (i = 0; i < cUnit->numBlocks; i++) {
BasicBlock *bb = cUnit->blockList[i];
if (bb->blockType == kDalvikByteCode ||
- bb->blockType == kEntryBlock) {
+ bb->blockType == kTraceEntryBlock) {
bb->dataFlowInfo = dvmCompilerNew(sizeof(BasicBlockDataFlow), true);
}
}
diff --git a/vm/compiler/Dataflow.h b/vm/compiler/Dataflow.h
index 72c8b256c..f3d39840d 100644
--- a/vm/compiler/Dataflow.h
+++ b/vm/compiler/Dataflow.h
@@ -41,6 +41,8 @@ typedef enum DataFlowAttributePos {
kFPA,
kFPB,
kFPC,
+ kGetter,
+ kSetter,
} DataFlowAttributes;
#define DF_NOP 0
@@ -64,6 +66,8 @@ typedef enum DataFlowAttributePos {
#define DF_FP_A (1 << kFPA)
#define DF_FP_B (1 << kFPB)
#define DF_FP_C (1 << kFPC)
+#define DF_IS_GETTER (1 << kGetter)
+#define DF_IS_SETTER (1 << kSetter)
#define DF_HAS_USES (DF_UA | DF_UB | DF_UC | DF_UA_WIDE | \
DF_UB_WIDE | DF_UC_WIDE)
@@ -77,6 +81,7 @@ typedef enum DataFlowAttributePos {
#define DF_A_IS_REG (DF_UA | DF_UA_WIDE | DF_DA | DF_DA_WIDE)
#define DF_B_IS_REG (DF_UB | DF_UB_WIDE)
#define DF_C_IS_REG (DF_UC | DF_UC_WIDE)
+#define DF_IS_GETTER_OR_SETTER (DF_IS_GETTER | DF_IS_SETTER)
extern int dvmCompilerDataFlowAttributes[kMirOpLast];
diff --git a/vm/compiler/Frontend.c b/vm/compiler/Frontend.c
index 4db75ad09..40da0e1d8 100644
--- a/vm/compiler/Frontend.c
+++ b/vm/compiler/Frontend.c
@@ -18,6 +18,7 @@
#include "libdex/OpCode.h"
#include "interp/Jit.h"
#include "CompilerInternals.h"
+#include "Dataflow.h"
/*
* Parse an instruction, return the length of the instruction
@@ -41,7 +42,7 @@ static inline int parseInsn(const u2 *codePtr, DecodedInstruction *decInsn,
dexDecodeInstruction(gDvm.instrFormat, codePtr, decInsn);
if (printMe) {
- char *decodedString = dvmCompilerGetDalvikDisassembly(decInsn);
+ char *decodedString = dvmCompilerGetDalvikDisassembly(decInsn, NULL);
LOGD("%p: %#06x %s\n", codePtr, opcode, decodedString);
}
return insnWidth;
@@ -185,7 +186,6 @@ static inline bool isUnconditionalBranch(MIR *insn)
/*
* dvmHashTableLookup() callback
*/
-#if defined(WITH_JIT_TUNING)
static int compareMethod(const CompilerMethodStats *m1,
const CompilerMethodStats *m2)
{
@@ -193,11 +193,69 @@ static int compareMethod(const CompilerMethodStats *m1,
}
/*
+ * Analyze the body of the method to collect high-level information regarding
+ * inlining:
+ * - is empty method?
+ * - is getter/setter?
+ * - can throw exception?
+ *
+ * Currently the inliner only handles getters and setters. When its capability
+ * becomes more sophisticated more information will be retrieved here.
+ */
+static int analyzeInlineTarget(DecodedInstruction *dalvikInsn, int attributes,
+ int offset)
+{
+ int flags = dexGetInstrFlags(gDvm.instrFlags, dalvikInsn->opCode);
+
+ if ((flags & kInstrInvoke) &&
+ (dalvikInsn->opCode != OP_INVOKE_DIRECT_EMPTY)) {
+ attributes &= ~METHOD_IS_LEAF;
+ }
+
+ if (!(flags & kInstrCanReturn)) {
+ if (!(dvmCompilerDataFlowAttributes[dalvikInsn->opCode] &
+ DF_IS_GETTER)) {
+ attributes &= ~METHOD_IS_GETTER;
+ }
+ if (!(dvmCompilerDataFlowAttributes[dalvikInsn->opCode] &
+ DF_IS_SETTER)) {
+ attributes &= ~METHOD_IS_SETTER;
+ }
+ }
+
+ /*
+ * The expected instruction sequence is setter will never return value and
+ * getter will also do. Clear the bits if the behavior is discovered
+ * otherwise.
+ */
+ if (flags & kInstrCanReturn) {
+ if (dalvikInsn->opCode == OP_RETURN_VOID) {
+ attributes &= ~METHOD_IS_GETTER;
+ }
+ else {
+ attributes &= ~METHOD_IS_SETTER;
+ }
+ }
+
+ if (flags & kInstrCanThrow) {
+ attributes &= ~METHOD_IS_THROW_FREE;
+ }
+
+ if (offset == 0 && dalvikInsn->opCode == OP_RETURN_VOID) {
+ attributes |= METHOD_IS_EMPTY;
+ }
+
+ return attributes;
+}
+
+/*
* Analyze each method whose traces are ever compiled. Collect a variety of
* statistics like the ratio of exercised vs overall code and code bloat
- * ratios.
+ * ratios. If isCallee is true, also analyze each instruction in more details
+ * to see if it is suitable for inlining.
*/
-static CompilerMethodStats *analyzeMethodBody(const Method *method)
+CompilerMethodStats *dvmCompilerAnalyzeMethodBody(const Method *method,
+ bool isCallee)
{
const DexCode *dexCode = dvmGetMethodCode(method);
const u2 *codePtr = dexCode->insns;
@@ -215,22 +273,40 @@ static CompilerMethodStats *analyzeMethodBody(const Method *method)
(HashCompareFunc) compareMethod,
false);
- /* Part of this method has been compiled before - just return the entry */
- if (realMethodEntry != NULL) {
- return realMethodEntry;
+ /* This method has never been analyzed before - create an entry */
+ if (realMethodEntry == NULL) {
+ realMethodEntry =
+ (CompilerMethodStats *) calloc(1, sizeof(CompilerMethodStats));
+ realMethodEntry->method = method;
+
+ dvmHashTableLookup(gDvmJit.methodStatsTable, hashValue,
+ realMethodEntry,
+ (HashCompareFunc) compareMethod,
+ true);
}
+ /* This method is invoked as a callee and has been analyzed - just return */
+ if ((isCallee == true) && (realMethodEntry->attributes & METHOD_IS_CALLEE))
+ return realMethodEntry;
+
/*
- * First time to compile this method - set up a new entry in the hash table
+ * Similarly, return if this method has been compiled before as a hot
+ * method already.
*/
- realMethodEntry =
- (CompilerMethodStats *) calloc(1, sizeof(CompilerMethodStats));
- realMethodEntry->method = method;
+ if ((isCallee == false) &&
+ (realMethodEntry->attributes & METHOD_IS_HOT))
+ return realMethodEntry;
- dvmHashTableLookup(gDvmJit.methodStatsTable, hashValue,
- realMethodEntry,
- (HashCompareFunc) compareMethod,
- true);
+ int attributes;
+
+ /* Method hasn't been analyzed for the desired purpose yet */
+ if (isCallee) {
+ /* Aggressively set the attributes until proven otherwise */
+ attributes = METHOD_IS_LEAF | METHOD_IS_THROW_FREE | METHOD_IS_CALLEE |
+ METHOD_IS_GETTER | METHOD_IS_SETTER;
+ } else {
+ attributes = METHOD_IS_HOT;
+ }
/* Count the number of instructions */
while (codePtr < codeEnd) {
@@ -241,14 +317,51 @@ static CompilerMethodStats *analyzeMethodBody(const Method *method)
if (width == 0)
break;
+ if (isCallee) {
+ attributes = analyzeInlineTarget(&dalvikInsn, attributes, insnSize);
+ }
+
insnSize += width;
codePtr += width;
}
+ /*
+ * Only handle simple getters/setters with one instruction followed by
+ * return
+ */
+ if ((attributes & (METHOD_IS_GETTER | METHOD_IS_SETTER)) &&
+ (insnSize != 3)) {
+ attributes &= ~(METHOD_IS_GETTER | METHOD_IS_SETTER);
+ }
+
realMethodEntry->dalvikSize = insnSize * 2;
+ realMethodEntry->attributes |= attributes;
+
+#if 0
+ /* Uncomment the following to explore various callee patterns */
+ if (attributes & METHOD_IS_THROW_FREE) {
+ LOGE("%s%s is inlinable%s", method->clazz->descriptor, method->name,
+ (attributes & METHOD_IS_EMPTY) ? " empty" : "");
+ }
+
+ if (attributes & METHOD_IS_LEAF) {
+ LOGE("%s%s is leaf %d%s", method->clazz->descriptor, method->name,
+ insnSize, insnSize < 5 ? " (small)" : "");
+ }
+
+ if (attributes & (METHOD_IS_GETTER | METHOD_IS_SETTER)) {
+ LOGE("%s%s is %s", method->clazz->descriptor, method->name,
+ attributes & METHOD_IS_GETTER ? "getter": "setter");
+ }
+ if (attributes ==
+ (METHOD_IS_LEAF | METHOD_IS_THROW_FREE | METHOD_IS_CALLEE)) {
+ LOGE("%s%s is inlinable non setter/getter", method->clazz->descriptor,
+ method->name);
+ }
+#endif
+
return realMethodEntry;
}
-#endif
/*
* Crawl the stack of the thread that requesed compilation to see if any of the
@@ -305,6 +418,11 @@ bool dvmCompileTrace(JitTraceDescription *desc, int numMaxInsts,
/* If we've already compiled this trace, just return success */
if (dvmJitGetCodeAddr(startCodePtr) && !info->discardResult) {
+ /*
+ * Make sure the codeAddress is NULL so that it won't clobber the
+ * existing entry.
+ */
+ info->codeAddress = NULL;
return true;
}
@@ -313,7 +431,7 @@ bool dvmCompileTrace(JitTraceDescription *desc, int numMaxInsts,
#if defined(WITH_JIT_TUNING)
/* Locate the entry to store compilation statistics for this method */
- methodStats = analyzeMethodBody(desc->method);
+ methodStats = dvmCompilerAnalyzeMethodBody(desc->method, false);
#endif
/* Set the recover buffer pointer */
@@ -325,6 +443,12 @@ bool dvmCompileTrace(JitTraceDescription *desc, int numMaxInsts,
/* Initialize the profile flag */
cUnit.executionCount = gDvmJit.profile;
+ /* Setup the method */
+ cUnit.method = desc->method;
+
+ /* Initialize the PC reconstruction list */
+ dvmInitGrowableList(&cUnit.pcReconstructionList, 8);
+
/* Identify traces that we don't want to compile */
if (gDvmJit.methodTable) {
int len = strlen(desc->method->clazz->descriptor) +
@@ -399,7 +523,7 @@ bool dvmCompileTrace(JitTraceDescription *desc, int numMaxInsts,
}
/* Allocate the entry block */
- lastBB = startBB = curBB = dvmCompilerNewBB(kEntryBlock);
+ lastBB = startBB = curBB = dvmCompilerNewBB(kTraceEntryBlock);
curBB->startOffset = curOffset;
curBB->id = numBlocks++;
@@ -434,6 +558,19 @@ bool dvmCompileTrace(JitTraceDescription *desc, int numMaxInsts,
traceSize += width;
dvmCompilerAppendMIR(curBB, insn);
cUnit.numInsts++;
+
+ int flags = dexGetInstrFlags(gDvm.instrFlags, insn->dalvikInsn.opCode);
+
+ if ((flags & kInstrInvoke) &&
+ (insn->dalvikInsn.opCode != OP_INVOKE_DIRECT_EMPTY)) {
+ assert(numInsts == 1);
+ CallsiteInfo *callsiteInfo =
+ dvmCompilerNew(sizeof(CallsiteInfo), true);
+ callsiteInfo->clazz = currRun[1].meta;
+ callsiteInfo->method = currRun[2].meta;
+ insn->meta.callsiteInfo = callsiteInfo;
+ }
+
/* Instruction limit reached - terminate the trace here */
if (cUnit.numInsts >= numMaxInsts) {
break;
@@ -442,11 +579,20 @@ bool dvmCompileTrace(JitTraceDescription *desc, int numMaxInsts,
if (currRun->frag.runEnd) {
break;
} else {
+ /* Advance to the next trace description (ie non-meta info) */
+ do {
+ currRun++;
+ } while (!currRun->frag.isCode);
+
+ /* Dummy end-of-run marker seen */
+ if (currRun->frag.numInsts == 0) {
+ break;
+ }
+
curBB = dvmCompilerNewBB(kDalvikByteCode);
lastBB->next = curBB;
lastBB = curBB;
curBB->id = numBlocks++;
- currRun++;
curOffset = currRun->frag.startOffset;
numInsts = currRun->frag.numInsts;
curBB->startOffset = curOffset;
@@ -486,6 +632,13 @@ bool dvmCompileTrace(JitTraceDescription *desc, int numMaxInsts,
/* Link the taken and fallthrough blocks */
BasicBlock *searchBB;
+ int flags = dexGetInstrFlags(gDvm.instrFlags,
+ lastInsn->dalvikInsn.opCode);
+
+ if (flags & kInstrInvoke) {
+ cUnit.hasInvoke = true;
+ }
+
/* No backward branch in the trace - start searching the next BB */
for (searchBB = curBB->next; searchBB; searchBB = searchBB->next) {
if (targetOffset == searchBB->startOffset) {
@@ -493,12 +646,18 @@ bool dvmCompileTrace(JitTraceDescription *desc, int numMaxInsts,
}
if (fallThroughOffset == searchBB->startOffset) {
curBB->fallThrough = searchBB;
+
+ /*
+ * Fallthrough block of an invoke instruction needs to be
+ * aligned to 4-byte boundary (alignment instruction to be
+ * inserted later.
+ */
+ if (flags & kInstrInvoke) {
+ searchBB->isFallThroughFromInvoke = true;
+ }
}
}
- int flags = dexGetInstrFlags(gDvm.instrFlags,
- lastInsn->dalvikInsn.opCode);
-
/*
* Some blocks are ended by non-control-flow-change instructions,
* currently only due to trace length constraint. In this case we need
@@ -523,7 +682,7 @@ bool dvmCompileTrace(JitTraceDescription *desc, int numMaxInsts,
if (cUnit.printMe) {
LOGD("Natural loop detected!");
}
- exitBB = dvmCompilerNewBB(kExitBlock);
+ exitBB = dvmCompilerNewBB(kTraceExitBlock);
lastBB->next = exitBB;
lastBB = exitBB;
@@ -698,10 +857,8 @@ bool dvmCompileTrace(JitTraceDescription *desc, int numMaxInsts,
BasicBlock **blockList;
- cUnit.method = desc->method;
cUnit.traceDesc = desc;
cUnit.numBlocks = numBlocks;
- dvmInitGrowableList(&cUnit.pcReconstructionList, 8);
blockList = cUnit.blockList =
dvmCompilerNew(sizeof(BasicBlock *) * numBlocks, true);
@@ -714,10 +871,17 @@ bool dvmCompileTrace(JitTraceDescription *desc, int numMaxInsts,
/* Make sure all blocks are added to the cUnit */
assert(curBB == NULL);
+ /* Set the instruction set to use (NOTE: later components may change it) */
+ cUnit.instructionSet = dvmCompilerInstructionSet();
+
+ /* Inline transformation @ the MIR level */
+ if (cUnit.hasInvoke && !(gDvmJit.disableOpt & (1 << kMethodInlining))) {
+ dvmCompilerInlineMIR(&cUnit);
+ }
+
/* Preparation for SSA conversion */
dvmInitializeSSAConversion(&cUnit);
-
if (cUnit.hasLoop) {
dvmCompilerLoopOpt(&cUnit);
}
@@ -731,9 +895,6 @@ bool dvmCompileTrace(JitTraceDescription *desc, int numMaxInsts,
dvmCompilerDumpCompilationUnit(&cUnit);
}
- /* Set the instruction set to use (NOTE: later components may change it) */
- cUnit.instructionSet = dvmCompilerInstructionSet();
-
/* Allocate Registers */
dvmCompilerRegAlloc(&cUnit);
@@ -771,13 +932,112 @@ bool dvmCompileTrace(JitTraceDescription *desc, int numMaxInsts,
}
/*
+ * Since we are including instructions from possibly a cold method into the
+ * current trace, we need to make sure that all the associated information
+ * with the callee is properly initialized. If not, we punt on this inline
+ * target.
+ *
+ * TODO: volatile instructions will handled later.
+ */
+bool dvmCompilerCanIncludeThisInstruction(const Method *method,
+ const DecodedInstruction *insn)
+{
+ switch (insn->opCode) {
+ case OP_NEW_INSTANCE:
+ case OP_CHECK_CAST: {
+ ClassObject *classPtr = (void*)
+ (method->clazz->pDvmDex->pResClasses[insn->vB]);
+
+ /* Class hasn't been initialized yet */
+ if (classPtr == NULL) {
+ return false;
+ }
+ return true;
+ }
+ case OP_SGET_OBJECT:
+ case OP_SGET_BOOLEAN:
+ case OP_SGET_CHAR:
+ case OP_SGET_BYTE:
+ case OP_SGET_SHORT:
+ case OP_SGET:
+ case OP_SGET_WIDE:
+ case OP_SPUT_OBJECT:
+ case OP_SPUT_BOOLEAN:
+ case OP_SPUT_CHAR:
+ case OP_SPUT_BYTE:
+ case OP_SPUT_SHORT:
+ case OP_SPUT:
+ case OP_SPUT_WIDE: {
+ void *fieldPtr = (void*)
+ (method->clazz->pDvmDex->pResFields[insn->vB]);
+
+ if (fieldPtr == NULL) {
+ return false;
+ }
+ return true;
+ }
+ case OP_INVOKE_SUPER:
+ case OP_INVOKE_SUPER_RANGE: {
+ int mIndex = method->clazz->pDvmDex->
+ pResMethods[insn->vB]->methodIndex;
+ const Method *calleeMethod = method->clazz->super->vtable[mIndex];
+ if (calleeMethod == NULL) {
+ return false;
+ }
+ return true;
+ }
+ case OP_INVOKE_SUPER_QUICK:
+ case OP_INVOKE_SUPER_QUICK_RANGE: {
+ const Method *calleeMethod = method->clazz->super->vtable[insn->vB];
+ if (calleeMethod == NULL) {
+ return false;
+ }
+ return true;
+ }
+ case OP_INVOKE_STATIC:
+ case OP_INVOKE_STATIC_RANGE:
+ case OP_INVOKE_DIRECT:
+ case OP_INVOKE_DIRECT_RANGE: {
+ const Method *calleeMethod =
+ method->clazz->pDvmDex->pResMethods[insn->vB];
+ if (calleeMethod == NULL) {
+ return false;
+ }
+ return true;
+ }
+ case OP_CONST_CLASS: {
+ void *classPtr = (void*)
+ (method->clazz->pDvmDex->pResClasses[insn->vB]);
+
+ if (classPtr == NULL) {
+ return false;
+ }
+ return true;
+ }
+ case OP_CONST_STRING_JUMBO:
+ case OP_CONST_STRING: {
+ void *strPtr = (void*)
+ (method->clazz->pDvmDex->pResStrings[insn->vB]);
+
+ if (strPtr == NULL) {
+ return false;
+ }
+ return true;
+ }
+ default:
+ return true;
+ }
+}
+
+/*
* Similar to dvmCompileTrace, but the entity processed here is the whole
* method.
*
* TODO: implementation will be revisited when the trace builder can provide
* whole-method traces.
*/
-bool dvmCompileMethod(const Method *method, JitTranslationInfo *info)
+bool dvmCompileMethod(CompilationUnit *cUnit, const Method *method,
+ JitTranslationInfo *info)
{
const DexCode *dexCode = dvmGetMethodCode(method);
const u2 *codePtr = dexCode->insns;
@@ -785,6 +1045,14 @@ bool dvmCompileMethod(const Method *method, JitTranslationInfo *info)
int blockID = 0;
unsigned int curOffset = 0;
+ /* If we've already compiled this trace, just return success */
+ if (dvmJitGetCodeAddr(codePtr) && !info->discardResult) {
+ return true;
+ }
+
+ /* Doing method-based compilation */
+ cUnit->wholeMethod = true;
+
BasicBlock *firstBlock = dvmCompilerNewBB(kDalvikByteCode);
firstBlock->id = blockID++;
@@ -793,6 +1061,8 @@ bool dvmCompileMethod(const Method *method, JitTranslationInfo *info)
false);
dvmCompilerSetBit(bbStartAddr, 0);
+ int numInvokeTargets = 0;
+
/*
* Sequentially go through every instruction first and put them in a single
* basic block. Identify block boundaries at the mean time.
@@ -808,6 +1078,12 @@ bool dvmCompileMethod(const Method *method, JitTranslationInfo *info)
/* Terminate when the data section is seen */
if (width == 0)
break;
+
+ if (!dvmCompilerCanIncludeThisInstruction(cUnit->method,
+ &insn->dalvikInsn)) {
+ return false;
+ }
+
dvmCompilerAppendMIR(firstBlock, insn);
/*
* Check whether this is a block ending instruction and whether it
@@ -823,7 +1099,12 @@ bool dvmCompileMethod(const Method *method, JitTranslationInfo *info)
if (findBlockBoundary(method, insn, curOffset, &target, &isInvoke,
&callee)) {
dvmCompilerSetBit(bbStartAddr, curOffset + width);
- if (target != curOffset) {
+ /* Each invoke needs a chaining cell block */
+ if (isInvoke) {
+ numInvokeTargets++;
+ }
+ /* A branch will end the current block */
+ else if (target != curOffset && target != UNKNOWN_TARGET) {
dvmCompilerSetBit(bbStartAddr, target);
}
}
@@ -837,26 +1118,26 @@ bool dvmCompileMethod(const Method *method, JitTranslationInfo *info)
* The number of blocks will be equal to the number of bits set to 1 in the
* bit vector minus 1, because the bit representing the location after the
* last instruction is set to one.
+ *
+ * We also add additional blocks for invoke chaining and the number is
+ * denoted by numInvokeTargets.
*/
int numBlocks = dvmCountSetBits(bbStartAddr);
if (dvmIsBitSet(bbStartAddr, dexCode->insnsSize)) {
numBlocks--;
}
- CompilationUnit cUnit;
BasicBlock **blockList;
-
- memset(&cUnit, 0, sizeof(CompilationUnit));
- cUnit.method = method;
- blockList = cUnit.blockList =
- dvmCompilerNew(sizeof(BasicBlock *) * numBlocks, true);
+ blockList = cUnit->blockList =
+ dvmCompilerNew(sizeof(BasicBlock *) * (numBlocks + numInvokeTargets),
+ true);
/*
- * Register the first block onto the list and start split it into block
- * boundaries from there.
+ * Register the first block onto the list and start splitting it into
+ * sub-blocks.
*/
blockList[0] = firstBlock;
- cUnit.numBlocks = 1;
+ cUnit->numBlocks = 1;
int i;
for (i = 0; i < numBlocks; i++) {
@@ -868,13 +1149,13 @@ bool dvmCompileMethod(const Method *method, JitTranslationInfo *info)
/* Found the beginning of a new block, see if it is created yet */
if (dvmIsBitSet(bbStartAddr, insn->offset)) {
int j;
- for (j = 0; j < cUnit.numBlocks; j++) {
+ for (j = 0; j < cUnit->numBlocks; j++) {
if (blockList[j]->firstMIRInsn->offset == insn->offset)
break;
}
/* Block not split yet - do it now */
- if (j == cUnit.numBlocks) {
+ if (j == cUnit->numBlocks) {
BasicBlock *newBB = dvmCompilerNewBB(kDalvikByteCode);
newBB->id = blockID++;
newBB->firstMIRInsn = insn;
@@ -892,17 +1173,28 @@ bool dvmCompileMethod(const Method *method, JitTranslationInfo *info)
curBB->fallThrough = newBB;
}
+ /*
+ * Fallthrough block of an invoke instruction needs to be
+ * aligned to 4-byte boundary (alignment instruction to be
+ * inserted later.
+ */
+ if (dexGetInstrFlags(gDvm.instrFlags,
+ curBB->lastMIRInsn->dalvikInsn.opCode) &
+ kInstrInvoke) {
+ newBB->isFallThroughFromInvoke = true;
+ }
+
/* enqueue the new block */
- blockList[cUnit.numBlocks++] = newBB;
+ blockList[cUnit->numBlocks++] = newBB;
break;
}
}
}
}
- if (numBlocks != cUnit.numBlocks) {
- LOGE("Expect %d vs %d basic blocks\n", numBlocks, cUnit.numBlocks);
- dvmCompilerAbort(&cUnit);
+ if (numBlocks != cUnit->numBlocks) {
+ LOGE("Expect %d vs %d basic blocks\n", numBlocks, cUnit->numBlocks);
+ dvmCompilerAbort(cUnit);
}
/* Connect the basic blocks through the taken links */
@@ -910,13 +1202,13 @@ bool dvmCompileMethod(const Method *method, JitTranslationInfo *info)
BasicBlock *curBB = blockList[i];
MIR *insn = curBB->lastMIRInsn;
unsigned int target = insn->offset;
- bool isInvoke;
- const Method *callee;
+ bool isInvoke = false;
+ const Method *callee = NULL;
findBlockBoundary(method, insn, target, &target, &isInvoke, &callee);
- /* Found a block ended on a branch */
- if (target != insn->offset) {
+ /* Found a block ended on a branch (not invoke) */
+ if (isInvoke == false && target != insn->offset) {
int j;
/* Forward branch */
if (target > insn->offset) {
@@ -931,24 +1223,60 @@ bool dvmCompileMethod(const Method *method, JitTranslationInfo *info)
break;
}
}
+ }
- /* Don't create dummy block for the callee yet */
- if (j == numBlocks && !isInvoke) {
- LOGE("Target not found for insn %x: expect target %x\n",
- curBB->lastMIRInsn->offset, target);
- dvmCompilerAbort(&cUnit);
+ if (isInvoke) {
+ BasicBlock *newBB;
+ /* Monomorphic callee */
+ if (callee) {
+ newBB = dvmCompilerNewBB(kChainingCellInvokeSingleton);
+ newBB->startOffset = 0;
+ newBB->containingMethod = callee;
+ /* Will resolve at runtime */
+ } else {
+ newBB = dvmCompilerNewBB(kChainingCellInvokePredicted);
+ newBB->startOffset = 0;
}
+ newBB->id = blockID++;
+ curBB->taken = newBB;
+ /* enqueue the new block */
+ blockList[cUnit->numBlocks++] = newBB;
}
}
+ if (cUnit->numBlocks != numBlocks + numInvokeTargets) {
+ LOGE("Expect %d vs %d total blocks\n", numBlocks + numInvokeTargets,
+ cUnit->numBlocks);
+ dvmCompilerDumpCompilationUnit(cUnit);
+ dvmCompilerAbort(cUnit);
+ }
+
/* Set the instruction set to use (NOTE: later components may change it) */
- cUnit.instructionSet = dvmCompilerInstructionSet();
+ cUnit->instructionSet = dvmCompilerInstructionSet();
- dvmCompilerMIR2LIR(&cUnit);
+ /* Preparation for SSA conversion */
+ dvmInitializeSSAConversion(cUnit);
- dvmCompilerAssembleLIR(&cUnit, info);
+ /* SSA analysis */
+ dvmCompilerNonLoopAnalysis(cUnit);
+
+ /* Needs to happen after SSA naming */
+ dvmCompilerInitializeRegAlloc(cUnit);
+
+ /* Allocate Registers */
+ dvmCompilerRegAlloc(cUnit);
+
+ /* Convert MIR to LIR, etc. */
+ dvmCompilerMIR2LIR(cUnit);
+
+ /* Convert LIR into machine code. */
+ dvmCompilerAssembleLIR(cUnit, info);
+
+ if (cUnit->halveInstCount) {
+ return false;
+ }
- dvmCompilerDumpCompilationUnit(&cUnit);
+ dvmCompilerDumpCompilationUnit(cUnit);
dvmCompilerArenaReset();
diff --git a/vm/compiler/InlineTransformation.c b/vm/compiler/InlineTransformation.c
new file mode 100644
index 000000000..6e04cfe86
--- /dev/null
+++ b/vm/compiler/InlineTransformation.c
@@ -0,0 +1,349 @@
+/*
+ * Copyright (C) 2010 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.
+ */
+
+#include "Dalvik.h"
+#include "Dataflow.h"
+#include "libdex/OpCodeNames.h"
+
+/* Convert the reg id from the callee to the original id passed by the caller */
+static inline u4 convertRegId(const DecodedInstruction *invoke,
+ const Method *calleeMethod,
+ int calleeRegId, bool isRange)
+{
+ /* The order in the original arg passing list */
+ int rank = calleeRegId -
+ (calleeMethod->registersSize - calleeMethod->insSize);
+ assert(rank >= 0);
+ if (!isRange) {
+ return invoke->arg[rank];
+ } else {
+ return invoke->vC + rank;
+ }
+}
+
+static void inlineGetter(CompilationUnit *cUnit,
+ const Method *calleeMethod,
+ MIR *invokeMIR,
+ BasicBlock *invokeBB,
+ bool isPredicted,
+ bool isRange)
+{
+ BasicBlock *moveResultBB = invokeBB->fallThrough;
+ MIR *moveResultMIR = moveResultBB->firstMIRInsn;
+ MIR *newGetterMIR = dvmCompilerNew(sizeof(MIR), true);
+ DecodedInstruction getterInsn;
+
+ dexDecodeInstruction(gDvm.instrFormat, calleeMethod->insns, &getterInsn);
+
+ if (!dvmCompilerCanIncludeThisInstruction(calleeMethod, &getterInsn))
+ return;
+
+ /*
+ * Some getters (especially invoked through interface) are not followed
+ * by a move result.
+ */
+ if ((moveResultMIR == NULL) ||
+ (moveResultMIR->dalvikInsn.opCode != OP_MOVE_RESULT &&
+ moveResultMIR->dalvikInsn.opCode != OP_MOVE_RESULT_OBJECT &&
+ moveResultMIR->dalvikInsn.opCode != OP_MOVE_RESULT_WIDE)) {
+ return;
+ }
+
+ int dfFlags = dvmCompilerDataFlowAttributes[getterInsn.opCode];
+
+ /* Expecting vA to be the destination register */
+ if (dfFlags & DF_UA) {
+ LOGE("opcode %d has DF_UA set (not expected)", getterInsn.opCode);
+ dvmAbort();
+ }
+
+ if (dfFlags & DF_UB) {
+ getterInsn.vB = convertRegId(&invokeMIR->dalvikInsn, calleeMethod,
+ getterInsn.vB, isRange);
+ }
+
+ if (dfFlags & DF_UC) {
+ getterInsn.vC = convertRegId(&invokeMIR->dalvikInsn, calleeMethod,
+ getterInsn.vC, isRange);
+ }
+
+ getterInsn.vA = moveResultMIR->dalvikInsn.vA;
+
+ /* Now setup the Dalvik instruction with converted src/dst registers */
+ newGetterMIR->dalvikInsn = getterInsn;
+
+ newGetterMIR->width = gDvm.instrWidth[getterInsn.opCode];
+
+ newGetterMIR->OptimizationFlags |= MIR_CALLEE;
+
+ /*
+ * If the getter instruction is about to raise any exception, punt to the
+ * interpreter and re-execute the invoke.
+ */
+ newGetterMIR->offset = invokeMIR->offset;
+
+ newGetterMIR->meta.calleeMethod = calleeMethod;
+
+ dvmCompilerInsertMIRAfter(invokeBB, invokeMIR, newGetterMIR);
+
+ if (isPredicted) {
+ MIR *invokeMIRSlow = dvmCompilerNew(sizeof(MIR), true);
+ *invokeMIRSlow = *invokeMIR;
+ invokeMIR->dalvikInsn.opCode = kMirOpCheckInlinePrediction;
+
+ /* Use vC to denote the first argument (ie this) */
+ if (!isRange) {
+ invokeMIR->dalvikInsn.vC = invokeMIRSlow->dalvikInsn.arg[0];
+ }
+
+ moveResultMIR->OptimizationFlags |= MIR_INLINED_PRED;
+
+ dvmCompilerInsertMIRAfter(invokeBB, newGetterMIR, invokeMIRSlow);
+ invokeMIRSlow->OptimizationFlags |= MIR_INLINED_PRED;
+#if defined(WITH_JIT_TUNING)
+ gDvmJit.invokePolyGetterInlined++;
+#endif
+ } else {
+ invokeMIR->OptimizationFlags |= MIR_INLINED;
+ moveResultMIR->OptimizationFlags |= MIR_INLINED;
+#if defined(WITH_JIT_TUNING)
+ gDvmJit.invokeMonoGetterInlined++;
+#endif
+ }
+
+ return;
+}
+
+static void inlineSetter(CompilationUnit *cUnit,
+ const Method *calleeMethod,
+ MIR *invokeMIR,
+ BasicBlock *invokeBB,
+ bool isPredicted,
+ bool isRange)
+{
+ MIR *newSetterMIR = dvmCompilerNew(sizeof(MIR), true);
+ DecodedInstruction setterInsn;
+
+ dexDecodeInstruction(gDvm.instrFormat, calleeMethod->insns, &setterInsn);
+
+ if (!dvmCompilerCanIncludeThisInstruction(calleeMethod, &setterInsn))
+ return;
+
+ int dfFlags = dvmCompilerDataFlowAttributes[setterInsn.opCode];
+
+ if (dfFlags & DF_UA) {
+ setterInsn.vA = convertRegId(&invokeMIR->dalvikInsn, calleeMethod,
+ setterInsn.vA, isRange);
+
+ }
+
+ if (dfFlags & DF_UB) {
+ setterInsn.vB = convertRegId(&invokeMIR->dalvikInsn, calleeMethod,
+ setterInsn.vB, isRange);
+
+ }
+
+ if (dfFlags & DF_UC) {
+ setterInsn.vC = convertRegId(&invokeMIR->dalvikInsn, calleeMethod,
+ setterInsn.vC, isRange);
+ }
+
+ /* Now setup the Dalvik instruction with converted src/dst registers */
+ newSetterMIR->dalvikInsn = setterInsn;
+
+ newSetterMIR->width = gDvm.instrWidth[setterInsn.opCode];
+
+ newSetterMIR->OptimizationFlags |= MIR_CALLEE;
+
+ /*
+ * If the setter instruction is about to raise any exception, punt to the
+ * interpreter and re-execute the invoke.
+ */
+ newSetterMIR->offset = invokeMIR->offset;
+
+ newSetterMIR->meta.calleeMethod = calleeMethod;
+
+ dvmCompilerInsertMIRAfter(invokeBB, invokeMIR, newSetterMIR);
+
+ if (isPredicted) {
+ MIR *invokeMIRSlow = dvmCompilerNew(sizeof(MIR), true);
+ *invokeMIRSlow = *invokeMIR;
+ invokeMIR->dalvikInsn.opCode = kMirOpCheckInlinePrediction;
+
+ /* Use vC to denote the first argument (ie this) */
+ if (!isRange) {
+ invokeMIR->dalvikInsn.vC = invokeMIRSlow->dalvikInsn.arg[0];
+ }
+
+ dvmCompilerInsertMIRAfter(invokeBB, newSetterMIR, invokeMIRSlow);
+ invokeMIRSlow->OptimizationFlags |= MIR_INLINED_PRED;
+#if defined(WITH_JIT_TUNING)
+ gDvmJit.invokePolySetterInlined++;
+#endif
+ } else {
+ invokeMIR->OptimizationFlags |= MIR_INLINED;
+#if defined(WITH_JIT_TUNING)
+ gDvmJit.invokeMonoSetterInlined++;
+#endif
+ }
+
+ return;
+}
+
+static void tryInlineSingletonCallsite(CompilationUnit *cUnit,
+ const Method *calleeMethod,
+ MIR *invokeMIR,
+ BasicBlock *invokeBB,
+ bool isRange)
+{
+ /* Not a Java method */
+ if (dvmIsNativeMethod(calleeMethod)) return;
+
+ CompilerMethodStats *methodStats =
+ dvmCompilerAnalyzeMethodBody(calleeMethod, true);
+
+ /* Empty callee - do nothing */
+ if (methodStats->attributes & METHOD_IS_EMPTY) {
+ /* The original invoke instruction is effectively turned into NOP */
+ invokeMIR->OptimizationFlags |= MIR_INLINED;
+ return;
+ }
+
+ if (methodStats->attributes & METHOD_IS_GETTER) {
+ inlineGetter(cUnit, calleeMethod, invokeMIR, invokeBB, false, isRange);
+ return;
+ } else if (methodStats->attributes & METHOD_IS_SETTER) {
+ inlineSetter(cUnit, calleeMethod, invokeMIR, invokeBB, false, isRange);
+ return;
+ }
+}
+
+static void inlineEmptyVirtualCallee(CompilationUnit *cUnit,
+ const Method *calleeMethod,
+ MIR *invokeMIR,
+ BasicBlock *invokeBB)
+{
+ MIR *invokeMIRSlow = dvmCompilerNew(sizeof(MIR), true);
+ *invokeMIRSlow = *invokeMIR;
+ invokeMIR->dalvikInsn.opCode = kMirOpCheckInlinePrediction;
+
+ dvmCompilerInsertMIRAfter(invokeBB, invokeMIR, invokeMIRSlow);
+ invokeMIRSlow->OptimizationFlags |= MIR_INLINED_PRED;
+}
+
+static void tryInlineVirtualCallsite(CompilationUnit *cUnit,
+ const Method *calleeMethod,
+ MIR *invokeMIR,
+ BasicBlock *invokeBB,
+ bool isRange)
+{
+ /* Not a Java method */
+ if (dvmIsNativeMethod(calleeMethod)) return;
+
+ 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;
+ }
+
+ if (methodStats->attributes & METHOD_IS_GETTER) {
+ inlineGetter(cUnit, calleeMethod, invokeMIR, invokeBB, true, isRange);
+ return;
+ } else if (methodStats->attributes & METHOD_IS_SETTER) {
+ inlineSetter(cUnit, calleeMethod, invokeMIR, invokeBB, true, isRange);
+ return;
+ }
+}
+
+
+void dvmCompilerInlineMIR(CompilationUnit *cUnit)
+{
+ int i;
+ bool isRange = false;
+
+ /*
+ * Analyze the basic block containing an invoke to see if it can be inlined
+ */
+ for (i = 0; i < cUnit->numBlocks; i++) {
+ BasicBlock *bb = cUnit->blockList[i];
+ if (bb->blockType != kDalvikByteCode)
+ continue;
+ MIR *lastMIRInsn = bb->lastMIRInsn;
+ int opCode = lastMIRInsn->dalvikInsn.opCode;
+ int flags = dexGetInstrFlags(gDvm.instrFlags, opCode);
+
+ /* No invoke - continue */
+ if ((flags & kInstrInvoke) == 0)
+ continue;
+
+ /* Not a real invoke - continue */
+ if (opCode == OP_INVOKE_DIRECT_EMPTY)
+ continue;
+
+ const Method *calleeMethod;
+
+ switch (opCode) {
+ case OP_INVOKE_SUPER:
+ case OP_INVOKE_DIRECT:
+ case OP_INVOKE_STATIC:
+ case OP_INVOKE_SUPER_QUICK:
+ calleeMethod = lastMIRInsn->meta.callsiteInfo->method;
+ break;
+ case OP_INVOKE_SUPER_RANGE:
+ case OP_INVOKE_DIRECT_RANGE:
+ case OP_INVOKE_STATIC_RANGE:
+ case OP_INVOKE_SUPER_QUICK_RANGE:
+ isRange = true;
+ calleeMethod = lastMIRInsn->meta.callsiteInfo->method;
+ break;
+ default:
+ calleeMethod = NULL;
+ break;
+ }
+
+ if (calleeMethod) {
+ tryInlineSingletonCallsite(cUnit, calleeMethod, lastMIRInsn, bb,
+ isRange);
+ return;
+ }
+
+ switch (opCode) {
+ case OP_INVOKE_VIRTUAL:
+ case OP_INVOKE_VIRTUAL_QUICK:
+ case OP_INVOKE_INTERFACE:
+ isRange = false;
+ calleeMethod = lastMIRInsn->meta.callsiteInfo->method;
+ break;
+ case OP_INVOKE_VIRTUAL_RANGE:
+ case OP_INVOKE_VIRTUAL_QUICK_RANGE:
+ case OP_INVOKE_INTERFACE_RANGE:
+ isRange = true;
+ calleeMethod = lastMIRInsn->meta.callsiteInfo->method;
+ break;
+ default:
+ break;
+ }
+
+ if (calleeMethod) {
+ tryInlineVirtualCallsite(cUnit, calleeMethod, lastMIRInsn, bb,
+ isRange);
+ return;
+ }
+ }
+}
diff --git a/vm/compiler/IntermediateRep.c b/vm/compiler/IntermediateRep.c
index b3e64907b..825a69079 100644
--- a/vm/compiler/IntermediateRep.c
+++ b/vm/compiler/IntermediateRep.c
@@ -55,6 +55,22 @@ void dvmCompilerPrependMIR(BasicBlock *bb, MIR *mir)
}
}
+/* Insert an MIR instruction after the specified MIR */
+void dvmCompilerInsertMIRAfter(BasicBlock *bb, MIR *currentMIR, MIR *newMIR)
+{
+ newMIR->prev = currentMIR;
+ newMIR->next = currentMIR->next;
+ currentMIR->next = newMIR;
+
+ if (newMIR->next) {
+ /* Is not the last MIR in the block */
+ newMIR->next->prev = newMIR;
+ } else {
+ /* Is the last MIR in the block */
+ bb->lastMIRInsn = newMIR;
+ }
+}
+
/*
* Append an LIR instruction to the LIR list maintained by a compilation
* unit
diff --git a/vm/compiler/Loop.c b/vm/compiler/Loop.c
index 53daf17f5..dede0ee68 100644
--- a/vm/compiler/Loop.c
+++ b/vm/compiler/Loop.c
@@ -462,9 +462,9 @@ void dvmCompilerLoopOpt(CompilationUnit *cUnit)
{
LoopAnalysis *loopAnalysis = dvmCompilerNew(sizeof(LoopAnalysis), true);
- assert(cUnit->blockList[0]->blockType == kEntryBlock);
+ assert(cUnit->blockList[0]->blockType == kTraceEntryBlock);
assert(cUnit->blockList[2]->blockType == kDalvikByteCode);
- assert(cUnit->blockList[3]->blockType == kExitBlock);
+ assert(cUnit->blockList[3]->blockType == kTraceExitBlock);
cUnit->loopAnalysis = loopAnalysis;
/*
diff --git a/vm/compiler/Ralloc.c b/vm/compiler/Ralloc.c
index 608b4b337..f22752794 100644
--- a/vm/compiler/Ralloc.c
+++ b/vm/compiler/Ralloc.c
@@ -31,7 +31,7 @@ int computeLiveRange(LiveRange *list, BasicBlock *bb, int seqNum)
int i;
if (bb->blockType != kDalvikByteCode &&
- bb->blockType != kEntryBlock)
+ bb->blockType != kTraceEntryBlock)
return seqNum;
for (mir = bb->firstMIRInsn; mir; mir = mir->next) {
@@ -64,7 +64,7 @@ static void inferTypes(CompilationUnit *cUnit, BasicBlock *bb)
{
MIR *mir;
if (bb->blockType != kDalvikByteCode &&
- bb->blockType != kEntryBlock)
+ bb->blockType != kTraceEntryBlock)
return;
for (mir = bb->firstMIRInsn; mir; mir = mir->next) {
diff --git a/vm/compiler/Utility.c b/vm/compiler/Utility.c
index 1aff02bec..711d4cf3f 100644
--- a/vm/compiler/Utility.c
+++ b/vm/compiler/Utility.c
@@ -30,6 +30,7 @@ bool dvmCompilerHeapInit(void)
LOGE("No memory left to create compiler heap memory\n");
return false;
}
+ arenaHead->blockSize = ARENA_DEFAULT_SIZE;
currentArena = arenaHead;
currentArena->bytesAllocated = 0;
currentArena->next = NULL;
@@ -44,7 +45,7 @@ void * dvmCompilerNew(size_t size, bool zero)
size = (size + 3) & ~3;
retry:
/* Normal case - space is available in the current page */
- if (size + currentArena->bytesAllocated <= ARENA_DEFAULT_SIZE) {
+ if (size + currentArena->bytesAllocated <= currentArena->blockSize) {
void *ptr;
ptr = &currentArena->ptr[currentArena->bytesAllocated];
currentArena->bytesAllocated += size;
@@ -61,15 +62,17 @@ retry:
currentArena = currentArena->next;
goto retry;
}
- /*
- * If we allocate really large variable-sized data structures that
- * could go above the limit we need to enhance the allocation
- * mechanism.
- */
- assert(size <= ARENA_DEFAULT_SIZE);
+
+ size_t blockSize = (size < ARENA_DEFAULT_SIZE) ?
+ ARENA_DEFAULT_SIZE : size;
/* Time to allocate a new arena */
ArenaMemBlock *newArena = (ArenaMemBlock *)
- malloc(sizeof(ArenaMemBlock) + ARENA_DEFAULT_SIZE);
+ malloc(sizeof(ArenaMemBlock) + blockSize);
+ if (newArena == NULL) {
+ LOGE("Arena allocation failure");
+ dvmAbort();
+ }
+ newArena->blockSize = blockSize;
newArena->bytesAllocated = 0;
newArena->next = NULL;
currentArena->next = newArena;
@@ -120,6 +123,7 @@ static void expandGrowableList(GrowableList *gList)
/* Insert a new element into the growable list */
void dvmInsertGrowableList(GrowableList *gList, void *elem)
{
+ assert(gList->numAllocated != 0);
if (gList->numUsed == gList->numAllocated) {
expandGrowableList(gList);
}
@@ -131,12 +135,34 @@ void dvmCompilerDumpCompilationUnit(CompilationUnit *cUnit)
{
int i;
BasicBlock *bb;
- LOGD("%d blocks in total\n", cUnit->numBlocks);
+ char *blockTypeNames[] = {
+ "Normal Chaining Cell",
+ "Hot Chaining Cell",
+ "Singleton Chaining Cell",
+ "Predicted Chaining Cell",
+ "Backward Branch",
+ "Chaining Cell Gap",
+ "N/A",
+ "Method Entry Block",
+ "Trace Entry Block",
+ "Code Block",
+ "Trace Exit Block",
+ "Method Exit Block",
+ "PC Reconstruction",
+ "Exception Handling",
+ };
+
+ LOGD("Compiling %s %s", cUnit->method->clazz->descriptor,
+ cUnit->method->name);
+ LOGD("%d insns", dvmGetMethodInsnsSize(cUnit->method));
+ LOGD("%d blocks in total", cUnit->numBlocks);
for (i = 0; i < cUnit->numBlocks; i++) {
bb = cUnit->blockList[i];
- LOGD("Block %d (insn %04x - %04x%s)\n",
- bb->id, bb->startOffset,
+ LOGD("Block %d (%s) (insn %04x - %04x%s)\n",
+ bb->id,
+ blockTypeNames[bb->blockType],
+ bb->startOffset,
bb->lastMIRInsn ? bb->lastMIRInsn->offset : bb->startOffset,
bb->lastMIRInsn ? "" : " empty");
if (bb->taken) {
diff --git a/vm/compiler/codegen/Optimizer.h b/vm/compiler/codegen/Optimizer.h
index 713aa4105..d42fe8738 100644
--- a/vm/compiler/codegen/Optimizer.h
+++ b/vm/compiler/codegen/Optimizer.h
@@ -28,6 +28,7 @@ typedef enum optControlVector {
kLoadHoisting,
kTrackLiveTemps,
kSuppressLoads,
+ kMethodInlining,
} optControlVector;
/* Forward declarations */
diff --git a/vm/compiler/codegen/arm/ArchUtility.c b/vm/compiler/codegen/arm/ArchUtility.c
index 2daa871ca..d5acd13ef 100644
--- a/vm/compiler/codegen/arm/ArchUtility.c
+++ b/vm/compiler/codegen/arm/ArchUtility.c
@@ -277,7 +277,8 @@ void dvmDumpLIRInsn(LIR *arg, unsigned char *baseAddr)
LOGD("-------- BARRIER");
break;
case kArmPseudoExtended:
- /* intentional fallthrough */
+ LOGD("-------- %s\n", (char *) dest);
+ break;
case kArmPseudoSSARep:
DUMP_SSA_REP(LOGD("-------- %s\n", (char *) dest));
break;
diff --git a/vm/compiler/codegen/arm/Assemble.c b/vm/compiler/codegen/arm/Assemble.c
index 832ee0fea..c1b08a3cc 100644
--- a/vm/compiler/codegen/arm/Assemble.c
+++ b/vm/compiler/codegen/arm/Assemble.c
@@ -905,11 +905,13 @@ static void installDataContent(CompilationUnit *cUnit)
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.runEnd)
+ if (desc->trace[runCount].frag.isCode &&
+ desc->trace[runCount].frag.runEnd)
break;
}
- return sizeof(JitCodeDesc) + ((runCount+1) * sizeof(JitTraceRun));
+ return sizeof(JitTraceDescription) + ((runCount+1) * sizeof(JitTraceRun));
}
/* Return TRUE if error happens */
@@ -1195,7 +1197,8 @@ void dvmCompilerAssembleLIR(CompilationUnit *cUnit, JitTranslationInfo *info)
int offset = 0;
int i;
ChainCellCounts chainCellCounts;
- int descSize = jitTraceDescriptionSize(cUnit->traceDesc);
+ int descSize =
+ cUnit->wholeMethod ? 0 : jitTraceDescriptionSize(cUnit->traceDesc);
int chainingCellGap;
info->instructionSet = cUnit->instructionSet;
diff --git a/vm/compiler/codegen/arm/CodegenDriver.c b/vm/compiler/codegen/arm/CodegenDriver.c
index cd0f18d99..37425ada1 100644
--- a/vm/compiler/codegen/arm/CodegenDriver.c
+++ b/vm/compiler/codegen/arm/CodegenDriver.c
@@ -1460,8 +1460,10 @@ static bool handleFmt21c_Fmt31c(CompilationUnit *cUnit, MIR *mir)
int valOffset = offsetof(StaticField, value);
int tReg = dvmCompilerAllocTemp(cUnit);
bool isVolatile;
+ const Method *method = (mir->OptimizationFlags & MIR_CALLEE) ?
+ mir->meta.calleeMethod : cUnit->method;
void *fieldPtr = (void*)
- (cUnit->method->clazz->pDvmDex->pResFields[mir->dalvikInsn.vB]);
+ (method->clazz->pDvmDex->pResFields[mir->dalvikInsn.vB]);
if (fieldPtr == NULL) {
LOGE("Unexpected null static field");
@@ -1488,8 +1490,10 @@ static bool handleFmt21c_Fmt31c(CompilationUnit *cUnit, MIR *mir)
}
case OP_SGET_WIDE: {
int valOffset = offsetof(StaticField, value);
+ const Method *method = (mir->OptimizationFlags & MIR_CALLEE) ?
+ mir->meta.calleeMethod : cUnit->method;
void *fieldPtr = (void*)
- (cUnit->method->clazz->pDvmDex->pResFields[mir->dalvikInsn.vB]);
+ (method->clazz->pDvmDex->pResFields[mir->dalvikInsn.vB]);
if (fieldPtr == NULL) {
LOGE("Unexpected null static field");
@@ -1517,8 +1521,10 @@ static bool handleFmt21c_Fmt31c(CompilationUnit *cUnit, MIR *mir)
int valOffset = offsetof(StaticField, value);
int tReg = dvmCompilerAllocTemp(cUnit);
bool isVolatile;
- Field *fieldPtr =
- (cUnit->method->clazz->pDvmDex->pResFields[mir->dalvikInsn.vB]);
+ const Method *method = (mir->OptimizationFlags & MIR_CALLEE) ?
+ mir->meta.calleeMethod : cUnit->method;
+ void *fieldPtr = (void*)
+ (method->clazz->pDvmDex->pResFields[mir->dalvikInsn.vB]);
isVolatile = (mir->dalvikInsn.opCode == OP_SPUT_VOLATILE) ||
(mir->dalvikInsn.opCode == OP_SPUT_OBJECT_VOLATILE) ||
@@ -1549,8 +1555,10 @@ static bool handleFmt21c_Fmt31c(CompilationUnit *cUnit, MIR *mir)
case OP_SPUT_WIDE: {
int tReg = dvmCompilerAllocTemp(cUnit);
int valOffset = offsetof(StaticField, value);
+ const Method *method = (mir->OptimizationFlags & MIR_CALLEE) ?
+ mir->meta.calleeMethod : cUnit->method;
void *fieldPtr = (void*)
- (cUnit->method->clazz->pDvmDex->pResFields[mir->dalvikInsn.vB]);
+ (method->clazz->pDvmDex->pResFields[mir->dalvikInsn.vB]);
if (fieldPtr == NULL) {
LOGE("Unexpected null static field");
@@ -1672,6 +1680,21 @@ static bool handleFmt21c_Fmt31c(CompilationUnit *cUnit, MIR *mir)
return false;
}
+/*
+ * A typical example of inlined getter/setter from a monomorphic callsite:
+ *
+ * D/dalvikvm( 289): -------- dalvik offset: 0x0000 @ invoke-static (I)
+ * D/dalvikvm( 289): -------- dalvik offset: 0x0000 @ sget-object (C) v0, ...
+ * D/dalvikvm( 289): 0x4427fc22 (0002): ldr r0, [pc, #56]
+ * D/dalvikvm( 289): 0x4427fc24 (0004): ldr r1, [r0, #0]
+ * D/dalvikvm( 289): 0x4427fc26 (0006): str r1, [r5, #0]
+ * D/dalvikvm( 289): 0x4427fc28 (0008): .align4
+ * D/dalvikvm( 289): L0x0003:
+ * D/dalvikvm( 289): -------- dalvik offset: 0x0003 @ move-result-object (I) v0
+ *
+ * Note the invoke-static and move-result-object with the (I) notation are
+ * turned into no-op.
+ */
static bool handleFmt11x(CompilationUnit *cUnit, MIR *mir)
{
OpCode dalvikOpCode = mir->dalvikInsn.opCode;
@@ -1693,6 +1716,9 @@ static bool handleFmt11x(CompilationUnit *cUnit, MIR *mir)
}
case OP_MOVE_RESULT:
case OP_MOVE_RESULT_OBJECT: {
+ /* An inlined move result is effectively no-op */
+ if (mir->OptimizationFlags & MIR_INLINED)
+ break;
RegLocation rlDest = dvmCompilerGetDest(cUnit, mir, 0);
RegLocation rlSrc = LOC_DALVIK_RETURN_VAL;
rlSrc.fp = rlDest.fp;
@@ -1700,6 +1726,9 @@ static bool handleFmt11x(CompilationUnit *cUnit, MIR *mir)
break;
}
case OP_MOVE_RESULT_WIDE: {
+ /* An inlined move result is effectively no-op */
+ if (mir->OptimizationFlags & MIR_INLINED)
+ break;
RegLocation rlDest = dvmCompilerGetDestWide(cUnit, mir, 0, 1);
RegLocation rlSrc = LOC_DALVIK_RETURN_VAL_WIDE;
rlSrc.fp = rlDest.fp;
@@ -2173,8 +2202,10 @@ static bool handleFmt22c(CompilationUnit *cUnit, MIR *mir)
case OP_IPUT_BYTE:
case OP_IPUT_CHAR:
case OP_IPUT_SHORT: {
+ const Method *method = (mir->OptimizationFlags & MIR_CALLEE) ?
+ mir->meta.calleeMethod : cUnit->method;
Field *fieldPtr =
- cUnit->method->clazz->pDvmDex->pResFields[mir->dalvikInsn.vC];
+ method->clazz->pDvmDex->pResFields[mir->dalvikInsn.vC];
if (fieldPtr == NULL) {
LOGE("Unexpected null instance field");
@@ -2714,12 +2745,47 @@ static bool handleFmt31t(CompilationUnit *cUnit, MIR *mir)
return false;
}
+/*
+ * See the example of predicted inlining listed before the
+ * genValidationForPredictedInline function. The function here takes care the
+ * branch over at 0x4858de78 and the misprediction target at 0x4858de7a.
+ */
+static void genLandingPadForMispredictedCallee(CompilationUnit *cUnit, MIR *mir,
+ BasicBlock *bb,
+ ArmLIR *labelList)
+{
+ BasicBlock *fallThrough = bb->fallThrough;
+
+ /* Bypass the move-result block if there is one */
+ if (fallThrough->firstMIRInsn) {
+ assert(fallThrough->firstMIRInsn->OptimizationFlags & MIR_INLINED_PRED);
+ fallThrough = fallThrough->fallThrough;
+ }
+ /* Generate a branch over if the predicted inlining is correct */
+ genUnconditionalBranch(cUnit, &labelList[fallThrough->id]);
+
+ /* Reset the register state */
+ dvmCompilerResetRegPool(cUnit);
+ dvmCompilerClobberAllRegs(cUnit);
+ dvmCompilerResetNullCheck(cUnit);
+
+ /* Target for the slow invoke path */
+ ArmLIR *target = newLIR0(cUnit, kArmPseudoTargetLabel);
+ target->defMask = ENCODE_ALL;
+ /* Hook up the target to the verification branch */
+ mir->meta.callsiteInfo->misPredBranchOver->target = (LIR *) target;
+}
+
static bool handleFmt35c_3rc(CompilationUnit *cUnit, MIR *mir, BasicBlock *bb,
ArmLIR *labelList)
{
ArmLIR *retChainingCell = NULL;
ArmLIR *pcrLabel = NULL;
+ /* An invoke with the MIR_INLINED is effectively a no-op */
+ if (mir->OptimizationFlags & MIR_INLINED)
+ return false;
+
if (bb->fallThrough != NULL)
retChainingCell = &labelList[bb->fallThrough->id];
@@ -2737,6 +2803,15 @@ static bool handleFmt35c_3rc(CompilationUnit *cUnit, MIR *mir, BasicBlock *bb,
cUnit->method->clazz->pDvmDex->pResMethods[dInsn->vB]->
methodIndex;
+ /*
+ * If the invoke has non-null misPredBranchOver, we need to generate
+ * the non-inlined version of the invoke here to handle the
+ * mispredicted case.
+ */
+ if (mir->meta.callsiteInfo->misPredBranchOver) {
+ genLandingPadForMispredictedCallee(cUnit, mir, bb, labelList);
+ }
+
if (mir->dalvikInsn.opCode == OP_INVOKE_VIRTUAL)
genProcessArgsNoRange(cUnit, mir, dInsn, &pcrLabel);
else
@@ -2754,10 +2829,11 @@ static bool handleFmt35c_3rc(CompilationUnit *cUnit, MIR *mir, BasicBlock *bb,
*/
case OP_INVOKE_SUPER:
case OP_INVOKE_SUPER_RANGE: {
- int mIndex = cUnit->method->clazz->pDvmDex->
- pResMethods[dInsn->vB]->methodIndex;
- const Method *calleeMethod =
- cUnit->method->clazz->super->vtable[mIndex];
+ /* Grab the method ptr directly from what the interpreter sees */
+ const Method *calleeMethod = mir->meta.callsiteInfo->method;
+ assert(calleeMethod == cUnit->method->clazz->super->vtable[
+ cUnit->method->clazz->pDvmDex->
+ pResMethods[dInsn->vB]->methodIndex]);
if (mir->dalvikInsn.opCode == OP_INVOKE_SUPER)
genProcessArgsNoRange(cUnit, mir, dInsn, &pcrLabel);
@@ -2774,8 +2850,10 @@ static bool handleFmt35c_3rc(CompilationUnit *cUnit, MIR *mir, BasicBlock *bb,
/* calleeMethod = method->clazz->pDvmDex->pResMethods[BBBB] */
case OP_INVOKE_DIRECT:
case OP_INVOKE_DIRECT_RANGE: {
- const Method *calleeMethod =
- cUnit->method->clazz->pDvmDex->pResMethods[dInsn->vB];
+ /* Grab the method ptr directly from what the interpreter sees */
+ const Method *calleeMethod = mir->meta.callsiteInfo->method;
+ assert(calleeMethod ==
+ cUnit->method->clazz->pDvmDex->pResMethods[dInsn->vB]);
if (mir->dalvikInsn.opCode == OP_INVOKE_DIRECT)
genProcessArgsNoRange(cUnit, mir, dInsn, &pcrLabel);
@@ -2792,8 +2870,10 @@ static bool handleFmt35c_3rc(CompilationUnit *cUnit, MIR *mir, BasicBlock *bb,
/* calleeMethod = method->clazz->pDvmDex->pResMethods[BBBB] */
case OP_INVOKE_STATIC:
case OP_INVOKE_STATIC_RANGE: {
- const Method *calleeMethod =
- cUnit->method->clazz->pDvmDex->pResMethods[dInsn->vB];
+ /* Grab the method ptr directly from what the interpreter sees */
+ const Method *calleeMethod = mir->meta.callsiteInfo->method;
+ assert(calleeMethod ==
+ cUnit->method->clazz->pDvmDex->pResMethods[dInsn->vB]);
if (mir->dalvikInsn.opCode == OP_INVOKE_STATIC)
genProcessArgsNoRange(cUnit, mir, dInsn,
@@ -2884,8 +2964,14 @@ static bool handleFmt35c_3rc(CompilationUnit *cUnit, MIR *mir, BasicBlock *bb,
case OP_INVOKE_INTERFACE_RANGE: {
ArmLIR *predChainingCell = &labelList[bb->taken->id];
- /* Ensure that nothing is both live and dirty */
- dvmCompilerFlushAllRegs(cUnit);
+ /*
+ * If the invoke has non-null misPredBranchOver, we need to generate
+ * the non-inlined version of the invoke here to handle the
+ * mispredicted case.
+ */
+ if (mir->meta.callsiteInfo->misPredBranchOver) {
+ genLandingPadForMispredictedCallee(cUnit, mir, bb, labelList);
+ }
if (mir->dalvikInsn.opCode == OP_INVOKE_INTERFACE)
genProcessArgsNoRange(cUnit, mir, dInsn, &pcrLabel);
@@ -3044,12 +3130,26 @@ static bool handleFmt35ms_3rms(CompilationUnit *cUnit, MIR *mir,
ArmLIR *predChainingCell = &labelList[bb->taken->id];
ArmLIR *pcrLabel = NULL;
+ /* An invoke with the MIR_INLINED is effectively a no-op */
+ if (mir->OptimizationFlags & MIR_INLINED)
+ return false;
+
DecodedInstruction *dInsn = &mir->dalvikInsn;
switch (mir->dalvikInsn.opCode) {
/* calleeMethod = this->clazz->vtable[BBBB] */
case OP_INVOKE_VIRTUAL_QUICK_RANGE:
case OP_INVOKE_VIRTUAL_QUICK: {
int methodIndex = dInsn->vB;
+
+ /*
+ * If the invoke has non-null misPredBranchOver, we need to generate
+ * the non-inlined version of the invoke here to handle the
+ * mispredicted case.
+ */
+ if (mir->meta.callsiteInfo->misPredBranchOver) {
+ genLandingPadForMispredictedCallee(cUnit, mir, bb, labelList);
+ }
+
if (mir->dalvikInsn.opCode == OP_INVOKE_VIRTUAL_QUICK)
genProcessArgsNoRange(cUnit, mir, dInsn, &pcrLabel);
else
@@ -3064,8 +3164,10 @@ static bool handleFmt35ms_3rms(CompilationUnit *cUnit, MIR *mir,
/* calleeMethod = method->clazz->super->vtable[BBBB] */
case OP_INVOKE_SUPER_QUICK:
case OP_INVOKE_SUPER_QUICK_RANGE: {
- const Method *calleeMethod =
- cUnit->method->clazz->super->vtable[dInsn->vB];
+ /* Grab the method ptr directly from what the interpreter sees */
+ const Method *calleeMethod = mir->meta.callsiteInfo->method;
+ assert(calleeMethod ==
+ cUnit->method->clazz->super->vtable[dInsn->vB]);
if (mir->dalvikInsn.opCode == OP_INVOKE_SUPER_QUICK)
genProcessArgsNoRange(cUnit, mir, dInsn, &pcrLabel);
@@ -3077,8 +3179,6 @@ static bool handleFmt35ms_3rms(CompilationUnit *cUnit, MIR *mir,
genInvokeSingletonCommon(cUnit, mir, bb, labelList, pcrLabel,
calleeMethod);
- /* Handle exceptions using the interpreter */
- genTrap(cUnit, mir->offset, pcrLabel);
break;
}
default:
@@ -3485,6 +3585,7 @@ static char *extendedMIROpNames[kMirOpLast - kMirOpFirst] = {
"kMirOpNullNRangeDownCheck",
"kMirOpLowerBound",
"kMirOpPunt",
+ "kMirOpCheckInlinePrediction",
};
/*
@@ -3596,6 +3697,110 @@ static void genHoistedLowerBoundCheck(CompilationUnit *cUnit, MIR *mir)
(ArmLIR *) cUnit->loopAnalysis->branchToPCR);
}
+/*
+ * vC = this
+ *
+ * A predicted inlining target looks like the following, where instructions
+ * between 0x4858de66 and 0x4858de72 are checking if the predicted class
+ * matches "this", and the verificaion code is generated by this routine.
+ *
+ * (C) means the instruction is inlined from the callee, and (PI) means the
+ * instruction is the predicted inlined invoke, whose corresponding
+ * instructions are still generated to handle the mispredicted case.
+ *
+ * D/dalvikvm( 86): -------- kMirOpCheckInlinePrediction
+ * D/dalvikvm( 86): 0x4858de66 (0002): ldr r0, [r5, #68]
+ * D/dalvikvm( 86): 0x4858de68 (0004): ldr r1, [pc, #140]
+ * D/dalvikvm( 86): 0x4858de6a (0006): cmp r0, #0
+ * D/dalvikvm( 86): 0x4858de6c (0008): beq 0x4858deb2
+ * D/dalvikvm( 86): 0x4858de6e (000a): ldr r2, [r0, #0]
+ * D/dalvikvm( 86): 0x4858de70 (000c): cmp r1, r2
+ * D/dalvikvm( 86): 0x4858de72 (000e): bne 0x4858de7a
+ * D/dalvikvm( 86): -------- dalvik offset: 0x004c @ +iget-object-quick (C)
+ * v4, v17, (#8)
+ * D/dalvikvm( 86): 0x4858de74 (0010): ldr r3, [r0, #8]
+ * D/dalvikvm( 86): 0x4858de76 (0012): str r3, [r5, #16]
+ * D/dalvikvm( 86): -------- dalvik offset: 0x004c @
+ * +invoke-virtual-quick/range (PI) v17..v17
+ * D/dalvikvm( 86): 0x4858de78 (0014): b 0x4858debc
+ * D/dalvikvm( 86): 0x4858de7a (0016): add r4,r5,#68
+ * D/dalvikvm( 86): -------- BARRIER
+ * D/dalvikvm( 86): 0x4858de7e (001a): ldmia r4, <r0>
+ * D/dalvikvm( 86): -------- BARRIER
+ * D/dalvikvm( 86): 0x4858de80 (001c): sub r7,r5,#24
+ * D/dalvikvm( 86): 0x4858de84 (0020): cmp r0, #0
+ * D/dalvikvm( 86): 0x4858de86 (0022): beq 0x4858deb6
+ * D/dalvikvm( 86): -------- BARRIER
+ * D/dalvikvm( 86): 0x4858de88 (0024): stmia r7, <r0>
+ * D/dalvikvm( 86): -------- BARRIER
+ * D/dalvikvm( 86): 0x4858de8a (0026): ldr r4, [pc, #104]
+ * D/dalvikvm( 86): 0x4858de8c (0028): add r1, pc, #28
+ * D/dalvikvm( 86): 0x4858de8e (002a): add r2, pc, #56
+ * D/dalvikvm( 86): 0x4858de90 (002c): blx_1 0x48589198
+ * D/dalvikvm( 86): 0x4858de92 (002e): blx_2 see above
+ * D/dalvikvm( 86): 0x4858de94 (0030): b 0x4858dec8
+ * D/dalvikvm( 86): 0x4858de96 (0032): b 0x4858deb6
+ * D/dalvikvm( 86): 0x4858de98 (0034): ldr r0, [r7, #72]
+ * D/dalvikvm( 86): 0x4858de9a (0036): cmp r1, #0
+ * D/dalvikvm( 86): 0x4858de9c (0038): bgt 0x4858dea4
+ * D/dalvikvm( 86): 0x4858de9e (003a): ldr r7, [r6, #116]
+ * D/dalvikvm( 86): 0x4858dea0 (003c): movs r1, r6
+ * D/dalvikvm( 86): 0x4858dea2 (003e): blx r7
+ * D/dalvikvm( 86): 0x4858dea4 (0040): add r1, pc, #4
+ * D/dalvikvm( 86): 0x4858dea6 (0042): blx_1 0x485890a0
+ * D/dalvikvm( 86): 0x4858dea8 (0044): blx_2 see above
+ * D/dalvikvm( 86): 0x4858deaa (0046): b 0x4858deb6
+ * D/dalvikvm( 86): 0x4858deac (0048): .align4
+ * D/dalvikvm( 86): L0x004f:
+ * D/dalvikvm( 86): -------- dalvik offset: 0x004f @ move-result-object (PI)
+ * v4, (#0), (#0)
+ * D/dalvikvm( 86): 0x4858deac (0048): ldr r4, [r6, #8]
+ * D/dalvikvm( 86): 0x4858deae (004a): str r4, [r5, #16]
+ * D/dalvikvm( 86): 0x4858deb0 (004c): b 0x4858debc
+ * D/dalvikvm( 86): -------- reconstruct dalvik PC : 0x42beefcc @ +0x004c
+ * D/dalvikvm( 86): 0x4858deb2 (004e): ldr r0, [pc, #64]
+ * D/dalvikvm( 86): 0x4858deb4 (0050): b 0x4858deb8
+ * D/dalvikvm( 86): -------- reconstruct dalvik PC : 0x42beefcc @ +0x004c
+ * D/dalvikvm( 86): 0x4858deb6 (0052): ldr r0, [pc, #60]
+ * D/dalvikvm( 86): Exception_Handling:
+ * D/dalvikvm( 86): 0x4858deb8 (0054): ldr r1, [r6, #100]
+ * D/dalvikvm( 86): 0x4858deba (0056): blx r1
+ * D/dalvikvm( 86): 0x4858debc (0058): .align4
+ * D/dalvikvm( 86): -------- chaining cell (hot): 0x0050
+ * D/dalvikvm( 86): 0x4858debc (0058): b 0x4858dec0
+ * D/dalvikvm( 86): 0x4858debe (005a): orrs r0, r0
+ * D/dalvikvm( 86): 0x4858dec0 (005c): ldr r0, [r6, #112]
+ * D/dalvikvm( 86): 0x4858dec2 (005e): blx r0
+ * D/dalvikvm( 86): 0x4858dec4 (0060): data 0xefd4(61396)
+ * D/dalvikvm( 86): 0x4858dec6 (0062): data 0x42be(17086)
+ * D/dalvikvm( 86): 0x4858dec8 (0064): .align4
+ * D/dalvikvm( 86): -------- chaining cell (predicted)
+ * D/dalvikvm( 86): 0x4858dec8 (0064): data 0xe7fe(59390)
+ * D/dalvikvm( 86): 0x4858deca (0066): data 0x0000(0)
+ * D/dalvikvm( 86): 0x4858decc (0068): data 0x0000(0)
+ * D/dalvikvm( 86): 0x4858dece (006a): data 0x0000(0)
+ * :
+ */
+static void genValidationForPredictedInline(CompilationUnit *cUnit, MIR *mir)
+{
+ CallsiteInfo *callsiteInfo = mir->meta.callsiteInfo;
+ RegLocation rlThis = cUnit->regLocation[mir->dalvikInsn.vC];
+
+ rlThis = loadValue(cUnit, rlThis, kCoreReg);
+ int regPredictedClass = dvmCompilerAllocTemp(cUnit);
+ loadConstant(cUnit, regPredictedClass, (int) callsiteInfo->clazz);
+ genNullCheck(cUnit, rlThis.sRegLow, rlThis.lowReg, mir->offset,
+ NULL);/* null object? */
+ int regActualClass = dvmCompilerAllocTemp(cUnit);
+ loadWordDisp(cUnit, rlThis.lowReg, offsetof(Object, clazz), regActualClass);
+ opRegReg(cUnit, kOpCmp, regPredictedClass, regActualClass);
+ /*
+ * Set the misPredBranchOver target so that it will be generated when the
+ * code for the non-optimized invoke is generated.
+ */
+ callsiteInfo->misPredBranchOver = (LIR *) opCondBranch(cUnit, kArmCondNe);
+}
+
/* Extended MIR instructions like PHI */
static void handleExtendedMIR(CompilationUnit *cUnit, MIR *mir)
{
@@ -3628,6 +3833,10 @@ static void handleExtendedMIR(CompilationUnit *cUnit, MIR *mir)
(ArmLIR *) cUnit->loopAnalysis->branchToPCR);
break;
}
+ case kMirOpCheckInlinePrediction: {
+ genValidationForPredictedInline(cUnit, mir);
+ break;
+ }
default:
break;
}
@@ -3674,7 +3883,7 @@ static bool selfVerificationPuntOps(MIR *mir)
{
DecodedInstruction *decInsn = &mir->dalvikInsn;
OpCode op = decInsn->opCode;
- int flags = dexGetInstrFlags(gDvm.instrFlags, op);
+
/*
* All opcodes that can throw exceptions and use the
* TEMPLATE_THROW_EXCEPTION_COMMON template should be excluded in the trace
@@ -3684,8 +3893,7 @@ static bool selfVerificationPuntOps(MIR *mir)
op == OP_NEW_INSTANCE || op == OP_NEW_ARRAY ||
op == OP_CHECK_CAST || op == OP_MOVE_EXCEPTION ||
op == OP_FILL_ARRAY_DATA || op == OP_EXECUTE_INLINE ||
- op == OP_EXECUTE_INLINE_RANGE ||
- (flags & kInstrInvoke));
+ op == OP_EXECUTE_INLINE_RANGE);
}
#endif
@@ -3748,13 +3956,7 @@ void dvmCompilerMIR2LIR(CompilationUnit *cUnit)
labelList[i].operands[0] = blockList[i]->startOffset;
if (blockList[i]->blockType >= kChainingCellGap) {
- if (blockList[i]->firstMIRInsn != NULL &&
- ((blockList[i]->firstMIRInsn->dalvikInsn.opCode ==
- OP_MOVE_RESULT) ||
- (blockList[i]->firstMIRInsn->dalvikInsn.opCode ==
- OP_MOVE_RESULT_WIDE) ||
- (blockList[i]->firstMIRInsn->dalvikInsn.opCode ==
- OP_MOVE_RESULT_OBJECT))) {
+ if (blockList[i]->isFallThroughFromInvoke == true) {
/* Align this block first since it is a return chaining cell */
newLIR0(cUnit, kArmPseudoPseudoAlign4);
}
@@ -3765,7 +3967,7 @@ void dvmCompilerMIR2LIR(CompilationUnit *cUnit)
dvmCompilerAppendLIR(cUnit, (LIR *) &labelList[i]);
}
- if (blockList[i]->blockType == kEntryBlock) {
+ if (blockList[i]->blockType == kTraceEntryBlock) {
labelList[i].opCode = kArmPseudoEntryBlock;
if (blockList[i]->firstMIRInsn == NULL) {
continue;
@@ -3773,7 +3975,7 @@ void dvmCompilerMIR2LIR(CompilationUnit *cUnit)
setupLoopEntryBlock(cUnit, blockList[i],
&labelList[blockList[i]->fallThrough->id]);
}
- } else if (blockList[i]->blockType == kExitBlock) {
+ } else if (blockList[i]->blockType == kTraceExitBlock) {
labelList[i].opCode = kArmPseudoExitBlock;
goto gen_fallthrough;
} else if (blockList[i]->blockType == kDalvikByteCode) {
@@ -3870,11 +4072,22 @@ void dvmCompilerMIR2LIR(CompilationUnit *cUnit)
OpCode dalvikOpCode = mir->dalvikInsn.opCode;
InstructionFormat dalvikFormat =
dexGetInstrFormat(gDvm.instrFormat, dalvikOpCode);
+ char *note;
+ if (mir->OptimizationFlags & MIR_INLINED) {
+ note = " (I)";
+ } else if (mir->OptimizationFlags & MIR_INLINED_PRED) {
+ note = " (PI)";
+ } else if (mir->OptimizationFlags & MIR_CALLEE) {
+ note = " (C)";
+ } else {
+ note = NULL;
+ }
+
ArmLIR *boundaryLIR =
newLIR2(cUnit, kArmPseudoDalvikByteCodeBoundary,
mir->offset,
- (int) dvmCompilerGetDalvikDisassembly(&mir->dalvikInsn)
- );
+ (int) dvmCompilerGetDalvikDisassembly(&mir->dalvikInsn,
+ note));
if (mir->ssaRep) {
char *ssaString = dvmCompilerGetSSAString(cUnit, mir->ssaRep);
newLIR1(cUnit, kArmPseudoSSARep, (int) ssaString);
@@ -4000,7 +4213,7 @@ void dvmCompilerMIR2LIR(CompilationUnit *cUnit)
}
}
- if (blockList[i]->blockType == kEntryBlock) {
+ if (blockList[i]->blockType == kTraceEntryBlock) {
dvmCompilerAppendLIR(cUnit,
(LIR *) cUnit->loopAnalysis->branchToBody);
dvmCompilerAppendLIR(cUnit,
@@ -4117,9 +4330,6 @@ bool dvmCompilerDoWork(CompilerWorkOrder *work)
}
switch (work->kind) {
- case kWorkOrderMethod:
- res = dvmCompileMethod(work->info, &work->result);
- break;
case kWorkOrderTrace:
/* Start compilation with maximally allowed trace length */
res = dvmCompileTrace(work->info, JIT_MAX_TRACE_LEN, &work->result,
diff --git a/vm/compiler/template/armv5te/TEMPLATE_RETURN.S b/vm/compiler/template/armv5te/TEMPLATE_RETURN.S
index 70044c236..b7ab97107 100644
--- a/vm/compiler/template/armv5te/TEMPLATE_RETURN.S
+++ b/vm/compiler/template/armv5te/TEMPLATE_RETURN.S
@@ -23,7 +23,7 @@
#else
blxeq lr @ punt to interpreter and compare state
#endif
- ldr r1, .LdvmJitToInterpNoChain @ defined in footer.S
+ ldr r1, .LdvmJitToInterpNoChainNoProfile @ defined in footer.S
mov rFP, r10 @ publish new FP
ldrne r10, [r2, #offMethod_clazz] @ r10<- method->clazz
ldr r8, [r8] @ r8<- suspendCount
diff --git a/vm/compiler/template/armv5te/footer.S b/vm/compiler/template/armv5te/footer.S
index 8e66ac64e..73fc3d7d6 100644
--- a/vm/compiler/template/armv5te/footer.S
+++ b/vm/compiler/template/armv5te/footer.S
@@ -76,6 +76,8 @@
.align 2
.LdvmAsmInstructionStart:
.word dvmAsmInstructionStart
+.LdvmJitToInterpNoChainNoProfile:
+ .word dvmJitToInterpNoChainNoProfile
.LdvmJitToInterpTraceSelectNoChain:
.word dvmJitToInterpTraceSelectNoChain
.LdvmJitToInterpNoChain:
diff --git a/vm/compiler/template/out/CompilerTemplateAsm-armv5te-vfp.S b/vm/compiler/template/out/CompilerTemplateAsm-armv5te-vfp.S
index 08233246a..60664fa60 100644
--- a/vm/compiler/template/out/CompilerTemplateAsm-armv5te-vfp.S
+++ b/vm/compiler/template/out/CompilerTemplateAsm-armv5te-vfp.S
@@ -101,7 +101,6 @@ unspecified registers or condition codes.
*/
#include "../../../mterp/common/asm-constants.h"
-
/* File: armv5te-vfp/platform.S */
/*
* ===========================================================================
@@ -166,7 +165,6 @@ dvmCompiler_TEMPLATE_CMP_LONG:
mov r0, #1 @ r0<- 1
bx lr
-
/* ------------------------------ */
.balign 4
.global dvmCompiler_TEMPLATE_RETURN
@@ -197,7 +195,7 @@ dvmCompiler_TEMPLATE_RETURN:
#else
blxeq lr @ punt to interpreter and compare state
#endif
- ldr r1, .LdvmJitToInterpNoChain @ defined in footer.S
+ ldr r1, .LdvmJitToInterpNoChainNoProfile @ defined in footer.S
mov rFP, r10 @ publish new FP
ldrne r10, [r2, #offMethod_clazz] @ r10<- method->clazz
ldr r8, [r8] @ r8<- suspendCount
@@ -334,8 +332,6 @@ dvmCompiler_TEMPLATE_INVOKE_METHOD_CHAIN:
bx lr @ return to the callee-chaining cell
-
-
/* ------------------------------ */
.balign 4
.global dvmCompiler_TEMPLATE_INVOKE_METHOD_PREDICTED_CHAIN
@@ -468,9 +464,6 @@ dvmCompiler_TEMPLATE_INVOKE_METHOD_NATIVE:
#endif
mov pc, r1
-
-
-
/* ------------------------------ */
.balign 4
.global dvmCompiler_TEMPLATE_MUL_LONG
@@ -547,7 +540,6 @@ dvmCompiler_TEMPLATE_SHR_LONG:
mov r1, r1, asr r2 @ r1<- r1 >> r2
bx lr
-
/* ------------------------------ */
.balign 4
.global dvmCompiler_TEMPLATE_USHR_LONG
@@ -569,7 +561,6 @@ dvmCompiler_TEMPLATE_USHR_LONG:
mov r1, r1, lsr r2 @ r1<- r1 >>> r2
bx lr
-
/* ------------------------------ */
.balign 4
.global dvmCompiler_TEMPLATE_ADD_FLOAT_VFP
@@ -919,7 +910,6 @@ dvmCompiler_TEMPLATE_CMPG_DOUBLE_VFP:
moveq r0, #0 @ (equal) r0<- 0
bx lr
-
/* ------------------------------ */
.balign 4
.global dvmCompiler_TEMPLATE_CMPL_DOUBLE_VFP
@@ -1226,7 +1216,6 @@ do_memcmp16:
.Lmemcmp16:
.word __memcmp16
-
/* ------------------------------ */
.balign 4
.global dvmCompiler_TEMPLATE_STRING_INDEXOF
@@ -1345,7 +1334,6 @@ match_3:
asr r0, r0, #1
bx lr
-
/* ------------------------------ */
.balign 4
.global dvmCompiler_TEMPLATE_INTERPRET
@@ -1406,7 +1394,6 @@ dvmCompiler_TEMPLATE_MONITOR_ENTER:
#endif
bx r2
-
/* ------------------------------ */
.balign 4
.global dvmCompiler_TEMPLATE_MONITOR_ENTER_DEBUG
@@ -1525,6 +1512,8 @@ dvmCompiler_TEMPLATE_MONITOR_ENTER_DEBUG:
.align 2
.LdvmAsmInstructionStart:
.word dvmAsmInstructionStart
+.LdvmJitToInterpNoChainNoProfile:
+ .word dvmJitToInterpNoChainNoProfile
.LdvmJitToInterpTraceSelectNoChain:
.word dvmJitToInterpTraceSelectNoChain
.LdvmJitToInterpNoChain:
@@ -1552,3 +1541,4 @@ dvmCompiler_TEMPLATE_MONITOR_ENTER_DEBUG:
dmvCompilerTemplateEnd:
#endif /* WITH_JIT */
+
diff --git a/vm/compiler/template/out/CompilerTemplateAsm-armv5te.S b/vm/compiler/template/out/CompilerTemplateAsm-armv5te.S
index b9a307531..ccdbcca21 100644
--- a/vm/compiler/template/out/CompilerTemplateAsm-armv5te.S
+++ b/vm/compiler/template/out/CompilerTemplateAsm-armv5te.S
@@ -101,7 +101,6 @@ unspecified registers or condition codes.
*/
#include "../../../mterp/common/asm-constants.h"
-
/* File: armv5te/platform.S */
/*
* ===========================================================================
@@ -166,7 +165,6 @@ dvmCompiler_TEMPLATE_CMP_LONG:
mov r0, #1 @ r0<- 1
bx lr
-
/* ------------------------------ */
.balign 4
.global dvmCompiler_TEMPLATE_RETURN
@@ -197,7 +195,7 @@ dvmCompiler_TEMPLATE_RETURN:
#else
blxeq lr @ punt to interpreter and compare state
#endif
- ldr r1, .LdvmJitToInterpNoChain @ defined in footer.S
+ ldr r1, .LdvmJitToInterpNoChainNoProfile @ defined in footer.S
mov rFP, r10 @ publish new FP
ldrne r10, [r2, #offMethod_clazz] @ r10<- method->clazz
ldr r8, [r8] @ r8<- suspendCount
@@ -334,8 +332,6 @@ dvmCompiler_TEMPLATE_INVOKE_METHOD_CHAIN:
bx lr @ return to the callee-chaining cell
-
-
/* ------------------------------ */
.balign 4
.global dvmCompiler_TEMPLATE_INVOKE_METHOD_PREDICTED_CHAIN
@@ -468,9 +464,6 @@ dvmCompiler_TEMPLATE_INVOKE_METHOD_NATIVE:
#endif
mov pc, r1
-
-
-
/* ------------------------------ */
.balign 4
.global dvmCompiler_TEMPLATE_CMPG_DOUBLE
@@ -514,7 +507,6 @@ dvmCompiler_TEMPLATE_CMPG_DOUBLE:
bx r11
-
/* ------------------------------ */
.balign 4
.global dvmCompiler_TEMPLATE_CMPL_DOUBLE
@@ -556,7 +548,6 @@ dvmCompiler_TEMPLATE_CMPL_DOUBLE:
mvn r0, #0 @ r1<- 1 or -1 for NaN
bx r11
-
/* ------------------------------ */
.balign 4
.global dvmCompiler_TEMPLATE_CMPG_FLOAT
@@ -618,8 +609,6 @@ dvmCompiler_TEMPLATE_CMPG_FLOAT:
bx r11
-
-
/* ------------------------------ */
.balign 4
.global dvmCompiler_TEMPLATE_CMPL_FLOAT
@@ -679,8 +668,6 @@ dvmCompiler_TEMPLATE_CMPL_FLOAT:
mvn r0, #0 @ r1<- 1 or -1 for NaN
bx r11
-
-
/* ------------------------------ */
.balign 4
.global dvmCompiler_TEMPLATE_MUL_LONG
@@ -757,7 +744,6 @@ dvmCompiler_TEMPLATE_SHR_LONG:
mov r1, r1, asr r2 @ r1<- r1 >> r2
bx lr
-
/* ------------------------------ */
.balign 4
.global dvmCompiler_TEMPLATE_USHR_LONG
@@ -779,7 +765,6 @@ dvmCompiler_TEMPLATE_USHR_LONG:
mov r1, r1, lsr r2 @ r1<- r1 >>> r2
bx lr
-
/* ------------------------------ */
.balign 4
.global dvmCompiler_TEMPLATE_THROW_EXCEPTION_COMMON
@@ -954,7 +939,6 @@ do_memcmp16:
.Lmemcmp16:
.word __memcmp16
-
/* ------------------------------ */
.balign 4
.global dvmCompiler_TEMPLATE_STRING_INDEXOF
@@ -1073,7 +1057,6 @@ match_3:
asr r0, r0, #1
bx lr
-
/* ------------------------------ */
.balign 4
.global dvmCompiler_TEMPLATE_INTERPRET
@@ -1134,7 +1117,6 @@ dvmCompiler_TEMPLATE_MONITOR_ENTER:
#endif
bx r2
-
/* ------------------------------ */
.balign 4
.global dvmCompiler_TEMPLATE_MONITOR_ENTER_DEBUG
@@ -1253,6 +1235,8 @@ dvmCompiler_TEMPLATE_MONITOR_ENTER_DEBUG:
.align 2
.LdvmAsmInstructionStart:
.word dvmAsmInstructionStart
+.LdvmJitToInterpNoChainNoProfile:
+ .word dvmJitToInterpNoChainNoProfile
.LdvmJitToInterpTraceSelectNoChain:
.word dvmJitToInterpTraceSelectNoChain
.LdvmJitToInterpNoChain:
@@ -1280,3 +1264,4 @@ dvmCompiler_TEMPLATE_MONITOR_ENTER_DEBUG:
dmvCompilerTemplateEnd:
#endif /* WITH_JIT */
+
diff --git a/vm/compiler/template/out/CompilerTemplateAsm-armv7-a-neon.S b/vm/compiler/template/out/CompilerTemplateAsm-armv7-a-neon.S
index 008c32443..e520056b9 100644
--- a/vm/compiler/template/out/CompilerTemplateAsm-armv7-a-neon.S
+++ b/vm/compiler/template/out/CompilerTemplateAsm-armv7-a-neon.S
@@ -101,7 +101,6 @@ unspecified registers or condition codes.
*/
#include "../../../mterp/common/asm-constants.h"
-
/* File: armv5te-vfp/platform.S */
/*
* ===========================================================================
@@ -166,7 +165,6 @@ dvmCompiler_TEMPLATE_CMP_LONG:
mov r0, #1 @ r0<- 1
bx lr
-
/* ------------------------------ */
.balign 4
.global dvmCompiler_TEMPLATE_RETURN
@@ -197,7 +195,7 @@ dvmCompiler_TEMPLATE_RETURN:
#else
blxeq lr @ punt to interpreter and compare state
#endif
- ldr r1, .LdvmJitToInterpNoChain @ defined in footer.S
+ ldr r1, .LdvmJitToInterpNoChainNoProfile @ defined in footer.S
mov rFP, r10 @ publish new FP
ldrne r10, [r2, #offMethod_clazz] @ r10<- method->clazz
ldr r8, [r8] @ r8<- suspendCount
@@ -334,8 +332,6 @@ dvmCompiler_TEMPLATE_INVOKE_METHOD_CHAIN:
bx lr @ return to the callee-chaining cell
-
-
/* ------------------------------ */
.balign 4
.global dvmCompiler_TEMPLATE_INVOKE_METHOD_PREDICTED_CHAIN
@@ -468,9 +464,6 @@ dvmCompiler_TEMPLATE_INVOKE_METHOD_NATIVE:
#endif
mov pc, r1
-
-
-
/* ------------------------------ */
.balign 4
.global dvmCompiler_TEMPLATE_MUL_LONG
@@ -547,7 +540,6 @@ dvmCompiler_TEMPLATE_SHR_LONG:
mov r1, r1, asr r2 @ r1<- r1 >> r2
bx lr
-
/* ------------------------------ */
.balign 4
.global dvmCompiler_TEMPLATE_USHR_LONG
@@ -569,7 +561,6 @@ dvmCompiler_TEMPLATE_USHR_LONG:
mov r1, r1, lsr r2 @ r1<- r1 >>> r2
bx lr
-
/* ------------------------------ */
.balign 4
.global dvmCompiler_TEMPLATE_ADD_FLOAT_VFP
@@ -919,7 +910,6 @@ dvmCompiler_TEMPLATE_CMPG_DOUBLE_VFP:
moveq r0, #0 @ (equal) r0<- 0
bx lr
-
/* ------------------------------ */
.balign 4
.global dvmCompiler_TEMPLATE_CMPL_DOUBLE_VFP
@@ -1226,7 +1216,6 @@ do_memcmp16:
.Lmemcmp16:
.word __memcmp16
-
/* ------------------------------ */
.balign 4
.global dvmCompiler_TEMPLATE_STRING_INDEXOF
@@ -1345,7 +1334,6 @@ match_3:
asr r0, r0, #1
bx lr
-
/* ------------------------------ */
.balign 4
.global dvmCompiler_TEMPLATE_INTERPRET
@@ -1406,7 +1394,6 @@ dvmCompiler_TEMPLATE_MONITOR_ENTER:
#endif
bx r2
-
/* ------------------------------ */
.balign 4
.global dvmCompiler_TEMPLATE_MONITOR_ENTER_DEBUG
@@ -1525,6 +1512,8 @@ dvmCompiler_TEMPLATE_MONITOR_ENTER_DEBUG:
.align 2
.LdvmAsmInstructionStart:
.word dvmAsmInstructionStart
+.LdvmJitToInterpNoChainNoProfile:
+ .word dvmJitToInterpNoChainNoProfile
.LdvmJitToInterpTraceSelectNoChain:
.word dvmJitToInterpTraceSelectNoChain
.LdvmJitToInterpNoChain:
@@ -1552,3 +1541,4 @@ dvmCompiler_TEMPLATE_MONITOR_ENTER_DEBUG:
dmvCompilerTemplateEnd:
#endif /* WITH_JIT */
+
diff --git a/vm/compiler/template/out/CompilerTemplateAsm-armv7-a.S b/vm/compiler/template/out/CompilerTemplateAsm-armv7-a.S
index 54410575f..87a0691bc 100644
--- a/vm/compiler/template/out/CompilerTemplateAsm-armv7-a.S
+++ b/vm/compiler/template/out/CompilerTemplateAsm-armv7-a.S
@@ -101,7 +101,6 @@ unspecified registers or condition codes.
*/
#include "../../../mterp/common/asm-constants.h"
-
/* File: armv5te-vfp/platform.S */
/*
* ===========================================================================
@@ -166,7 +165,6 @@ dvmCompiler_TEMPLATE_CMP_LONG:
mov r0, #1 @ r0<- 1
bx lr
-
/* ------------------------------ */
.balign 4
.global dvmCompiler_TEMPLATE_RETURN
@@ -197,7 +195,7 @@ dvmCompiler_TEMPLATE_RETURN:
#else
blxeq lr @ punt to interpreter and compare state
#endif
- ldr r1, .LdvmJitToInterpNoChain @ defined in footer.S
+ ldr r1, .LdvmJitToInterpNoChainNoProfile @ defined in footer.S
mov rFP, r10 @ publish new FP
ldrne r10, [r2, #offMethod_clazz] @ r10<- method->clazz
ldr r8, [r8] @ r8<- suspendCount
@@ -334,8 +332,6 @@ dvmCompiler_TEMPLATE_INVOKE_METHOD_CHAIN:
bx lr @ return to the callee-chaining cell
-
-
/* ------------------------------ */
.balign 4
.global dvmCompiler_TEMPLATE_INVOKE_METHOD_PREDICTED_CHAIN
@@ -468,9 +464,6 @@ dvmCompiler_TEMPLATE_INVOKE_METHOD_NATIVE:
#endif
mov pc, r1
-
-
-
/* ------------------------------ */
.balign 4
.global dvmCompiler_TEMPLATE_MUL_LONG
@@ -547,7 +540,6 @@ dvmCompiler_TEMPLATE_SHR_LONG:
mov r1, r1, asr r2 @ r1<- r1 >> r2
bx lr
-
/* ------------------------------ */
.balign 4
.global dvmCompiler_TEMPLATE_USHR_LONG
@@ -569,7 +561,6 @@ dvmCompiler_TEMPLATE_USHR_LONG:
mov r1, r1, lsr r2 @ r1<- r1 >>> r2
bx lr
-
/* ------------------------------ */
.balign 4
.global dvmCompiler_TEMPLATE_ADD_FLOAT_VFP
@@ -919,7 +910,6 @@ dvmCompiler_TEMPLATE_CMPG_DOUBLE_VFP:
moveq r0, #0 @ (equal) r0<- 0
bx lr
-
/* ------------------------------ */
.balign 4
.global dvmCompiler_TEMPLATE_CMPL_DOUBLE_VFP
@@ -1226,7 +1216,6 @@ do_memcmp16:
.Lmemcmp16:
.word __memcmp16
-
/* ------------------------------ */
.balign 4
.global dvmCompiler_TEMPLATE_STRING_INDEXOF
@@ -1345,7 +1334,6 @@ match_3:
asr r0, r0, #1
bx lr
-
/* ------------------------------ */
.balign 4
.global dvmCompiler_TEMPLATE_INTERPRET
@@ -1406,7 +1394,6 @@ dvmCompiler_TEMPLATE_MONITOR_ENTER:
#endif
bx r2
-
/* ------------------------------ */
.balign 4
.global dvmCompiler_TEMPLATE_MONITOR_ENTER_DEBUG
@@ -1525,6 +1512,8 @@ dvmCompiler_TEMPLATE_MONITOR_ENTER_DEBUG:
.align 2
.LdvmAsmInstructionStart:
.word dvmAsmInstructionStart
+.LdvmJitToInterpNoChainNoProfile:
+ .word dvmJitToInterpNoChainNoProfile
.LdvmJitToInterpTraceSelectNoChain:
.word dvmJitToInterpTraceSelectNoChain
.LdvmJitToInterpNoChain:
@@ -1552,3 +1541,4 @@ dvmCompiler_TEMPLATE_MONITOR_ENTER_DEBUG:
dmvCompilerTemplateEnd:
#endif /* WITH_JIT */
+
diff --git a/vm/interp/Interp.c b/vm/interp/Interp.c
index daaf0c0da..ab6188232 100644
--- a/vm/interp/Interp.c
+++ b/vm/interp/Interp.c
@@ -1285,7 +1285,13 @@ void dvmInterpret(Thread* self, const Method* method, JValue* pResult)
#endif
};
- assert(self->inJitCodeCache == NULL);
+ /*
+ * If the previous VM left the code cache through single-stepping the
+ * inJitCodeCache flag will be set when the VM is re-entered (for example,
+ * in self-verification mode we single-step NEW_INSTANCE which may re-enter
+ * the VM through findClassFromLoaderNoInit). Because of that, we cannot
+ * assert that self->inJitCodeCache is NULL here.
+ */
#endif
diff --git a/vm/interp/Jit.c b/vm/interp/Jit.c
index 0665dcddb..4129e8a44 100644
--- a/vm/interp/Jit.c
+++ b/vm/interp/Jit.c
@@ -135,7 +135,7 @@ void* dvmSelfVerificationSaveState(const u2* pc, const void* fp,
* Return a pointer to the shadow space for JIT to restore state.
*/
void* dvmSelfVerificationRestoreState(const u2* pc, const void* fp,
- SelfVerificationState exitPoint)
+ SelfVerificationState exitState)
{
Thread *self = dvmThreadSelf();
ShadowSpace *shadowSpace = self->shadowSpace;
@@ -143,6 +143,7 @@ void* dvmSelfVerificationRestoreState(const u2* pc, const void* fp,
InterpState *realGlue = shadowSpace->glue;
shadowSpace->endPC = pc;
shadowSpace->endShadowFP = fp;
+ shadowSpace->jitExitState = exitState;
//LOGD("### selfVerificationRestoreState(%d) pc: 0x%x fp: 0x%x endPC: 0x%x",
// self->threadId, (int)shadowSpace->startPC, (int)shadowSpace->fp,
@@ -161,7 +162,7 @@ void* dvmSelfVerificationRestoreState(const u2* pc, const void* fp,
// Move the resume [ND]PC from the shadow space to the real space so that
// the debug interpreter can return to the translation
- if (exitPoint == kSVSSingleStep) {
+ if (exitState == kSVSSingleStep) {
realGlue->jitResumeNPC = shadowSpace->interpState.jitResumeNPC;
realGlue->jitResumeDPC = shadowSpace->interpState.jitResumeDPC;
} else {
@@ -170,10 +171,10 @@ void* dvmSelfVerificationRestoreState(const u2* pc, const void* fp,
}
// Special case when punting after a single instruction
- if (exitPoint == kSVSPunt && pc == shadowSpace->startPC) {
+ if (exitState == kSVSPunt && pc == shadowSpace->startPC) {
shadowSpace->selfVerificationState = kSVSIdle;
} else {
- shadowSpace->selfVerificationState = exitPoint;
+ shadowSpace->selfVerificationState = exitState;
}
return shadowSpace;
@@ -477,6 +478,9 @@ void dvmJitStats()
LOGD("JIT: Invoke: %d mono, %d poly, %d native, %d return",
gDvmJit.invokeMonomorphic, gDvmJit.invokePolymorphic,
gDvmJit.invokeNative, gDvmJit.returnOp);
+ LOGD("JIT: Inline: %d mgetter, %d msetter, %d pgetter, %d psetter",
+ gDvmJit.invokeMonoGetterInlined, gDvmJit.invokeMonoSetterInlined,
+ gDvmJit.invokePolyGetterInlined, gDvmJit.invokePolySetterInlined);
LOGD("JIT: Total compilation time: %llu ms", gDvmJit.jitTime / 1000);
LOGD("JIT: Avg unit compilation time: %llu us",
gDvmJit.jitTime / gDvmJit.numCompilations);
@@ -607,8 +611,32 @@ static JitEntry *lookupAndAdd(const u2* dPC, bool callerLocked)
}
/*
+ * Append the class ptr of "this" and the current method ptr to the current
+ * trace. That is, the trace runs will contain the following components:
+ * + trace run that ends with an invoke (existing entry)
+ * + thisClass (new)
+ * + calleeMethod (new)
+ */
+static void insertClassMethodInfo(InterpState* interpState,
+ const ClassObject* thisClass,
+ const Method* calleeMethod,
+ const DecodedInstruction* insn)
+{
+ int currTraceRun = ++interpState->currTraceRun;
+ interpState->trace[currTraceRun].meta = (void *) thisClass;
+ currTraceRun = ++interpState->currTraceRun;
+ interpState->trace[currTraceRun].meta = (void *) calleeMethod;
+}
+
+/*
* Check if the next instruction following the invoke is a move-result and if
- * so add it to the trace.
+ * so add it to the trace. That is, this will add the trace run that includes
+ * the move-result to the trace list.
+ *
+ * + trace run that ends with an invoke (existing entry)
+ * + thisClass (existing entry)
+ * + calleeMethod (existing entry)
+ * + move result (new)
*
* lastPC, len, offset are all from the preceding invoke instruction
*/
@@ -631,6 +659,7 @@ static void insertMoveResult(const u2 *lastPC, int len, int offset,
interpState->trace[currTraceRun].frag.numInsts = 1;
interpState->trace[currTraceRun].frag.runEnd = false;
interpState->trace[currTraceRun].frag.hint = kJitHintNone;
+ interpState->trace[currTraceRun].frag.isCode = true;
interpState->totalTraceLen++;
interpState->currRunLen = dexGetInstrOrTableWidthAbs(gDvm.instrWidth,
@@ -653,11 +682,14 @@ static void insertMoveResult(const u2 *lastPC, int len, int offset,
* because returns cannot throw in a way that causes problems for the
* translated code.
*/
-int dvmCheckJit(const u2* pc, Thread* self, InterpState* interpState)
+int dvmCheckJit(const u2* pc, Thread* self, InterpState* interpState,
+ const ClassObject* thisClass, const Method* curMethod)
{
int flags, len;
int switchInterp = false;
bool debugOrProfile = dvmDebuggerOrProfilerActive();
+ /* Stay in the dbg interpreter for the next instruction */
+ bool stayOneMoreInst = false;
/*
* Bug 2710533 - dalvik crash when disconnecting debugger
@@ -711,6 +743,7 @@ int dvmCheckJit(const u2* pc, Thread* self, InterpState* interpState)
interpState->trace[currTraceRun].frag.numInsts = 0;
interpState->trace[currTraceRun].frag.runEnd = false;
interpState->trace[currTraceRun].frag.hint = kJitHintNone;
+ interpState->trace[currTraceRun].frag.isCode = true;
}
interpState->trace[interpState->currTraceRun].frag.numInsts++;
interpState->totalTraceLen++;
@@ -742,10 +775,14 @@ int dvmCheckJit(const u2* pc, Thread* self, InterpState* interpState)
#endif
/*
+ * If the current invoke is a {virtual,interface}, get the
+ * current class/method pair into the trace as well.
* If the next instruction is a variant of move-result, insert
- * it to the trace as well.
+ * it to the trace too.
*/
if (flags & kInstrInvoke) {
+ insertClassMethodInfo(interpState, thisClass, curMethod,
+ &decInsn);
insertMoveResult(lastPC, len, offset, interpState);
}
}
@@ -764,6 +801,18 @@ int dvmCheckJit(const u2* pc, Thread* self, InterpState* interpState)
if ((flags & kInstrCanReturn) != kInstrCanReturn) {
break;
}
+ else {
+ /*
+ * Last instruction is a return - stay in the dbg interpreter
+ * for one more instruction if it is a non-void return, since
+ * we don't want to start a trace with move-result as the first
+ * instruction (which is already included in the trace
+ * containing the invoke.
+ */
+ if (decInsn.opCode != OP_RETURN_VOID) {
+ stayOneMoreInst = true;
+ }
+ }
/* NOTE: intentional fallthrough for returns */
case kJitTSelectEnd:
{
@@ -774,9 +823,25 @@ int dvmCheckJit(const u2* pc, Thread* self, InterpState* interpState)
switchInterp = true;
break;
}
+
+ int lastTraceDesc = interpState->currTraceRun;
+
+ /* Extend a new empty desc if the last slot is meta info */
+ if (!interpState->trace[lastTraceDesc].frag.isCode) {
+ lastTraceDesc = ++interpState->currTraceRun;
+ interpState->trace[lastTraceDesc].frag.startOffset = 0;
+ interpState->trace[lastTraceDesc].frag.numInsts = 0;
+ interpState->trace[lastTraceDesc].frag.hint = kJitHintNone;
+ interpState->trace[lastTraceDesc].frag.isCode = true;
+ }
+
+ /* Mark the end of the trace runs */
+ interpState->trace[lastTraceDesc].frag.runEnd = true;
+
JitTraceDescription* desc =
(JitTraceDescription*)malloc(sizeof(JitTraceDescription) +
sizeof(JitTraceRun) * (interpState->currTraceRun+1));
+
if (desc == NULL) {
LOGE("Out of memory in trace selection");
dvmJitStopTranslationRequests();
@@ -784,8 +849,7 @@ int dvmCheckJit(const u2* pc, Thread* self, InterpState* interpState)
switchInterp = true;
break;
}
- interpState->trace[interpState->currTraceRun].frag.runEnd =
- true;
+
desc->method = interpState->method;
memcpy((char*)&(desc->trace[0]),
(char*)&(interpState->trace[0]),
@@ -859,7 +923,7 @@ int dvmCheckJit(const u2* pc, Thread* self, InterpState* interpState)
*/
assert(switchInterp == false || interpState->jitState == kJitDone ||
interpState->jitState == kJitNot);
- return switchInterp && !debugOrProfile;
+ return switchInterp && !debugOrProfile && !stayOneMoreInst;
}
JitEntry *dvmFindJitEntry(const u2* pc)
@@ -1095,6 +1159,7 @@ bool dvmJitCheckTraceRequest(Thread* self, InterpState* interpState)
interpState->trace[0].frag.numInsts = 0;
interpState->trace[0].frag.runEnd = false;
interpState->trace[0].frag.hint = kJitHintNone;
+ interpState->trace[0].frag.isCode = true;
interpState->lastPC = 0;
break;
/*
diff --git a/vm/interp/Jit.h b/vm/interp/Jit.h
index 9d17a5268..6101f54ae 100644
--- a/vm/interp/Jit.h
+++ b/vm/interp/Jit.h
@@ -43,7 +43,8 @@ typedef struct ShadowSpace {
const u2* startPC; /* starting pc of jitted region */
const void* fp; /* starting fp of jitted region */
void* glue; /* starting glue of jitted region */
- SelfVerificationState selfVerificationState; /* self verification state */
+ SelfVerificationState jitExitState; /* exit point for JIT'ed code */
+ SelfVerificationState selfVerificationState; /* current SV running state */
const u2* endPC; /* ending pc of jitted region */
void* shadowFP; /* pointer to fp in shadow space */
InterpState interpState; /* copy of interpState */
@@ -108,7 +109,8 @@ typedef struct JitEntry {
void* codeAddress; /* Code address of native translation */
} JitEntry;
-int dvmCheckJit(const u2* pc, Thread* self, InterpState* interpState);
+int dvmCheckJit(const u2* pc, Thread* self, InterpState* interpState,
+ const ClassObject *callsiteClass, const Method* curMethod);
void* dvmJitGetCodeAddr(const u2* dPC);
bool dvmJitCheckTraceRequest(Thread* self, InterpState* interpState);
void dvmJitStopTranslationRequests(void);
diff --git a/vm/mterp/armv5te/entry.S b/vm/mterp/armv5te/entry.S
index 881c0e0ca..eddac5300 100644
--- a/vm/mterp/armv5te/entry.S
+++ b/vm/mterp/armv5te/entry.S
@@ -68,14 +68,27 @@ dvmMterpStdRun:
#if defined(WITH_JIT)
.LentryInstr:
- ldr r10, [rGLUE, #offGlue_self] @ callee saved r10 <- glue->self
+ ldr r10, [rGLUE, #offGlue_self] @ callee saved r10 <- glue->self
/* Entry is always a possible trace start */
GET_JIT_PROF_TABLE(r0)
FETCH_INST()
- mov r1, #0 @ prepare the value for the new state
- str r1, [r10, #offThread_inJitCodeCache] @ back to the interp land
- cmp r0,#0
- bne common_updateProfile
+ mov r1, #0 @ prepare the value for the new state
+ str r1, [r10, #offThread_inJitCodeCache] @ back to the interp land
+ cmp r0,#0 @ is profiling disabled?
+#if !defined(WITH_SELF_VERIFICATION)
+ bne common_updateProfile @ profiling is enabled
+#else
+ ldr r2, [r10, #offThread_shadowSpace] @ to find out the jit exit state
+ beq 1f @ profiling is disabled
+ ldr r3, [r2, #offShadowSpace_jitExitState] @ jit exit state
+ cmp r3, #kSVSTraceSelect @ hot trace following?
+ moveq r2,#kJitTSelectRequestHot @ ask for trace selection
+ beq common_selectTrace @ go build the trace
+ cmp r3, #kSVSNoProfile @ don't profile the next instruction?
+ beq 1f @ intrepret the next instruction
+ b common_updateProfile @ collect profiles
+#endif
+1:
GET_INST_OPCODE(ip)
GOTO_OPCODE(ip)
#else
diff --git a/vm/mterp/armv5te/footer.S b/vm/mterp/armv5te/footer.S
index 72eb5ce6e..3212126c0 100644
--- a/vm/mterp/armv5te/footer.S
+++ b/vm/mterp/armv5te/footer.S
@@ -27,12 +27,21 @@ dvmJitToInterpSingleStep:
mov r2,#kSVSSingleStep @ r2<- interpreter entry point
b jitSVShadowRunEnd @ doesn't return
+ .global dvmJitToInterpNoChainNoProfile
+dvmJitToInterpNoChainNoProfile:
+ ldr r10, [rGLUE, #offGlue_self] @ callee saved r10 <- glue->self
+ mov r0,rPC @ pass our target PC
+ mov r2,#kSVSNoProfile @ r2<- interpreter entry point
+ mov r3, #0 @ 0 means !inJitCodeCache
+ str r3, [r10, #offThread_inJitCodeCache] @ back to the interp land
+ b jitSVShadowRunEnd @ doesn't return
+
.global dvmJitToInterpTraceSelectNoChain
dvmJitToInterpTraceSelectNoChain:
ldr r10, [rGLUE, #offGlue_self] @ callee saved r10 <- glue->self
mov r0,rPC @ pass our target PC
- mov r2,#kSVSTraceSelectNoChain @ r2<- interpreter entry point
- mov r3, #0
+ mov r2,#kSVSTraceSelect @ r2<- interpreter entry point
+ mov r3, #0 @ 0 means !inJitCodeCache
str r3, [r10, #offThread_inJitCodeCache] @ Back to the interp land
b jitSVShadowRunEnd @ doesn't return
@@ -41,7 +50,7 @@ dvmJitToInterpTraceSelect:
ldr r10, [rGLUE, #offGlue_self] @ callee saved r10 <- glue->self
ldr r0,[lr, #-1] @ pass our target PC
mov r2,#kSVSTraceSelect @ r2<- interpreter entry point
- mov r3, #0
+ mov r3, #0 @ 0 means !inJitCodeCache
str r3, [r10, #offThread_inJitCodeCache] @ Back to the interp land
b jitSVShadowRunEnd @ doesn't return
@@ -50,7 +59,7 @@ dvmJitToInterpBackwardBranch:
ldr r10, [rGLUE, #offGlue_self] @ callee saved r10 <- glue->self
ldr r0,[lr, #-1] @ pass our target PC
mov r2,#kSVSBackwardBranch @ r2<- interpreter entry point
- mov r3, #0
+ mov r3, #0 @ 0 means !inJitCodeCache
str r3, [r10, #offThread_inJitCodeCache] @ Back to the interp land
b jitSVShadowRunEnd @ doesn't return
@@ -59,7 +68,7 @@ dvmJitToInterpNormal:
ldr r10, [rGLUE, #offGlue_self] @ callee saved r10 <- glue->self
ldr r0,[lr, #-1] @ pass our target PC
mov r2,#kSVSNormal @ r2<- interpreter entry point
- mov r3, #0
+ mov r3, #0 @ 0 means !inJitCodeCache
str r3, [r10, #offThread_inJitCodeCache] @ Back to the interp land
b jitSVShadowRunEnd @ doesn't return
@@ -68,7 +77,7 @@ dvmJitToInterpNoChain:
ldr r10, [rGLUE, #offGlue_self] @ callee saved r10 <- glue->self
mov r0,rPC @ pass our target PC
mov r2,#kSVSNoChain @ r2<- interpreter entry point
- mov r3, #0
+ mov r3, #0 @ 0 means !inJitCodeCache
str r3, [r10, #offThread_inJitCodeCache] @ Back to the interp land
b jitSVShadowRunEnd @ doesn't return
#else
@@ -133,9 +142,9 @@ dvmJitToInterpTraceSelectNoChain:
str r0, [r10, #offThread_inJitCodeCache] @ set the inJitCodeCache flag
mov r1, rPC @ arg1 of translation may need this
mov lr, #0 @ in case target is HANDLER_INTERPRET
- cmp r0,#0
+ cmp r0,#0 @ !0 means translation exists
bxne r0 @ continue native execution if so
- b 2f
+ b 2f @ branch over to use the interpreter
/*
* Return from the translation cache and immediately request
@@ -212,6 +221,29 @@ dvmJitToInterpNormal:
* Return from the translation cache to the interpreter to do method invocation.
* Check if translation exists for the callee, but don't chain to it.
*/
+ .global dvmJitToInterpNoChainNoProfile
+dvmJitToInterpNoChainNoProfile:
+#if defined(WITH_JIT_TUNING)
+ bl dvmBumpNoChain
+#endif
+ ldr r10, [rGLUE, #offGlue_self] @ callee saved r10 <- glue->self
+ mov r0,rPC
+ bl dvmJitGetCodeAddr @ Is there a translation?
+ str r0, [r10, #offThread_inJitCodeCache] @ set the inJitCodeCache flag
+ mov r1, rPC @ arg1 of translation may need this
+ mov lr, #0 @ in case target is HANDLER_INTERPRET
+ cmp r0,#0
+ bxne r0 @ continue native execution if so
+ EXPORT_PC()
+ adrl rIBASE, dvmAsmInstructionStart
+ FETCH_INST()
+ GET_INST_OPCODE(ip) @ extract opcode from rINST
+ GOTO_OPCODE(ip) @ jump to next instruction
+
+/*
+ * Return from the translation cache to the interpreter to do method invocation.
+ * Check if translation exists for the callee, but don't chain to it.
+ */
.global dvmJitToInterpNoChain
dvmJitToInterpNoChain:
#if defined(WITH_JIT_TUNING)
@@ -239,6 +271,7 @@ toInterpreter:
FETCH_INST()
GET_JIT_PROF_TABLE(r0)
@ NOTE: intended fallthrough
+
/*
* Common code to update potential trace start counter, and initiate
* a trace-build if appropriate. On entry, rPC should point to the
@@ -779,15 +812,12 @@ common_returnFromMethod:
str rFP, [r3, #offThread_curFrame] @ self->curFrame = fp
#if defined(WITH_JIT)
ldr r10, [r0, #offStackSaveArea_returnAddr] @ r10 = saveArea->returnAddr
- GET_JIT_PROF_TABLE(r0)
mov rPC, r9 @ publish new rPC
str r1, [rGLUE, #offGlue_methodClassDex]
str r10, [r3, #offThread_inJitCodeCache] @ may return to JIT'ed land
cmp r10, #0 @ caller is compiled code
blxne r10
GET_INST_OPCODE(ip) @ extract opcode from rINST
- cmp r0,#0
- bne common_updateProfile
GOTO_OPCODE(ip) @ jump to next instruction
#else
GET_INST_OPCODE(ip) @ extract opcode from rINST
diff --git a/vm/mterp/c/gotoTargets.c b/vm/mterp/c/gotoTargets.c
index 842171d86..b17fb80d2 100644
--- a/vm/mterp/c/gotoTargets.c
+++ b/vm/mterp/c/gotoTargets.c
@@ -154,6 +154,10 @@ GOTO_TARGET(invokeVirtual, bool methodCallRange)
assert(baseMethod->methodIndex < thisPtr->clazz->vtableCount);
methodToCall = thisPtr->clazz->vtable[baseMethod->methodIndex];
+#if defined(WITH_JIT) && (INTERP_TYPE == INTERP_DBG)
+ callsiteClass = thisPtr->clazz;
+#endif
+
#if 0
if (dvmIsAbstractMethod(methodToCall)) {
/*
@@ -305,6 +309,10 @@ GOTO_TARGET(invokeInterface, bool methodCallRange)
thisClass = thisPtr->clazz;
+#if defined(WITH_JIT) && (INTERP_TYPE == INTERP_DBG)
+ callsiteClass = thisClass;
+#endif
+
/*
* Given a class and a method index, find the Method* with the
* actual code we want to execute.
@@ -419,6 +427,10 @@ GOTO_TARGET(invokeVirtualQuick, bool methodCallRange)
if (!checkForNull(thisPtr))
GOTO_exceptionThrown();
+#if defined(WITH_JIT) && (INTERP_TYPE == INTERP_DBG)
+ callsiteClass = thisPtr->clazz;
+#endif
+
/*
* Combine the object we found with the vtable offset in the
* method.
diff --git a/vm/mterp/common/asm-constants.h b/vm/mterp/common/asm-constants.h
index bcff8f096..475b89719 100644
--- a/vm/mterp/common/asm-constants.h
+++ b/vm/mterp/common/asm-constants.h
@@ -184,12 +184,13 @@ MTERP_SIZEOF(sizeofStackSaveArea, StackSaveArea, 20)
/* ShadowSpace fields */
#if defined(WITH_JIT) && defined(WITH_SELF_VERIFICATION)
-MTERP_OFFSET(offShadowSpace_startPC, ShadowSpace, startPC, 0)
-MTERP_OFFSET(offShadowSpace_fp, ShadowSpace, fp, 4)
-MTERP_OFFSET(offShadowSpace_glue, ShadowSpace, glue, 8)
-MTERP_OFFSET(offShadowSpace_svState, ShadowSpace, selfVerificationState, 12)
-MTERP_OFFSET(offShadowSpace_shadowFP, ShadowSpace, shadowFP, 20)
-MTERP_OFFSET(offShadowSpace_interpState, ShadowSpace, interpState, 24)
+MTERP_OFFSET(offShadowSpace_startPC, ShadowSpace, startPC, 0)
+MTERP_OFFSET(offShadowSpace_fp, ShadowSpace, fp, 4)
+MTERP_OFFSET(offShadowSpace_glue, ShadowSpace, glue, 8)
+MTERP_OFFSET(offShadowSpace_jitExitState,ShadowSpace, jitExitState, 12)
+MTERP_OFFSET(offShadowSpace_svState, ShadowSpace, selfVerificationState, 16)
+MTERP_OFFSET(offShadowSpace_shadowFP, ShadowSpace, shadowFP, 24)
+MTERP_OFFSET(offShadowSpace_interpState, ShadowSpace, interpState, 32)
#endif
/* InstField fields */
@@ -226,6 +227,16 @@ MTERP_OFFSET(offThread_exception, Thread, exception, 48)
#if defined(WITH_JIT)
MTERP_OFFSET(offThread_inJitCodeCache, Thread, inJitCodeCache, 76)
+#if defined(WITH_SELF_VERIFICATION)
+MTERP_OFFSET(offThread_shadowSpace, Thread, shadowSpace, 80)
+#ifdef USE_INDIRECT_REF
+MTERP_OFFSET(offThread_jniLocal_topCookie, \
+ Thread, jniLocalRefTable.segmentState.all, 84)
+#else
+MTERP_OFFSET(offThread_jniLocal_topCookie, \
+ Thread, jniLocalRefTable.nextEntry, 84)
+#endif
+#else
#ifdef USE_INDIRECT_REF
MTERP_OFFSET(offThread_jniLocal_topCookie, \
Thread, jniLocalRefTable.segmentState.all, 80)
@@ -233,6 +244,7 @@ MTERP_OFFSET(offThread_jniLocal_topCookie, \
MTERP_OFFSET(offThread_jniLocal_topCookie, \
Thread, jniLocalRefTable.nextEntry, 80)
#endif
+#endif
#else
#ifdef USE_INDIRECT_REF
MTERP_OFFSET(offThread_jniLocal_topCookie, \
@@ -313,7 +325,7 @@ MTERP_CONSTANT(kSVSIdle, 0)
MTERP_CONSTANT(kSVSStart, 1)
MTERP_CONSTANT(kSVSPunt, 2)
MTERP_CONSTANT(kSVSSingleStep, 3)
-MTERP_CONSTANT(kSVSTraceSelectNoChain, 4)
+MTERP_CONSTANT(kSVSNoProfile, 4)
MTERP_CONSTANT(kSVSTraceSelect, 5)
MTERP_CONSTANT(kSVSNormal, 6)
MTERP_CONSTANT(kSVSNoChain, 7)
diff --git a/vm/mterp/out/InterpAsm-armv4t.S b/vm/mterp/out/InterpAsm-armv4t.S
index d82272f7f..5ce80ff79 100644
--- a/vm/mterp/out/InterpAsm-armv4t.S
+++ b/vm/mterp/out/InterpAsm-armv4t.S
@@ -320,14 +320,27 @@ dvmMterpStdRun:
#if defined(WITH_JIT)
.LentryInstr:
- ldr r10, [rGLUE, #offGlue_self] @ callee saved r10 <- glue->self
+ ldr r10, [rGLUE, #offGlue_self] @ callee saved r10 <- glue->self
/* Entry is always a possible trace start */
GET_JIT_PROF_TABLE(r0)
FETCH_INST()
- mov r1, #0 @ prepare the value for the new state
- str r1, [r10, #offThread_inJitCodeCache] @ back to the interp land
- cmp r0,#0
- bne common_updateProfile
+ mov r1, #0 @ prepare the value for the new state
+ str r1, [r10, #offThread_inJitCodeCache] @ back to the interp land
+ cmp r0,#0 @ is profiling disabled?
+#if !defined(WITH_SELF_VERIFICATION)
+ bne common_updateProfile @ profiling is enabled
+#else
+ ldr r2, [r10, #offThread_shadowSpace] @ to find out the jit exit state
+ beq 1f @ profiling is disabled
+ ldr r3, [r2, #offShadowSpace_jitExitState] @ jit exit state
+ cmp r3, #kSVSTraceSelect @ hot trace following?
+ moveq r2,#kJitTSelectRequestHot @ ask for trace selection
+ beq common_selectTrace @ go build the trace
+ cmp r3, #kSVSNoProfile @ don't profile the next instruction?
+ beq 1f @ intrepret the next instruction
+ b common_updateProfile @ collect profiles
+#endif
+1:
GET_INST_OPCODE(ip)
GOTO_OPCODE(ip)
#else
@@ -9862,12 +9875,21 @@ dvmJitToInterpSingleStep:
mov r2,#kSVSSingleStep @ r2<- interpreter entry point
b jitSVShadowRunEnd @ doesn't return
+ .global dvmJitToInterpNoChainNoProfile
+dvmJitToInterpNoChainNoProfile:
+ ldr r10, [rGLUE, #offGlue_self] @ callee saved r10 <- glue->self
+ mov r0,rPC @ pass our target PC
+ mov r2,#kSVSNoProfile @ r2<- interpreter entry point
+ mov r3, #0 @ 0 means !inJitCodeCache
+ str r3, [r10, #offThread_inJitCodeCache] @ back to the interp land
+ b jitSVShadowRunEnd @ doesn't return
+
.global dvmJitToInterpTraceSelectNoChain
dvmJitToInterpTraceSelectNoChain:
ldr r10, [rGLUE, #offGlue_self] @ callee saved r10 <- glue->self
mov r0,rPC @ pass our target PC
- mov r2,#kSVSTraceSelectNoChain @ r2<- interpreter entry point
- mov r3, #0
+ mov r2,#kSVSTraceSelect @ r2<- interpreter entry point
+ mov r3, #0 @ 0 means !inJitCodeCache
str r3, [r10, #offThread_inJitCodeCache] @ Back to the interp land
b jitSVShadowRunEnd @ doesn't return
@@ -9876,7 +9898,7 @@ dvmJitToInterpTraceSelect:
ldr r10, [rGLUE, #offGlue_self] @ callee saved r10 <- glue->self
ldr r0,[lr, #-1] @ pass our target PC
mov r2,#kSVSTraceSelect @ r2<- interpreter entry point
- mov r3, #0
+ mov r3, #0 @ 0 means !inJitCodeCache
str r3, [r10, #offThread_inJitCodeCache] @ Back to the interp land
b jitSVShadowRunEnd @ doesn't return
@@ -9885,7 +9907,7 @@ dvmJitToInterpBackwardBranch:
ldr r10, [rGLUE, #offGlue_self] @ callee saved r10 <- glue->self
ldr r0,[lr, #-1] @ pass our target PC
mov r2,#kSVSBackwardBranch @ r2<- interpreter entry point
- mov r3, #0
+ mov r3, #0 @ 0 means !inJitCodeCache
str r3, [r10, #offThread_inJitCodeCache] @ Back to the interp land
b jitSVShadowRunEnd @ doesn't return
@@ -9894,7 +9916,7 @@ dvmJitToInterpNormal:
ldr r10, [rGLUE, #offGlue_self] @ callee saved r10 <- glue->self
ldr r0,[lr, #-1] @ pass our target PC
mov r2,#kSVSNormal @ r2<- interpreter entry point
- mov r3, #0
+ mov r3, #0 @ 0 means !inJitCodeCache
str r3, [r10, #offThread_inJitCodeCache] @ Back to the interp land
b jitSVShadowRunEnd @ doesn't return
@@ -9903,7 +9925,7 @@ dvmJitToInterpNoChain:
ldr r10, [rGLUE, #offGlue_self] @ callee saved r10 <- glue->self
mov r0,rPC @ pass our target PC
mov r2,#kSVSNoChain @ r2<- interpreter entry point
- mov r3, #0
+ mov r3, #0 @ 0 means !inJitCodeCache
str r3, [r10, #offThread_inJitCodeCache] @ Back to the interp land
b jitSVShadowRunEnd @ doesn't return
#else
@@ -9968,9 +9990,9 @@ dvmJitToInterpTraceSelectNoChain:
str r0, [r10, #offThread_inJitCodeCache] @ set the inJitCodeCache flag
mov r1, rPC @ arg1 of translation may need this
mov lr, #0 @ in case target is HANDLER_INTERPRET
- cmp r0,#0
+ cmp r0,#0 @ !0 means translation exists
bxne r0 @ continue native execution if so
- b 2f
+ b 2f @ branch over to use the interpreter
/*
* Return from the translation cache and immediately request
@@ -10047,6 +10069,29 @@ dvmJitToInterpNormal:
* Return from the translation cache to the interpreter to do method invocation.
* Check if translation exists for the callee, but don't chain to it.
*/
+ .global dvmJitToInterpNoChainNoProfile
+dvmJitToInterpNoChainNoProfile:
+#if defined(WITH_JIT_TUNING)
+ bl dvmBumpNoChain
+#endif
+ ldr r10, [rGLUE, #offGlue_self] @ callee saved r10 <- glue->self
+ mov r0,rPC
+ bl dvmJitGetCodeAddr @ Is there a translation?
+ str r0, [r10, #offThread_inJitCodeCache] @ set the inJitCodeCache flag
+ mov r1, rPC @ arg1 of translation may need this
+ mov lr, #0 @ in case target is HANDLER_INTERPRET
+ cmp r0,#0
+ bxne r0 @ continue native execution if so
+ EXPORT_PC()
+ adrl rIBASE, dvmAsmInstructionStart
+ FETCH_INST()
+ GET_INST_OPCODE(ip) @ extract opcode from rINST
+ GOTO_OPCODE(ip) @ jump to next instruction
+
+/*
+ * Return from the translation cache to the interpreter to do method invocation.
+ * Check if translation exists for the callee, but don't chain to it.
+ */
.global dvmJitToInterpNoChain
dvmJitToInterpNoChain:
#if defined(WITH_JIT_TUNING)
@@ -10074,6 +10119,7 @@ toInterpreter:
FETCH_INST()
GET_JIT_PROF_TABLE(r0)
@ NOTE: intended fallthrough
+
/*
* Common code to update potential trace start counter, and initiate
* a trace-build if appropriate. On entry, rPC should point to the
@@ -10614,15 +10660,12 @@ common_returnFromMethod:
str rFP, [r3, #offThread_curFrame] @ self->curFrame = fp
#if defined(WITH_JIT)
ldr r10, [r0, #offStackSaveArea_returnAddr] @ r10 = saveArea->returnAddr
- GET_JIT_PROF_TABLE(r0)
mov rPC, r9 @ publish new rPC
str r1, [rGLUE, #offGlue_methodClassDex]
str r10, [r3, #offThread_inJitCodeCache] @ may return to JIT'ed land
cmp r10, #0 @ caller is compiled code
blxne r10
GET_INST_OPCODE(ip) @ extract opcode from rINST
- cmp r0,#0
- bne common_updateProfile
GOTO_OPCODE(ip) @ jump to next instruction
#else
GET_INST_OPCODE(ip) @ extract opcode from rINST
diff --git a/vm/mterp/out/InterpAsm-armv5te-vfp.S b/vm/mterp/out/InterpAsm-armv5te-vfp.S
index 633a32d19..6421454ba 100644
--- a/vm/mterp/out/InterpAsm-armv5te-vfp.S
+++ b/vm/mterp/out/InterpAsm-armv5te-vfp.S
@@ -320,14 +320,27 @@ dvmMterpStdRun:
#if defined(WITH_JIT)
.LentryInstr:
- ldr r10, [rGLUE, #offGlue_self] @ callee saved r10 <- glue->self
+ ldr r10, [rGLUE, #offGlue_self] @ callee saved r10 <- glue->self
/* Entry is always a possible trace start */
GET_JIT_PROF_TABLE(r0)
FETCH_INST()
- mov r1, #0 @ prepare the value for the new state
- str r1, [r10, #offThread_inJitCodeCache] @ back to the interp land
- cmp r0,#0
- bne common_updateProfile
+ mov r1, #0 @ prepare the value for the new state
+ str r1, [r10, #offThread_inJitCodeCache] @ back to the interp land
+ cmp r0,#0 @ is profiling disabled?
+#if !defined(WITH_SELF_VERIFICATION)
+ bne common_updateProfile @ profiling is enabled
+#else
+ ldr r2, [r10, #offThread_shadowSpace] @ to find out the jit exit state
+ beq 1f @ profiling is disabled
+ ldr r3, [r2, #offShadowSpace_jitExitState] @ jit exit state
+ cmp r3, #kSVSTraceSelect @ hot trace following?
+ moveq r2,#kJitTSelectRequestHot @ ask for trace selection
+ beq common_selectTrace @ go build the trace
+ cmp r3, #kSVSNoProfile @ don't profile the next instruction?
+ beq 1f @ intrepret the next instruction
+ b common_updateProfile @ collect profiles
+#endif
+1:
GET_INST_OPCODE(ip)
GOTO_OPCODE(ip)
#else
@@ -9400,12 +9413,21 @@ dvmJitToInterpSingleStep:
mov r2,#kSVSSingleStep @ r2<- interpreter entry point
b jitSVShadowRunEnd @ doesn't return
+ .global dvmJitToInterpNoChainNoProfile
+dvmJitToInterpNoChainNoProfile:
+ ldr r10, [rGLUE, #offGlue_self] @ callee saved r10 <- glue->self
+ mov r0,rPC @ pass our target PC
+ mov r2,#kSVSNoProfile @ r2<- interpreter entry point
+ mov r3, #0 @ 0 means !inJitCodeCache
+ str r3, [r10, #offThread_inJitCodeCache] @ back to the interp land
+ b jitSVShadowRunEnd @ doesn't return
+
.global dvmJitToInterpTraceSelectNoChain
dvmJitToInterpTraceSelectNoChain:
ldr r10, [rGLUE, #offGlue_self] @ callee saved r10 <- glue->self
mov r0,rPC @ pass our target PC
- mov r2,#kSVSTraceSelectNoChain @ r2<- interpreter entry point
- mov r3, #0
+ mov r2,#kSVSTraceSelect @ r2<- interpreter entry point
+ mov r3, #0 @ 0 means !inJitCodeCache
str r3, [r10, #offThread_inJitCodeCache] @ Back to the interp land
b jitSVShadowRunEnd @ doesn't return
@@ -9414,7 +9436,7 @@ dvmJitToInterpTraceSelect:
ldr r10, [rGLUE, #offGlue_self] @ callee saved r10 <- glue->self
ldr r0,[lr, #-1] @ pass our target PC
mov r2,#kSVSTraceSelect @ r2<- interpreter entry point
- mov r3, #0
+ mov r3, #0 @ 0 means !inJitCodeCache
str r3, [r10, #offThread_inJitCodeCache] @ Back to the interp land
b jitSVShadowRunEnd @ doesn't return
@@ -9423,7 +9445,7 @@ dvmJitToInterpBackwardBranch:
ldr r10, [rGLUE, #offGlue_self] @ callee saved r10 <- glue->self
ldr r0,[lr, #-1] @ pass our target PC
mov r2,#kSVSBackwardBranch @ r2<- interpreter entry point
- mov r3, #0
+ mov r3, #0 @ 0 means !inJitCodeCache
str r3, [r10, #offThread_inJitCodeCache] @ Back to the interp land
b jitSVShadowRunEnd @ doesn't return
@@ -9432,7 +9454,7 @@ dvmJitToInterpNormal:
ldr r10, [rGLUE, #offGlue_self] @ callee saved r10 <- glue->self
ldr r0,[lr, #-1] @ pass our target PC
mov r2,#kSVSNormal @ r2<- interpreter entry point
- mov r3, #0
+ mov r3, #0 @ 0 means !inJitCodeCache
str r3, [r10, #offThread_inJitCodeCache] @ Back to the interp land
b jitSVShadowRunEnd @ doesn't return
@@ -9441,7 +9463,7 @@ dvmJitToInterpNoChain:
ldr r10, [rGLUE, #offGlue_self] @ callee saved r10 <- glue->self
mov r0,rPC @ pass our target PC
mov r2,#kSVSNoChain @ r2<- interpreter entry point
- mov r3, #0
+ mov r3, #0 @ 0 means !inJitCodeCache
str r3, [r10, #offThread_inJitCodeCache] @ Back to the interp land
b jitSVShadowRunEnd @ doesn't return
#else
@@ -9506,9 +9528,9 @@ dvmJitToInterpTraceSelectNoChain:
str r0, [r10, #offThread_inJitCodeCache] @ set the inJitCodeCache flag
mov r1, rPC @ arg1 of translation may need this
mov lr, #0 @ in case target is HANDLER_INTERPRET
- cmp r0,#0
+ cmp r0,#0 @ !0 means translation exists
bxne r0 @ continue native execution if so
- b 2f
+ b 2f @ branch over to use the interpreter
/*
* Return from the translation cache and immediately request
@@ -9585,6 +9607,29 @@ dvmJitToInterpNormal:
* Return from the translation cache to the interpreter to do method invocation.
* Check if translation exists for the callee, but don't chain to it.
*/
+ .global dvmJitToInterpNoChainNoProfile
+dvmJitToInterpNoChainNoProfile:
+#if defined(WITH_JIT_TUNING)
+ bl dvmBumpNoChain
+#endif
+ ldr r10, [rGLUE, #offGlue_self] @ callee saved r10 <- glue->self
+ mov r0,rPC
+ bl dvmJitGetCodeAddr @ Is there a translation?
+ str r0, [r10, #offThread_inJitCodeCache] @ set the inJitCodeCache flag
+ mov r1, rPC @ arg1 of translation may need this
+ mov lr, #0 @ in case target is HANDLER_INTERPRET
+ cmp r0,#0
+ bxne r0 @ continue native execution if so
+ EXPORT_PC()
+ adrl rIBASE, dvmAsmInstructionStart
+ FETCH_INST()
+ GET_INST_OPCODE(ip) @ extract opcode from rINST
+ GOTO_OPCODE(ip) @ jump to next instruction
+
+/*
+ * Return from the translation cache to the interpreter to do method invocation.
+ * Check if translation exists for the callee, but don't chain to it.
+ */
.global dvmJitToInterpNoChain
dvmJitToInterpNoChain:
#if defined(WITH_JIT_TUNING)
@@ -9612,6 +9657,7 @@ toInterpreter:
FETCH_INST()
GET_JIT_PROF_TABLE(r0)
@ NOTE: intended fallthrough
+
/*
* Common code to update potential trace start counter, and initiate
* a trace-build if appropriate. On entry, rPC should point to the
@@ -10152,15 +10198,12 @@ common_returnFromMethod:
str rFP, [r3, #offThread_curFrame] @ self->curFrame = fp
#if defined(WITH_JIT)
ldr r10, [r0, #offStackSaveArea_returnAddr] @ r10 = saveArea->returnAddr
- GET_JIT_PROF_TABLE(r0)
mov rPC, r9 @ publish new rPC
str r1, [rGLUE, #offGlue_methodClassDex]
str r10, [r3, #offThread_inJitCodeCache] @ may return to JIT'ed land
cmp r10, #0 @ caller is compiled code
blxne r10
GET_INST_OPCODE(ip) @ extract opcode from rINST
- cmp r0,#0
- bne common_updateProfile
GOTO_OPCODE(ip) @ jump to next instruction
#else
GET_INST_OPCODE(ip) @ extract opcode from rINST
diff --git a/vm/mterp/out/InterpAsm-armv5te.S b/vm/mterp/out/InterpAsm-armv5te.S
index 66f3a3d7c..f756471fa 100644
--- a/vm/mterp/out/InterpAsm-armv5te.S
+++ b/vm/mterp/out/InterpAsm-armv5te.S
@@ -320,14 +320,27 @@ dvmMterpStdRun:
#if defined(WITH_JIT)
.LentryInstr:
- ldr r10, [rGLUE, #offGlue_self] @ callee saved r10 <- glue->self
+ ldr r10, [rGLUE, #offGlue_self] @ callee saved r10 <- glue->self
/* Entry is always a possible trace start */
GET_JIT_PROF_TABLE(r0)
FETCH_INST()
- mov r1, #0 @ prepare the value for the new state
- str r1, [r10, #offThread_inJitCodeCache] @ back to the interp land
- cmp r0,#0
- bne common_updateProfile
+ mov r1, #0 @ prepare the value for the new state
+ str r1, [r10, #offThread_inJitCodeCache] @ back to the interp land
+ cmp r0,#0 @ is profiling disabled?
+#if !defined(WITH_SELF_VERIFICATION)
+ bne common_updateProfile @ profiling is enabled
+#else
+ ldr r2, [r10, #offThread_shadowSpace] @ to find out the jit exit state
+ beq 1f @ profiling is disabled
+ ldr r3, [r2, #offShadowSpace_jitExitState] @ jit exit state
+ cmp r3, #kSVSTraceSelect @ hot trace following?
+ moveq r2,#kJitTSelectRequestHot @ ask for trace selection
+ beq common_selectTrace @ go build the trace
+ cmp r3, #kSVSNoProfile @ don't profile the next instruction?
+ beq 1f @ intrepret the next instruction
+ b common_updateProfile @ collect profiles
+#endif
+1:
GET_INST_OPCODE(ip)
GOTO_OPCODE(ip)
#else
@@ -9858,12 +9871,21 @@ dvmJitToInterpSingleStep:
mov r2,#kSVSSingleStep @ r2<- interpreter entry point
b jitSVShadowRunEnd @ doesn't return
+ .global dvmJitToInterpNoChainNoProfile
+dvmJitToInterpNoChainNoProfile:
+ ldr r10, [rGLUE, #offGlue_self] @ callee saved r10 <- glue->self
+ mov r0,rPC @ pass our target PC
+ mov r2,#kSVSNoProfile @ r2<- interpreter entry point
+ mov r3, #0 @ 0 means !inJitCodeCache
+ str r3, [r10, #offThread_inJitCodeCache] @ back to the interp land
+ b jitSVShadowRunEnd @ doesn't return
+
.global dvmJitToInterpTraceSelectNoChain
dvmJitToInterpTraceSelectNoChain:
ldr r10, [rGLUE, #offGlue_self] @ callee saved r10 <- glue->self
mov r0,rPC @ pass our target PC
- mov r2,#kSVSTraceSelectNoChain @ r2<- interpreter entry point
- mov r3, #0
+ mov r2,#kSVSTraceSelect @ r2<- interpreter entry point
+ mov r3, #0 @ 0 means !inJitCodeCache
str r3, [r10, #offThread_inJitCodeCache] @ Back to the interp land
b jitSVShadowRunEnd @ doesn't return
@@ -9872,7 +9894,7 @@ dvmJitToInterpTraceSelect:
ldr r10, [rGLUE, #offGlue_self] @ callee saved r10 <- glue->self
ldr r0,[lr, #-1] @ pass our target PC
mov r2,#kSVSTraceSelect @ r2<- interpreter entry point
- mov r3, #0
+ mov r3, #0 @ 0 means !inJitCodeCache
str r3, [r10, #offThread_inJitCodeCache] @ Back to the interp land
b jitSVShadowRunEnd @ doesn't return
@@ -9881,7 +9903,7 @@ dvmJitToInterpBackwardBranch:
ldr r10, [rGLUE, #offGlue_self] @ callee saved r10 <- glue->self
ldr r0,[lr, #-1] @ pass our target PC
mov r2,#kSVSBackwardBranch @ r2<- interpreter entry point
- mov r3, #0
+ mov r3, #0 @ 0 means !inJitCodeCache
str r3, [r10, #offThread_inJitCodeCache] @ Back to the interp land
b jitSVShadowRunEnd @ doesn't return
@@ -9890,7 +9912,7 @@ dvmJitToInterpNormal:
ldr r10, [rGLUE, #offGlue_self] @ callee saved r10 <- glue->self
ldr r0,[lr, #-1] @ pass our target PC
mov r2,#kSVSNormal @ r2<- interpreter entry point
- mov r3, #0
+ mov r3, #0 @ 0 means !inJitCodeCache
str r3, [r10, #offThread_inJitCodeCache] @ Back to the interp land
b jitSVShadowRunEnd @ doesn't return
@@ -9899,7 +9921,7 @@ dvmJitToInterpNoChain:
ldr r10, [rGLUE, #offGlue_self] @ callee saved r10 <- glue->self
mov r0,rPC @ pass our target PC
mov r2,#kSVSNoChain @ r2<- interpreter entry point
- mov r3, #0
+ mov r3, #0 @ 0 means !inJitCodeCache
str r3, [r10, #offThread_inJitCodeCache] @ Back to the interp land
b jitSVShadowRunEnd @ doesn't return
#else
@@ -9964,9 +9986,9 @@ dvmJitToInterpTraceSelectNoChain:
str r0, [r10, #offThread_inJitCodeCache] @ set the inJitCodeCache flag
mov r1, rPC @ arg1 of translation may need this
mov lr, #0 @ in case target is HANDLER_INTERPRET
- cmp r0,#0
+ cmp r0,#0 @ !0 means translation exists
bxne r0 @ continue native execution if so
- b 2f
+ b 2f @ branch over to use the interpreter
/*
* Return from the translation cache and immediately request
@@ -10043,6 +10065,29 @@ dvmJitToInterpNormal:
* Return from the translation cache to the interpreter to do method invocation.
* Check if translation exists for the callee, but don't chain to it.
*/
+ .global dvmJitToInterpNoChainNoProfile
+dvmJitToInterpNoChainNoProfile:
+#if defined(WITH_JIT_TUNING)
+ bl dvmBumpNoChain
+#endif
+ ldr r10, [rGLUE, #offGlue_self] @ callee saved r10 <- glue->self
+ mov r0,rPC
+ bl dvmJitGetCodeAddr @ Is there a translation?
+ str r0, [r10, #offThread_inJitCodeCache] @ set the inJitCodeCache flag
+ mov r1, rPC @ arg1 of translation may need this
+ mov lr, #0 @ in case target is HANDLER_INTERPRET
+ cmp r0,#0
+ bxne r0 @ continue native execution if so
+ EXPORT_PC()
+ adrl rIBASE, dvmAsmInstructionStart
+ FETCH_INST()
+ GET_INST_OPCODE(ip) @ extract opcode from rINST
+ GOTO_OPCODE(ip) @ jump to next instruction
+
+/*
+ * Return from the translation cache to the interpreter to do method invocation.
+ * Check if translation exists for the callee, but don't chain to it.
+ */
.global dvmJitToInterpNoChain
dvmJitToInterpNoChain:
#if defined(WITH_JIT_TUNING)
@@ -10070,6 +10115,7 @@ toInterpreter:
FETCH_INST()
GET_JIT_PROF_TABLE(r0)
@ NOTE: intended fallthrough
+
/*
* Common code to update potential trace start counter, and initiate
* a trace-build if appropriate. On entry, rPC should point to the
@@ -10610,15 +10656,12 @@ common_returnFromMethod:
str rFP, [r3, #offThread_curFrame] @ self->curFrame = fp
#if defined(WITH_JIT)
ldr r10, [r0, #offStackSaveArea_returnAddr] @ r10 = saveArea->returnAddr
- GET_JIT_PROF_TABLE(r0)
mov rPC, r9 @ publish new rPC
str r1, [rGLUE, #offGlue_methodClassDex]
str r10, [r3, #offThread_inJitCodeCache] @ may return to JIT'ed land
cmp r10, #0 @ caller is compiled code
blxne r10
GET_INST_OPCODE(ip) @ extract opcode from rINST
- cmp r0,#0
- bne common_updateProfile
GOTO_OPCODE(ip) @ jump to next instruction
#else
GET_INST_OPCODE(ip) @ extract opcode from rINST
diff --git a/vm/mterp/out/InterpAsm-armv7-a-neon.S b/vm/mterp/out/InterpAsm-armv7-a-neon.S
index e837ddaaa..a08d936c7 100644
--- a/vm/mterp/out/InterpAsm-armv7-a-neon.S
+++ b/vm/mterp/out/InterpAsm-armv7-a-neon.S
@@ -330,14 +330,27 @@ dvmMterpStdRun:
#if defined(WITH_JIT)
.LentryInstr:
- ldr r10, [rGLUE, #offGlue_self] @ callee saved r10 <- glue->self
+ ldr r10, [rGLUE, #offGlue_self] @ callee saved r10 <- glue->self
/* Entry is always a possible trace start */
GET_JIT_PROF_TABLE(r0)
FETCH_INST()
- mov r1, #0 @ prepare the value for the new state
- str r1, [r10, #offThread_inJitCodeCache] @ back to the interp land
- cmp r0,#0
- bne common_updateProfile
+ mov r1, #0 @ prepare the value for the new state
+ str r1, [r10, #offThread_inJitCodeCache] @ back to the interp land
+ cmp r0,#0 @ is profiling disabled?
+#if !defined(WITH_SELF_VERIFICATION)
+ bne common_updateProfile @ profiling is enabled
+#else
+ ldr r2, [r10, #offThread_shadowSpace] @ to find out the jit exit state
+ beq 1f @ profiling is disabled
+ ldr r3, [r2, #offShadowSpace_jitExitState] @ jit exit state
+ cmp r3, #kSVSTraceSelect @ hot trace following?
+ moveq r2,#kJitTSelectRequestHot @ ask for trace selection
+ beq common_selectTrace @ go build the trace
+ cmp r3, #kSVSNoProfile @ don't profile the next instruction?
+ beq 1f @ intrepret the next instruction
+ b common_updateProfile @ collect profiles
+#endif
+1:
GET_INST_OPCODE(ip)
GOTO_OPCODE(ip)
#else
@@ -9334,12 +9347,21 @@ dvmJitToInterpSingleStep:
mov r2,#kSVSSingleStep @ r2<- interpreter entry point
b jitSVShadowRunEnd @ doesn't return
+ .global dvmJitToInterpNoChainNoProfile
+dvmJitToInterpNoChainNoProfile:
+ ldr r10, [rGLUE, #offGlue_self] @ callee saved r10 <- glue->self
+ mov r0,rPC @ pass our target PC
+ mov r2,#kSVSNoProfile @ r2<- interpreter entry point
+ mov r3, #0 @ 0 means !inJitCodeCache
+ str r3, [r10, #offThread_inJitCodeCache] @ back to the interp land
+ b jitSVShadowRunEnd @ doesn't return
+
.global dvmJitToInterpTraceSelectNoChain
dvmJitToInterpTraceSelectNoChain:
ldr r10, [rGLUE, #offGlue_self] @ callee saved r10 <- glue->self
mov r0,rPC @ pass our target PC
- mov r2,#kSVSTraceSelectNoChain @ r2<- interpreter entry point
- mov r3, #0
+ mov r2,#kSVSTraceSelect @ r2<- interpreter entry point
+ mov r3, #0 @ 0 means !inJitCodeCache
str r3, [r10, #offThread_inJitCodeCache] @ Back to the interp land
b jitSVShadowRunEnd @ doesn't return
@@ -9348,7 +9370,7 @@ dvmJitToInterpTraceSelect:
ldr r10, [rGLUE, #offGlue_self] @ callee saved r10 <- glue->self
ldr r0,[lr, #-1] @ pass our target PC
mov r2,#kSVSTraceSelect @ r2<- interpreter entry point
- mov r3, #0
+ mov r3, #0 @ 0 means !inJitCodeCache
str r3, [r10, #offThread_inJitCodeCache] @ Back to the interp land
b jitSVShadowRunEnd @ doesn't return
@@ -9357,7 +9379,7 @@ dvmJitToInterpBackwardBranch:
ldr r10, [rGLUE, #offGlue_self] @ callee saved r10 <- glue->self
ldr r0,[lr, #-1] @ pass our target PC
mov r2,#kSVSBackwardBranch @ r2<- interpreter entry point
- mov r3, #0
+ mov r3, #0 @ 0 means !inJitCodeCache
str r3, [r10, #offThread_inJitCodeCache] @ Back to the interp land
b jitSVShadowRunEnd @ doesn't return
@@ -9366,7 +9388,7 @@ dvmJitToInterpNormal:
ldr r10, [rGLUE, #offGlue_self] @ callee saved r10 <- glue->self
ldr r0,[lr, #-1] @ pass our target PC
mov r2,#kSVSNormal @ r2<- interpreter entry point
- mov r3, #0
+ mov r3, #0 @ 0 means !inJitCodeCache
str r3, [r10, #offThread_inJitCodeCache] @ Back to the interp land
b jitSVShadowRunEnd @ doesn't return
@@ -9375,7 +9397,7 @@ dvmJitToInterpNoChain:
ldr r10, [rGLUE, #offGlue_self] @ callee saved r10 <- glue->self
mov r0,rPC @ pass our target PC
mov r2,#kSVSNoChain @ r2<- interpreter entry point
- mov r3, #0
+ mov r3, #0 @ 0 means !inJitCodeCache
str r3, [r10, #offThread_inJitCodeCache] @ Back to the interp land
b jitSVShadowRunEnd @ doesn't return
#else
@@ -9440,9 +9462,9 @@ dvmJitToInterpTraceSelectNoChain:
str r0, [r10, #offThread_inJitCodeCache] @ set the inJitCodeCache flag
mov r1, rPC @ arg1 of translation may need this
mov lr, #0 @ in case target is HANDLER_INTERPRET
- cmp r0,#0
+ cmp r0,#0 @ !0 means translation exists
bxne r0 @ continue native execution if so
- b 2f
+ b 2f @ branch over to use the interpreter
/*
* Return from the translation cache and immediately request
@@ -9519,6 +9541,29 @@ dvmJitToInterpNormal:
* Return from the translation cache to the interpreter to do method invocation.
* Check if translation exists for the callee, but don't chain to it.
*/
+ .global dvmJitToInterpNoChainNoProfile
+dvmJitToInterpNoChainNoProfile:
+#if defined(WITH_JIT_TUNING)
+ bl dvmBumpNoChain
+#endif
+ ldr r10, [rGLUE, #offGlue_self] @ callee saved r10 <- glue->self
+ mov r0,rPC
+ bl dvmJitGetCodeAddr @ Is there a translation?
+ str r0, [r10, #offThread_inJitCodeCache] @ set the inJitCodeCache flag
+ mov r1, rPC @ arg1 of translation may need this
+ mov lr, #0 @ in case target is HANDLER_INTERPRET
+ cmp r0,#0
+ bxne r0 @ continue native execution if so
+ EXPORT_PC()
+ adrl rIBASE, dvmAsmInstructionStart
+ FETCH_INST()
+ GET_INST_OPCODE(ip) @ extract opcode from rINST
+ GOTO_OPCODE(ip) @ jump to next instruction
+
+/*
+ * Return from the translation cache to the interpreter to do method invocation.
+ * Check if translation exists for the callee, but don't chain to it.
+ */
.global dvmJitToInterpNoChain
dvmJitToInterpNoChain:
#if defined(WITH_JIT_TUNING)
@@ -9546,6 +9591,7 @@ toInterpreter:
FETCH_INST()
GET_JIT_PROF_TABLE(r0)
@ NOTE: intended fallthrough
+
/*
* Common code to update potential trace start counter, and initiate
* a trace-build if appropriate. On entry, rPC should point to the
@@ -10086,15 +10132,12 @@ common_returnFromMethod:
str rFP, [r3, #offThread_curFrame] @ self->curFrame = fp
#if defined(WITH_JIT)
ldr r10, [r0, #offStackSaveArea_returnAddr] @ r10 = saveArea->returnAddr
- GET_JIT_PROF_TABLE(r0)
mov rPC, r9 @ publish new rPC
str r1, [rGLUE, #offGlue_methodClassDex]
str r10, [r3, #offThread_inJitCodeCache] @ may return to JIT'ed land
cmp r10, #0 @ caller is compiled code
blxne r10
GET_INST_OPCODE(ip) @ extract opcode from rINST
- cmp r0,#0
- bne common_updateProfile
GOTO_OPCODE(ip) @ jump to next instruction
#else
GET_INST_OPCODE(ip) @ extract opcode from rINST
diff --git a/vm/mterp/out/InterpAsm-armv7-a.S b/vm/mterp/out/InterpAsm-armv7-a.S
index dc336387a..213c51388 100644
--- a/vm/mterp/out/InterpAsm-armv7-a.S
+++ b/vm/mterp/out/InterpAsm-armv7-a.S
@@ -330,14 +330,27 @@ dvmMterpStdRun:
#if defined(WITH_JIT)
.LentryInstr:
- ldr r10, [rGLUE, #offGlue_self] @ callee saved r10 <- glue->self
+ ldr r10, [rGLUE, #offGlue_self] @ callee saved r10 <- glue->self
/* Entry is always a possible trace start */
GET_JIT_PROF_TABLE(r0)
FETCH_INST()
- mov r1, #0 @ prepare the value for the new state
- str r1, [r10, #offThread_inJitCodeCache] @ back to the interp land
- cmp r0,#0
- bne common_updateProfile
+ mov r1, #0 @ prepare the value for the new state
+ str r1, [r10, #offThread_inJitCodeCache] @ back to the interp land
+ cmp r0,#0 @ is profiling disabled?
+#if !defined(WITH_SELF_VERIFICATION)
+ bne common_updateProfile @ profiling is enabled
+#else
+ ldr r2, [r10, #offThread_shadowSpace] @ to find out the jit exit state
+ beq 1f @ profiling is disabled
+ ldr r3, [r2, #offShadowSpace_jitExitState] @ jit exit state
+ cmp r3, #kSVSTraceSelect @ hot trace following?
+ moveq r2,#kJitTSelectRequestHot @ ask for trace selection
+ beq common_selectTrace @ go build the trace
+ cmp r3, #kSVSNoProfile @ don't profile the next instruction?
+ beq 1f @ intrepret the next instruction
+ b common_updateProfile @ collect profiles
+#endif
+1:
GET_INST_OPCODE(ip)
GOTO_OPCODE(ip)
#else
@@ -9334,12 +9347,21 @@ dvmJitToInterpSingleStep:
mov r2,#kSVSSingleStep @ r2<- interpreter entry point
b jitSVShadowRunEnd @ doesn't return
+ .global dvmJitToInterpNoChainNoProfile
+dvmJitToInterpNoChainNoProfile:
+ ldr r10, [rGLUE, #offGlue_self] @ callee saved r10 <- glue->self
+ mov r0,rPC @ pass our target PC
+ mov r2,#kSVSNoProfile @ r2<- interpreter entry point
+ mov r3, #0 @ 0 means !inJitCodeCache
+ str r3, [r10, #offThread_inJitCodeCache] @ back to the interp land
+ b jitSVShadowRunEnd @ doesn't return
+
.global dvmJitToInterpTraceSelectNoChain
dvmJitToInterpTraceSelectNoChain:
ldr r10, [rGLUE, #offGlue_self] @ callee saved r10 <- glue->self
mov r0,rPC @ pass our target PC
- mov r2,#kSVSTraceSelectNoChain @ r2<- interpreter entry point
- mov r3, #0
+ mov r2,#kSVSTraceSelect @ r2<- interpreter entry point
+ mov r3, #0 @ 0 means !inJitCodeCache
str r3, [r10, #offThread_inJitCodeCache] @ Back to the interp land
b jitSVShadowRunEnd @ doesn't return
@@ -9348,7 +9370,7 @@ dvmJitToInterpTraceSelect:
ldr r10, [rGLUE, #offGlue_self] @ callee saved r10 <- glue->self
ldr r0,[lr, #-1] @ pass our target PC
mov r2,#kSVSTraceSelect @ r2<- interpreter entry point
- mov r3, #0
+ mov r3, #0 @ 0 means !inJitCodeCache
str r3, [r10, #offThread_inJitCodeCache] @ Back to the interp land
b jitSVShadowRunEnd @ doesn't return
@@ -9357,7 +9379,7 @@ dvmJitToInterpBackwardBranch:
ldr r10, [rGLUE, #offGlue_self] @ callee saved r10 <- glue->self
ldr r0,[lr, #-1] @ pass our target PC
mov r2,#kSVSBackwardBranch @ r2<- interpreter entry point
- mov r3, #0
+ mov r3, #0 @ 0 means !inJitCodeCache
str r3, [r10, #offThread_inJitCodeCache] @ Back to the interp land
b jitSVShadowRunEnd @ doesn't return
@@ -9366,7 +9388,7 @@ dvmJitToInterpNormal:
ldr r10, [rGLUE, #offGlue_self] @ callee saved r10 <- glue->self
ldr r0,[lr, #-1] @ pass our target PC
mov r2,#kSVSNormal @ r2<- interpreter entry point
- mov r3, #0
+ mov r3, #0 @ 0 means !inJitCodeCache
str r3, [r10, #offThread_inJitCodeCache] @ Back to the interp land
b jitSVShadowRunEnd @ doesn't return
@@ -9375,7 +9397,7 @@ dvmJitToInterpNoChain:
ldr r10, [rGLUE, #offGlue_self] @ callee saved r10 <- glue->self
mov r0,rPC @ pass our target PC
mov r2,#kSVSNoChain @ r2<- interpreter entry point
- mov r3, #0
+ mov r3, #0 @ 0 means !inJitCodeCache
str r3, [r10, #offThread_inJitCodeCache] @ Back to the interp land
b jitSVShadowRunEnd @ doesn't return
#else
@@ -9440,9 +9462,9 @@ dvmJitToInterpTraceSelectNoChain:
str r0, [r10, #offThread_inJitCodeCache] @ set the inJitCodeCache flag
mov r1, rPC @ arg1 of translation may need this
mov lr, #0 @ in case target is HANDLER_INTERPRET
- cmp r0,#0
+ cmp r0,#0 @ !0 means translation exists
bxne r0 @ continue native execution if so
- b 2f
+ b 2f @ branch over to use the interpreter
/*
* Return from the translation cache and immediately request
@@ -9519,6 +9541,29 @@ dvmJitToInterpNormal:
* Return from the translation cache to the interpreter to do method invocation.
* Check if translation exists for the callee, but don't chain to it.
*/
+ .global dvmJitToInterpNoChainNoProfile
+dvmJitToInterpNoChainNoProfile:
+#if defined(WITH_JIT_TUNING)
+ bl dvmBumpNoChain
+#endif
+ ldr r10, [rGLUE, #offGlue_self] @ callee saved r10 <- glue->self
+ mov r0,rPC
+ bl dvmJitGetCodeAddr @ Is there a translation?
+ str r0, [r10, #offThread_inJitCodeCache] @ set the inJitCodeCache flag
+ mov r1, rPC @ arg1 of translation may need this
+ mov lr, #0 @ in case target is HANDLER_INTERPRET
+ cmp r0,#0
+ bxne r0 @ continue native execution if so
+ EXPORT_PC()
+ adrl rIBASE, dvmAsmInstructionStart
+ FETCH_INST()
+ GET_INST_OPCODE(ip) @ extract opcode from rINST
+ GOTO_OPCODE(ip) @ jump to next instruction
+
+/*
+ * Return from the translation cache to the interpreter to do method invocation.
+ * Check if translation exists for the callee, but don't chain to it.
+ */
.global dvmJitToInterpNoChain
dvmJitToInterpNoChain:
#if defined(WITH_JIT_TUNING)
@@ -9546,6 +9591,7 @@ toInterpreter:
FETCH_INST()
GET_JIT_PROF_TABLE(r0)
@ NOTE: intended fallthrough
+
/*
* Common code to update potential trace start counter, and initiate
* a trace-build if appropriate. On entry, rPC should point to the
@@ -10086,15 +10132,12 @@ common_returnFromMethod:
str rFP, [r3, #offThread_curFrame] @ self->curFrame = fp
#if defined(WITH_JIT)
ldr r10, [r0, #offStackSaveArea_returnAddr] @ r10 = saveArea->returnAddr
- GET_JIT_PROF_TABLE(r0)
mov rPC, r9 @ publish new rPC
str r1, [rGLUE, #offGlue_methodClassDex]
str r10, [r3, #offThread_inJitCodeCache] @ may return to JIT'ed land
cmp r10, #0 @ caller is compiled code
blxne r10
GET_INST_OPCODE(ip) @ extract opcode from rINST
- cmp r0,#0
- bne common_updateProfile
GOTO_OPCODE(ip) @ jump to next instruction
#else
GET_INST_OPCODE(ip) @ extract opcode from rINST
diff --git a/vm/mterp/out/InterpC-allstubs.c b/vm/mterp/out/InterpC-allstubs.c
index 4a7a5a95e..365671340 100644
--- a/vm/mterp/out/InterpC-allstubs.c
+++ b/vm/mterp/out/InterpC-allstubs.c
@@ -3288,6 +3288,10 @@ GOTO_TARGET(invokeVirtual, bool methodCallRange)
assert(baseMethod->methodIndex < thisPtr->clazz->vtableCount);
methodToCall = thisPtr->clazz->vtable[baseMethod->methodIndex];
+#if defined(WITH_JIT) && (INTERP_TYPE == INTERP_DBG)
+ callsiteClass = thisPtr->clazz;
+#endif
+
#if 0
if (dvmIsAbstractMethod(methodToCall)) {
/*
@@ -3439,6 +3443,10 @@ GOTO_TARGET(invokeInterface, bool methodCallRange)
thisClass = thisPtr->clazz;
+#if defined(WITH_JIT) && (INTERP_TYPE == INTERP_DBG)
+ callsiteClass = thisClass;
+#endif
+
/*
* Given a class and a method index, find the Method* with the
* actual code we want to execute.
@@ -3553,6 +3561,10 @@ GOTO_TARGET(invokeVirtualQuick, bool methodCallRange)
if (!checkForNull(thisPtr))
GOTO_exceptionThrown();
+#if defined(WITH_JIT) && (INTERP_TYPE == INTERP_DBG)
+ callsiteClass = thisPtr->clazz;
+#endif
+
/*
* Combine the object we found with the vtable offset in the
* method.
diff --git a/vm/mterp/out/InterpC-portdbg.c b/vm/mterp/out/InterpC-portdbg.c
index 44916fb0e..47b3d7fe4 100644
--- a/vm/mterp/out/InterpC-portdbg.c
+++ b/vm/mterp/out/InterpC-portdbg.c
@@ -425,8 +425,10 @@ static inline bool checkForNullExportPC(Object* obj, u4* fp, const u2* pc)
checkDebugAndProf(pc, fp, self, curMethod, &debugIsMethodEntry)
#if defined(WITH_JIT)
-#define CHECK_JIT_BOOL() (dvmCheckJit(pc, self, interpState))
-#define CHECK_JIT_VOID() (dvmCheckJit(pc, self, interpState))
+#define CHECK_JIT_BOOL() (dvmCheckJit(pc, self, interpState, callsiteClass,\
+ methodToCall))
+#define CHECK_JIT_VOID() (dvmCheckJit(pc, self, interpState, callsiteClass,\
+ methodToCall))
#define ABORT_JIT_TSELECT() (dvmJitAbortTraceSelect(interpState))
#else
#define CHECK_JIT_BOOL() (false)
@@ -1493,6 +1495,14 @@ bool INTERP_FUNC_NAME(Thread* self, InterpState* interpState)
interpState->method->name);
#endif
#if INTERP_TYPE == INTERP_DBG
+ const ClassObject* callsiteClass = NULL;
+
+#if defined(WITH_SELF_VERIFICATION)
+ if (interpState->jitState != kJitSelfVerification) {
+ interpState->self->shadowSpace->jitExitState = kSVSIdle;
+ }
+#endif
+
/* Check to see if we've got a trace selection request. */
if (
/*
@@ -3572,6 +3582,10 @@ GOTO_TARGET(invokeVirtual, bool methodCallRange)
assert(baseMethod->methodIndex < thisPtr->clazz->vtableCount);
methodToCall = thisPtr->clazz->vtable[baseMethod->methodIndex];
+#if defined(WITH_JIT) && (INTERP_TYPE == INTERP_DBG)
+ callsiteClass = thisPtr->clazz;
+#endif
+
#if 0
if (dvmIsAbstractMethod(methodToCall)) {
/*
@@ -3723,6 +3737,10 @@ GOTO_TARGET(invokeInterface, bool methodCallRange)
thisClass = thisPtr->clazz;
+#if defined(WITH_JIT) && (INTERP_TYPE == INTERP_DBG)
+ callsiteClass = thisClass;
+#endif
+
/*
* Given a class and a method index, find the Method* with the
* actual code we want to execute.
@@ -3837,6 +3855,10 @@ GOTO_TARGET(invokeVirtualQuick, bool methodCallRange)
if (!checkForNull(thisPtr))
GOTO_exceptionThrown();
+#if defined(WITH_JIT) && (INTERP_TYPE == INTERP_DBG)
+ callsiteClass = thisPtr->clazz;
+#endif
+
/*
* Combine the object we found with the vtable offset in the
* method.
diff --git a/vm/mterp/out/InterpC-portstd.c b/vm/mterp/out/InterpC-portstd.c
index e863abef7..165c032e3 100644
--- a/vm/mterp/out/InterpC-portstd.c
+++ b/vm/mterp/out/InterpC-portstd.c
@@ -1232,6 +1232,14 @@ bool INTERP_FUNC_NAME(Thread* self, InterpState* interpState)
interpState->method->name);
#endif
#if INTERP_TYPE == INTERP_DBG
+ const ClassObject* callsiteClass = NULL;
+
+#if defined(WITH_SELF_VERIFICATION)
+ if (interpState->jitState != kJitSelfVerification) {
+ interpState->self->shadowSpace->jitExitState = kSVSIdle;
+ }
+#endif
+
/* Check to see if we've got a trace selection request. */
if (
/*
@@ -3311,6 +3319,10 @@ GOTO_TARGET(invokeVirtual, bool methodCallRange)
assert(baseMethod->methodIndex < thisPtr->clazz->vtableCount);
methodToCall = thisPtr->clazz->vtable[baseMethod->methodIndex];
+#if defined(WITH_JIT) && (INTERP_TYPE == INTERP_DBG)
+ callsiteClass = thisPtr->clazz;
+#endif
+
#if 0
if (dvmIsAbstractMethod(methodToCall)) {
/*
@@ -3462,6 +3474,10 @@ GOTO_TARGET(invokeInterface, bool methodCallRange)
thisClass = thisPtr->clazz;
+#if defined(WITH_JIT) && (INTERP_TYPE == INTERP_DBG)
+ callsiteClass = thisClass;
+#endif
+
/*
* Given a class and a method index, find the Method* with the
* actual code we want to execute.
@@ -3576,6 +3592,10 @@ GOTO_TARGET(invokeVirtualQuick, bool methodCallRange)
if (!checkForNull(thisPtr))
GOTO_exceptionThrown();
+#if defined(WITH_JIT) && (INTERP_TYPE == INTERP_DBG)
+ callsiteClass = thisPtr->clazz;
+#endif
+
/*
* Combine the object we found with the vtable offset in the
* method.
diff --git a/vm/mterp/out/InterpC-x86-atom.c b/vm/mterp/out/InterpC-x86-atom.c
index 46e25b0de..3b85384b6 100644
--- a/vm/mterp/out/InterpC-x86-atom.c
+++ b/vm/mterp/out/InterpC-x86-atom.c
@@ -1482,6 +1482,10 @@ GOTO_TARGET(invokeVirtual, bool methodCallRange)
assert(baseMethod->methodIndex < thisPtr->clazz->vtableCount);
methodToCall = thisPtr->clazz->vtable[baseMethod->methodIndex];
+#if defined(WITH_JIT) && (INTERP_TYPE == INTERP_DBG)
+ callsiteClass = thisPtr->clazz;
+#endif
+
#if 0
if (dvmIsAbstractMethod(methodToCall)) {
/*
@@ -1633,6 +1637,10 @@ GOTO_TARGET(invokeInterface, bool methodCallRange)
thisClass = thisPtr->clazz;
+#if defined(WITH_JIT) && (INTERP_TYPE == INTERP_DBG)
+ callsiteClass = thisClass;
+#endif
+
/*
* Given a class and a method index, find the Method* with the
* actual code we want to execute.
@@ -1747,6 +1755,10 @@ GOTO_TARGET(invokeVirtualQuick, bool methodCallRange)
if (!checkForNull(thisPtr))
GOTO_exceptionThrown();
+#if defined(WITH_JIT) && (INTERP_TYPE == INTERP_DBG)
+ callsiteClass = thisPtr->clazz;
+#endif
+
/*
* Combine the object we found with the vtable offset in the
* method.
diff --git a/vm/mterp/out/InterpC-x86.c b/vm/mterp/out/InterpC-x86.c
index 6fc1ce19d..ec076913c 100644
--- a/vm/mterp/out/InterpC-x86.c
+++ b/vm/mterp/out/InterpC-x86.c
@@ -1419,6 +1419,10 @@ GOTO_TARGET(invokeVirtual, bool methodCallRange)
assert(baseMethod->methodIndex < thisPtr->clazz->vtableCount);
methodToCall = thisPtr->clazz->vtable[baseMethod->methodIndex];
+#if defined(WITH_JIT) && (INTERP_TYPE == INTERP_DBG)
+ callsiteClass = thisPtr->clazz;
+#endif
+
#if 0
if (dvmIsAbstractMethod(methodToCall)) {
/*
@@ -1570,6 +1574,10 @@ GOTO_TARGET(invokeInterface, bool methodCallRange)
thisClass = thisPtr->clazz;
+#if defined(WITH_JIT) && (INTERP_TYPE == INTERP_DBG)
+ callsiteClass = thisClass;
+#endif
+
/*
* Given a class and a method index, find the Method* with the
* actual code we want to execute.
@@ -1684,6 +1692,10 @@ GOTO_TARGET(invokeVirtualQuick, bool methodCallRange)
if (!checkForNull(thisPtr))
GOTO_exceptionThrown();
+#if defined(WITH_JIT) && (INTERP_TYPE == INTERP_DBG)
+ callsiteClass = thisPtr->clazz;
+#endif
+
/*
* Combine the object we found with the vtable offset in the
* method.
diff --git a/vm/mterp/portable/entry.c b/vm/mterp/portable/entry.c
index b2ec1d843..6b989a221 100644
--- a/vm/mterp/portable/entry.c
+++ b/vm/mterp/portable/entry.c
@@ -46,6 +46,14 @@ bool INTERP_FUNC_NAME(Thread* self, InterpState* interpState)
interpState->method->name);
#endif
#if INTERP_TYPE == INTERP_DBG
+ const ClassObject* callsiteClass = NULL;
+
+#if defined(WITH_SELF_VERIFICATION)
+ if (interpState->jitState != kJitSelfVerification) {
+ interpState->self->shadowSpace->jitExitState = kSVSIdle;
+ }
+#endif
+
/* Check to see if we've got a trace selection request. */
if (
/*
diff --git a/vm/mterp/portable/portdbg.c b/vm/mterp/portable/portdbg.c
index 76b7637fe..65349e9e5 100644
--- a/vm/mterp/portable/portdbg.c
+++ b/vm/mterp/portable/portdbg.c
@@ -5,8 +5,10 @@
checkDebugAndProf(pc, fp, self, curMethod, &debugIsMethodEntry)
#if defined(WITH_JIT)
-#define CHECK_JIT_BOOL() (dvmCheckJit(pc, self, interpState))
-#define CHECK_JIT_VOID() (dvmCheckJit(pc, self, interpState))
+#define CHECK_JIT_BOOL() (dvmCheckJit(pc, self, interpState, callsiteClass,\
+ methodToCall))
+#define CHECK_JIT_VOID() (dvmCheckJit(pc, self, interpState, callsiteClass,\
+ methodToCall))
#define ABORT_JIT_TSELECT() (dvmJitAbortTraceSelect(interpState))
#else
#define CHECK_JIT_BOOL() (false)