OSDN Git Service

Jit: Rework delayed start plus misc. cleanup
authorBill Buzbee <buzbee@google.com>
Thu, 28 Jan 2010 20:54:19 +0000 (12:54 -0800)
committerBill Buzbee <buzbee@google.com>
Thu, 28 Jan 2010 21:42:44 +0000 (13:42 -0800)
Defer initialization of jit to support upcoming feature to wait until
first screen is painted to start in order to avoid wasting effort on
jit'ng initialization code.  Timed delay in place for the moment.
To change the on/off state, call dvmSuspendAllThreads(), update the
value of gDvmJit.pJitTable and then dvmResumeAllThreads().
Each time a thread goes through the heavyweight check suspend path, returns
from a monitor lock/unlock or returns from a JNI call, it will refresh
its on/off state.

Also:
   Recognize and handle failure to increase size of JitTable.
   Avoid repeated lock/unlock of JitTable modification mutex during resize
   Make all work order enqueue actions non-blocking, which includes adding
      a non-blocking mutex lock: dvmTryLockMutex().
   Fix bug Jeff noticed where we were using a half-word form of a Thumb2
      instruction rather than the byte form.
   Minor comment changes.

21 files changed:
vm/Thread.c
vm/Thread.h
vm/compiler/Compiler.c
vm/compiler/Frontend.c
vm/compiler/codegen/arm/CodegenDriver.c
vm/compiler/codegen/arm/Thumb2/Factory.c
vm/compiler/codegen/arm/Thumb2/Gen.c
vm/compiler/template/armv5te/footer.S
vm/compiler/template/out/CompilerTemplateAsm-armv5te-vfp.S
vm/compiler/template/out/CompilerTemplateAsm-armv5te.S
vm/compiler/template/out/CompilerTemplateAsm-armv7-a.S
vm/interp/InterpDefs.h
vm/interp/Jit.c
vm/interp/Jit.h
vm/mterp/Mterp.c
vm/mterp/armv5te/footer.S
vm/mterp/common/asm-constants.h
vm/mterp/out/InterpAsm-armv4t.S
vm/mterp/out/InterpAsm-armv5te-vfp.S
vm/mterp/out/InterpAsm-armv5te.S
vm/mterp/out/InterpAsm-armv7-a.S

index 05c89e2..e26e679 100644 (file)
@@ -525,6 +525,7 @@ static const char* getSuspendCauseStr(SuspendCause why)
     case SUSPEND_FOR_TBL_RESIZE:    return "table-resize";
     case SUSPEND_FOR_IC_PATCH:      return "inline-cache-patch";
     case SUSPEND_FOR_CC_RESET:      return "reset-code-cache";
+    case SUSPEND_FOR_REFRESH:       return "refresh jit status";
 #endif
     default:                        return "UNKNOWN";
     }
index 5e0ad4d..964c968 100644 (file)
@@ -300,6 +300,7 @@ typedef enum SuspendCause {
     SUSPEND_FOR_TBL_RESIZE,  // jit-table resize
     SUSPEND_FOR_IC_PATCH,    // polymorphic callsite inline-cache patch
     SUSPEND_FOR_CC_RESET,    // code-cache reset
+    SUSPEND_FOR_REFRESH,     // Reload data cached in interpState
 #endif
 } SuspendCause;
 void dvmSuspendThread(Thread* thread);
@@ -378,6 +379,14 @@ INLINE void dvmLockMutex(pthread_mutex_t* pMutex)
 }
 
 /*
+ * Try grabbing a plain mutex.  Returns 0 if successful.
+ */
+INLINE int dvmTryLockMutex(pthread_mutex_t* pMutex)
+{
+    return pthread_mutex_trylock(pMutex);
+}
+
+/*
  * Unlock pthread mutex.
  */
 INLINE void dvmUnlockMutex(pthread_mutex_t* pMutex)
index 3886cce..ceb1da1 100644 (file)
@@ -49,15 +49,21 @@ static CompilerWorkOrder workDequeue(void)
     return work;
 }
 
+/*
+ * Attempt to enqueue a work order, returning true if successful.
+ * This routine will not block, but simply return if it couldn't
+ * aquire the lock or if the queue is full.
+ */
 bool dvmCompilerWorkEnqueue(const u2 *pc, WorkOrderKind kind, void* info)
 {
     int cc;
     int i;
     int numWork;
-    int oldStatus = dvmChangeStatus(NULL, THREAD_VMWAIT);
     bool result = true;
 
-    dvmLockMutex(&gDvmJit.compilerLock);
+    if (dvmTryLockMutex(&gDvmJit.compilerLock)) {
+        return false;  // Couldn't aquire the lock
+    }
 
     /*
      * Return if queue is full.
@@ -66,7 +72,7 @@ bool dvmCompilerWorkEnqueue(const u2 *pc, WorkOrderKind kind, void* info)
      */
     if (gDvmJit.compilerQueueLength == COMPILER_WORK_QUEUE_SIZE) {
         result = false;
-        goto done;
+        goto unlockAndExit;
     }
 
     for (numWork = gDvmJit.compilerQueueLength,
@@ -75,7 +81,7 @@ bool dvmCompilerWorkEnqueue(const u2 *pc, WorkOrderKind kind, void* info)
          numWork--) {
         /* Already enqueued */
         if (gDvmJit.compilerWorkQueue[i++].pc == pc)
-            goto done;
+            goto unlockAndExit;
         /* Wrap around */
         if (i == COMPILER_WORK_QUEUE_SIZE)
             i = 0;
@@ -99,9 +105,8 @@ bool dvmCompilerWorkEnqueue(const u2 *pc, WorkOrderKind kind, void* info)
     cc = pthread_cond_signal(&gDvmJit.compilerQueueActivity);
     assert(cc == 0);
 
-done:
+unlockAndExit:
     dvmUnlockMutex(&gDvmJit.compilerLock);
-    dvmChangeStatus(NULL, oldStatus);
     return result;
 }
 
@@ -267,21 +272,112 @@ done:
     dvmResumeAllThreads(SUSPEND_FOR_CC_RESET);
 }
 
+bool compilerThreadStartup(void)
+{
+    JitEntry *pJitTable = NULL;
+    unsigned char *pJitProfTable = NULL;
+    unsigned int i;
+
+    if (!dvmCompilerArchInit())
+        goto fail;
+
+    /*
+     * Setup the code cache if we have not inherited a valid code cache
+     * from the zygote.
+     */
+    if (gDvmJit.codeCache == NULL) {
+        if (!dvmCompilerSetupCodeCache())
+            goto fail;
+    }
+
+    /* Allocate the initial arena block */
+    if (dvmCompilerHeapInit() == false) {
+        goto fail;
+    }
+
+    dvmInitMutex(&gDvmJit.compilerLock);
+    pthread_cond_init(&gDvmJit.compilerQueueActivity, NULL);
+    pthread_cond_init(&gDvmJit.compilerQueueEmpty, NULL);
+
+    dvmLockMutex(&gDvmJit.compilerLock);
+
+    gDvmJit.haltCompilerThread = false;
+
+    /* Reset the work queue */
+    memset(gDvmJit.compilerWorkQueue, 0,
+           sizeof(CompilerWorkOrder) * COMPILER_WORK_QUEUE_SIZE);
+    gDvmJit.compilerWorkEnqueueIndex = gDvmJit.compilerWorkDequeueIndex = 0;
+    gDvmJit.compilerQueueLength = 0;
+
+    /* Track method-level compilation statistics */
+    gDvmJit.methodStatsTable =  dvmHashTableCreate(32, NULL);
+
+    dvmUnlockMutex(&gDvmJit.compilerLock);
+
+    /* Set up the JitTable */
+
+    /* Power of 2? */
+    assert(gDvmJit.jitTableSize &&
+           !(gDvmJit.jitTableSize & (gDvmJit.jitTableSize - 1)));
+
+    dvmInitMutex(&gDvmJit.tableLock);
+    dvmLockMutex(&gDvmJit.tableLock);
+    pJitTable = (JitEntry*)
+                calloc(gDvmJit.jitTableSize, sizeof(*pJitTable));
+    if (!pJitTable) {
+        LOGE("jit table allocation failed\n");
+        dvmUnlockMutex(&gDvmJit.tableLock);
+        goto fail;
+    }
+    /*
+     * NOTE: the profile table must only be allocated once, globally.
+     * Profiling is turned on and off by nulling out gDvm.pJitProfTable
+     * and then restoring its original value.  However, this action
+     * is not syncronized for speed so threads may continue to hold
+     * and update the profile table after profiling has been turned
+     * off by null'ng the global pointer.  Be aware.
+     */
+    pJitProfTable = (unsigned char *)malloc(JIT_PROF_SIZE);
+    if (!pJitProfTable) {
+        LOGE("jit prof table allocation failed\n");
+        dvmUnlockMutex(&gDvmJit.tableLock);
+        goto fail;
+    }
+    memset(pJitProfTable, gDvmJit.threshold, JIT_PROF_SIZE);
+    for (i=0; i < gDvmJit.jitTableSize; i++) {
+       pJitTable[i].u.info.chain = gDvmJit.jitTableSize;
+    }
+    /* Is chain field wide enough for termination pattern? */
+    assert(pJitTable[0].u.info.chain == gDvmJit.jitTableSize);
+
+    gDvmJit.pJitEntryTable = pJitTable;
+    gDvmJit.jitTableMask = gDvmJit.jitTableSize - 1;
+    gDvmJit.jitTableEntriesUsed = 0;
+    gDvmJit.compilerHighWater =
+        COMPILER_WORK_QUEUE_SIZE - (COMPILER_WORK_QUEUE_SIZE/4);
+    gDvmJit.pProfTable = pJitProfTable;
+    dvmUnlockMutex(&gDvmJit.tableLock);
+
+    /* Signal running threads to refresh their cached pJitTable pointers */
+    dvmSuspendAllThreads(SUSPEND_FOR_REFRESH);
+    dvmResumeAllThreads(SUSPEND_FOR_REFRESH);
+    return true;
+
+fail:
+    return false;
+
+}
+
 static void *compilerThreadStart(void *arg)
 {
     dvmChangeStatus(NULL, THREAD_VMWAIT);
 
     /*
      * Wait a little before recieving translation requests on the assumption
-     * that process start-up code isn't worth compiling.  The trace
-     * selector won't attempt to request a translation if the queue is
-     * filled, so we'll prevent by keeping the high water mark at zero
-     * for a shore time.
+     * that process start-up code isn't worth compiling.
      */
-    assert(gDvmJit.compilerHighWater == 0);
-    usleep(1000);
-    gDvmJit.compilerHighWater =
-        COMPILER_WORK_QUEUE_SIZE - (COMPILER_WORK_QUEUE_SIZE/4);
+    usleep(1 * 1000 * 1000);
+    compilerThreadStartup();
 
     dvmLockMutex(&gDvmJit.compilerLock);
     /*
@@ -299,18 +395,22 @@ static void *compilerThreadStart(void *arg)
             continue;
         } else {
             do {
+                bool resizeFail = false;
                 CompilerWorkOrder work = workDequeue();
                 dvmUnlockMutex(&gDvmJit.compilerLock);
-                /* Check whether there is a suspend request on me */
+                /*
+                 * Check whether there is a suspend request on me.  This
+                 * is necessary to allow a clean shutdown.
+                 */
                 dvmCheckSuspendPending(NULL);
                 /* Is JitTable filling up? */
                 if (gDvmJit.jitTableEntriesUsed >
                     (gDvmJit.jitTableSize - gDvmJit.jitTableSize/4)) {
-                    dvmJitResizeJitTable(gDvmJit.jitTableSize * 2);
+                    resizeFail = dvmJitResizeJitTable(gDvmJit.jitTableSize * 2);
                 }
                 if (gDvmJit.haltCompilerThread) {
                     LOGD("Compiler shutdown in progress - discarding request");
-                } else {
+                } else if (!resizeFail) {
                     /* If compilation failed, use interpret-template */
                     if (!dvmCompilerDoWork(&work)) {
                         work.result.codeAddress = gDvmJit.interpretTemplate;
@@ -328,7 +428,7 @@ static void *compilerThreadStart(void *arg)
                  * stale code stops leaking.
                  */
 #if 0
-                if (gDvmJit.codeCacheFull == true) {
+                if (gDvmJit.codeCacheFull == true || resizeFail) {
                     if (gDvmJit.delayCodeCacheReset == 0) {
                         resetCodeCache();
                         assert(workQueueLength() == 0 ||
@@ -359,60 +459,13 @@ static void *compilerThreadStart(void *arg)
 
 bool dvmCompilerStartup(void)
 {
-    /* Make sure the BBType enum is in sane state */
-    assert(kChainingCellNormal == 0);
-
-    /* Architecture-specific chores to initialize */
-    if (!dvmCompilerArchInit())
-        goto fail;
-
     /*
-     * Setup the code cache if it is not done so already. For apps it should be
-     * done by the Zygote already, but for command-line dalvikvm invocation we
-     * need to do it here.
+     * Defer initialization until we're sure JIT'ng makes sense.  Launch
+     * the compiler thread, which will do the real initialization if and
+     * when it is signalled to do so.
      */
-    if (gDvmJit.codeCache == NULL) {
-        if (!dvmCompilerSetupCodeCache())
-            goto fail;
-    }
-
-    /* Allocate the initial arena block */
-    if (dvmCompilerHeapInit() == false) {
-        goto fail;
-    }
-
-    dvmInitMutex(&gDvmJit.compilerLock);
-    pthread_cond_init(&gDvmJit.compilerQueueActivity, NULL);
-    pthread_cond_init(&gDvmJit.compilerQueueEmpty, NULL);
-
-    dvmLockMutex(&gDvmJit.compilerLock);
-
-    gDvmJit.haltCompilerThread = false;
-
-    /* Reset the work queue */
-    memset(gDvmJit.compilerWorkQueue, 0,
-           sizeof(CompilerWorkOrder) * COMPILER_WORK_QUEUE_SIZE);
-    gDvmJit.compilerWorkEnqueueIndex = gDvmJit.compilerWorkDequeueIndex = 0;
-    gDvmJit.compilerQueueLength = 0;
-    /* Block new entries via HighWater until compiler thread is ready */
-    gDvmJit.compilerHighWater = 0;
-
-    assert(gDvmJit.compilerHighWater < COMPILER_WORK_QUEUE_SIZE);
-    if (!dvmCreateInternalThread(&gDvmJit.compilerHandle, "Compiler",
-                                 compilerThreadStart, NULL)) {
-        dvmUnlockMutex(&gDvmJit.compilerLock);
-        goto fail;
-    }
-
-    /* Track method-level compilation statistics */
-    gDvmJit.methodStatsTable =  dvmHashTableCreate(32, NULL);
-
-    dvmUnlockMutex(&gDvmJit.compilerLock);
-
-    return true;
-
-fail:
-    return false;
+    return dvmCreateInternalThread(&gDvmJit.compilerHandle, "Compiler",
+                                   compilerThreadStart, NULL);
 }
 
 void dvmCompilerShutdown(void)
index a4a82c9..347bc50 100644 (file)
@@ -299,6 +299,11 @@ bool dvmCompileTrace(JitTraceDescription *desc, int numMaxInsts,
     CompilationUnit cUnit;
     CompilerMethodStats *methodStats;
 
+    /* If we've already compiled this trace, just return success */
+    if (dvmJitGetCodeAddr(startCodePtr)) {
+        return true;
+    }
+
     compilationId++;
     memset(&cUnit, 0, sizeof(CompilationUnit));
 
index 8861102..648d8f4 100644 (file)
@@ -1709,6 +1709,14 @@ static void genMonitorPortable(CompilationUnit *cUnit, MIR *mir)
     genNullCheck(cUnit, rlSrc.sRegLow, r1, mir->offset, NULL);
     /* Do the call */
     opReg(cUnit, kOpBlx, r2);
+    /*
+     * Refresh Jit's on/off status, which may have changed if we were
+     * sent to VM_MONITOR state above.
+     * TUNING: pointer chase, but must reload following call
+     */
+    loadWordDisp(cUnit, rGLUE, offsetof(InterpState, ppJitProfTable), r0);
+    loadWordDisp(cUnit, r0, 0, r0);
+    storeWordDisp(cUnit, rGLUE, offsetof(InterpState, pJitProfTable), r0);
 #if defined(WITH_DEADLOCK_PREDICTION)
     if (isEnter) {
         loadWordDisp(cUnit, rGLUE, offsetof(InterpState, self), r0);
@@ -1786,6 +1794,7 @@ static bool handleFmt11n_Fmt31i(CompilationUnit *cUnit, MIR *mir)
         }
         case OP_CONST_WIDE_32: {
             //TUNING: single routine to load constant pair for support doubles
+            //TUNING: load 0/-1 separately to avoid load dependency
             rlResult = evalLoc(cUnit, rlDest, kCoreReg, true);
             loadConstantValue(cUnit, rlResult.lowReg, mir->dalvikInsn.vB);
             opRegRegImm(cUnit, kOpAsr, rlResult.highReg,
@@ -2165,6 +2174,7 @@ static bool handleFmt12x(CompilationUnit *cUnit, MIR *mir)
         case OP_INT_TO_LONG:
             rlSrc = updateLoc(cUnit, rlSrc);
             rlResult = evalLoc(cUnit, rlDest, kCoreReg, true);
+            //TUNING: shouldn't loadValueDirect already check for phys reg?
             if (rlSrc.location == kLocPhysReg) {
                 genRegCopy(cUnit, rlResult.lowReg, rlSrc.lowReg);
             } else {
@@ -2227,6 +2237,7 @@ static bool handleFmt21s(CompilationUnit *cUnit, MIR *mir)
         rlDest = getDestLocWide(cUnit, mir, 0, 1);
         rlResult = evalLoc(cUnit, rlDest, kCoreReg, true);
         loadConstantValue(cUnit, rlResult.lowReg, BBBB);
+        //TUNING: do high separately to avoid load dependency
         opRegRegImm(cUnit, kOpAsr, rlResult.highReg, rlResult.lowReg, 31);
         storeValueWide(cUnit, rlDest, rlResult);
     } else if (dalvikOpCode == OP_CONST_16) {
index dfa60fe..ea93bbf 100644 (file)
@@ -964,7 +964,7 @@ static ArmLIR *storeBaseDispBody(CompilationUnit *cUnit, int rBase,
                 opCode = kThumbStrbRRI5;
             } else if (thumb2Form) {
                 shortForm = true;
-                opCode = kThumb2StrhRRI12;
+                opCode = kThumb2StrbRRI12;
             }
             break;
         default:
index f4c7aa2..5f2a6a2 100644 (file)
@@ -241,6 +241,14 @@ static void genMonitor(CompilationUnit *cUnit, MIR *mir)
     }
     genExportPC(cUnit, mir);
     opReg(cUnit, kOpBlx, r7);
+    /*
+     * Refresh Jit's on/off status, which may have changed if we were
+     * sent to VM_MONITOR state above.
+     * TUNING: pointer chase, but must refresh following return from call
+     */
+    loadWordDisp(cUnit, rGLUE, offsetof(InterpState, ppJitProfTable), r0);
+    loadWordDisp(cUnit, r0, 0, r0);
+    storeWordDisp(cUnit, rGLUE, offsetof(InterpState, pJitProfTable), r0);
 
     clobberCallRegs(cUnit);
 
index c1487dd..5d76f48 100644 (file)
 
     LDR_PC_LR "[r2, #offMethod_nativeFunc]"
 
+    @ Refresh Jit's on/off status
+    ldr     r3, [rGLUE, #offGlue_ppJitProfTable]
+
     @ native return; r9=self, r10=newSaveArea
     @ equivalent to dvmPopJniLocals
     ldr     r2, [r10, #offStackSaveArea_returnAddr] @ r2 = chaining cell ret
     ldr     r0, [r10, #offStackSaveArea_localRefCookie] @ r0<- saved->top
     ldr     r1, [r9, #offThread_exception] @ check for exception
+    ldr     r3, [r3]    @ r1 <- pointer to Jit profile table
     str     rFP, [r9, #offThread_curFrame]  @ self->curFrame = fp
     cmp     r1, #0                      @ null?
     str     r0, [r9, #offThread_jniLocal_topCookie] @ new top <- old top
     ldr     r0, [r10, #offStackSaveArea_savedPc] @ reload rPC
+    str     r3, [rGLUE, #offGlue_pJitProfTable]  @ cache current JitProfTable
 
     @ r0 = dalvikCallsitePC
     bne     .LhandleException           @ no, handle exception
index 36d3ea1..afd69f3 100644 (file)
@@ -243,7 +243,7 @@ dvmCompiler_TEMPLATE_INVOKE_METHOD_NO_OPT:
     sub     r1, r1, r7, lsl #2          @ r1<- newFp (old savearea - regsSize)
     SAVEAREA_FROM_FP(r10, r1)           @ r10<- stack save area
     sub     r10, r10, r2, lsl #2        @ r10<- bottom (newsave - outsSize)
-    ldr     r8, [r8]                    @ r3<- suspendCount (int)
+    ldr     r8, [r8]                    @ r8<- suspendCount (int)
     cmp     r10, r9                     @ bottom < interpStackEnd?
     bxlt    lr                          @ return to raise stack overflow excep.
     @ r1 = newFP, r0 = methodToCall, r3 = returnCell, rPC = dalvikCallsite
@@ -306,7 +306,7 @@ dvmCompiler_TEMPLATE_INVOKE_METHOD_CHAIN:
     SAVEAREA_FROM_FP(r10, r1)           @ r10<- stack save area
     add     r12, lr, #2                 @ setup the punt-to-interp address
     sub     r10, r10, r2, lsl #2        @ r10<- bottom (newsave - outsSize)
-    ldr     r8, [r8]                    @ r3<- suspendCount (int)
+    ldr     r8, [r8]                    @ r8<- suspendCount (int)
     cmp     r10, r9                     @ bottom < interpStackEnd?
     bxlt    r12                         @ return to raise stack overflow excep.
     @ r1 = newFP, r0 = methodToCall, r3 = returnCell, rPC = dalvikCallsite
@@ -1417,15 +1417,20 @@ dvmCompiler_TEMPLATE_INTERPRET:
 
     LDR_PC_LR "[r2, #offMethod_nativeFunc]"
 
+    @ Refresh Jit's on/off status
+    ldr     r3, [rGLUE, #offGlue_ppJitProfTable]
+
     @ native return; r9=self, r10=newSaveArea
     @ equivalent to dvmPopJniLocals
     ldr     r2, [r10, #offStackSaveArea_returnAddr] @ r2 = chaining cell ret
     ldr     r0, [r10, #offStackSaveArea_localRefCookie] @ r0<- saved->top
     ldr     r1, [r9, #offThread_exception] @ check for exception
+    ldr     r3, [r3]    @ r1 <- pointer to Jit profile table
     str     rFP, [r9, #offThread_curFrame]  @ self->curFrame = fp
     cmp     r1, #0                      @ null?
     str     r0, [r9, #offThread_jniLocal_topCookie] @ new top <- old top
     ldr     r0, [r10, #offStackSaveArea_savedPc] @ reload rPC
+    str     r3, [rGLUE, #offGlue_pJitProfTable]  @ cache current JitProfTable
 
     @ r0 = dalvikCallsitePC
     bne     .LhandleException           @ no, handle exception
index 48dd707..d73e010 100644 (file)
@@ -243,7 +243,7 @@ dvmCompiler_TEMPLATE_INVOKE_METHOD_NO_OPT:
     sub     r1, r1, r7, lsl #2          @ r1<- newFp (old savearea - regsSize)
     SAVEAREA_FROM_FP(r10, r1)           @ r10<- stack save area
     sub     r10, r10, r2, lsl #2        @ r10<- bottom (newsave - outsSize)
-    ldr     r8, [r8]                    @ r3<- suspendCount (int)
+    ldr     r8, [r8]                    @ r8<- suspendCount (int)
     cmp     r10, r9                     @ bottom < interpStackEnd?
     bxlt    lr                          @ return to raise stack overflow excep.
     @ r1 = newFP, r0 = methodToCall, r3 = returnCell, rPC = dalvikCallsite
@@ -306,7 +306,7 @@ dvmCompiler_TEMPLATE_INVOKE_METHOD_CHAIN:
     SAVEAREA_FROM_FP(r10, r1)           @ r10<- stack save area
     add     r12, lr, #2                 @ setup the punt-to-interp address
     sub     r10, r10, r2, lsl #2        @ r10<- bottom (newsave - outsSize)
-    ldr     r8, [r8]                    @ r3<- suspendCount (int)
+    ldr     r8, [r8]                    @ r8<- suspendCount (int)
     cmp     r10, r9                     @ bottom < interpStackEnd?
     bxlt    r12                         @ return to raise stack overflow excep.
     @ r1 = newFP, r0 = methodToCall, r3 = returnCell, rPC = dalvikCallsite
@@ -1142,15 +1142,20 @@ dvmCompiler_TEMPLATE_INTERPRET:
 
     LDR_PC_LR "[r2, #offMethod_nativeFunc]"
 
+    @ Refresh Jit's on/off status
+    ldr     r3, [rGLUE, #offGlue_ppJitProfTable]
+
     @ native return; r9=self, r10=newSaveArea
     @ equivalent to dvmPopJniLocals
     ldr     r2, [r10, #offStackSaveArea_returnAddr] @ r2 = chaining cell ret
     ldr     r0, [r10, #offStackSaveArea_localRefCookie] @ r0<- saved->top
     ldr     r1, [r9, #offThread_exception] @ check for exception
+    ldr     r3, [r3]    @ r1 <- pointer to Jit profile table
     str     rFP, [r9, #offThread_curFrame]  @ self->curFrame = fp
     cmp     r1, #0                      @ null?
     str     r0, [r9, #offThread_jniLocal_topCookie] @ new top <- old top
     ldr     r0, [r10, #offStackSaveArea_savedPc] @ reload rPC
+    str     r3, [rGLUE, #offGlue_pJitProfTable]  @ cache current JitProfTable
 
     @ r0 = dalvikCallsitePC
     bne     .LhandleException           @ no, handle exception
index 469919a..12af0d2 100644 (file)
@@ -243,7 +243,7 @@ dvmCompiler_TEMPLATE_INVOKE_METHOD_NO_OPT:
     sub     r1, r1, r7, lsl #2          @ r1<- newFp (old savearea - regsSize)
     SAVEAREA_FROM_FP(r10, r1)           @ r10<- stack save area
     sub     r10, r10, r2, lsl #2        @ r10<- bottom (newsave - outsSize)
-    ldr     r8, [r8]                    @ r3<- suspendCount (int)
+    ldr     r8, [r8]                    @ r8<- suspendCount (int)
     cmp     r10, r9                     @ bottom < interpStackEnd?
     bxlt    lr                          @ return to raise stack overflow excep.
     @ r1 = newFP, r0 = methodToCall, r3 = returnCell, rPC = dalvikCallsite
@@ -306,7 +306,7 @@ dvmCompiler_TEMPLATE_INVOKE_METHOD_CHAIN:
     SAVEAREA_FROM_FP(r10, r1)           @ r10<- stack save area
     add     r12, lr, #2                 @ setup the punt-to-interp address
     sub     r10, r10, r2, lsl #2        @ r10<- bottom (newsave - outsSize)
-    ldr     r8, [r8]                    @ r3<- suspendCount (int)
+    ldr     r8, [r8]                    @ r8<- suspendCount (int)
     cmp     r10, r9                     @ bottom < interpStackEnd?
     bxlt    r12                         @ return to raise stack overflow excep.
     @ r1 = newFP, r0 = methodToCall, r3 = returnCell, rPC = dalvikCallsite
@@ -1417,15 +1417,20 @@ dvmCompiler_TEMPLATE_INTERPRET:
 
     LDR_PC_LR "[r2, #offMethod_nativeFunc]"
 
+    @ Refresh Jit's on/off status
+    ldr     r3, [rGLUE, #offGlue_ppJitProfTable]
+
     @ native return; r9=self, r10=newSaveArea
     @ equivalent to dvmPopJniLocals
     ldr     r2, [r10, #offStackSaveArea_returnAddr] @ r2 = chaining cell ret
     ldr     r0, [r10, #offStackSaveArea_localRefCookie] @ r0<- saved->top
     ldr     r1, [r9, #offThread_exception] @ check for exception
+    ldr     r3, [r3]    @ r1 <- pointer to Jit profile table
     str     rFP, [r9, #offThread_curFrame]  @ self->curFrame = fp
     cmp     r1, #0                      @ null?
     str     r0, [r9, #offThread_jniLocal_topCookie] @ new top <- old top
     ldr     r0, [r10, #offStackSaveArea_savedPc] @ reload rPC
+    str     r3, [rGLUE, #offGlue_pJitProfTable]  @ cache current JitProfTable
 
     @ r0 = dalvikCallsitePC
     bne     .LhandleException           @ no, handle exception
index 2928371..3231968 100644 (file)
@@ -159,6 +159,14 @@ typedef struct InterpState {
     void*              jitResume;
     u2*                jitResumePC;
     int                jitThreshold;
+    /*
+     * ppJitProfTable holds the address of gDvmJit.pJitProfTable, which
+     * doubles as an on/off switch for the Jit.  Because a change in
+     * the value of gDvmJit.pJitProfTable isn't reflected in the cached
+     * copy above (pJitProfTable), we need to periodically refresh it.
+     * ppJitProfTable is used for that purpose.
+     */
+    unsigned char**    ppJitProfTable; // Used to refresh pJitProfTable
 #endif
 
 #if defined(WITH_PROFILER) || defined(WITH_DEBUGGER)
index 2d35e51..34a7736 100644 (file)
@@ -348,51 +348,9 @@ int dvmJitStartup(void)
     unsigned int i;
     bool res = true;  /* Assume success */
 
-    // Create the compiler thread and setup miscellaneous chores */
-    res &= dvmCompilerStartup();
-
-    dvmInitMutex(&gDvmJit.tableLock);
-    if (res && gDvm.executionMode == kExecutionModeJit) {
-        JitEntry *pJitTable = NULL;
-        unsigned char *pJitProfTable = NULL;
-        // Power of 2?
-        assert(gDvmJit.jitTableSize &&
-               !(gDvmJit.jitTableSize & (gDvmJit.jitTableSize - 1)));
-        dvmLockMutex(&gDvmJit.tableLock);
-        pJitTable = (JitEntry*)
-                    calloc(gDvmJit.jitTableSize, sizeof(*pJitTable));
-        if (!pJitTable) {
-            LOGE("jit table allocation failed\n");
-            res = false;
-            goto done;
-        }
-        /*
-         * NOTE: the profile table must only be allocated once, globally.
-         * Profiling is turned on and off by nulling out gDvm.pJitProfTable
-         * and then restoring its original value.  However, this action
-         * is not syncronized for speed so threads may continue to hold
-         * and update the profile table after profiling has been turned
-         * off by null'ng the global pointer.  Be aware.
-         */
-        pJitProfTable = (unsigned char *)malloc(JIT_PROF_SIZE);
-        if (!pJitProfTable) {
-            LOGE("jit prof table allocation failed\n");
-            res = false;
-            goto done;
-        }
-        memset(pJitProfTable, gDvmJit.threshold, JIT_PROF_SIZE);
-        for (i=0; i < gDvmJit.jitTableSize; i++) {
-           pJitTable[i].u.info.chain = gDvmJit.jitTableSize;
-        }
-        /* Is chain field wide enough for termination pattern? */
-        assert(pJitTable[0].u.info.chain == gDvmJit.jitTableSize);
-
-done:
-        gDvmJit.pJitEntryTable = pJitTable;
-        gDvmJit.jitTableMask = gDvmJit.jitTableSize - 1;
-        gDvmJit.jitTableEntriesUsed = 0;
-        gDvmJit.pProfTable = pJitProfTable;
-        dvmUnlockMutex(&gDvmJit.tableLock);
+    // Create the compiler thread, which will complete initialization
+    if (gDvm.executionMode == kExecutionModeJit) {
+        res = dvmCompilerStartup();
     }
     return res;
 }
@@ -553,6 +511,94 @@ static bool selfVerificationPuntOps(DecodedInstruction *decInsn)
 #endif
 
 /*
+ * Find an entry in the JitTable, creating if necessary.
+ * Returns null if table is full.
+ */
+static JitEntry *lookupAndAdd(const u2* dPC, bool callerLocked)
+{
+    u4 chainEndMarker = gDvmJit.jitTableSize;
+    u4 idx = dvmJitHash(dPC);
+
+    /* Walk the bucket chain to find an exact match for our PC */
+    while ((gDvmJit.pJitEntryTable[idx].u.info.chain != chainEndMarker) &&
+           (gDvmJit.pJitEntryTable[idx].dPC != dPC)) {
+        idx = gDvmJit.pJitEntryTable[idx].u.info.chain;
+    }
+
+    if (gDvmJit.pJitEntryTable[idx].dPC != dPC) {
+        /*
+         * No match.  Aquire jitTableLock and find the last
+         * slot in the chain. Possibly continue the chain walk in case
+         * some other thread allocated the slot we were looking
+         * at previuosly (perhaps even the dPC we're trying to enter).
+         */
+        if (!callerLocked)
+            dvmLockMutex(&gDvmJit.tableLock);
+        /*
+         * At this point, if .dPC is NULL, then the slot we're
+         * looking at is the target slot from the primary hash
+         * (the simple, and common case).  Otherwise we're going
+         * to have to find a free slot and chain it.
+         */
+        MEM_BARRIER(); /* Make sure we reload [].dPC after lock */
+        if (gDvmJit.pJitEntryTable[idx].dPC != NULL) {
+            u4 prev;
+            while (gDvmJit.pJitEntryTable[idx].u.info.chain != chainEndMarker) {
+                if (gDvmJit.pJitEntryTable[idx].dPC == dPC) {
+                    /* Another thread got there first for this dPC */
+                    if (!callerLocked)
+                        dvmUnlockMutex(&gDvmJit.tableLock);
+                    return &gDvmJit.pJitEntryTable[idx];
+                }
+                idx = gDvmJit.pJitEntryTable[idx].u.info.chain;
+            }
+            /* Here, idx should be pointing to the last cell of an
+             * active chain whose last member contains a valid dPC */
+            assert(gDvmJit.pJitEntryTable[idx].dPC != NULL);
+            /* Linear walk to find a free cell and add it to the end */
+            prev = idx;
+            while (true) {
+                idx++;
+                if (idx == chainEndMarker)
+                    idx = 0;  /* Wraparound */
+                if ((gDvmJit.pJitEntryTable[idx].dPC == NULL) ||
+                    (idx == prev))
+                    break;
+            }
+            if (idx != prev) {
+                JitEntryInfoUnion oldValue;
+                JitEntryInfoUnion newValue;
+                /*
+                 * Although we hold the lock so that noone else will
+                 * be trying to update a chain field, the other fields
+                 * packed into the word may be in use by other threads.
+                 */
+                do {
+                    oldValue = gDvmJit.pJitEntryTable[prev].u;
+                    newValue = oldValue;
+                    newValue.info.chain = idx;
+                } while (!ATOMIC_CMP_SWAP(
+                         &gDvmJit.pJitEntryTable[prev].u.infoWord,
+                         oldValue.infoWord, newValue.infoWord));
+            }
+        }
+        if (gDvmJit.pJitEntryTable[idx].dPC == NULL) {
+            /*
+             * Initialize codeAddress and allocate the slot.  Must
+             * happen in this order (since dPC is set, the entry is live.
+             */
+            gDvmJit.pJitEntryTable[idx].dPC = dPC;
+            gDvmJit.jitTableEntriesUsed++;
+        } else {
+            /* Table is full */
+            idx = chainEndMarker;
+        }
+        if (!callerLocked)
+            dvmUnlockMutex(&gDvmJit.tableLock);
+    }
+    return (idx == chainEndMarker) ? NULL : &gDvmJit.pJitEntryTable[idx];
+}
+/*
  * Adds to the current trace request one instruction at a time, just
  * before that instruction is interpreted.  This is the primary trace
  * selection function.  NOTE: return instruction are handled a little
@@ -707,13 +753,19 @@ int dvmCheckJit(const u2* pc, Thread* self, InterpState* interpState)
 #if defined(SHOW_TRACE)
                 LOGD("TraceGen:  trace done, adding to queue");
 #endif
-                dvmCompilerWorkEnqueue(
-                       interpState->currTraceHead,kWorkOrderTrace,desc);
-                setTraceConstruction(
-                     dvmJitLookupAndAdd(interpState->currTraceHead), false);
-                if (gDvmJit.blockingMode) {
-                    dvmCompilerDrainQueue();
+                if (dvmCompilerWorkEnqueue(
+                       interpState->currTraceHead,kWorkOrderTrace,desc)) {
+                    /* Work order successfully enqueued */
+                    if (gDvmJit.blockingMode) {
+                        dvmCompilerDrainQueue();
+                    }
                 }
+                /*
+                 * Reset "trace in progress" flag whether or not we
+                 * successfully entered a work order.
+                 */
+                setTraceConstruction(
+                     lookupAndAdd(interpState->currTraceHead, false), false);
                 switchInterp = !debugOrProfile;
             }
             break;
@@ -811,91 +863,6 @@ void* dvmJitGetCodeAddr(const u2* dPC)
 }
 
 /*
- * Find an entry in the JitTable, creating if necessary.
- * Returns null if table is full.
- */
-JitEntry *dvmJitLookupAndAdd(const u2* dPC)
-{
-    u4 chainEndMarker = gDvmJit.jitTableSize;
-    u4 idx = dvmJitHash(dPC);
-
-    /* Walk the bucket chain to find an exact match for our PC */
-    while ((gDvmJit.pJitEntryTable[idx].u.info.chain != chainEndMarker) &&
-           (gDvmJit.pJitEntryTable[idx].dPC != dPC)) {
-        idx = gDvmJit.pJitEntryTable[idx].u.info.chain;
-    }
-
-    if (gDvmJit.pJitEntryTable[idx].dPC != dPC) {
-        /*
-         * No match.  Aquire jitTableLock and find the last
-         * slot in the chain. Possibly continue the chain walk in case
-         * some other thread allocated the slot we were looking
-         * at previuosly (perhaps even the dPC we're trying to enter).
-         */
-        dvmLockMutex(&gDvmJit.tableLock);
-        /*
-         * At this point, if .dPC is NULL, then the slot we're
-         * looking at is the target slot from the primary hash
-         * (the simple, and common case).  Otherwise we're going
-         * to have to find a free slot and chain it.
-         */
-        MEM_BARRIER(); /* Make sure we reload [].dPC after lock */
-        if (gDvmJit.pJitEntryTable[idx].dPC != NULL) {
-            u4 prev;
-            while (gDvmJit.pJitEntryTable[idx].u.info.chain != chainEndMarker) {
-                if (gDvmJit.pJitEntryTable[idx].dPC == dPC) {
-                    /* Another thread got there first for this dPC */
-                    dvmUnlockMutex(&gDvmJit.tableLock);
-                    return &gDvmJit.pJitEntryTable[idx];
-                }
-                idx = gDvmJit.pJitEntryTable[idx].u.info.chain;
-            }
-            /* Here, idx should be pointing to the last cell of an
-             * active chain whose last member contains a valid dPC */
-            assert(gDvmJit.pJitEntryTable[idx].dPC != NULL);
-            /* Linear walk to find a free cell and add it to the end */
-            prev = idx;
-            while (true) {
-                idx++;
-                if (idx == chainEndMarker)
-                    idx = 0;  /* Wraparound */
-                if ((gDvmJit.pJitEntryTable[idx].dPC == NULL) ||
-                    (idx == prev))
-                    break;
-            }
-            if (idx != prev) {
-                JitEntryInfoUnion oldValue;
-                JitEntryInfoUnion newValue;
-                /*
-                 * Although we hold the lock so that noone else will
-                 * be trying to update a chain field, the other fields
-                 * packed into the word may be in use by other threads.
-                 */
-                do {
-                    oldValue = gDvmJit.pJitEntryTable[prev].u;
-                    newValue = oldValue;
-                    newValue.info.chain = idx;
-                } while (!ATOMIC_CMP_SWAP(
-                         &gDvmJit.pJitEntryTable[prev].u.infoWord,
-                         oldValue.infoWord, newValue.infoWord));
-            }
-        }
-        if (gDvmJit.pJitEntryTable[idx].dPC == NULL) {
-            /*
-             * Initialize codeAddress and allocate the slot.  Must
-             * happen in this order (since dPC is set, the entry is live.
-             */
-            gDvmJit.pJitEntryTable[idx].dPC = dPC;
-            gDvmJit.jitTableEntriesUsed++;
-        } else {
-            /* Table is full */
-            idx = chainEndMarker;
-        }
-        dvmUnlockMutex(&gDvmJit.tableLock);
-    }
-    return (idx == chainEndMarker) ? NULL : &gDvmJit.pJitEntryTable[idx];
-}
-/*
  * Register the translated code pointer into the JitTable.
  * NOTE: Once a codeAddress field transitions from initial state to
  * JIT'd code, it must not be altered without first halting all
@@ -905,7 +872,7 @@ JitEntry *dvmJitLookupAndAdd(const u2* dPC)
 void dvmJitSetCodeAddr(const u2* dPC, void *nPC, JitInstructionSetType set) {
     JitEntryInfoUnion oldValue;
     JitEntryInfoUnion newValue;
-    JitEntry *jitEntry = dvmJitLookupAndAdd(dPC);
+    JitEntry *jitEntry = lookupAndAdd(dPC, false);
     assert(jitEntry);
     /* Note: order of update is important */
     do {
@@ -966,7 +933,7 @@ bool dvmJitCheckTraceRequest(Thread* self, InterpState* interpState)
                 interpState->jitState = kJitNormal;
             }
         } else if (interpState->jitState == kJitTSelectRequest) {
-            JitEntry *slot = dvmJitLookupAndAdd(interpState->pc);
+            JitEntry *slot = lookupAndAdd(interpState->pc, false);
             if (slot == NULL) {
                 /*
                  * Table is full.  This should have been
@@ -1041,12 +1008,14 @@ bool dvmJitCheckTraceRequest(Thread* self, InterpState* interpState)
 
 /*
  * Resizes the JitTable.  Must be a power of 2, and returns true on failure.
- * Stops all threads, and thus is a heavyweight operation.
+ * Stops all threads, and thus is a heavyweight operation. May only be called
+ * by the compiler thread.
  */
 bool dvmJitResizeJitTable( unsigned int size )
 {
     JitEntry *pNewTable;
     JitEntry *pOldTable;
+    JitEntry tempEntry;
     u4 newMask;
     unsigned int oldSize;
     unsigned int i;
@@ -1062,6 +1031,13 @@ bool dvmJitResizeJitTable( unsigned int size )
         return true;
     }
 
+    /* Make sure requested size is compatible with chain field width */
+    tempEntry.u.info.chain = size;
+    if (tempEntry.u.info.chain != size) {
+        LOGD("Jit: JitTable request of %d too big", size);
+        return true;
+    }
+
     pNewTable = (JitEntry*)calloc(size, sizeof(*pNewTable));
     if (pNewTable == NULL) {
         return true;
@@ -1081,29 +1057,20 @@ bool dvmJitResizeJitTable( unsigned int size )
     gDvmJit.jitTableSize = size;
     gDvmJit.jitTableMask = size - 1;
     gDvmJit.jitTableEntriesUsed = 0;
-    dvmUnlockMutex(&gDvmJit.tableLock);
 
     for (i=0; i < oldSize; i++) {
         if (pOldTable[i].dPC) {
             JitEntry *p;
             u2 chain;
-            p = dvmJitLookupAndAdd(pOldTable[i].dPC);
-            p->dPC = pOldTable[i].dPC;
-            /*
-             * Compiler thread may have just updated the new entry's
-             * code address field, so don't blindly copy null.
-             */
-            if (pOldTable[i].codeAddress != NULL) {
-                p->codeAddress = pOldTable[i].codeAddress;
-            }
+            p = lookupAndAdd(pOldTable[i].dPC, true /* holds tableLock*/ );
+            p->codeAddress = pOldTable[i].codeAddress;
             /* We need to preserve the new chain field, but copy the rest */
-            dvmLockMutex(&gDvmJit.tableLock);
             chain = p->u.info.chain;
             p->u = pOldTable[i].u;
             p->u.info.chain = chain;
-            dvmUnlockMutex(&gDvmJit.tableLock);
         }
     }
+    dvmUnlockMutex(&gDvmJit.tableLock);
 
     free(pOldTable);
 
index 177a734..3afaa6a 100644 (file)
@@ -123,7 +123,5 @@ s8 dvmJitd2l(double d);
 s8 dvmJitf2l(float f);
 void dvmJitSetCodeAddr(const u2* dPC, void *nPC, JitInstructionSetType set);
 void dvmJitAbortTraceSelect(InterpState* interpState);
-JitEntry *dvmJitLookupAndAdd(const u2* dPC);
-
 
 #endif /*_DALVIK_INTERP_JIT*/
index d14f6b2..ca2ca16 100644 (file)
@@ -83,6 +83,7 @@ bool dvmMterpStd(Thread* self, InterpState* glue)
     glue->pSelfSuspendCount = &self->suspendCount;
 #if defined(WITH_JIT)
     glue->pJitProfTable = gDvmJit.pProfTable;
+    glue->ppJitProfTable = &gDvmJit.pProfTable;
     glue->jitThreshold = gDvmJit.threshold;
 #endif
 #if defined(WITH_DEBUGGER)
index 7476e29..3f4321c 100644 (file)
@@ -377,8 +377,20 @@ common_periodicChecks:
     bx      lr                          @ nothing to do, return
 
 2:  @ check suspend
+#if defined(WITH_JIT)
+    /*
+     * Refresh the Jit's cached copy of profile table pointer.  This pointer
+     * doubles as the Jit's on/off switch.
+     */
+    ldr     r3, [rGLUE, #offGlue_ppJitProfTable] @ r10<-&gDvmJit.pJitProfTable
     ldr     r0, [rGLUE, #offGlue_self]  @ r0<- glue->self
+    ldr     r3, [r3] @ r10 <- pJitProfTable
     EXPORT_PC()                         @ need for precise GC
+    str     r3, [rGLUE, #offGlue_pJitProfTable] @ refresh Jit's on/off switch
+#else
+    ldr     r0, [rGLUE, #offGlue_self]  @ r0<- glue->self
+    EXPORT_PC()                         @ need for precise GC
+#endif
     b       dvmCheckSuspendPending      @ suspend if necessary, then return
 
 3:  @ debugger/profiler enabled, bail out
@@ -574,13 +586,23 @@ dalvik_mterp:
     @ldr     pc, [r2, #offMethod_nativeFunc] @ pc<- methodToCall->nativeFunc
     LDR_PC_LR "[r2, #offMethod_nativeFunc]"
 
+#if defined(WITH_JIT)
+    ldr     r3, [rGLUE, #offGlue_ppJitProfTable] @ Refresh Jit's on/off status
+#endif
+
     @ native return; r9=self, r10=newSaveArea
     @ equivalent to dvmPopJniLocals
     ldr     r0, [r10, #offStackSaveArea_localRefCookie] @ r0<- saved top
     ldr     r1, [r9, #offThread_exception] @ check for exception
+#if defined(WITH_JIT)
+    ldr     r3, [r3]                    @ r3 <- gDvmJit.pProfTable
+#endif
     str     rFP, [r9, #offThread_curFrame]  @ self->curFrame = fp
     cmp     r1, #0                      @ null?
     str     r0, [r9, #offThread_jniLocal_topCookie] @ new top <- old top
+#if defined(WITH_JIT)
+    str     r3, [rGLUE, #offGlue_pJitProfTable] @ refresh cached on/off switch
+#endif
     bne     common_exceptionThrown      @ no, handle exception
 
     FETCH_ADVANCE_INST(3)               @ advance rPC, load rINST
index d6ff482..a3c8cec 100644 (file)
@@ -107,6 +107,7 @@ MTERP_OFFSET(offGlue_jitState,          MterpGlue, jitState, 60)
 MTERP_OFFSET(offGlue_jitResume,         MterpGlue, jitResume, 64)
 MTERP_OFFSET(offGlue_jitResumePC,       MterpGlue, jitResumePC, 68)
 MTERP_OFFSET(offGlue_jitThreshold,      MterpGlue, jitThreshold, 72)
+MTERP_OFFSET(offGlue_ppJitProfTable,    MterpGlue, ppJitProfTable, 76)
 #endif
 #elif defined(WITH_DEBUGGER)
 MTERP_OFFSET(offGlue_pDebuggerActive,   MterpGlue, pDebuggerActive, 40)
@@ -117,6 +118,7 @@ MTERP_OFFSET(offGlue_jitState,          MterpGlue, jitState, 56)
 MTERP_OFFSET(offGlue_jitResume,         MterpGlue, jitResume, 60)
 MTERP_OFFSET(offGlue_jitResumePC,       MterpGlue, jitResumePC, 64)
 MTERP_OFFSET(offGlue_jitThreshold,      MterpGlue, jitThreshold, 68)
+MTERP_OFFSET(offGlue_jitppJitProfTable, MterpGlue, ppJitProfTable, 72)
 #endif
 #elif defined(WITH_PROFILER)
 MTERP_OFFSET(offGlue_pActiveProfilers,  MterpGlue, pActiveProfilers, 40)
@@ -127,6 +129,7 @@ MTERP_OFFSET(offGlue_jitState,          MterpGlue, jitState, 56)
 MTERP_OFFSET(offGlue_jitResume,         MterpGlue, jitResume, 60)
 MTERP_OFFSET(offGlue_jitResumePC,       MterpGlue, jitResumePC, 64)
 MTERP_OFFSET(offGlue_jitThreshold,      MterpGlue, jitThreshold, 68)
+MTERP_OFFSET(offGlue_jitppJitProfTable, MterpGlue, ppJitProfTable, 72)
 #endif
 #else
 MTERP_OFFSET(offGlue_entryPoint,        MterpGlue, entryPoint, 40)
@@ -136,6 +139,7 @@ MTERP_OFFSET(offGlue_jitState,          MterpGlue, jitState, 52)
 MTERP_OFFSET(offGlue_jitResume,         MterpGlue, jitResume, 56)
 MTERP_OFFSET(offGlue_jitResumePC,       MterpGlue, jitResumePC, 60)
 MTERP_OFFSET(offGlue_jitThreshold,      MterpGlue, jitThreshold, 64)
+MTERP_OFFSET(offGlue_jitppJitProfTable, MterpGlue, ppJitProfTable, 68)
 #endif
 #endif
 /* make sure all JValue union members are stored at the same offset */
index ba248de..da3199e 100644 (file)
@@ -9904,8 +9904,20 @@ common_periodicChecks:
     bx      lr                          @ nothing to do, return
 
 2:  @ check suspend
+#if defined(WITH_JIT)
+    /*
+     * Refresh the Jit's cached copy of profile table pointer.  This pointer
+     * doubles as the Jit's on/off switch.
+     */
+    ldr     r3, [rGLUE, #offGlue_ppJitProfTable] @ r10<-&gDvmJit.pJitProfTable
     ldr     r0, [rGLUE, #offGlue_self]  @ r0<- glue->self
+    ldr     r3, [r3] @ r10 <- pJitProfTable
     EXPORT_PC()                         @ need for precise GC
+    str     r3, [rGLUE, #offGlue_pJitProfTable] @ refresh Jit's on/off switch
+#else
+    ldr     r0, [rGLUE, #offGlue_self]  @ r0<- glue->self
+    EXPORT_PC()                         @ need for precise GC
+#endif
     b       dvmCheckSuspendPending      @ suspend if necessary, then return
 
 3:  @ debugger/profiler enabled, bail out
@@ -10101,13 +10113,23 @@ dalvik_mterp:
     @ldr     pc, [r2, #offMethod_nativeFunc] @ pc<- methodToCall->nativeFunc
     LDR_PC_LR "[r2, #offMethod_nativeFunc]"
 
+#if defined(WITH_JIT)
+    ldr     r3, [rGLUE, #offGlue_ppJitProfTable] @ Refresh Jit's on/off status
+#endif
+
     @ native return; r9=self, r10=newSaveArea
     @ equivalent to dvmPopJniLocals
     ldr     r0, [r10, #offStackSaveArea_localRefCookie] @ r0<- saved top
     ldr     r1, [r9, #offThread_exception] @ check for exception
+#if defined(WITH_JIT)
+    ldr     r3, [r3]                    @ r3 <- gDvmJit.pProfTable
+#endif
     str     rFP, [r9, #offThread_curFrame]  @ self->curFrame = fp
     cmp     r1, #0                      @ null?
     str     r0, [r9, #offThread_jniLocal_topCookie] @ new top <- old top
+#if defined(WITH_JIT)
+    str     r3, [rGLUE, #offGlue_pJitProfTable] @ refresh cached on/off switch
+#endif
     bne     common_exceptionThrown      @ no, handle exception
 
     FETCH_ADVANCE_INST(3)               @ advance rPC, load rINST
index 966e4f0..336d9f2 100644 (file)
@@ -9422,8 +9422,20 @@ common_periodicChecks:
     bx      lr                          @ nothing to do, return
 
 2:  @ check suspend
+#if defined(WITH_JIT)
+    /*
+     * Refresh the Jit's cached copy of profile table pointer.  This pointer
+     * doubles as the Jit's on/off switch.
+     */
+    ldr     r3, [rGLUE, #offGlue_ppJitProfTable] @ r10<-&gDvmJit.pJitProfTable
     ldr     r0, [rGLUE, #offGlue_self]  @ r0<- glue->self
+    ldr     r3, [r3] @ r10 <- pJitProfTable
     EXPORT_PC()                         @ need for precise GC
+    str     r3, [rGLUE, #offGlue_pJitProfTable] @ refresh Jit's on/off switch
+#else
+    ldr     r0, [rGLUE, #offGlue_self]  @ r0<- glue->self
+    EXPORT_PC()                         @ need for precise GC
+#endif
     b       dvmCheckSuspendPending      @ suspend if necessary, then return
 
 3:  @ debugger/profiler enabled, bail out
@@ -9619,13 +9631,23 @@ dalvik_mterp:
     @ldr     pc, [r2, #offMethod_nativeFunc] @ pc<- methodToCall->nativeFunc
     LDR_PC_LR "[r2, #offMethod_nativeFunc]"
 
+#if defined(WITH_JIT)
+    ldr     r3, [rGLUE, #offGlue_ppJitProfTable] @ Refresh Jit's on/off status
+#endif
+
     @ native return; r9=self, r10=newSaveArea
     @ equivalent to dvmPopJniLocals
     ldr     r0, [r10, #offStackSaveArea_localRefCookie] @ r0<- saved top
     ldr     r1, [r9, #offThread_exception] @ check for exception
+#if defined(WITH_JIT)
+    ldr     r3, [r3]                    @ r3 <- gDvmJit.pProfTable
+#endif
     str     rFP, [r9, #offThread_curFrame]  @ self->curFrame = fp
     cmp     r1, #0                      @ null?
     str     r0, [r9, #offThread_jniLocal_topCookie] @ new top <- old top
+#if defined(WITH_JIT)
+    str     r3, [rGLUE, #offGlue_pJitProfTable] @ refresh cached on/off switch
+#endif
     bne     common_exceptionThrown      @ no, handle exception
 
     FETCH_ADVANCE_INST(3)               @ advance rPC, load rINST
index da56e6c..b947e27 100644 (file)
@@ -9898,8 +9898,20 @@ common_periodicChecks:
     bx      lr                          @ nothing to do, return
 
 2:  @ check suspend
+#if defined(WITH_JIT)
+    /*
+     * Refresh the Jit's cached copy of profile table pointer.  This pointer
+     * doubles as the Jit's on/off switch.
+     */
+    ldr     r3, [rGLUE, #offGlue_ppJitProfTable] @ r10<-&gDvmJit.pJitProfTable
     ldr     r0, [rGLUE, #offGlue_self]  @ r0<- glue->self
+    ldr     r3, [r3] @ r10 <- pJitProfTable
     EXPORT_PC()                         @ need for precise GC
+    str     r3, [rGLUE, #offGlue_pJitProfTable] @ refresh Jit's on/off switch
+#else
+    ldr     r0, [rGLUE, #offGlue_self]  @ r0<- glue->self
+    EXPORT_PC()                         @ need for precise GC
+#endif
     b       dvmCheckSuspendPending      @ suspend if necessary, then return
 
 3:  @ debugger/profiler enabled, bail out
@@ -10095,13 +10107,23 @@ dalvik_mterp:
     @ldr     pc, [r2, #offMethod_nativeFunc] @ pc<- methodToCall->nativeFunc
     LDR_PC_LR "[r2, #offMethod_nativeFunc]"
 
+#if defined(WITH_JIT)
+    ldr     r3, [rGLUE, #offGlue_ppJitProfTable] @ Refresh Jit's on/off status
+#endif
+
     @ native return; r9=self, r10=newSaveArea
     @ equivalent to dvmPopJniLocals
     ldr     r0, [r10, #offStackSaveArea_localRefCookie] @ r0<- saved top
     ldr     r1, [r9, #offThread_exception] @ check for exception
+#if defined(WITH_JIT)
+    ldr     r3, [r3]                    @ r3 <- gDvmJit.pProfTable
+#endif
     str     rFP, [r9, #offThread_curFrame]  @ self->curFrame = fp
     cmp     r1, #0                      @ null?
     str     r0, [r9, #offThread_jniLocal_topCookie] @ new top <- old top
+#if defined(WITH_JIT)
+    str     r3, [rGLUE, #offGlue_pJitProfTable] @ refresh cached on/off switch
+#endif
     bne     common_exceptionThrown      @ no, handle exception
 
     FETCH_ADVANCE_INST(3)               @ advance rPC, load rINST
index 606b064..0d1bcc8 100644 (file)
@@ -9358,8 +9358,20 @@ common_periodicChecks:
     bx      lr                          @ nothing to do, return
 
 2:  @ check suspend
+#if defined(WITH_JIT)
+    /*
+     * Refresh the Jit's cached copy of profile table pointer.  This pointer
+     * doubles as the Jit's on/off switch.
+     */
+    ldr     r3, [rGLUE, #offGlue_ppJitProfTable] @ r10<-&gDvmJit.pJitProfTable
     ldr     r0, [rGLUE, #offGlue_self]  @ r0<- glue->self
+    ldr     r3, [r3] @ r10 <- pJitProfTable
     EXPORT_PC()                         @ need for precise GC
+    str     r3, [rGLUE, #offGlue_pJitProfTable] @ refresh Jit's on/off switch
+#else
+    ldr     r0, [rGLUE, #offGlue_self]  @ r0<- glue->self
+    EXPORT_PC()                         @ need for precise GC
+#endif
     b       dvmCheckSuspendPending      @ suspend if necessary, then return
 
 3:  @ debugger/profiler enabled, bail out
@@ -9555,13 +9567,23 @@ dalvik_mterp:
     @ldr     pc, [r2, #offMethod_nativeFunc] @ pc<- methodToCall->nativeFunc
     LDR_PC_LR "[r2, #offMethod_nativeFunc]"
 
+#if defined(WITH_JIT)
+    ldr     r3, [rGLUE, #offGlue_ppJitProfTable] @ Refresh Jit's on/off status
+#endif
+
     @ native return; r9=self, r10=newSaveArea
     @ equivalent to dvmPopJniLocals
     ldr     r0, [r10, #offStackSaveArea_localRefCookie] @ r0<- saved top
     ldr     r1, [r9, #offThread_exception] @ check for exception
+#if defined(WITH_JIT)
+    ldr     r3, [r3]                    @ r3 <- gDvmJit.pProfTable
+#endif
     str     rFP, [r9, #offThread_curFrame]  @ self->curFrame = fp
     cmp     r1, #0                      @ null?
     str     r0, [r9, #offThread_jniLocal_topCookie] @ new top <- old top
+#if defined(WITH_JIT)
+    str     r3, [rGLUE, #offGlue_pJitProfTable] @ refresh cached on/off switch
+#endif
     bne     common_exceptionThrown      @ no, handle exception
 
     FETCH_ADVANCE_INST(3)               @ advance rPC, load rINST