参考源码版本:Android-4.4.4_r2
提示:大部分分析直接注释在代码内。
dvmInterpret
函数中调用了dvmInterpretPortable
函数对方法的字节码进行解释执行,dvmInterpret
在dalvik/vm/interp/Interp.cpp
文件中。
dvmInterpretPortable
函数在dalvik/vm/mterp/out/InterpC-portable.cpp
文件中。
使用gcc -E -P -C InterpC-portable.cpp > InterpC-portable_.cpp
命令,把这个函数中的宏全部展开,简单解释一下这一条 命令:
- -E 预编译,解释预处理命令如:#include、#define。
- -P 不要生成`#line’信息,这个信息我们不需要。
- -C GCC处理的过程中不删除注释。
上面 -P 和 -C 的作用描述仅仅用于 -E 的情况下。
使用 -E 把函数中的宏全部展开也会导致代码的部分丢失,如:
#if defined(EASY_GDB)
StackSaveArea* debugSaveArea = SAVEAREA_FROM_FP(self->interpSave.curFrame);
#endif
如果文件中没有定义宏
EASY_GDB
那么上面的那段代码就不会输出。
还有如下面的代码也不会输出:
#if 0
if (self->debugIsMethodEntry) {
ILOGD("|-- Now interpreting %s.%s", curMethod->clazz->descriptor,
curMethod->name);
DUMP_REGS(curMethod, self->interpSave.curFrame, false);
}
#endif
dvmInterpretPortable函数在InterpC-portable.cpp
文件中,这个文件是通过gen-mterp.py脚本生成的,可以查看有关分析文章:
下面是dvmInterpretPortable
函数的部分代码:
/* File: portable/entry.cpp */
/*
* Main interpreter loop.
*
* This was written with an ARM implementation in mind.
*/
void dvmInterpretPortable(Thread* self) {
DvmDex* methodClassDex; // curMethod->clazz->pDvmDex
JValue retval;
/* core state */
const Method* curMethod; // 我们要解释的方法。
const u2* pc; // 程序计数器。
u4* fp; // 栈指针(frame pointer)。经过分析我认为fp保存了方法的信息和寄存器数组。
u2 inst; // 当前指令。
/* instruction decoding */
u4 ref; // 16 or 32-bit quantity fetched directly
u2 vsrc1, vsrc2, vdst; // usually used for register indexes
/* method call setup */
const Method* methodToCall;
bool methodCallRange;
/* static computed goto table */
// DEFINE_GOTO_TABLE 定义在 dalvik/libdex/DexOpcodes.h 中。
// handlerTable 保存的goto跳转标签的地址。
DEFINE_GOTO_TABLE (handlerTable);
/* copy state in */
// curMethod将指向Method结构。
// 对 self->interpSave.method 赋值的代码可以在dvmInterpret函数中找到。
curMethod = self->interpSave.method;
// 此时,pc指向的是方法指令的起始地址。
// self->interpSave.pc保存的地址来自于method->inst,可以在dvmInterpret函数中找到相关代码。
pc = self->interpSave.pc;
fp = self->interpSave.curFrame;
retval = self->interpSave.retval; /* only need for kInterpEntryReturn? */
// pc的值应该与curMethod->inst相等。
methodClassDex = curMethod->clazz->pDvmDex;
LOGVV("threadid=%d: %s.%s pc=%#x fp=%p", self->threadId,
curMethod->clazz->descriptor, curMethod->name,
pc - curMethod->insns, fp);
/*
* Handle any ongoing profiling and prep for debugging.
*/
if (self->interpBreak.ctl.subMode != 0) {
TRACE_METHOD_ENTER(self, curMethod);
self->debugIsMethodEntry = true; // Always true on startup
}
/*
* DEBUG: scramble this to ensure we're not relying on it.
*/
methodToCall = (const Method*) -1;
// 抓取和执行第一条指令。
{
do {
pc += 0;
;
} while (false);
inst = (pc[(0)]);
if (self->interpBreak.ctl.subMode) {
dvmCheckBefore(pc, fp, self);
}
goto *handlerTable[((inst) & 0xff)];
}; /* fetch and execute first instruction */
// 经过分析下面的指令得出,代表指令的二进制保存在16位中的低8位。
/*--- start of opcodes ---*/
/* File: c/OP_NOP.cpp */
op_OP_NOP: {
do {
pc += 1;
;
} while (false);
inst = (pc[(0)]);
if (self->interpBreak.ctl.subMode) {
dvmCheckBefore(pc, fp, self);
}
goto *handlerTable[((inst) & 0xff)];
};
/* File: c/OP_MOVE.cpp */
op_OP_MOVE /*vA, vB*/:
// vA、vB的索引在16位中的高8位。
vdst = (((inst) >> 8) & 0x0f); // vA
vsrc1 = ((inst) >> 12); // vB
((void) 0);
(fp[(vdst)] = ((fp[(vsrc1)])));
{
do {
pc += 1;
;
} while (false);
inst = (pc[(0)]); // 获得的是下一条指令。
if (self->interpBreak.ctl.subMode) {
dvmCheckBefore(pc, fp, self);
}
goto *handlerTable[((inst) & 0xff)]; // 跳转到下一条指令继续解释执行。
};
// 这个指令占用32位,而pc是一个u2的数组。
// 所以下面的pc加2。
/* File: c/OP_MOVE_FROM16.cpp */
op_OP_MOVE_FROM16 /*vAA, vBBBB*/:
// vA的索引在16位中的高8位
vdst = ((inst) >> 8);
vsrc1 = (pc[(1)]); // vB 占用16位。
((void) 0);
(fp[(vdst)] = ((fp[(vsrc1)])));
{
do {
pc += 2;
;
} while (false);
inst = (pc[(0)]); // 获取下一条指令。
if (self->interpBreak.ctl.subMode) {
dvmCheckBefore(pc, fp, self);
}
goto *handlerTable[((inst) & 0xff)]; // 跳转到下一条指令继续解释执行。
};
......
/* File: c/OP_RETURN_VOID.cpp */
op_OP_RETURN_VOID /**/:
((void) 0);
retval.j = 0xababababULL; // placate valgrind
goto returnFromMethod;;
/* File: c/OP_RETURN.cpp */
op_OP_RETURN /*vAA*/:
vsrc1 = ((inst) >> 8);
((void) 0);
retval.i = (fp[(vsrc1)]); // 获得返回值。
goto returnFromMethod;;
/* File: c/OP_RETURN_WIDE.cpp */
op_OP_RETURN_WIDE /*vAA*/:
vsrc1 = ((inst) >> 8);
((void) 0);
retval.j = getLongFromArray(fp, (vsrc1)); // 获得返回值。
goto returnFromMethod;;
/* File: c/OP_RETURN_OBJECT.cpp */
/* File: c/OP_RETURN.cpp */
op_OP_RETURN_OBJECT /*vAA*/:
vsrc1 = ((inst) >> 8);
((void) 0);
retval.i = (fp[(vsrc1)]); // 获得返回值。
goto returnFromMethod;;
......
/* File: c/OP_INVOKE_VIRTUAL.cpp */
op_OP_INVOKE_VIRTUAL /*vB, {vD, vE, vF, vG, vA}, meth@CCCC*/:
do {
methodCallRange = false; // 不是invoke-kind/range类的调用。
goto invokeVirtual;
} while (false);
/* File: c/OP_INVOKE_SUPER.cpp */
op_OP_INVOKE_SUPER /*vB, {vD, vE, vF, vG, vA}, meth@CCCC*/:
do {
methodCallRange = false;
goto invokeSuper;
} while (false);
/* File: c/OP_INVOKE_DIRECT.cpp */
op_OP_INVOKE_DIRECT /*vB, {vD, vE, vF, vG, vA}, meth@CCCC*/: do {
methodCallRange = false;
goto invokeDirect;
} while (false);
/* File: c/OP_INVOKE_STATIC.cpp */
op_OP_INVOKE_STATIC /*vB, {vD, vE, vF, vG, vA}, meth@CCCC*/: do {
methodCallRange = false;
goto invokeStatic;
} while (false);
/* File: c/OP_INVOKE_INTERFACE.cpp */
op_OP_INVOKE_INTERFACE /*vB, {vD, vE, vF, vG, vA}, meth@CCCC*/: do {
methodCallRange = false;
goto invokeInterface;
} while (false);
/* File: c/OP_UNUSED_73.cpp */
op_OP_UNUSED_73:
/* File: c/OP_INVOKE_VIRTUAL_RANGE.cpp */
op_OP_INVOKE_VIRTUAL_RANGE /*{vCCCC..v(CCCC+AA-1)}, meth@BBBB*/:
do {
methodCallRange = true; // 是invoke-kind/range类的调用。
goto invokeVirtual;
} while (false);
/* File: c/OP_INVOKE_SUPER_RANGE.cpp */
op_OP_INVOKE_SUPER_RANGE /*{vCCCC..v(CCCC+AA-1)}, meth@BBBB*/:
do {
methodCallRange = true;
goto invokeSuper;
} while (false);
/* File: c/OP_INVOKE_DIRECT_RANGE.cpp */
op_OP_INVOKE_DIRECT_RANGE /*{vCCCC..v(CCCC+AA-1)}, meth@BBBB*/:
do {
methodCallRange = true;
goto invokeDirect;
} while (false);
/* File: c/OP_INVOKE_STATIC_RANGE.cpp */
op_OP_INVOKE_STATIC_RANGE /*{vCCCC..v(CCCC+AA-1)}, meth@BBBB*/:
do {
methodCallRange = true;
goto invokeStatic;
} while (false);
/* File: c/OP_INVOKE_INTERFACE_RANGE.cpp */
op_OP_INVOKE_INTERFACE_RANGE /*{vCCCC..v(CCCC+AA-1)}, meth@BBBB*/:
do {
methodCallRange = true;
goto invokeInterface;
} while (false);
......
invokeVirtual: {
Method* baseMethod;
Object* thisPtr;
(((StackSaveArea*)(fp) -1)->xtra.currentPc = pc);
// 保存的vsrc1是寄存器个数。
vsrc1 = ((inst) >> 8); /* AA (count) or BA (count + arg 5) */
ref = (pc[(1)]); /* method ref */ // 方法引用。
// 如果不是range调用,vdst代表的是4个寄存器,每个寄存器占4位,
// 这也就解释了为什么invoke-kind指令中的寄存器索引不能大于16。
// 如果是range调用,那么vdst代表的就是第一个寄存器。
vdst = (pc[(2)]); /* 4 regs -or- first reg */
// 我们正在执行的方法的第一个参数总是这个方法所属的类对象。
/*
* The object against which we are executing a method is always
* in the first argument.
*/
if (methodCallRange) {
assert(vsrc1 > 0);
((void) 0);
thisPtr = (Object*) (fp[(vdst)]); // invoke-kind/range的this对象。
} else {
assert((vsrc1 >> 4) > 0);
((void) 0);
thisPtr = (Object*) (fp[(vdst & 0x0f)]); // invoke-kind的this对象。
}
if (!checkForNull(thisPtr))
goto exceptionThrown;;
// 解析方法。这是对象的静态类型中正确的方法。我们也在此验证访问权限。
// dvmDexGetResolvedMethod这个函数应该是获得类中的方法。
/*
* Resolve the method. This is the correct method for the static
* type of the object. We also verify access permissions here.
*/
baseMethod = dvmDexGetResolvedMethod(methodClassDex, ref);
if (baseMethod == NULL) {
baseMethod = dvmResolveMethod(curMethod->clazz, ref,
METHOD_VIRTUAL);
if (baseMethod == NULL) {
((void) 0);
goto exceptionThrown;;
}
}
// 结合对象中方法的虚函数表偏移。
/*
* Combine the object we found with the vtable offset in the
* method.
*/
assert(baseMethod->methodIndex < thisPtr->clazz->vtableCount);
methodToCall = thisPtr->clazz->vtable[baseMethod->methodIndex];
assert(
!dvmIsAbstractMethod(methodToCall)
|| methodToCall->nativeFunc != NULL);
LOGVV("+++ base=%s.%s virtual[%d]=%s.%s", baseMethod->clazz->descriptor,
baseMethod->name, (u4) baseMethod->methodIndex,
methodToCall->clazz->descriptor, methodToCall->name);
assert(methodToCall != NULL);
goto invokeMethod;;
}
invokeSuper: {
Method* baseMethod;
u2 thisReg;
(((StackSaveArea*)(fp) -1)->xtra.currentPc = pc);
vsrc1 = ((inst) >> 8); /* AA (count) or BA (count + arg 5) */
ref = (pc[(1)]); /* method ref */
vdst = (pc[(2)]); /* 4 regs -or- first reg */
if (methodCallRange) {
((void) 0);
thisReg = vdst;
} else {
((void) 0);
thisReg = vdst & 0x0f;
}
/* impossible in well-formed code, but we must check nevertheless */
if (!checkForNull((Object*) (fp[(thisReg)])))
goto exceptionThrown;;
/*
* Resolve the method. This is the correct method for the static
* type of the object. We also verify access permissions here.
* The first arg to dvmResolveMethod() is just the referring class
* (used for class loaders and such), so we don't want to pass
* the superclass into the resolution call.
*/
baseMethod = dvmDexGetResolvedMethod(methodClassDex, ref);
if (baseMethod == NULL) {
baseMethod = dvmResolveMethod(curMethod->clazz, ref,
METHOD_VIRTUAL);
if (baseMethod == NULL) {
((void) 0);
goto exceptionThrown;;
}
}
/*
* Combine the object we found with the vtable offset in the
* method's class.
*
* We're using the current method's class' superclass, not the
* superclass of "this". This is because we might be executing
* in a method inherited from a superclass, and we want to run
* in that class' superclass.
*/
if (baseMethod->methodIndex >= curMethod->clazz->super->vtableCount) {
/*
* Method does not exist in the superclass. Could happen if
* superclass gets updated.
*/
dvmThrowNoSuchMethodError(baseMethod->name);
goto exceptionThrown;;
}
methodToCall = curMethod->clazz->super->vtable[baseMethod->methodIndex];
assert(
!dvmIsAbstractMethod(methodToCall)
|| methodToCall->nativeFunc != NULL);
LOGVV("+++ base=%s.%s super-virtual=%s.%s",
baseMethod->clazz->descriptor, baseMethod->name,
methodToCall->clazz->descriptor, methodToCall->name);
assert(methodToCall != NULL);
goto invokeMethod;;
}
invokeInterface: {
Object* thisPtr;
ClassObject* thisClass;
(((StackSaveArea*)(fp) -1)->xtra.currentPc = pc);
vsrc1 = ((inst) >> 8); /* AA (count) or BA (count + arg 5) */
ref = (pc[(1)]); /* method ref */
vdst = (pc[(2)]); /* 4 regs -or- first reg */
/*
* The object against which we are executing a method is always
* in the first argument.
*/
if (methodCallRange) {
assert(vsrc1 > 0);
((void) 0);
thisPtr = (Object*) (fp[(vdst)]);
} else {
assert((vsrc1 >> 4) > 0);
((void) 0);
thisPtr = (Object*) (fp[(vdst & 0x0f)]);
}
if (!checkForNull(thisPtr))
goto exceptionThrown;;
thisClass = thisPtr->clazz;
/*
* Given a class and a method index, find the Method* with the
* actual code we want to execute.
*/
methodToCall = dvmFindInterfaceMethodInCache(thisClass, ref, curMethod,
methodClassDex);
if (methodToCall == NULL) {
assert(dvmCheckException(self));
goto exceptionThrown;;
}
goto invokeMethod;;
}
invokeDirect: {
u2 thisReg;
(((StackSaveArea*)(fp) -1)->xtra.currentPc = pc);
vsrc1 = ((inst) >> 8); /* AA (count) or BA (count + arg 5) */
ref = (pc[(1)]); /* method ref */
vdst = (pc[(2)]); /* 4 regs -or- first reg */
if (methodCallRange) {
((void) 0);
thisReg = vdst;
} else {
((void) 0);
thisReg = vdst & 0x0f;
}
if (!checkForNull((Object*) (fp[(thisReg)])))
goto exceptionThrown;;
methodToCall = dvmDexGetResolvedMethod(methodClassDex, ref);
if (methodToCall == NULL) {
methodToCall = dvmResolveMethod(curMethod->clazz, ref,
METHOD_DIRECT);
if (methodToCall == NULL) {
((void) 0); // should be impossible
goto exceptionThrown;;
}
}
goto invokeMethod;;
}
invokeStatic: (((StackSaveArea*)(fp) -1)->xtra.currentPc = pc);
vsrc1 = ((inst) >> 8); /* AA (count) or BA (count + arg 5) */
ref = (pc[(1)]); /* method ref */
vdst = (pc[(2)]); /* 4 regs -or- first reg */
if (methodCallRange)
((void) 0);
else
((void) 0);
methodToCall = dvmDexGetResolvedMethod(methodClassDex, ref);
if (methodToCall == NULL) {
methodToCall = dvmResolveMethod(curMethod->clazz, ref, METHOD_STATIC);
if (methodToCall == NULL) {
((void) 0);
goto exceptionThrown;;
}
}
goto invokeMethod;;
......
// 处理return-void、return和return-wide。
// 在跳转到这里之前要把返回值放到"retval"中。
/*
* General handling for return-void, return, and return-wide. Put the
* return value in "retval" before jumping here.
*/
returnFromMethod: {
StackSaveArea* saveArea;
/*
* We must do this BEFORE we pop the previous stack frame off, so
* that the GC can see the return value (if any) in the local vars.
*
* Since this is now an interpreter switch point, we must do it before
* we do anything at all.
*/
{
if (dvmCheckSuspendQuick(self)) {
(((StackSaveArea*)(fp) -1)->xtra.currentPc = pc);
dvmCheckSuspendPending(self);
}
};
((void) 0);
//DUMP_REGS(curMethod, fp);
saveArea = ((StackSaveArea*)(fp) -1);
// 恢复之前的fp。
/* back up to previous frame and see if we hit a break */
fp = (u4*) saveArea->prevFrame;
assert(fp != NULL);
/* Handle any special subMode requirements */
if (self->interpBreak.ctl.subMode != 0) {
self->interpSave.pc = pc;
self->interpSave.curFrame = fp;
;
dvmReportReturn(self);
}
if (dvmIsBreakFrame(fp)) {
/* bail without popping the method frame from stack */
LOGVV("+++ returned into break frame");
goto bail;;
}
// 更新fp并重置局部变量。
/* update thread FP, and reset local variables */
self->interpSave.curFrame = fp;
curMethod = ((StackSaveArea*)(fp) -1)->method;
self->interpSave.method = curMethod;
//methodClass = curMethod->clazz;
methodClassDex = curMethod->clazz->pDvmDex;
pc = saveArea->savedPc; // 恢复pc。
((void) 0);
/* use FINISH on the caller's invoke instruction */
//u2 invokeInstr = INST_INST(FETCH(0));
if (true /*invokeInstr >= OP_INVOKE_VIRTUAL &&
invokeInstr <= OP_INVOKE_INTERFACE*/) {
{
do {
// 跳过invoke指令,无论是invoke-kind还是invoke-kind/range指令都是占6个字节。
// pc += 3;正好跳过6个字节。
pc += 3;
;
} while (false);
inst = (pc[(0)]); // 取下一条指令,
if (self->interpBreak.ctl.subMode) {
dvmCheckBefore(pc, fp, self);
}
goto *handlerTable[((inst) & 0xff)]; // 继续执行指令。
};
} else {
//ALOGE("Unknown invoke instr %02x at %d",
// invokeInstr, (int) (pc - curMethod->insns));
assert(false);
}
}
......
/*
* General handling for invoke-{virtual,super,direct,static,interface},
* including "quick" variants.
*
* Set "methodToCall" to the Method we're calling, and "methodCallRange"
* depending on whether this is a "/range" instruction.
*
* For a range call:
* "vsrc1" holds the argument count (8 bits)
* "vdst" holds the first argument in the range
* For a non-range call:
* "vsrc1" holds the argument count (4 bits) and the 5th argument index
* "vdst" holds four 4-bit register indices
*
* The caller must EXPORT_PC before jumping here, because any method
* call can throw a stack overflow exception.
*/
invokeMethod: {
;
//printf("range=%d call=%p count=%d regs=0x%04x\n",
// methodCallRange, methodToCall, count, regs);
//printf(" --> %s.%s %s\n", methodToCall->clazz->descriptor,
// methodToCall->name, methodToCall->shorty);
u4* outs;
int i;
// vsrc1的高4位保存了寄存器的个数。
// vsrc1的低4位也可以保存一个寄存器索引。
// vdst保存了寄存器索引或第一个寄存器的索引。
// 拷贝参数,这可能会破坏 vsrc1/vdst 。
/*
* Copy args. This may corrupt vsrc1/vdst.
*/
if (methodCallRange) {
// 可以使用 memcpy 或 一个 "Duff's device";
// could use memcpy or a "Duff's device"; most functions have
// so few args it won't matter much
assert(vsrc1 <= curMethod->outsSize);
assert(vsrc1 == methodToCall->insSize);
outs = ((u4*) ((u1*)((StackSaveArea*)(fp) -1) - sizeof(u4) * (vsrc1)));
for (i = 0; i < vsrc1; i++)
outs[i] = (fp[(vdst + i)]);
} else {
u4 count = vsrc1 >> 4;
assert(count <= curMethod->outsSize);
assert(count == methodToCall->insSize);
assert(count <= 5);
outs = ((u4*) ((u1*)((StackSaveArea*)(fp) -1) - sizeof(u4) * (count)));
#if 0 // 这里的#if部分的代码是从源文件中拷贝出来的。
// 这里是循环赋值,但是却永远都不会执行,这是为什么哪?
// else部分的代码才是不合理的代码啊。
if (count == 5) {
outs[4] = GET_REGISTER(vsrc1 & 0x0f);
count--;
}
for (i = 0; i < (int) count; i++) {
outs[i] = GET_REGISTER(vdst & 0x0f);
vdst >>= 4;
}
#else
// This version executes fewer instructions but is larger
// overall. Seems to be a teensy bit faster.
assert((vdst >> 16) == 0); // 16 bits -or- high 16 bits clear
switch (count) {
case 5:
outs[4] = (fp[(vsrc1 & 0x0f)]);
case 4:
outs[3] = (fp[(vdst >> 12)]);
case 3:
outs[2] = (fp[((vdst & 0x0f00) >> 8)]);
case 2:
outs[1] = (fp[((vdst & 0x00f0) >> 4)]);
case 1:
outs[0] = (fp[(vdst & 0x0f)]);
default:
;
}
#endif
}
}
/*
* (This was originally a "goto" target; I've kept it separate from the
* stuff above in case we want to refactor things again.)
*
* At this point, we have the arguments stored in the "outs" area of
* the current method's stack frame, and the method to call in
* "methodToCall". Push a new stack frame.
*/
{
StackSaveArea* newSaveArea;
u4* newFp;
((void) 0);
// 新的栈帧。
newFp = (u4*) ((StackSaveArea*)(fp) -1) - methodToCall->registersSize;
newSaveArea = ((StackSaveArea*)(newFp) -1);
// 验证我们是否有足够的空间。
/* verify that we have enough space */
if (true) {
u1* bottom;
bottom = (u1*) newSaveArea - methodToCall->outsSize * sizeof(u4);
if (bottom < self->interpStackEnd) {
// 溢出。
/* stack overflow */
ALOGV(
"Stack overflow on method call (start=%p end=%p newBot=%p(%d) size=%d '%s')",
self->interpStackStart, self->interpStackEnd, bottom,
(u1*) fp - bottom, self->interpStackSize,
methodToCall->name);
dvmHandleStackOverflow(self, methodToCall);
assert(dvmCheckException(self));
goto exceptionThrown;;
}
//ALOGD("+++ fp=%p newFp=%p newSave=%p bottom=%p",
// fp, newFp, newSaveArea, bottom);
}
newSaveArea->prevFrame = fp;
newSaveArea->savedPc = pc;
newSaveArea->method = methodToCall;
if (self->interpBreak.ctl.subMode != 0) {
/*
* We mark ENTER here for both native and non-native
* calls. For native calls, we'll mark EXIT on return.
* For non-native calls, EXIT is marked in the RETURN op.
*/
self->interpSave.pc = pc;
;
dvmReportInvoke(self, methodToCall);
}
if (!dvmIsNativeMethod(methodToCall)) {
// 调用解释的代码。复位 PC,更新栈帧和其他本地状态,并继续。
// 在这里切换了方法的上下文。
/*
* "Call" interpreted code. Reposition the PC, update the
* frame pointer and other local state, and continue.
*/
curMethod = methodToCall;
self->interpSave.method = curMethod;
methodClassDex = curMethod->clazz->pDvmDex;
pc = methodToCall->insns;
fp = newFp;
self->interpSave.curFrame = fp;
self->debugIsMethodEntry = true; // profiling, debugging
((void) 0);
((void) 0); // show input args
{
do {
pc += 0;
;
} while (false);
inst = (pc[(0)]);
if (self->interpBreak.ctl.subMode) {
dvmCheckBefore(pc, fp, self);
}
goto *handlerTable[((inst) & 0xff)];
}; // jump to method start
} else {
/* set this up for JNI locals, even if not a JNI native */
newSaveArea->xtra.localRefCookie =
self->jniLocalRefTable.segmentState.all;
self->interpSave.curFrame = newFp;
((void) 0); // show input args
if (self->interpBreak.ctl.subMode != 0) {
dvmReportPreNativeInvoke(methodToCall, self,
newSaveArea->prevFrame);
}
((void) 0);
/*
* Jump through native call bridge. Because we leave no
* space for locals on native calls, "newFp" points directly
* to the method arguments.
*/
(*methodToCall->nativeFunc)(newFp, &retval, methodToCall, self);
if (self->interpBreak.ctl.subMode != 0) {
dvmReportPostNativeInvoke(methodToCall, self,
newSaveArea->prevFrame);
}
/* pop frame off */
dvmPopJniLocals(self, newSaveArea);
self->interpSave.curFrame = newSaveArea->prevFrame;
fp = newSaveArea->prevFrame;
/*
* If the native code threw an exception, or interpreted code
* invoked by the native call threw one and nobody has cleared
* it, jump to our local exception handling.
*/
if (dvmCheckException(self)) {
ALOGV("Exception thrown by/below native code");
goto exceptionThrown;;
}
((void) 0);
((void) 0);
//u2 invokeInstr = INST_INST(FETCH(0));
if (true /*invokeInstr >= OP_INVOKE_VIRTUAL &&
invokeInstr <= OP_INVOKE_INTERFACE*/) {
{
do {
pc += 3;
;
} while (false);
inst = (pc[(0)]);
if (self->interpBreak.ctl.subMode) {
dvmCheckBefore(pc, fp, self);
}
goto *handlerTable[((inst) & 0xff)];
};
} else {
//ALOGE("Unknown invoke instr %02x at %d",
// invokeInstr, (int) (pc - curMethod->insns));
assert(false);
}
}
}
assert(false); // should not get here
/* File: portable/enddefs.cpp */
/*--- end of opcodes ---*/
bail:
((void) 0); // note "curMethod" may be NULL
self->interpSave.retval = retval;
}