* facilitates switching between them. The standard interpreter may
* use the "fast" or "portable" implementation.
*
- * Some debugger support functions are included here. Ideally their
- * entire existence would be "#ifdef WITH_DEBUGGER", but we're not that
- * aggressive in other parts of the code yet.
+ * Some debugger support functions are included here.
*/
#include "Dalvik.h"
#include "interp/InterpDefs.h"
*/
bool dvmBreakpointStartup(void)
{
-#ifdef WITH_DEBUGGER
gDvm.breakpointSet = dvmBreakpointSetAlloc();
return (gDvm.breakpointSet != NULL);
-#else
- return true;
-#endif
}
/*
*/
void dvmBreakpointShutdown(void)
{
-#ifdef WITH_DEBUGGER
dvmBreakpointSetFree(gDvm.breakpointSet);
-#endif
}
-#ifdef WITH_DEBUGGER
/*
* This represents a breakpoint inserted in the instruction stream.
*
typedef struct {
Method* method; /* method we're associated with */
u2* addr; /* absolute memory address */
- u1 originalOpCode; /* original 8-bit opcode value */
+ u1 originalOpcode; /* original 8-bit opcode value */
int setCount; /* #of times this breakpoint was set */
} Breakpoint;
*
* Returns "true" with the opcode in *pOrig on success.
*/
-static bool dvmBreakpointSetOriginalOpCode(const BreakpointSet* pSet,
+static bool dvmBreakpointSetOriginalOpcode(const BreakpointSet* pSet,
const u2* addr, u1* pOrig)
{
int idx = dvmBreakpointSetFind(pSet, addr);
if (idx < 0)
return false;
- *pOrig = pSet->breakpoints[idx].originalOpCode;
+ *pOrig = pSet->breakpoints[idx].originalOpcode;
return true;
}
LOGV("+++ increasing breakpoint set size to %d\n", newSize);
/* pSet->breakpoints will be NULL on first entry */
- newVec = realloc(pSet->breakpoints, newSize * sizeof(Breakpoint));
+ newVec = (Breakpoint*)realloc(pSet->breakpoints, newSize * sizeof(Breakpoint));
if (newVec == NULL)
return false;
pBreak = &pSet->breakpoints[pSet->count++];
pBreak->method = method;
pBreak->addr = (u2*)addr;
- pBreak->originalOpCode = *(u1*)addr;
+ pBreak->originalOpcode = *(u1*)addr;
pBreak->setCount = 1;
/*
* need to. (Not worth worrying about.)
*/
dvmDexChangeDex1(method->clazz->pDvmDex, (u1*)addr,
- pBreak->originalOpCode);
+ pBreak->originalOpcode);
ANDROID_MEMBAR_FULL();
if (idx != pSet->count-1) {
}
}
}
-#endif /*WITH_DEBUGGER*/
/*
*/
void dvmInitBreakpoints(void)
{
-#ifdef WITH_DEBUGGER
/* quick sanity check */
BreakpointSet* pSet = gDvm.breakpointSet;
dvmBreakpointSetLock(pSet);
/* generally not good, but we can keep going */
}
dvmBreakpointSetUnlock(pSet);
-#else
- assert(false);
-#endif
}
/*
*/
void dvmAddBreakAddr(Method* method, unsigned int instrOffset)
{
-#ifdef WITH_DEBUGGER
BreakpointSet* pSet = gDvm.breakpointSet;
dvmBreakpointSetLock(pSet);
dvmBreakpointSetAdd(pSet, method, instrOffset);
dvmBreakpointSetUnlock(pSet);
-#else
- assert(false);
-#endif
}
/*
*/
void dvmClearBreakAddr(Method* method, unsigned int instrOffset)
{
-#ifdef WITH_DEBUGGER
BreakpointSet* pSet = gDvm.breakpointSet;
dvmBreakpointSetLock(pSet);
dvmBreakpointSetRemove(pSet, method, instrOffset);
dvmBreakpointSetUnlock(pSet);
-
-#else
- assert(false);
-#endif
}
-#ifdef WITH_DEBUGGER
/*
* Get the original opcode from under a breakpoint.
+ *
+ * On SMP hardware it's possible one core might try to execute a breakpoint
+ * after another core has cleared it. We need to handle the case where
+ * there's no entry in the breakpoint set. (The memory barriers in the
+ * locks and in the breakpoint update code should ensure that, once we've
+ * observed the absence of a breakpoint entry, we will also now observe
+ * the restoration of the original opcode. The fact that we're holding
+ * the lock prevents other threads from confusing things further.)
*/
-u1 dvmGetOriginalOpCode(const u2* addr)
+u1 dvmGetOriginalOpcode(const u2* addr)
{
BreakpointSet* pSet = gDvm.breakpointSet;
u1 orig = 0;
dvmBreakpointSetLock(pSet);
- if (!dvmBreakpointSetOriginalOpCode(pSet, addr, &orig)) {
+ if (!dvmBreakpointSetOriginalOpcode(pSet, addr, &orig)) {
orig = *(u1*)addr;
if (orig == OP_BREAKPOINT) {
LOGE("GLITCH: can't find breakpoint, opcode is still set\n");
dvmBreakpointSetFlush(pSet, clazz);
dvmBreakpointSetUnlock(pSet);
}
-#endif
/*
* Add a single step event. Currently this is a global item.
*/
bool dvmAddSingleStep(Thread* thread, int size, int depth)
{
-#ifdef WITH_DEBUGGER
StepControl* pCtrl = &gDvm.stepControl;
if (pCtrl->active && thread != pCtrl->thread) {
saveArea = SAVEAREA_FROM_FP(fp);
method = saveArea->method;
- if (!dvmIsBreakFrame(fp) && !dvmIsNativeMethod(method))
+ if (!dvmIsBreakFrame((u4*)fp) && !dvmIsNativeMethod(method))
break;
prevFp = fp;
}
*/
LOGV("##### init step while in native method\n");
fp = prevFp;
- assert(!dvmIsBreakFrame(fp));
+ assert(!dvmIsBreakFrame((u4*)fp));
assert(dvmIsNativeMethod(SAVEAREA_FROM_FP(fp)->method));
saveArea = SAVEAREA_FROM_FP(fp);
}
dvmJdwpStepSizeStr(pCtrl->size));
return true;
-#else
- assert(false);
- return false;
-#endif
}
/*
*/
void dvmClearSingleStep(Thread* thread)
{
-#ifdef WITH_DEBUGGER
UNUSED_PARAMETER(thread);
gDvm.stepControl.active = false;
-#else
- assert(false);
-#endif
}
size = arrayData[2] | (((u4)arrayData[3]) << 16);
if (size > arrayObj->length) {
- dvmThrowException("Ljava/lang/ArrayIndexOutOfBoundsException;", NULL);
+ dvmThrowAIOOBE(size, arrayObj->length);
return false;
}
copySwappedArrayData(arrayObj->contents, &arrayData[4], size, width);
}
const char* className = dexStringByTypeIdx(pDvmDex->pDexFile, ref);
- char* dotClassName = dvmDescriptorToDot(className);
+ char* dotClassName = dvmHumanReadableDescriptor(className);
if (flags == 0)
return dotClassName;
char* result = (char*) malloc(kBufLen);
if ((flags & kThrowShow_accessFromClass) != 0) {
- char* dotFromName = dvmDescriptorToDot(method->clazz->descriptor);
+ char* dotFromName =
+ dvmHumanReadableDescriptor(method->clazz->descriptor);
snprintf(result, kBufLen, "tried to access class %s from class %s",
dotClassName, dotFromName);
free(dotFromName);
className = dexStringByTypeIdx(pDvmDex->pDexFile, pFieldId->classIdx);
fieldName = dexStringById(pDvmDex->pDexFile, pFieldId->nameIdx);
- char* dotName = dvmDescriptorToDot(className);
+ char* dotName = dvmHumanReadableDescriptor(className);
char* result = (char*) malloc(kBufLen);
if ((flags & kThrowShow_accessFromClass) != 0) {
- char* dotFromName = dvmDescriptorToDot(method->clazz->descriptor);
+ char* dotFromName =
+ dvmHumanReadableDescriptor(method->clazz->descriptor);
snprintf(result, kBufLen, "tried to access field %s.%s from class %s",
dotName, fieldName, dotFromName);
free(dotFromName);
className = dexStringByTypeIdx(pDvmDex->pDexFile, pMethodId->classIdx);
methodName = dexStringById(pDvmDex->pDexFile, pMethodId->nameIdx);
- char* dotName = dvmDescriptorToDot(className);
+ char* dotName = dvmHumanReadableDescriptor(className);
char* result = (char*) malloc(kBufLen);
if ((flags & kThrowShow_accessFromClass) != 0) {
- char* dotFromName = dvmDescriptorToDot(method->clazz->descriptor);
+ char* dotFromName =
+ dvmHumanReadableDescriptor(method->clazz->descriptor);
char* desc = dexProtoCopyMethodDescriptor(&method->prototype);
snprintf(result, kBufLen,
"tried to access method %s.%s:%s from class %s",
extern void dvmJitToInterpSingleStep();
extern void dvmJitToInterpTraceSelectNoChain();
extern void dvmJitToInterpTraceSelect();
- extern void dvmJitToPatchPredictedChain();
#if defined(WITH_SELF_VERIFICATION)
extern void dvmJitToInterpBackwardBranch();
#endif
dvmJitToInterpSingleStep,
dvmJitToInterpTraceSelectNoChain,
dvmJitToInterpTraceSelect,
- dvmJitToPatchPredictedChain,
#if defined(WITH_SELF_VERIFICATION)
dvmJitToInterpBackwardBranch,
#endif
};
- assert(self->inJitCodeCache == NULL);
+ /*
+ * If the previous VM left the code cache through single-stepping the
+ * inJitCodeCache flag will be set when the VM is re-entered (for example,
+ * in self-verification mode we single-step NEW_INSTANCE which may re-enter
+ * the VM through findClassFromLoaderNoInit). Because of that, we cannot
+ * assert that self->inJitCodeCache is NULL here.
+ */
#endif
interpState.debugTrackedRefStart =
dvmReferenceTableEntries(&self->internalLocalRefTable);
#endif
-#if defined(WITH_PROFILER) || defined(WITH_DEBUGGER)
interpState.debugIsMethodEntry = true;
-#endif
#if defined(WITH_JIT)
dvmJitCalleeSave(interpState.calleeSave);
/* Initialize the state to kJitNot */
LOGVV("threadid=%d: interp STD\n", self->threadId);
change = (*stdInterp)(self, &interpState);
break;
-#if defined(WITH_PROFILER) || defined(WITH_DEBUGGER) || defined(WITH_JIT)
case INTERP_DBG:
LOGVV("threadid=%d: interp DBG\n", self->threadId);
change = dvmInterpretDbg(self, &interpState);
break;
-#endif
default:
dvmAbort();
}
}
- /* Never on the heap, so no write barrier needed. */
- assert(!dvmIsValidObjectAddress(pResult));
*pResult = interpState.retval;
#if defined(WITH_JIT)
dvmJitCalleeRestore(interpState.calleeSave);