/* * Rebuild the interpreter frame then punt to the interpreter to execute * instruction at specified PC. * * Currently parameters are passed to the current frame, so we just need to * grow the stack save area above it, fill certain fields in StackSaveArea and * Thread that are skipped during whole-method invocation (specified below), * then return to the interpreter. * * StackSaveArea: * - prevSave * - prevFrame * - savedPc * - returnAddr * - method * * Thread: * - method * - methodClassDex * - curFrame */ static void genMethodInflateAndPunt(CompilationUnit *cUnit, MIR *mir, BasicBlock *bb) { int oldStackSave = r0; int newStackSave = r1; int oldFP = r2; int savedPC = r3; int currentPC = r4PC; int returnAddr = r7; int method = r8; int pDvmDex = r9; /* * TODO: check whether to raise the stack overflow exception when growing * the stack save area. */ /* Send everything to home location */ dvmCompilerFlushAllRegs(cUnit); /* oldStackSave = r5FP + sizeof(current frame) */ opRegRegImm(cUnit, kOpAdd, oldStackSave, r5FP, cUnit->method->registersSize * 4); /* oldFP = oldStackSave + sizeof(stackSaveArea) */ opRegRegImm(cUnit, kOpAdd, oldFP, oldStackSave, sizeof(StackSaveArea)); /* newStackSave = r5FP - sizeof(StackSaveArea) */ opRegRegImm(cUnit, kOpSub, newStackSave, r5FP, sizeof(StackSaveArea)); loadWordDisp(cUnit, r13sp, 0, savedPC); loadConstant(cUnit, currentPC, (int) (cUnit->method->insns + mir->offset)); loadConstant(cUnit, method, (int) cUnit->method); loadConstant(cUnit, pDvmDex, (int) cUnit->method->clazz->pDvmDex); #ifdef EASY_GDB /* newStackSave->prevSave = oldStackSave */ storeWordDisp(cUnit, newStackSave, offsetof(StackSaveArea, prevSave), oldStackSave); #endif /* newStackSave->prevSave = oldStackSave */ storeWordDisp(cUnit, newStackSave, offsetof(StackSaveArea, prevFrame), oldFP); /* newStackSave->savedPc = savedPC */ storeWordDisp(cUnit, newStackSave, offsetof(StackSaveArea, savedPc), savedPC); /* return address */ loadConstant(cUnit, returnAddr, 0); storeWordDisp(cUnit, newStackSave, offsetof(StackSaveArea, returnAddr), returnAddr); /* newStackSave->method = method */ storeWordDisp(cUnit, newStackSave, offsetof(StackSaveArea, method), method); /* thread->method = method */ storeWordDisp(cUnit, r6SELF, offsetof(InterpSaveState, method), method); /* thread->interpSave.curFrame = current FP */ storeWordDisp(cUnit, r6SELF, offsetof(Thread, interpSave.curFrame), r5FP); /* thread->methodClassDex = pDvmDex */ storeWordDisp(cUnit, r6SELF, offsetof(InterpSaveState, methodClassDex), pDvmDex); /* Restore the stack pointer */ opRegImm(cUnit, kOpAdd, r13sp, 16); genPuntToInterp(cUnit, mir->offset); }
static void genInterpSingleStep(CompilationUnit *cUnit, MIR *mir) { int flags = dexGetFlagsFromOpcode(mir->dalvikInsn.opcode); int flagsToCheck = kInstrCanBranch | kInstrCanSwitch | kInstrCanReturn | kInstrCanThrow; //If already optimized out, just ignore if (mir->dalvikInsn.opcode == OP_NOP) return; //Ugly, but necessary. Flush all Dalvik regs so Interp can find them dvmCompilerFlushAllRegs(cUnit); if ((mir->next == NULL) || (flags & flagsToCheck)) { genPuntToInterp(cUnit, mir->offset); return; } int entryAddr = offsetof(Thread, jitToInterpEntries.dvmJitToInterpSingleStep); loadWordDisp(cUnit, rEBP, 0, rECX); // Get glue loadWordDisp(cUnit, rECX, entryAddr, rEAX); // rEAX<- entry address /* rPC = dalvik pc */ loadConstant(cUnit, rPC, (int) (cUnit->method->insns + mir->offset)); /* rECX = dalvik pc of following instruction */ loadConstant(cUnit, rECX, (int) (cUnit->method->insns + mir->next->offset)); /* Pass on the stack */ storeWordDisp(cUnit, rESP, OUT_ARG0, rECX); opReg(cUnit, kOpCall, rEAX); }