码迷,mamicode.com
首页 > 其他好文 > 详细

【分析】dalvik虚拟机解释执行字节码

时间:2015-04-04 08:02:46      阅读:264      评论:0      收藏:0      [点我收藏+]

标签:dalvik   android   dvminterpretportable   

参考源码版本:Android-4.4.4_r2

提示:大部分分析直接注释在代码内。


dvmInterpret函数中调用了dvmInterpretPortable函数对方法的字节码进行解释执行,dvmInterpretdalvik/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 保存的是处理 dalvik 指令的表,它是一个 "const void*" 类型的数组。
    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;
}


【分析】dalvik虚拟机解释执行字节码

标签:dalvik   android   dvminterpretportable   

原文地址:http://blog.csdn.net/zylc369/article/details/44870595

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!