/* Table to track the overall and trace statistics of hot methods */
HashTable* methodStatsTable;
+ /* Filter method compilation blacklist with call-graph information */
+ bool checkCallGraph;
+
#if defined(WITH_SELF_VERIFICATION)
/* Spin when error is detected, volatile so GDB can reset it */
volatile bool selfVerificationSpin;
dvmFprintf(stderr, " -Xjitblocking\n");
dvmFprintf(stderr, " -Xjitmethod:signature[,signature]* "
"(eg Ljava/lang/String\\;replace)\n");
+ dvmFprintf(stderr, " -Xjitcheckcg\n");
dvmFprintf(stderr, " -Xjitverbose\n");
dvmFprintf(stderr, " -Xjitprofile\n");
dvmFprintf(stderr, " -Xjitdisableopt\n");
gDvmJit.includeSelectedOp = true;
} else if (strncmp(argv[i], "-Xincludeselectedmethod", 23) == 0) {
gDvmJit.includeSelectedMethod = true;
+ } else if (strncmp(argv[i], "-Xjitcheckcg", 12) == 0) {
+ gDvmJit.checkCallGraph = true;
+ /* Need to enable blocking mode due to stack crawling */
+ gDvmJit.blockingMode = true;
} else if (strncmp(argv[i], "-Xjitverbose", 12) == 0) {
gDvmJit.printMe = true;
} else if (strncmp(argv[i], "-Xjitprofile", 12) == 0) {
newOrder->result.discardResult =
(kind == kWorkOrderTraceDebug || kind == kWorkOrderICPatch) ?
true : false;
+ newOrder->result.requestingThread = dvmThreadSelf();
+
gDvmJit.compilerWorkEnqueueIndex++;
if (gDvmJit.compilerWorkEnqueueIndex == COMPILER_WORK_QUEUE_SIZE)
gDvmJit.compilerWorkEnqueueIndex = 0;
* limitations under the License.
*/
+#include <Thread.h>
+
#ifndef _DALVIK_VM_COMPILER
#define _DALVIK_VM_COMPILER
void *codeAddress;
JitInstructionSetType instructionSet;
bool discardResult; // Used for debugging divergence and IC patching
+ Thread *requestingThread; // For debugging purpose
} JitTranslationInfo;
typedef enum WorkOrderKind {
}
/*
+ * Crawl the stack of the thread that requesed compilation to see if any of the
+ * ancestors are on the blacklist.
+ */
+bool filterMethodByCallGraph(Thread *thread, const char *curMethodName)
+{
+ /* Crawl the Dalvik stack frames and compare the method name*/
+ StackSaveArea *ssaPtr = ((StackSaveArea *) thread->curFrame) - 1;
+ while (ssaPtr != ((StackSaveArea *) NULL) - 1) {
+ const Method *method = ssaPtr->method;
+ if (method) {
+ int hashValue = dvmComputeUtf8Hash(method->name);
+ bool found =
+ dvmHashTableLookup(gDvmJit.methodTable, hashValue,
+ (char *) method->name,
+ (HashCompareFunc) strcmp, false) !=
+ NULL;
+ if (found) {
+ LOGD("Method %s (--> %s) found on the JIT %s list",
+ method->name, curMethodName,
+ gDvmJit.includeSelectedMethod ? "white" : "black");
+ return true;
+ }
+
+ }
+ ssaPtr = ((StackSaveArea *) ssaPtr->prevFrame) - 1;
+ };
+ return false;
+}
+
+/*
* Main entry point to start trace compilation. Basic blocks are constructed
* first and they will be passed to the codegen routines to convert Dalvik
* bytecode into machine code.
(char *) desc->method->name,
(HashCompareFunc) strcmp, false) !=
NULL;
+
+ /*
+ * Debug by call-graph is enabled. Check if the debug list
+ * covers any methods on the VM stack.
+ */
+ if (methodFound == false && gDvmJit.checkCallGraph == true) {
+ methodFound =
+ filterMethodByCallGraph(info->requestingThread,
+ desc->method->name);
+ }
}
}
#undef JIT_TEMPLATE
/* Target-specific configuration */
- gDvmJit.blockingMode = false;
gDvmJit.jitTableSize = 1 << 9; // 512
gDvmJit.jitTableMask = gDvmJit.jitTableSize - 1;
gDvmJit.threshold = 200;
#undef JIT_TEMPLATE
/* Target-specific configuration */
- gDvmJit.blockingMode = false;
gDvmJit.jitTableSize = 1 << 9; // 512
gDvmJit.jitTableMask = gDvmJit.jitTableSize - 1;
gDvmJit.threshold = 200;
#undef JIT_TEMPLATE
/* Target-specific configuration */
- gDvmJit.blockingMode = false;
gDvmJit.jitTableSize = 1 << 12; // 4096
gDvmJit.jitTableMask = gDvmJit.jitTableSize - 1;
gDvmJit.threshold = 40;
void* dvmJitGetCodeAddr(const u2* dPC)
{
int idx = dvmJitHash(dPC);
- u2* npc = gDvmJit.pJitEntryTable[idx].dPC;
+ const u2* npc = gDvmJit.pJitEntryTable[idx].dPC;
if (npc != NULL) {
if (npc == dPC) {