This is a step towards full debug & profiling support in JIT'd code.
Previously, the interpreter made multiple distinct checks for pending
suspend requests, debugger and profiler checks at each safe point.
This CL moves the individual controls into a single control word,
significantly speeding up the safe-point check code path in the common
fast case.
In short, any time some VM component wants control to break at a safe
point it will set a bit in gDvm.interpBreak, which will be examined
at the safe point check in footer.S. In the old code, the safe point
check consisted of 11 instructions (including 6 loads). The new sequence
is 6 instructions (4 loads - two of which are needed and two are
speculative to fill otherwise stalling slots).
This code path is hot enough in the interpreter that we actually see
some measureable speedups in benchmarks. The old sieve benchmark
improves from 252 to 256 (~1.5%).
As part of the change, global debuggerActive and activeProfilers variables
have been eliminated as redundant. Note also that there is a subtle
change in thread suspension. Thread suspend request counts are kept on
a per-thread basis, and previously each thread would only examine its own
suspend count. With this change, a bit has been allocated in interpBreak
to signify that at least one suspend request is active across all
threads. This bit is treated as "some thread is supposed to
suspend, check to see if it's me".
Change-Id: I527dc918f58d1486ef3324136080ef541a775ba8
*/
void dvmDbgActive(void)
{
- if (gDvm.debuggerActive)
+ if (DEBUGGER_ACTIVE)
return;
LOGI("Debugger is active\n");
dvmInitBreakpoints();
- gDvm.debuggerActive = true;
-#if defined(WITH_JIT)
- dvmCompilerStateRefresh();
-#endif
+ dvmUpdateInterpBreak(kSubModeDebuggerActive, true);
}
/*
{
assert(gDvm.debuggerConnected);
- gDvm.debuggerActive = false;
+ dvmUpdateInterpBreak(kSubModeDebuggerActive, false);
dvmHashTableLock(gDvm.dbgRegistry);
gDvm.debuggerConnected = false;
dvmHashTableClear(gDvm.dbgRegistry);
dvmHashTableUnlock(gDvm.dbgRegistry);
-#if defined(WITH_JIT)
- dvmCompilerStateRefresh();
-#endif
}
/*
*/
bool dvmDbgIsDebuggerConnected(void)
{
- return gDvm.debuggerActive;
+ return DEBUGGER_ACTIVE;
}
/*
*/
void dvmDbgPostThreadStart(Thread* thread)
{
- if (gDvm.debuggerActive) {
+ if (DEBUGGER_ACTIVE) {
dvmJdwpPostThreadChange(gDvm.jdwpState,
objectToObjectId(thread->threadObj), true);
}
*/
void dvmDbgPostThreadDeath(Thread* thread)
{
- if (gDvm.debuggerActive) {
+ if (DEBUGGER_ACTIVE) {
dvmJdwpPostThreadChange(gDvm.jdwpState,
objectToObjectId(thread->threadObj), false);
}
struct Method;
struct Thread;
+#define DEBUGGER_ACTIVE (gDvm.interpBreak & kSubModeDebuggerActive)
+
/*
* Used by StepControl to track a set of addresses associated with
* a single line.
} ExecutionMode;
/*
+ * Execution sub modes, e.g. debugging, profiling, etc.
+ * Treated as bit flags for fast access. These values are used directly
+ * by assembly code in the mterp interpeter and may also be used by
+ * code generated by the JIT. Take care when changing.
+ */
+typedef enum ExecutionSubModes {
+ kSubModeNormal = 0x00,
+ kSubModeMethodTrace = 0x01,
+ kSubModeEmulatorTrace = 0x02,
+ kSubModeInstCounting = 0x04,
+ kSubModeDebuggerActive = 0x08,
+ kSubModeSuspendRequest = 0x10, /* Set if any suspend request active */
+} ExecutionSubModes;
+
+/*
* Register map generation mode. Only applicable when generateRegisterMaps
* is enabled. (The "disabled" state is not folded into this because
* there are callers like dexopt that want to enable/disable without
pthread_cond_t threadSuspendCountCond;
/*
- * Sum of all threads' suspendCount fields. The JIT needs to know if any
- * thread is suspended. Guarded by threadSuspendCountLock.
+ * Sum of all threads' suspendCount fields. Guarded by
+ * threadSuspendCountLock.
*/
int sumThreadSuspendCount;
/*
* JDWP debugger support.
- *
- * Note "debuggerActive" is accessed from mterp, so its storage size and
- * meaning must not be changed without updating the assembly sources.
*/
bool debuggerConnected; /* debugger or DDMS is connected */
- u1 debuggerActive; /* debugger is making requests */
JdwpState* jdwpState;
/*
#endif
/*
- * When a profiler is enabled, this is incremented. Distinct profilers
- * include "dmtrace" method tracing, emulator method tracing, and
- * possibly instruction counting.
- *
- * The purpose of this is to have a single value that the interpreter
- * can check to see if any profiling activity is enabled.
+ * When normal control flow needs to be interrupted because
+ * of an attached debugger, profiler, thread stop request, etc.,
+ * a bit is set here. We collapse all stop reasons into
+ * a single location for performance reasons.
*/
- volatile int activeProfilers;
+ volatile int interpBreak;
/*
* State for method-trace profiling.
}
/*
- * Update the "active profilers" count.
- *
- * "count" should be +1 or -1.
+ * Update the set of active profilers
*/
-static void updateActiveProfilers(int count)
+static void updateActiveProfilers(ExecutionSubModes newMode, bool enable)
{
- int oldValue, newValue;
-
- do {
- oldValue = gDvm.activeProfilers;
- newValue = oldValue + count;
- if (newValue < 0) {
- LOGE("Can't have %d active profilers\n", newValue);
- dvmAbort();
- }
- } while (android_atomic_release_cas(oldValue, newValue,
- &gDvm.activeProfilers) != 0);
-
- LOGD("+++ active profiler count now %d\n", newValue);
-#if defined(WITH_JIT)
- dvmCompilerStateRefresh();
-#endif
+ dvmUpdateInterpBreak(newMode, enable);
+ LOGD("+++ active profiler set now %d\n", gDvm.interpBreak);
}
dvmMethodTraceStop();
dvmLockMutex(&state->startStopLock);
}
- updateActiveProfilers(1);
+ /* Should only have a single trace going at once */
+ assert((gDvm.interpBreak & kSubModeMethodTrace) == 0);
+ updateActiveProfilers(kSubModeMethodTrace, true);
LOGI("TRACE STARTED: '%s' %dKB\n", traceFileName, bufferSize / 1024);
/*
return;
fail:
- updateActiveProfilers(-1);
+ updateActiveProfilers(kSubModeMethodTrace, false);
if (state->traceFile != NULL) {
fclose(state->traceFile);
state->traceFile = NULL;
dvmUnlockMutex(&state->startStopLock);
return;
} else {
- updateActiveProfilers(-1);
+ updateActiveProfilers(kSubModeMethodTrace, false);
}
/* compute elapsed time */
LOGI("TRACE STOPPED%s: writing %d records\n",
state->overflow ? " (NOTE: overflowed buffer)" : "",
(finalCurOffset - TRACE_HEADER_LEN) / TRACE_REC_SIZE);
- if (gDvm.debuggerActive) {
+ if (DEBUGGER_ACTIVE) {
LOGW("WARNING: a debugger is active; method-tracing results "
"will be skewed\n");
}
void dvmFastMethodTraceEnter(const Method* method,
const struct InterpState* interpState)
{
- if (gDvm.activeProfilers) {
+ if (gDvm.interpBreak & kSubModeMethodTrace) {
dvmMethodTraceAdd(interpState->self, method, METHOD_TRACE_ENTER);
}
}
*/
void dvmFastJavaMethodTraceExit(const struct InterpState* interpState)
{
- if (gDvm.activeProfilers) {
+ if (gDvm.interpBreak & kSubModeMethodTrace) {
dvmMethodTraceAdd(interpState->self, interpState->method,
METHOD_TRACE_EXIT);
}
void dvmFastNativeMethodTraceExit(const Method* method,
const struct InterpState* interpState)
{
- if (gDvm.activeProfilers) {
+ if (gDvm.interpBreak & kSubModeMethodTrace) {
dvmMethodTraceAdd(interpState->self, method, METHOD_TRACE_EXIT);
}
}
if (gDvm.emulatorTracePage == NULL)
return;
- updateActiveProfilers(1);
-
/* in theory we should make this an atomic inc; in practice not important */
gDvm.emulatorTraceEnableCount++;
if (gDvm.emulatorTraceEnableCount == 1)
LOGD("--- emulator method traces enabled\n");
+ updateActiveProfilers(kSubModeEmulatorTrace, true);
}
/*
LOGE("ERROR: emulator tracing not enabled\n");
return;
}
- updateActiveProfilers(-1);
/* in theory we should make this an atomic inc; in practice not important */
gDvm.emulatorTraceEnableCount--;
if (gDvm.emulatorTraceEnableCount == 0)
LOGD("--- emulator method traces disabled\n");
+ updateActiveProfilers(kSubModeEmulatorTrace,
+ (gDvm.emulatorTraceEnableCount != 0));
}
#if defined(WITH_INLINE_PROFILING)
LOGW("Instruction counting not supported with inline profiling");
#endif
- updateActiveProfilers(1);
/* in theory we should make this an atomic inc; in practice not important */
gDvm.instructionCountEnableCount++;
+ updateActiveProfilers(kSubModeInstCounting, true);
}
/*
LOGE("ERROR: instruction counting not enabled\n");
dvmAbort();
}
- updateActiveProfilers(-1);
gDvm.instructionCountEnableCount--;
+ updateActiveProfilers(kSubModeInstCounting,
+ (gDvm.instructionCountEnableCount != 0));
}
*/
#define TRACE_METHOD_ENTER(_self, _method) \
do { \
- if (gDvm.activeProfilers != 0) { \
- if (gDvm.methodTrace.traceEnabled) \
- dvmMethodTraceAdd(_self, _method, METHOD_TRACE_ENTER); \
- if (gDvm.emulatorTraceEnableCount != 0) \
- dvmEmitEmulatorTrace(_method, METHOD_TRACE_ENTER); \
- } \
+ if (gDvm.interpBreak & kSubModeMethodTrace) \
+ dvmMethodTraceAdd(_self, _method, METHOD_TRACE_ENTER); \
+ if (gDvm.interpBreak & kSubModeEmulatorTrace) \
+ dvmEmitEmulatorTrace(_method, METHOD_TRACE_ENTER); \
} while(0);
#define TRACE_METHOD_EXIT(_self, _method) \
do { \
- if (gDvm.activeProfilers != 0) { \
- if (gDvm.methodTrace.traceEnabled) \
- dvmMethodTraceAdd(_self, _method, METHOD_TRACE_EXIT); \
- if (gDvm.emulatorTraceEnableCount != 0) \
- dvmEmitEmulatorTrace(_method, METHOD_TRACE_EXIT); \
- } \
+ if (gDvm.interpBreak & kSubModeMethodTrace) \
+ dvmMethodTraceAdd(_self, _method, METHOD_TRACE_EXIT); \
+ if (gDvm.interpBreak & kSubModeEmulatorTrace) \
+ dvmEmitEmulatorTrace(_method, METHOD_TRACE_EXIT); \
} while(0);
#define TRACE_METHOD_UNROLL(_self, _method) \
do { \
- if (gDvm.activeProfilers != 0) { \
- if (gDvm.methodTrace.traceEnabled) \
- dvmMethodTraceAdd(_self, _method, METHOD_TRACE_UNROLL); \
- if (gDvm.emulatorTraceEnableCount != 0) \
- dvmEmitEmulatorTrace(_method, METHOD_TRACE_UNROLL); \
- } \
+ if (gDvm.interpBreak & kSubModeMethodTrace) \
+ dvmMethodTraceAdd(_self, _method, METHOD_TRACE_UNROLL); \
+ if (gDvm.interpBreak & kSubModeEmulatorTrace) \
+ dvmEmitEmulatorTrace(_method, METHOD_TRACE_UNROLL); \
} while(0);
void dvmMethodTraceAdd(struct Thread* self, const Method* method, int action);
static int getThreadPriorityFromSystem(void);
/*
- * The JIT needs to know if any thread is suspended. We do this by
- * maintaining a global sum of all threads' suspend counts. All suspendCount
- * updates should go through this after aquiring threadSuspendCountLock.
+ * If there is any thread suspend request outstanding,
+ * we need to mark it in interpState to signal the interpreter that
+ * something is pending. We do this by maintaining a global sum of
+ * all threads' suspend counts. All suspendCount updates should go
+ * through this after aquiring threadSuspendCountLock.
*/
-static inline void dvmAddToThreadSuspendCount(int *pSuspendCount, int delta)
+static void dvmAddToThreadSuspendCount(int *pSuspendCount, int delta)
{
*pSuspendCount += delta;
gDvm.sumThreadSuspendCount += delta;
+ dvmUpdateInterpBreak(kSubModeSuspendRequest,
+ (gDvm.sumThreadSuspendCount != 0));
}
/*
}
bail:
-#if defined(WITH_JIT)
/* Remove this thread's suspendCount from global suspendCount sum */
lockThreadSuspendCount();
dvmAddToThreadSuspendCount(&self->suspendCount, -self->suspendCount);
unlockThreadSuspendCount();
-#endif
dvmReleaseTrackedAlloc(exception, self);
}
u8 delta = now - heapWorkerInterpStartTime;
if (delta > HEAP_WORKER_WATCHDOG_TIMEOUT &&
- (gDvm.debuggerActive || gDvm.nativeDebuggerActive))
+ (DEBUGGER_ACTIVE || gDvm.nativeDebuggerActive))
{
/*
* Debugger suspension can block the thread indefinitely. For
dvmLockMutex(&gDvmJit.tableLock);
jitActive = gDvmJit.pProfTable != NULL;
- bool disableJit = gDvm.debuggerActive;
-#if !defined(WITH_INLINE_PROFILING)
- disableJit = disableJit || (gDvm.activeProfilers > 0);
-#endif
- jitActivate = !disableJit;
+ jitActivate = !dvmDebuggerOrProfilerActive();
if (jitActivate && !jitActive) {
gDvmJit.pProfTable = gDvmJit.pProfTableCopy;
}
/*
+ * Update interpBreak
+ */
+void dvmUpdateInterpBreak(int newMode, bool enable)
+{
+ ExecutionSubModes oldValue, newValue;
+
+ do {
+ oldValue = gDvm.interpBreak;
+ newValue = enable ? oldValue | newMode : oldValue & ~newMode;
+ } while (android_atomic_release_cas(oldValue, newValue,
+ &gDvm.interpBreak) != 0);
+#if defined(WITH_JIT)
+ dvmCompilerStateRefresh();
+#endif
+}
+
+/*
* Main interpreter loop entry point. Select "standard" or "debug"
* interpreter and switch between them as required.
*
*/
void dvmFlushBreakpoints(ClassObject* clazz);
+/*
+ * Update interpBreak
+ */
+void dvmUpdateInterpBreak(int newMode, bool enable);
+
#endif /*_DALVIK_INTERP_INTERP*/
volatile int* pSelfSuspendCount;
/* Biased base of GC's card table */
u1* cardTable;
- /* points at gDvm.debuggerActive, or NULL if debugger not enabled */
- volatile u1* pDebuggerActive;
- /* points at gDvm.activeProfilers */
- volatile int* pActiveProfilers;
+ /* points at gDvm.interpBreak */
+ volatile int* pInterpBreak;
/* ----------------------------------------------------------------------
*/
*/
static inline bool dvmDebuggerOrProfilerActive(void)
{
- bool result = gDvm.debuggerActive;
-#if !defined(WITH_INLINE_PROFILING)
- result = result || (gDvm.activeProfilers != 0);
+#if defined(WITH_INLINE_PROFILING)
+ return gDvm.interpBreak & (kSubModeDebuggerActive |
+ kSubModeEmulatorTrace |
+ kSubModeInstCounting);
+#else
+ return gDvm.interpBreak & (kSubModeDebuggerActive |
+ kSubModeEmulatorTrace |
+ kSubModeMethodTrace |
+ kSubModeInstCounting);
#endif
- return result;
}
#if defined(WITH_JIT)
*/
static inline bool dvmJitDebuggerOrProfilerActive()
{
- bool result = (gDvmJit.pProfTable != NULL) || gDvm.debuggerActive;
-#if !defined(WITH_INLINE_PROFILING)
- result = result || (gDvm.activeProfilers != 0);
-#endif
- return result;
+ return (gDvmJit.pProfTable != NULL) || dvmDebuggerOrProfilerActive();
}
/*
*/
s8 dvmJdwpLastDebuggerActivity(JdwpState* state)
{
- if (!gDvm.debuggerActive) {
+ if (!DEBUGGER_ACTIVE) {
LOGD("dvmJdwpLastDebuggerActivity: no active debugger\n");
return -1;
}
TRACE_METHOD_ENTER(self, glue->method);
}
#endif
- if (gDvm.jdwpConfigured) {
- glue->pDebuggerActive = &gDvm.debuggerActive;
- } else {
- glue->pDebuggerActive = NULL;
- }
- glue->pActiveProfilers = &gDvm.activeProfilers;
+ glue->pInterpBreak = &gDvm.interpBreak;
IF_LOGVV() {
char* desc = dexProtoCopyMethodDescriptor(&glue->method->prototype);
* r9 is trampoline PC adjustment *in bytes*
*/
common_periodicChecks:
+ ldr r1, [rGLUE, #offGlue_pInterpBreak] @ r3<- &interpBreak
+ /* speculatively load address of thread-specific suspend count */
ldr r3, [rGLUE, #offGlue_pSelfSuspendCount] @ r3<- &suspendCount
-
- ldr r1, [rGLUE, #offGlue_pDebuggerActive] @ r1<- &debuggerActive
- ldr r2, [rGLUE, #offGlue_pActiveProfilers] @ r2<- &activeProfilers
-
+ ldr r1, [r1] @ r1<- interpBreak
+ /* speculatively load thread-specific suspend count */
ldr ip, [r3] @ ip<- suspendCount (int)
-
- cmp r1, #0 @ debugger enabled?
-#if defined(WORKAROUND_CORTEX_A9_745320)
- /* Don't use conditional loads if the HW defect exists */
- beq 101f
- ldrb r1, [r1] @ yes, r1<- debuggerActive (boolean)
-101:
-#else
- ldrneb r1, [r1] @ yes, r1<- debuggerActive (boolean)
-#endif
- ldr r2, [r2] @ r2<- activeProfilers (int)
- orrnes ip, ip, r1 @ ip<- suspendCount | debuggerActive
- /*
- * Don't switch the interpreter in the libdvm_traceview build even if the
- * profiler is active.
- * The code here is opted for less intrusion instead of performance.
- * That is, *pActiveProfilers is still loaded into r2 even though it is not
- * used when WITH_INLINE_PROFILING is defined.
- */
-#if !defined(WITH_INLINE_PROFILING)
- orrs ip, ip, r2 @ ip<- suspend|debugger|profiler; set Z
-#endif
-
-
- bxeq lr @ all zero, return
-
+ cmp r1, #0 @ anything unusual?
+ bxeq lr @ return if not
/*
* One or more interesting events have happened. Figure out what.
*
- * If debugging or profiling are compiled in, we need to disambiguate.
- *
* r0 still holds the reentry type.
*/
- ldr ip, [r3] @ ip<- suspendCount (int)
cmp ip, #0 @ want suspend?
- beq 1f @ no, must be debugger/profiler
+ beq 3f @ no, must be something else
stmfd sp!, {r0, lr} @ preserve r0 and lr
#if defined(WITH_JIT)
ldmfd sp!, {r0, lr} @ restore r0 and lr
/*
- * Reload the debugger/profiler enable flags. We're checking to see
- * if either of these got set while we were suspended.
- *
- * If WITH_INLINE_PROFILING is configured, don't check whether the profiler
- * is enabled or not as the profiling will be done inline.
+ * Reload the interpBreak flags - they may have changed while we
+ * were suspended.
*/
- ldr r1, [rGLUE, #offGlue_pDebuggerActive] @ r1<- &debuggerActive
- cmp r1, #0 @ debugger enabled?
-#if defined(WORKAROUND_CORTEX_A9_745320)
- /* Don't use conditional loads if the HW defect exists */
- beq 101f
- ldrb r1, [r1] @ yes, r1<- debuggerActive (boolean)
-101:
-#else
- ldrneb r1, [r1] @ yes, r1<- debuggerActive (boolean)
-#endif
-
-#if !defined(WITH_INLINE_PROFILING)
- ldr r2, [rGLUE, #offGlue_pActiveProfilers] @ r2<- &activeProfilers
- ldr r2, [r2] @ r2<- activeProfilers (int)
- orrs r1, r1, r2
+ ldr r1, [rGLUE, #offGlue_pInterpBreak] @ r1<- &interpBreak
+ ldr r1, [r1] @ r1<- interpBreak
+3:
+ /*
+ * TODO: this code is too fragile. Need a general mechanism
+ * to identify what actions to take by submode. Some profiling modes
+ * (instruction count) need to single-step, while method tracing
+ * may not. Debugging with breakpoints can run unfettered, but
+ * source-level single-stepping requires Dalvik singlestepping.
+ * GC may require a one-shot action and then full-speed resumption.
+ */
+#if defined(WITH_INLINE_PROFILING)
+ ands r1, #(kSubModeDebuggerActive | kSubModeEmulatorTrace | kSubModeInstCounting)
#else
- cmp r1, #0 @ only consult the debuggerActive flag
+ ands r1, #(kSubModeDebuggerActive | kSubModeEmulatorTrace | kSubModeInstCounting | kSubModeMethodTrace)
#endif
+ bxeq lr @ nothing to do, return
- beq 2f
-
-1: @ debugger/profiler enabled, bail out; glue->entryPoint was set above
+ @ debugger/profiler enabled, bail out; glue->entryPoint was set above
str r0, [rGLUE, #offGlue_entryPoint] @ store r0, need for debug/prof
add rPC, rPC, r9 @ update rPC
mov r1, #1 @ "want switch" = true
b common_gotoBail @ side exit
-2:
- bx lr @ nothing to do, return
-
/*
* The equivalent of "goto bail", this calls through the "bail handler".
//LOGI("Ignoring empty\n");
FINISH(3);
#else
- if (!gDvm.debuggerActive) {
+ if (!DEBUGGER_ACTIVE) {
//LOGI("Skipping empty\n");
FINISH(3); // don't want it to show up in profiler output
} else {
* here, and have the JNI exception code do the reporting to the
* debugger.
*/
- if (gDvm.debuggerActive) {
+ if (DEBUGGER_ACTIVE) {
void* catchFrame;
catchRelPc = dvmFindCatchBlock(self, pc - curMethod->insns,
exception, true, &catchFrame);
DUMP_REGS(methodToCall, newFp, true); // show input args
#if (INTERP_TYPE == INTERP_DBG)
- if (gDvm.debuggerActive) {
+ if (DEBUGGER_ACTIVE) {
dvmDbgPostLocationEvent(methodToCall, -1,
dvmGetThisPtr(curMethod, fp), DBG_METHOD_ENTRY);
}
(*methodToCall->nativeFunc)(newFp, &retval, methodToCall, self);
#if (INTERP_TYPE == INTERP_DBG)
- if (gDvm.debuggerActive) {
+ if (DEBUGGER_ACTIVE) {
dvmDbgPostLocationEvent(methodToCall, -1,
dvmGetThisPtr(curMethod, fp), DBG_METHOD_EXIT);
}
* values are incorrect.
*/
-/* globals (sanity check for LDR vs LDRB) */
-MTERP_SIZEOF(sizeofGlobal_debuggerActive, gDvm.debuggerActive, 1)
-MTERP_SIZEOF(sizeofGlobal_activeProfilers, gDvm.activeProfilers, 4)
-
/* MterpGlue fields */
MTERP_OFFSET(offGlue_pc, MterpGlue, pc, 0)
MTERP_OFFSET(offGlue_fp, MterpGlue, fp, 4)
MTERP_OFFSET(offGlue_interpStackEnd, MterpGlue, interpStackEnd, 32)
MTERP_OFFSET(offGlue_pSelfSuspendCount, MterpGlue, pSelfSuspendCount, 36)
MTERP_OFFSET(offGlue_cardTable, MterpGlue, cardTable, 40)
-MTERP_OFFSET(offGlue_pDebuggerActive, MterpGlue, pDebuggerActive, 44)
-MTERP_OFFSET(offGlue_pActiveProfilers, MterpGlue, pActiveProfilers, 48)
-MTERP_OFFSET(offGlue_entryPoint, MterpGlue, entryPoint, 52)
+MTERP_OFFSET(offGlue_pInterpBreak, MterpGlue, pInterpBreak, 44)
+MTERP_OFFSET(offGlue_entryPoint, MterpGlue, entryPoint, 48)
#if defined(WITH_JIT)
-MTERP_OFFSET(offGlue_pJitProfTable, MterpGlue, pJitProfTable, 60)
-MTERP_OFFSET(offGlue_jitState, MterpGlue, jitState, 64)
-MTERP_OFFSET(offGlue_jitResumeNPC, MterpGlue, jitResumeNPC, 68)
-MTERP_OFFSET(offGlue_jitResumeDPC, MterpGlue, jitResumeDPC, 72)
-MTERP_OFFSET(offGlue_jitThreshold, MterpGlue, jitThreshold, 76)
-MTERP_OFFSET(offGlue_ppJitProfTable, MterpGlue, ppJitProfTable, 80)
-MTERP_OFFSET(offGlue_icRechainCount, MterpGlue, icRechainCount, 84)
-MTERP_OFFSET(offGlue_pProfileCountdown, MterpGlue, pProfileCountdown, 88)
+MTERP_OFFSET(offGlue_pJitProfTable, MterpGlue, pJitProfTable, 56)
+MTERP_OFFSET(offGlue_jitState, MterpGlue, jitState, 60)
+MTERP_OFFSET(offGlue_jitResumeNPC, MterpGlue, jitResumeNPC, 64)
+MTERP_OFFSET(offGlue_jitResumeDPC, MterpGlue, jitResumeDPC, 68)
+MTERP_OFFSET(offGlue_jitThreshold, MterpGlue, jitThreshold, 72)
+MTERP_OFFSET(offGlue_ppJitProfTable, MterpGlue, ppJitProfTable, 76)
+MTERP_OFFSET(offGlue_icRechainCount, MterpGlue, icRechainCount, 80)
+MTERP_OFFSET(offGlue_pProfileCountdown, MterpGlue, pProfileCountdown, 84)
#if defined(WITH_SELF_VERIFICATION)
-MTERP_OFFSET(offGlue_jitCacheStart, MterpGlue, jitCacheStart, 116)
-MTERP_OFFSET(offGlue_jitCacheEnd, MterpGlue, jitCacheEnd, 120)
-#else
MTERP_OFFSET(offGlue_jitCacheStart, MterpGlue, jitCacheStart, 112)
MTERP_OFFSET(offGlue_jitCacheEnd, MterpGlue, jitCacheEnd, 116)
+#else
+MTERP_OFFSET(offGlue_jitCacheStart, MterpGlue, jitCacheStart, 108)
+MTERP_OFFSET(offGlue_jitCacheEnd, MterpGlue, jitCacheEnd, 112)
#endif
#endif
/* make sure all JValue union members are stored at the same offset */
/* opcode number */
MTERP_CONSTANT(OP_MOVE_EXCEPTION, 0x0d)
+
+/* flags for interpBreak */
+MTERP_CONSTANT(kSubModeNormal, 0x0000)
+MTERP_CONSTANT(kSubModeMethodTrace, 0x0001)
+MTERP_CONSTANT(kSubModeEmulatorTrace, 0x0002)
+MTERP_CONSTANT(kSubModeInstCounting, 0x0004)
+MTERP_CONSTANT(kSubModeDebuggerActive, 0x0008)
+MTERP_CONSTANT(kSubModeSuspendRequest, 0x0010)
* r9 is trampoline PC adjustment *in bytes*
*/
common_periodicChecks:
+ ldr r1, [rGLUE, #offGlue_pInterpBreak] @ r3<- &interpBreak
+ /* speculatively load address of thread-specific suspend count */
ldr r3, [rGLUE, #offGlue_pSelfSuspendCount] @ r3<- &suspendCount
-
- ldr r1, [rGLUE, #offGlue_pDebuggerActive] @ r1<- &debuggerActive
- ldr r2, [rGLUE, #offGlue_pActiveProfilers] @ r2<- &activeProfilers
-
+ ldr r1, [r1] @ r1<- interpBreak
+ /* speculatively load thread-specific suspend count */
ldr ip, [r3] @ ip<- suspendCount (int)
-
- cmp r1, #0 @ debugger enabled?
-#if defined(WORKAROUND_CORTEX_A9_745320)
- /* Don't use conditional loads if the HW defect exists */
- beq 101f
- ldrb r1, [r1] @ yes, r1<- debuggerActive (boolean)
-101:
-#else
- ldrneb r1, [r1] @ yes, r1<- debuggerActive (boolean)
-#endif
- ldr r2, [r2] @ r2<- activeProfilers (int)
- orrnes ip, ip, r1 @ ip<- suspendCount | debuggerActive
- /*
- * Don't switch the interpreter in the libdvm_traceview build even if the
- * profiler is active.
- * The code here is opted for less intrusion instead of performance.
- * That is, *pActiveProfilers is still loaded into r2 even though it is not
- * used when WITH_INLINE_PROFILING is defined.
- */
-#if !defined(WITH_INLINE_PROFILING)
- orrs ip, ip, r2 @ ip<- suspend|debugger|profiler; set Z
-#endif
-
-
- bxeq lr @ all zero, return
-
+ cmp r1, #0 @ anything unusual?
+ bxeq lr @ return if not
/*
* One or more interesting events have happened. Figure out what.
*
- * If debugging or profiling are compiled in, we need to disambiguate.
- *
* r0 still holds the reentry type.
*/
- ldr ip, [r3] @ ip<- suspendCount (int)
cmp ip, #0 @ want suspend?
- beq 1f @ no, must be debugger/profiler
+ beq 3f @ no, must be something else
stmfd sp!, {r0, lr} @ preserve r0 and lr
#if defined(WITH_JIT)
ldmfd sp!, {r0, lr} @ restore r0 and lr
/*
- * Reload the debugger/profiler enable flags. We're checking to see
- * if either of these got set while we were suspended.
- *
- * If WITH_INLINE_PROFILING is configured, don't check whether the profiler
- * is enabled or not as the profiling will be done inline.
+ * Reload the interpBreak flags - they may have changed while we
+ * were suspended.
*/
- ldr r1, [rGLUE, #offGlue_pDebuggerActive] @ r1<- &debuggerActive
- cmp r1, #0 @ debugger enabled?
-#if defined(WORKAROUND_CORTEX_A9_745320)
- /* Don't use conditional loads if the HW defect exists */
- beq 101f
- ldrb r1, [r1] @ yes, r1<- debuggerActive (boolean)
-101:
-#else
- ldrneb r1, [r1] @ yes, r1<- debuggerActive (boolean)
-#endif
-
-#if !defined(WITH_INLINE_PROFILING)
- ldr r2, [rGLUE, #offGlue_pActiveProfilers] @ r2<- &activeProfilers
- ldr r2, [r2] @ r2<- activeProfilers (int)
- orrs r1, r1, r2
+ ldr r1, [rGLUE, #offGlue_pInterpBreak] @ r1<- &interpBreak
+ ldr r1, [r1] @ r1<- interpBreak
+3:
+ /*
+ * TODO: this code is too fragile. Need a general mechanism
+ * to identify what actions to take by submode. Some profiling modes
+ * (instruction count) need to single-step, while method tracing
+ * may not. Debugging with breakpoints can run unfettered, but
+ * source-level single-stepping requires Dalvik singlestepping.
+ * GC may require a one-shot action and then full-speed resumption.
+ */
+#if defined(WITH_INLINE_PROFILING)
+ ands r1, #(kSubModeDebuggerActive | kSubModeEmulatorTrace | kSubModeInstCounting)
#else
- cmp r1, #0 @ only consult the debuggerActive flag
+ ands r1, #(kSubModeDebuggerActive | kSubModeEmulatorTrace | kSubModeInstCounting | kSubModeMethodTrace)
#endif
+ bxeq lr @ nothing to do, return
- beq 2f
-
-1: @ debugger/profiler enabled, bail out; glue->entryPoint was set above
+ @ debugger/profiler enabled, bail out; glue->entryPoint was set above
str r0, [rGLUE, #offGlue_entryPoint] @ store r0, need for debug/prof
add rPC, rPC, r9 @ update rPC
mov r1, #1 @ "want switch" = true
b common_gotoBail @ side exit
-2:
- bx lr @ nothing to do, return
-
/*
* The equivalent of "goto bail", this calls through the "bail handler".
* r9 is trampoline PC adjustment *in bytes*
*/
common_periodicChecks:
+ ldr r1, [rGLUE, #offGlue_pInterpBreak] @ r3<- &interpBreak
+ /* speculatively load address of thread-specific suspend count */
ldr r3, [rGLUE, #offGlue_pSelfSuspendCount] @ r3<- &suspendCount
-
- ldr r1, [rGLUE, #offGlue_pDebuggerActive] @ r1<- &debuggerActive
- ldr r2, [rGLUE, #offGlue_pActiveProfilers] @ r2<- &activeProfilers
-
+ ldr r1, [r1] @ r1<- interpBreak
+ /* speculatively load thread-specific suspend count */
ldr ip, [r3] @ ip<- suspendCount (int)
-
- cmp r1, #0 @ debugger enabled?
-#if defined(WORKAROUND_CORTEX_A9_745320)
- /* Don't use conditional loads if the HW defect exists */
- beq 101f
- ldrb r1, [r1] @ yes, r1<- debuggerActive (boolean)
-101:
-#else
- ldrneb r1, [r1] @ yes, r1<- debuggerActive (boolean)
-#endif
- ldr r2, [r2] @ r2<- activeProfilers (int)
- orrnes ip, ip, r1 @ ip<- suspendCount | debuggerActive
- /*
- * Don't switch the interpreter in the libdvm_traceview build even if the
- * profiler is active.
- * The code here is opted for less intrusion instead of performance.
- * That is, *pActiveProfilers is still loaded into r2 even though it is not
- * used when WITH_INLINE_PROFILING is defined.
- */
-#if !defined(WITH_INLINE_PROFILING)
- orrs ip, ip, r2 @ ip<- suspend|debugger|profiler; set Z
-#endif
-
-
- bxeq lr @ all zero, return
-
+ cmp r1, #0 @ anything unusual?
+ bxeq lr @ return if not
/*
* One or more interesting events have happened. Figure out what.
*
- * If debugging or profiling are compiled in, we need to disambiguate.
- *
* r0 still holds the reentry type.
*/
- ldr ip, [r3] @ ip<- suspendCount (int)
cmp ip, #0 @ want suspend?
- beq 1f @ no, must be debugger/profiler
+ beq 3f @ no, must be something else
stmfd sp!, {r0, lr} @ preserve r0 and lr
#if defined(WITH_JIT)
ldmfd sp!, {r0, lr} @ restore r0 and lr
/*
- * Reload the debugger/profiler enable flags. We're checking to see
- * if either of these got set while we were suspended.
- *
- * If WITH_INLINE_PROFILING is configured, don't check whether the profiler
- * is enabled or not as the profiling will be done inline.
+ * Reload the interpBreak flags - they may have changed while we
+ * were suspended.
*/
- ldr r1, [rGLUE, #offGlue_pDebuggerActive] @ r1<- &debuggerActive
- cmp r1, #0 @ debugger enabled?
-#if defined(WORKAROUND_CORTEX_A9_745320)
- /* Don't use conditional loads if the HW defect exists */
- beq 101f
- ldrb r1, [r1] @ yes, r1<- debuggerActive (boolean)
-101:
-#else
- ldrneb r1, [r1] @ yes, r1<- debuggerActive (boolean)
-#endif
-
-#if !defined(WITH_INLINE_PROFILING)
- ldr r2, [rGLUE, #offGlue_pActiveProfilers] @ r2<- &activeProfilers
- ldr r2, [r2] @ r2<- activeProfilers (int)
- orrs r1, r1, r2
+ ldr r1, [rGLUE, #offGlue_pInterpBreak] @ r1<- &interpBreak
+ ldr r1, [r1] @ r1<- interpBreak
+3:
+ /*
+ * TODO: this code is too fragile. Need a general mechanism
+ * to identify what actions to take by submode. Some profiling modes
+ * (instruction count) need to single-step, while method tracing
+ * may not. Debugging with breakpoints can run unfettered, but
+ * source-level single-stepping requires Dalvik singlestepping.
+ * GC may require a one-shot action and then full-speed resumption.
+ */
+#if defined(WITH_INLINE_PROFILING)
+ ands r1, #(kSubModeDebuggerActive | kSubModeEmulatorTrace | kSubModeInstCounting)
#else
- cmp r1, #0 @ only consult the debuggerActive flag
+ ands r1, #(kSubModeDebuggerActive | kSubModeEmulatorTrace | kSubModeInstCounting | kSubModeMethodTrace)
#endif
+ bxeq lr @ nothing to do, return
- beq 2f
-
-1: @ debugger/profiler enabled, bail out; glue->entryPoint was set above
+ @ debugger/profiler enabled, bail out; glue->entryPoint was set above
str r0, [rGLUE, #offGlue_entryPoint] @ store r0, need for debug/prof
add rPC, rPC, r9 @ update rPC
mov r1, #1 @ "want switch" = true
b common_gotoBail @ side exit
-2:
- bx lr @ nothing to do, return
-
/*
* The equivalent of "goto bail", this calls through the "bail handler".
* r9 is trampoline PC adjustment *in bytes*
*/
common_periodicChecks:
+ ldr r1, [rGLUE, #offGlue_pInterpBreak] @ r3<- &interpBreak
+ /* speculatively load address of thread-specific suspend count */
ldr r3, [rGLUE, #offGlue_pSelfSuspendCount] @ r3<- &suspendCount
-
- ldr r1, [rGLUE, #offGlue_pDebuggerActive] @ r1<- &debuggerActive
- ldr r2, [rGLUE, #offGlue_pActiveProfilers] @ r2<- &activeProfilers
-
+ ldr r1, [r1] @ r1<- interpBreak
+ /* speculatively load thread-specific suspend count */
ldr ip, [r3] @ ip<- suspendCount (int)
-
- cmp r1, #0 @ debugger enabled?
-#if defined(WORKAROUND_CORTEX_A9_745320)
- /* Don't use conditional loads if the HW defect exists */
- beq 101f
- ldrb r1, [r1] @ yes, r1<- debuggerActive (boolean)
-101:
-#else
- ldrneb r1, [r1] @ yes, r1<- debuggerActive (boolean)
-#endif
- ldr r2, [r2] @ r2<- activeProfilers (int)
- orrnes ip, ip, r1 @ ip<- suspendCount | debuggerActive
- /*
- * Don't switch the interpreter in the libdvm_traceview build even if the
- * profiler is active.
- * The code here is opted for less intrusion instead of performance.
- * That is, *pActiveProfilers is still loaded into r2 even though it is not
- * used when WITH_INLINE_PROFILING is defined.
- */
-#if !defined(WITH_INLINE_PROFILING)
- orrs ip, ip, r2 @ ip<- suspend|debugger|profiler; set Z
-#endif
-
-
- bxeq lr @ all zero, return
-
+ cmp r1, #0 @ anything unusual?
+ bxeq lr @ return if not
/*
* One or more interesting events have happened. Figure out what.
*
- * If debugging or profiling are compiled in, we need to disambiguate.
- *
* r0 still holds the reentry type.
*/
- ldr ip, [r3] @ ip<- suspendCount (int)
cmp ip, #0 @ want suspend?
- beq 1f @ no, must be debugger/profiler
+ beq 3f @ no, must be something else
stmfd sp!, {r0, lr} @ preserve r0 and lr
#if defined(WITH_JIT)
ldmfd sp!, {r0, lr} @ restore r0 and lr
/*
- * Reload the debugger/profiler enable flags. We're checking to see
- * if either of these got set while we were suspended.
- *
- * If WITH_INLINE_PROFILING is configured, don't check whether the profiler
- * is enabled or not as the profiling will be done inline.
+ * Reload the interpBreak flags - they may have changed while we
+ * were suspended.
*/
- ldr r1, [rGLUE, #offGlue_pDebuggerActive] @ r1<- &debuggerActive
- cmp r1, #0 @ debugger enabled?
-#if defined(WORKAROUND_CORTEX_A9_745320)
- /* Don't use conditional loads if the HW defect exists */
- beq 101f
- ldrb r1, [r1] @ yes, r1<- debuggerActive (boolean)
-101:
-#else
- ldrneb r1, [r1] @ yes, r1<- debuggerActive (boolean)
-#endif
-
-#if !defined(WITH_INLINE_PROFILING)
- ldr r2, [rGLUE, #offGlue_pActiveProfilers] @ r2<- &activeProfilers
- ldr r2, [r2] @ r2<- activeProfilers (int)
- orrs r1, r1, r2
+ ldr r1, [rGLUE, #offGlue_pInterpBreak] @ r1<- &interpBreak
+ ldr r1, [r1] @ r1<- interpBreak
+3:
+ /*
+ * TODO: this code is too fragile. Need a general mechanism
+ * to identify what actions to take by submode. Some profiling modes
+ * (instruction count) need to single-step, while method tracing
+ * may not. Debugging with breakpoints can run unfettered, but
+ * source-level single-stepping requires Dalvik singlestepping.
+ * GC may require a one-shot action and then full-speed resumption.
+ */
+#if defined(WITH_INLINE_PROFILING)
+ ands r1, #(kSubModeDebuggerActive | kSubModeEmulatorTrace | kSubModeInstCounting)
#else
- cmp r1, #0 @ only consult the debuggerActive flag
+ ands r1, #(kSubModeDebuggerActive | kSubModeEmulatorTrace | kSubModeInstCounting | kSubModeMethodTrace)
#endif
+ bxeq lr @ nothing to do, return
- beq 2f
-
-1: @ debugger/profiler enabled, bail out; glue->entryPoint was set above
+ @ debugger/profiler enabled, bail out; glue->entryPoint was set above
str r0, [rGLUE, #offGlue_entryPoint] @ store r0, need for debug/prof
add rPC, rPC, r9 @ update rPC
mov r1, #1 @ "want switch" = true
b common_gotoBail @ side exit
-2:
- bx lr @ nothing to do, return
-
/*
* The equivalent of "goto bail", this calls through the "bail handler".
* r9 is trampoline PC adjustment *in bytes*
*/
common_periodicChecks:
+ ldr r1, [rGLUE, #offGlue_pInterpBreak] @ r3<- &interpBreak
+ /* speculatively load address of thread-specific suspend count */
ldr r3, [rGLUE, #offGlue_pSelfSuspendCount] @ r3<- &suspendCount
-
- ldr r1, [rGLUE, #offGlue_pDebuggerActive] @ r1<- &debuggerActive
- ldr r2, [rGLUE, #offGlue_pActiveProfilers] @ r2<- &activeProfilers
-
+ ldr r1, [r1] @ r1<- interpBreak
+ /* speculatively load thread-specific suspend count */
ldr ip, [r3] @ ip<- suspendCount (int)
-
- cmp r1, #0 @ debugger enabled?
-#if defined(WORKAROUND_CORTEX_A9_745320)
- /* Don't use conditional loads if the HW defect exists */
- beq 101f
- ldrb r1, [r1] @ yes, r1<- debuggerActive (boolean)
-101:
-#else
- ldrneb r1, [r1] @ yes, r1<- debuggerActive (boolean)
-#endif
- ldr r2, [r2] @ r2<- activeProfilers (int)
- orrnes ip, ip, r1 @ ip<- suspendCount | debuggerActive
- /*
- * Don't switch the interpreter in the libdvm_traceview build even if the
- * profiler is active.
- * The code here is opted for less intrusion instead of performance.
- * That is, *pActiveProfilers is still loaded into r2 even though it is not
- * used when WITH_INLINE_PROFILING is defined.
- */
-#if !defined(WITH_INLINE_PROFILING)
- orrs ip, ip, r2 @ ip<- suspend|debugger|profiler; set Z
-#endif
-
-
- bxeq lr @ all zero, return
-
+ cmp r1, #0 @ anything unusual?
+ bxeq lr @ return if not
/*
* One or more interesting events have happened. Figure out what.
*
- * If debugging or profiling are compiled in, we need to disambiguate.
- *
* r0 still holds the reentry type.
*/
- ldr ip, [r3] @ ip<- suspendCount (int)
cmp ip, #0 @ want suspend?
- beq 1f @ no, must be debugger/profiler
+ beq 3f @ no, must be something else
stmfd sp!, {r0, lr} @ preserve r0 and lr
#if defined(WITH_JIT)
ldmfd sp!, {r0, lr} @ restore r0 and lr
/*
- * Reload the debugger/profiler enable flags. We're checking to see
- * if either of these got set while we were suspended.
- *
- * If WITH_INLINE_PROFILING is configured, don't check whether the profiler
- * is enabled or not as the profiling will be done inline.
+ * Reload the interpBreak flags - they may have changed while we
+ * were suspended.
*/
- ldr r1, [rGLUE, #offGlue_pDebuggerActive] @ r1<- &debuggerActive
- cmp r1, #0 @ debugger enabled?
-#if defined(WORKAROUND_CORTEX_A9_745320)
- /* Don't use conditional loads if the HW defect exists */
- beq 101f
- ldrb r1, [r1] @ yes, r1<- debuggerActive (boolean)
-101:
-#else
- ldrneb r1, [r1] @ yes, r1<- debuggerActive (boolean)
-#endif
-
-#if !defined(WITH_INLINE_PROFILING)
- ldr r2, [rGLUE, #offGlue_pActiveProfilers] @ r2<- &activeProfilers
- ldr r2, [r2] @ r2<- activeProfilers (int)
- orrs r1, r1, r2
+ ldr r1, [rGLUE, #offGlue_pInterpBreak] @ r1<- &interpBreak
+ ldr r1, [r1] @ r1<- interpBreak
+3:
+ /*
+ * TODO: this code is too fragile. Need a general mechanism
+ * to identify what actions to take by submode. Some profiling modes
+ * (instruction count) need to single-step, while method tracing
+ * may not. Debugging with breakpoints can run unfettered, but
+ * source-level single-stepping requires Dalvik singlestepping.
+ * GC may require a one-shot action and then full-speed resumption.
+ */
+#if defined(WITH_INLINE_PROFILING)
+ ands r1, #(kSubModeDebuggerActive | kSubModeEmulatorTrace | kSubModeInstCounting)
#else
- cmp r1, #0 @ only consult the debuggerActive flag
+ ands r1, #(kSubModeDebuggerActive | kSubModeEmulatorTrace | kSubModeInstCounting | kSubModeMethodTrace)
#endif
+ bxeq lr @ nothing to do, return
- beq 2f
-
-1: @ debugger/profiler enabled, bail out; glue->entryPoint was set above
+ @ debugger/profiler enabled, bail out; glue->entryPoint was set above
str r0, [rGLUE, #offGlue_entryPoint] @ store r0, need for debug/prof
add rPC, rPC, r9 @ update rPC
mov r1, #1 @ "want switch" = true
b common_gotoBail @ side exit
-2:
- bx lr @ nothing to do, return
-
/*
* The equivalent of "goto bail", this calls through the "bail handler".
* is a bit ugly, but will happen in the relatively uncommon path.
* TODO: Basic-block style Jit will need a hook here as well. Fold it into
* the suspendCount check so we can get both in 1 shot.
+ * TUNING: Improve scheduling here & do initial single test for all.
*/
common_periodicChecks:
movl offGlue_pSelfSuspendCount(%ecx),%eax # eax <- &suspendCount
jne 1f
6:
- movl offGlue_pDebuggerActive(%ecx),%eax # eax <- &DebuggerActive
- movl offGlue_pActiveProfilers(%ecx),%ecx # ecx <- &ActiveProfilers
- testl %eax,%eax # debugger enabled?
- je 2f
- movzbl (%eax),%eax # get active count
-2:
- orl (%ecx),%eax # eax <- debuggerActive | activeProfilers
- movl rGLUE,%ecx # restore rGLUE
- jne 3f # one or both active - switch interp
-
-5:
+ movl offGlue_pInterpBreak(%ecx),%eax # eax <- &interpBreak
+ cmpl $0,(%eax) # something interesting happening?
+ jne 3f # yes - switch interpreters
ret
/* Check for suspend */
//LOGI("Ignoring empty\n");
FINISH(3);
#else
- if (!gDvm.debuggerActive) {
+ if (!DEBUGGER_ACTIVE) {
//LOGI("Skipping empty\n");
FINISH(3); // don't want it to show up in profiler output
} else {
* here, and have the JNI exception code do the reporting to the
* debugger.
*/
- if (gDvm.debuggerActive) {
+ if (DEBUGGER_ACTIVE) {
void* catchFrame;
catchRelPc = dvmFindCatchBlock(self, pc - curMethod->insns,
exception, true, &catchFrame);
DUMP_REGS(methodToCall, newFp, true); // show input args
#if (INTERP_TYPE == INTERP_DBG)
- if (gDvm.debuggerActive) {
+ if (DEBUGGER_ACTIVE) {
dvmDbgPostLocationEvent(methodToCall, -1,
dvmGetThisPtr(curMethod, fp), DBG_METHOD_ENTRY);
}
(*methodToCall->nativeFunc)(newFp, &retval, methodToCall, self);
#if (INTERP_TYPE == INTERP_DBG)
- if (gDvm.debuggerActive) {
+ if (DEBUGGER_ACTIVE) {
dvmDbgPostLocationEvent(methodToCall, -1,
dvmGetThisPtr(curMethod, fp), DBG_METHOD_EXIT);
}
static const char* mn = "shiftTest2";
static const char* sg = "()V";
- if (/*gDvm.debuggerActive &&*/
+ if (/*DEBUGGER_ACTIVE &&*/
strcmp(method->clazz->descriptor, cd) == 0 &&
strcmp(method->name, mn) == 0 &&
strcmp(method->shorty, sg) == 0)
dumpRegs(method, fp, true);
}
- if (!gDvm.debuggerActive)
+ if (!DEBUGGER_ACTIVE)
*pIsMethodEntry = false;
}
#endif
*pIsMethodEntry = false;
TRACE_METHOD_ENTER(self, method);
}
- if (gDvm.debuggerActive) {
+ if (DEBUGGER_ACTIVE) {
updateDebugger(method, pc, fp, isEntry, self);
}
if (gDvm.instructionCountEnableCount != 0) {
//LOGI("Ignoring empty\n");
FINISH(3);
#else
- if (!gDvm.debuggerActive) {
+ if (!DEBUGGER_ACTIVE) {
//LOGI("Skipping empty\n");
FINISH(3); // don't want it to show up in profiler output
} else {
* here, and have the JNI exception code do the reporting to the
* debugger.
*/
- if (gDvm.debuggerActive) {
+ if (DEBUGGER_ACTIVE) {
void* catchFrame;
catchRelPc = dvmFindCatchBlock(self, pc - curMethod->insns,
exception, true, &catchFrame);
DUMP_REGS(methodToCall, newFp, true); // show input args
#if (INTERP_TYPE == INTERP_DBG)
- if (gDvm.debuggerActive) {
+ if (DEBUGGER_ACTIVE) {
dvmDbgPostLocationEvent(methodToCall, -1,
dvmGetThisPtr(curMethod, fp), DBG_METHOD_ENTRY);
}
(*methodToCall->nativeFunc)(newFp, &retval, methodToCall, self);
#if (INTERP_TYPE == INTERP_DBG)
- if (gDvm.debuggerActive) {
+ if (DEBUGGER_ACTIVE) {
dvmDbgPostLocationEvent(methodToCall, -1,
dvmGetThisPtr(curMethod, fp), DBG_METHOD_EXIT);
}
//LOGI("Ignoring empty\n");
FINISH(3);
#else
- if (!gDvm.debuggerActive) {
+ if (!DEBUGGER_ACTIVE) {
//LOGI("Skipping empty\n");
FINISH(3); // don't want it to show up in profiler output
} else {
* here, and have the JNI exception code do the reporting to the
* debugger.
*/
- if (gDvm.debuggerActive) {
+ if (DEBUGGER_ACTIVE) {
void* catchFrame;
catchRelPc = dvmFindCatchBlock(self, pc - curMethod->insns,
exception, true, &catchFrame);
DUMP_REGS(methodToCall, newFp, true); // show input args
#if (INTERP_TYPE == INTERP_DBG)
- if (gDvm.debuggerActive) {
+ if (DEBUGGER_ACTIVE) {
dvmDbgPostLocationEvent(methodToCall, -1,
dvmGetThisPtr(curMethod, fp), DBG_METHOD_ENTRY);
}
(*methodToCall->nativeFunc)(newFp, &retval, methodToCall, self);
#if (INTERP_TYPE == INTERP_DBG)
- if (gDvm.debuggerActive) {
+ if (DEBUGGER_ACTIVE) {
dvmDbgPostLocationEvent(methodToCall, -1,
dvmGetThisPtr(curMethod, fp), DBG_METHOD_EXIT);
}
* here, and have the JNI exception code do the reporting to the
* debugger.
*/
- if (gDvm.debuggerActive) {
+ if (DEBUGGER_ACTIVE) {
void* catchFrame;
catchRelPc = dvmFindCatchBlock(self, pc - curMethod->insns,
exception, true, &catchFrame);
DUMP_REGS(methodToCall, newFp, true); // show input args
#if (INTERP_TYPE == INTERP_DBG)
- if (gDvm.debuggerActive) {
+ if (DEBUGGER_ACTIVE) {
dvmDbgPostLocationEvent(methodToCall, -1,
dvmGetThisPtr(curMethod, fp), DBG_METHOD_ENTRY);
}
(*methodToCall->nativeFunc)(newFp, &retval, methodToCall, self);
#if (INTERP_TYPE == INTERP_DBG)
- if (gDvm.debuggerActive) {
+ if (DEBUGGER_ACTIVE) {
dvmDbgPostLocationEvent(methodToCall, -1,
dvmGetThisPtr(curMethod, fp), DBG_METHOD_EXIT);
}
* here, and have the JNI exception code do the reporting to the
* debugger.
*/
- if (gDvm.debuggerActive) {
+ if (DEBUGGER_ACTIVE) {
void* catchFrame;
catchRelPc = dvmFindCatchBlock(self, pc - curMethod->insns,
exception, true, &catchFrame);
DUMP_REGS(methodToCall, newFp, true); // show input args
#if (INTERP_TYPE == INTERP_DBG)
- if (gDvm.debuggerActive) {
+ if (DEBUGGER_ACTIVE) {
dvmDbgPostLocationEvent(methodToCall, -1,
dvmGetThisPtr(curMethod, fp), DBG_METHOD_ENTRY);
}
(*methodToCall->nativeFunc)(newFp, &retval, methodToCall, self);
#if (INTERP_TYPE == INTERP_DBG)
- if (gDvm.debuggerActive) {
+ if (DEBUGGER_ACTIVE) {
dvmDbgPostLocationEvent(methodToCall, -1,
dvmGetThisPtr(curMethod, fp), DBG_METHOD_EXIT);
}
static const char* mn = "shiftTest2";
static const char* sg = "()V";
- if (/*gDvm.debuggerActive &&*/
+ if (/*DEBUGGER_ACTIVE &&*/
strcmp(method->clazz->descriptor, cd) == 0 &&
strcmp(method->name, mn) == 0 &&
strcmp(method->shorty, sg) == 0)
dumpRegs(method, fp, true);
}
- if (!gDvm.debuggerActive)
+ if (!DEBUGGER_ACTIVE)
*pIsMethodEntry = false;
}
#endif
*pIsMethodEntry = false;
TRACE_METHOD_ENTER(self, method);
}
- if (gDvm.debuggerActive) {
+ if (DEBUGGER_ACTIVE) {
updateDebugger(method, pc, fp, isEntry, self);
}
if (gDvm.instructionCountEnableCount != 0) {
* is a bit ugly, but will happen in the relatively uncommon path.
* TODO: Basic-block style Jit will need a hook here as well. Fold it into
* the suspendCount check so we can get both in 1 shot.
+ * TUNING: Improve scheduling here & do initial single test for all.
*/
common_periodicChecks:
movl offGlue_pSelfSuspendCount(%ecx),%eax # eax <- &suspendCount
jne 1f
6:
- movl offGlue_pDebuggerActive(%ecx),%eax # eax <- &DebuggerActive
- movl offGlue_pActiveProfilers(%ecx),%ecx # ecx <- &ActiveProfilers
- testl %eax,%eax # debugger enabled?
- je 2f
- movzbl (%eax),%eax # get active count
-2:
- orl (%ecx),%eax # eax <- debuggerActive | activeProfilers
- movl rGLUE,%ecx # restore rGLUE
- jne 3f # one or both active - switch interp
-
-5:
+ movl offGlue_pInterpBreak(%ecx),%eax # eax <- &interpBreak
+ cmpl $$0,(%eax) # something interesting happening?
+ jne 3f # yes - switch interpreters
ret
/* Check for suspend */
* The class has been prepared and resolved but possibly not yet verified
* at this point.
*/
- if (gDvm.debuggerActive) {
+ if (DEBUGGER_ACTIVE) {
dvmDbgPostClassPrepare(clazz);
}