/* * 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 genMultiplyByShiftAndReverseSubtract(CompilationUnit *cUnit, RegLocation rlSrc, RegLocation rlResult, int lit) { int tReg = dvmCompilerAllocTemp(cUnit); opRegRegImm(cUnit, kOpLsl, tReg, rlSrc.lowReg, lit); opRegRegReg(cUnit, kOpSub, rlResult.lowReg, tReg, rlSrc.lowReg); }
static void genMultiplyByTwoBitMultiplier(CompilationUnit *cUnit, RegLocation rlSrc, RegLocation rlResult, int lit, int firstBit, int secondBit) { // We can't implement "add src, src, src, lsl#shift" on Thumb, so we have // to do a regular multiply. opRegRegImm(cUnit, kOpMul, rlResult.lowReg, rlSrc.lowReg, lit); }
/* * Perform a "reg cmp imm" operation and jump to the PCR region if condition * satisfies. */ static void genNegFloat(CompilationUnit *cUnit, RegLocation rlDest, RegLocation rlSrc) { RegLocation rlResult; rlSrc = loadValue(cUnit, rlSrc, kCoreReg); rlResult = dvmCompilerEvalLoc(cUnit, rlDest, kCoreReg, true); opRegRegImm(cUnit, kOpAdd, rlResult.lowReg, rlSrc.lowReg, 0x80000000); storeValue(cUnit, rlDest, rlResult); }
static void genMultiplyByTwoBitMultiplier(CompilationUnit *cUnit, RegLocation rlSrc, RegLocation rlResult, int lit, int firstBit, int secondBit) { opRegRegRegShift(cUnit, kOpAdd, rlResult.lowReg, rlSrc.lowReg, rlSrc.lowReg, encodeShift(kArmLsl, secondBit - firstBit)); if (firstBit != 0) { opRegRegImm(cUnit, kOpLsl, rlResult.lowReg, rlResult.lowReg, firstBit); } }
/* * For monitor unlock, we don't have to use ldrex/strex. Once * we've determined that the lock is thin and that we own it with * a zero recursion count, it's safe to punch it back to the * initial, unlock thin state with a store word. */ static void genMonitorExit(CompilationUnit *cUnit, MIR *mir) { RegLocation rlSrc = dvmCompilerGetSrc(cUnit, mir, 0); ArmLIR *target; ArmLIR *branch; ArmLIR *hopTarget; ArmLIR *hopBranch; assert(LW_SHAPE_THIN == 0); loadValueDirectFixed(cUnit, rlSrc, r1); // Get obj dvmCompilerLockAllTemps(cUnit); // Prepare for explicit register usage dvmCompilerFreeTemp(cUnit, r4PC); // Free up r4 for general use genNullCheck(cUnit, rlSrc.sRegLow, r1, mir->offset, NULL); loadWordDisp(cUnit, r1, offsetof(Object, lock), r2); // Get object->lock loadWordDisp(cUnit, r6SELF, offsetof(Thread, threadId), r3); // Get threadId // Is lock unheld on lock or held by us (==threadId) on unlock? opRegRegImm(cUnit, kOpAnd, r7, r2, (LW_HASH_STATE_MASK << LW_HASH_STATE_SHIFT)); opRegImm(cUnit, kOpLsl, r3, LW_LOCK_OWNER_SHIFT); // Align owner newLIR3(cUnit, kThumb2Bfc, r2, LW_HASH_STATE_SHIFT, LW_LOCK_OWNER_SHIFT - 1); opRegReg(cUnit, kOpSub, r2, r3); hopBranch = opCondBranch(cUnit, kArmCondNe); dvmCompilerGenMemBarrier(cUnit, kSY); storeWordDisp(cUnit, r1, offsetof(Object, lock), r7); branch = opNone(cUnit, kOpUncondBr); hopTarget = newLIR0(cUnit, kArmPseudoTargetLabel); hopTarget->defMask = ENCODE_ALL; hopBranch->generic.target = (LIR *)hopTarget; // Export PC (part 1) loadConstant(cUnit, r3, (int) (cUnit->method->insns + mir->offset)); LOAD_FUNC_ADDR(cUnit, r7, (int)dvmUnlockObject); genRegCopy(cUnit, r0, r6SELF); // Export PC (part 2) newLIR3(cUnit, kThumb2StrRRI8Predec, r3, r5FP, sizeof(StackSaveArea) - offsetof(StackSaveArea, xtra.currentPc)); opReg(cUnit, kOpBlx, r7); /* Did we throw? */ ArmLIR *branchOver = genCmpImmBranch(cUnit, kArmCondNe, r0, 0); loadConstant(cUnit, r0, (int) (cUnit->method->insns + mir->offset + dexGetWidthFromOpcode(OP_MONITOR_EXIT))); genDispatchToHandler(cUnit, TEMPLATE_THROW_EXCEPTION_COMMON); // Resume here target = newLIR0(cUnit, kArmPseudoTargetLabel); target->defMask = ENCODE_ALL; branch->generic.target = (LIR *)target; branchOver->generic.target = (LIR *) target; }
/* * Take the address of a Dalvik register and store it into rDest. * Clobber any live values associated either with the Dalvik value * or the target register and lock the target fixed register. */ static void loadValueAddressDirect(CompilationUnit *cUnit, RegLocation rlSrc, int rDest) { rlSrc = rlSrc.wide ? dvmCompilerUpdateLocWide(cUnit, rlSrc) : dvmCompilerUpdateLoc(cUnit, rlSrc); if (rlSrc.location == kLocPhysReg) { if (rlSrc.wide) { dvmCompilerFlushRegWideForV5TEVFP(cUnit, rlSrc.lowReg, rlSrc.highReg); } else { dvmCompilerFlushRegForV5TEVFP(cUnit, rlSrc.lowReg); } } dvmCompilerClobber(cUnit, rDest); dvmCompilerLockTemp(cUnit, rDest); opRegRegImm(cUnit, kOpAdd, rDest, rFP, dvmCompilerS2VReg(cUnit, rlSrc.sRegLow) << 2); }
/* * Generate array store * */ static void genArrayPut(CompilationUnit *cUnit, MIR *mir, OpSize size, RegLocation rlArray, RegLocation rlIndex, RegLocation rlSrc, int scale) { RegisterClass regClass = dvmCompilerRegClassBySize(size); int lenOffset = OFFSETOF_MEMBER(ArrayObject, length); int dataOffset = OFFSETOF_MEMBER(ArrayObject, contents); int regPtr; rlArray = loadValue(cUnit, rlArray, kCoreReg); rlIndex = loadValue(cUnit, rlIndex, kCoreReg); if (dvmCompilerIsTemp(cUnit, rlArray.lowReg)) { dvmCompilerClobber(cUnit, rlArray.lowReg); regPtr = rlArray.lowReg; } else { regPtr = dvmCompilerAllocTemp(cUnit); genRegCopy(cUnit, regPtr, rlArray.lowReg); } /* null object? */ ArmLIR * pcrLabel = NULL; if (!(mir->OptimizationFlags & MIR_IGNORE_NULL_CHECK)) { pcrLabel = genNullCheck(cUnit, rlArray.sRegLow, rlArray.lowReg, mir->offset, NULL); } if (!(mir->OptimizationFlags & MIR_IGNORE_RANGE_CHECK)) { int regLen = dvmCompilerAllocTemp(cUnit); //NOTE: max live temps(4) here. /* Get len */ loadWordDisp(cUnit, rlArray.lowReg, lenOffset, regLen); /* regPtr -> array data */ opRegImm(cUnit, kOpAdd, regPtr, dataOffset); genBoundsCheck(cUnit, rlIndex.lowReg, regLen, mir->offset, pcrLabel); dvmCompilerFreeTemp(cUnit, regLen); } else { /* regPtr -> array data */ opRegImm(cUnit, kOpAdd, regPtr, dataOffset); } /* at this point, regPtr points to array, 2 live temps */ if ((size == kLong) || (size == kDouble)) { //TODO: need specific wide routine that can handle fp regs if (scale) { int rNewIndex = dvmCompilerAllocTemp(cUnit); opRegRegImm(cUnit, kOpLsl, rNewIndex, rlIndex.lowReg, scale); opRegReg(cUnit, kOpAdd, regPtr, rNewIndex); } else { opRegReg(cUnit, kOpAdd, regPtr, rlIndex.lowReg); } rlSrc = loadValueWide(cUnit, rlSrc, regClass); HEAP_ACCESS_SHADOW(true); storePair(cUnit, regPtr, rlSrc.lowReg, rlSrc.highReg); HEAP_ACCESS_SHADOW(false); dvmCompilerFreeTemp(cUnit, regPtr); } else { rlSrc = loadValue(cUnit, rlSrc, regClass); HEAP_ACCESS_SHADOW(true); storeBaseIndexed(cUnit, regPtr, rlIndex.lowReg, rlSrc.lowReg, scale, size); HEAP_ACCESS_SHADOW(false); } }
/* * Generate array load */ static void genArrayGet(CompilationUnit *cUnit, MIR *mir, OpSize size, RegLocation rlArray, RegLocation rlIndex, RegLocation rlDest, int scale) { RegisterClass regClass = dvmCompilerRegClassBySize(size); int lenOffset = OFFSETOF_MEMBER(ArrayObject, length); int dataOffset = OFFSETOF_MEMBER(ArrayObject, contents); RegLocation rlResult; rlArray = loadValue(cUnit, rlArray, kCoreReg); rlIndex = loadValue(cUnit, rlIndex, kCoreReg); int regPtr; /* null object? */ ArmLIR * pcrLabel = NULL; if (!(mir->OptimizationFlags & MIR_IGNORE_NULL_CHECK)) { pcrLabel = genNullCheck(cUnit, rlArray.sRegLow, rlArray.lowReg, mir->offset, NULL); } regPtr = dvmCompilerAllocTemp(cUnit); if (!(mir->OptimizationFlags & MIR_IGNORE_RANGE_CHECK)) { int regLen = dvmCompilerAllocTemp(cUnit); /* Get len */ loadWordDisp(cUnit, rlArray.lowReg, lenOffset, regLen); /* regPtr -> array data */ opRegRegImm(cUnit, kOpAdd, regPtr, rlArray.lowReg, dataOffset); genBoundsCheck(cUnit, rlIndex.lowReg, regLen, mir->offset, pcrLabel); dvmCompilerFreeTemp(cUnit, regLen); } else { /* regPtr -> array data */ opRegRegImm(cUnit, kOpAdd, regPtr, rlArray.lowReg, dataOffset); } if ((size == kLong) || (size == kDouble)) { if (scale) { int rNewIndex = dvmCompilerAllocTemp(cUnit); opRegRegImm(cUnit, kOpLsl, rNewIndex, rlIndex.lowReg, scale); opRegReg(cUnit, kOpAdd, regPtr, rNewIndex); dvmCompilerFreeTemp(cUnit, rNewIndex); } else { opRegReg(cUnit, kOpAdd, regPtr, rlIndex.lowReg); } rlResult = dvmCompilerEvalLoc(cUnit, rlDest, regClass, true); HEAP_ACCESS_SHADOW(true); loadPair(cUnit, regPtr, rlResult.lowReg, rlResult.highReg); HEAP_ACCESS_SHADOW(false); dvmCompilerFreeTemp(cUnit, regPtr); storeValueWide(cUnit, rlDest, rlResult); } else { rlResult = dvmCompilerEvalLoc(cUnit, rlDest, regClass, true); HEAP_ACCESS_SHADOW(true); loadBaseIndexed(cUnit, regPtr, rlIndex.lowReg, rlResult.lowReg, scale, size); HEAP_ACCESS_SHADOW(false); dvmCompilerFreeTemp(cUnit, regPtr); storeValue(cUnit, rlDest, rlResult); } }