diff options
| author | The Android Open Source Project <initial-contribution@android.com> | 2009-01-20 14:03:55 -0800 |
|---|---|---|
| committer | The Android Open Source Project <initial-contribution@android.com> | 2009-01-20 14:03:55 -0800 |
| commit | 4c1a2915e40eceeb68dbc323d28b8bf8763af83b (patch) | |
| tree | b6df7a910dfb981a44919eb33fc29aaaca02b7b2 /vm/analysis/RegisterMap.c | |
| parent | 066bed5fb19102e4f560f242b0cee645f1ed8b31 (diff) | |
| download | android_dalvik-4c1a2915e40eceeb68dbc323d28b8bf8763af83b.tar.gz android_dalvik-4c1a2915e40eceeb68dbc323d28b8bf8763af83b.tar.bz2 android_dalvik-4c1a2915e40eceeb68dbc323d28b8bf8763af83b.zip | |
auto import from //branches/cupcake/...@127101
Diffstat (limited to 'vm/analysis/RegisterMap.c')
| -rw-r--r-- | vm/analysis/RegisterMap.c | 695 |
1 files changed, 675 insertions, 20 deletions
diff --git a/vm/analysis/RegisterMap.c b/vm/analysis/RegisterMap.c index 8e0054ebf..eb243af2a 100644 --- a/vm/analysis/RegisterMap.c +++ b/vm/analysis/RegisterMap.c @@ -14,11 +14,13 @@ * limitations under the License. */ +// ** UNDER CONSTRUCTION ** + /* * This code generate "register maps" for Dalvik bytecode. In a stack-based - * VM we would call these "stack maps". They are used to increase the - * precision in the garbage collector when finding references in the - * interpreter call stack. + * VM we might call these "stack maps". They are used to increase the + * precision in the garbage collector when scanning references in the + * interpreter thread stacks. */ #include "Dalvik.h" #include "analysis/CodeVerify.h" @@ -36,6 +38,11 @@ results in the optimized DEX file, which increases their size by about 25% unless we use compression, and for performance reasons we don't want to just re-run the verifier. +On the plus side, we know that verification has completed successfully -- +or at least are allowed to assume that it would -- so we skip a lot of +the checks (like verifying that the register indices in instructions +are reasonable). + Both type-precise and live-precise information can be generated knowing only whether or not a register holds a reference. We don't need to know what kind of reference or whether the object has been initialized. @@ -64,7 +71,7 @@ typedef u1 SRegType; * can be category 1 or 2, so we need two slots. */ #define kExtraRegs 2 -#define RESULT_REGISTER(_insnRegCount) (_insnRegCount) +#define RESULT_REGISTER(_insnRegCountPlus) (_insnRegCountPlus - kExtraRegs) /* * Working state. @@ -84,7 +91,7 @@ typedef struct WorkState { * Number of registers we track for each instruction. This is equal * to the method's declared "registersSize" plus kExtraRegs. */ - int insnRegCount; + int insnRegCountPlus; /* * Instruction widths and flags, one entry per code unit. @@ -197,7 +204,7 @@ RegisterMap* dvmGenerateRegisterMap(const Method* meth) pState->method = meth; pState->insnsSize = dvmGetMethodInsnsSize(meth); - pState->insnRegCount = meth->registersSize + kExtraRegs; + pState->insnRegCountPlus = meth->registersSize + kExtraRegs; pState->insnFlags = calloc(sizeof(InsnFlags), pState->insnsSize); pState->addrRegs = calloc(sizeof(SRegType*), pState->insnsSize); @@ -228,7 +235,7 @@ RegisterMap* dvmGenerateRegisterMap(const Method* meth) for (offset = 0; offset < pState->insnsSize; offset++) { if (dvmInsnIsGcPoint(pState->insnFlags, offset)) { pState->addrRegs[offset] = regPtr; - regPtr += pState->insnRegCount; + regPtr += pState->insnRegCountPlus; } } assert(regPtr - pState->regAlloc == pState->insnsSize * gcPointCount); @@ -313,7 +320,7 @@ static bool setTypesFromSignature(WorkState* pState) while (*ccp != 0) { switch (*ccp) { case 'L': - case '[': + //case '[': *pCurReg++ = kRegTypeReference; break; case 'Z': @@ -386,7 +393,7 @@ static inline int compareRegisters(const SRegType* src1, const SRegType* src2, static bool analyzeMethod(WorkState* pState) { const Method* meth = pState->method; - SRegType workRegs[pState->insnRegCount]; + SRegType workRegs[pState->insnRegCountPlus]; InsnFlags* insnFlags = pState->insnFlags; int insnsSize = pState->insnsSize; int insnIdx, startGuess; @@ -454,7 +461,7 @@ static bool analyzeMethod(WorkState* pState) if (dvmInsnIsBranchTarget(insnFlags, insnIdx)) { SRegType* insnRegs = getRegisterLine(pState, insnIdx); assert(insnRegs != NULL); - copyRegisters(workRegs, insnRegs, pState->insnRegCount); + copyRegisters(workRegs, insnRegs, pState->insnRegCountPlus); } else { #ifndef NDEBUG @@ -464,7 +471,8 @@ static bool analyzeMethod(WorkState* pState) */ SRegType* insnRegs = getRegisterLine(pState, insnIdx); if (insnRegs != NULL && - compareRegisters(workRegs, insnRegs, pState->insnRegCount) != 0) + compareRegisters(workRegs, insnRegs, + pState->insnRegCountPlus) != 0) { char* desc = dexProtoCopyMethodDescriptor(&meth->prototype); LOG_VFY("HUH? workRegs diverged in %s.%s %s\n", @@ -494,6 +502,129 @@ bail: } /* + * Get a pointer to the method being invoked. + * + * Returns NULL on failure. + */ +static Method* getInvokedMethod(const Method* meth, + const DecodedInstruction* pDecInsn, MethodType methodType) +{ + Method* resMethod; + char* sigOriginal = NULL; + + /* + * Resolve the method. This could be an abstract or concrete method + * depending on what sort of call we're making. + */ + if (methodType == METHOD_INTERFACE) { + resMethod = dvmOptResolveInterfaceMethod(meth->clazz, pDecInsn->vB); + } else { + resMethod = dvmOptResolveMethod(meth->clazz, pDecInsn->vB, methodType); + } + if (resMethod == NULL) { + /* failed; print a meaningful failure message */ + DexFile* pDexFile = meth->clazz->pDvmDex->pDexFile; + const DexMethodId* pMethodId; + const char* methodName; + char* methodDesc; + const char* classDescriptor; + + pMethodId = dexGetMethodId(pDexFile, pDecInsn->vB); + methodName = dexStringById(pDexFile, pMethodId->nameIdx); + methodDesc = dexCopyDescriptorFromMethodId(pDexFile, pMethodId); + classDescriptor = dexStringByTypeIdx(pDexFile, pMethodId->classIdx); + + LOG_VFY("VFY: unable to resolve %s method %u: %s.%s %s\n", + dvmMethodTypeStr(methodType), pDecInsn->vB, + classDescriptor, methodName, methodDesc); + free(methodDesc); + return NULL; + } + + return resMethod; +} + +/* + * Return the register type for the method. Since we don't care about + * the actual type, we can just look at the "shorty" signature. + * + * Returns kRegTypeUnknown for "void". + */ +static SRegType getMethodReturnType(const Method* meth) +{ + SRegType type; + + switch (meth->shorty[0]) { + case 'I': + type = kRegTypeInteger; + break; + case 'C': + type = kRegTypeChar; + break; + case 'S': + type = kRegTypeShort; + break; + case 'B': + type = kRegTypeByte; + break; + case 'Z': + type = kRegTypeBoolean; + break; + case 'V': + type = kRegTypeUnknown; + break; + case 'F': + type = kRegTypeFloat; + break; + case 'D': + type = kRegTypeDoubleLo; + break; + case 'J': + type = kRegTypeLongLo; + break; + case 'L': + //case '[': + type = kRegTypeReference; + break; + default: + /* we verified signature return type earlier, so this is impossible */ + assert(false); + type = kRegTypeConflict; + break; + } + + return type; +} + +/* + * Copy a category 1 register. + */ +static inline void copyRegister1(SRegType* insnRegs, u4 vdst, u4 vsrc) +{ + insnRegs[vdst] = insnRegs[vsrc]; +} + +/* + * Copy a category 2 register. Note the source and destination may overlap. + */ +static inline void copyRegister2(SRegType* insnRegs, u4 vdst, u4 vsrc) +{ + //memmove(&insnRegs[vdst], &insnRegs[vsrc], sizeof(SRegType) * 2); + SRegType r1 = insnRegs[vsrc]; + SRegType r2 = insnRegs[vsrc+1]; + insnRegs[vdst] = r1; + insnRegs[vdst+1] = r2; +} + +/* + * Set the type of a category 1 register. + */ +static inline void setRegisterType(SRegType* insnRegs, u4 vdst, SRegType type) +{ + insnRegs[vdst] = type; +} + +/* * Decode the specified instruction and update the register info. */ static bool handleInstruction(WorkState* pState, SRegType* workRegs, @@ -524,14 +655,15 @@ static bool handleInstruction(WorkState* pState, SRegType* workRegs, * The behavior can be determined from the InstrFlags. */ DecodedInstruction decInsn; - SRegType entryRegs[pState->insnRegCount]; + SRegType entryRegs[pState->insnRegCountPlus]; + const int insnRegCountPlus = pState->insnRegCountPlus; bool justSetResult = false; int branchTarget = 0; + SRegType tmpType; dexDecodeInstruction(gDvm.instrFormat, insns, &decInsn); const int nextFlags = dexGetInstrFlags(gDvm.instrFlags, decInsn.opCode); - /* * Make a copy of the previous register state. If the instruction * throws an exception, we merge *this* into the destination rather @@ -541,14 +673,537 @@ static bool handleInstruction(WorkState* pState, SRegType* workRegs, */ if ((nextFlags & kInstrCanThrow) != 0 && dvmInsnIsInTry(insnFlags, insnIdx)) { - copyRegisters(entryRegs, workRegs, pState->insnRegCount); + copyRegisters(entryRegs, workRegs, insnRegCountPlus); } switch (decInsn.opCode) { case OP_NOP: break; - default: break; // TODO: fill this in + case OP_MOVE: + case OP_MOVE_FROM16: + case OP_MOVE_16: + case OP_MOVE_OBJECT: + case OP_MOVE_OBJECT_FROM16: + case OP_MOVE_OBJECT_16: + copyRegister1(workRegs, decInsn.vA, decInsn.vB); + break; + case OP_MOVE_WIDE: + case OP_MOVE_WIDE_FROM16: + case OP_MOVE_WIDE_16: + copyRegister2(workRegs, decInsn.vA, decInsn.vB); + break; + + /* + * The move-result instructions copy data out of a "pseudo-register" + * with the results from the last method invocation. In practice we + * might want to hold the result in an actual CPU register, so the + * Dalvik spec requires that these only appear immediately after an + * invoke or filled-new-array. + * + * These calls invalidate the "result" register. (This is now + * redundant with the reset done below, but it can make the debug info + * easier to read in some cases.) + */ + case OP_MOVE_RESULT: + case OP_MOVE_RESULT_OBJECT: + copyRegister1(workRegs, decInsn.vA, RESULT_REGISTER(insnRegCountPlus)); + break; + case OP_MOVE_RESULT_WIDE: + copyRegister2(workRegs, decInsn.vA, RESULT_REGISTER(insnRegCountPlus)); + break; + + case OP_MOVE_EXCEPTION: + /* + * This statement can only appear as the first instruction in an + * exception handler (though not all exception handlers need to + * have one of these). We verify that as part of extracting the + * exception type from the catch block list. + */ + setRegisterType(workRegs, decInsn.vA, kRegTypeReference); + break; + + case OP_RETURN_VOID: + case OP_RETURN: + case OP_RETURN_WIDE: + case OP_RETURN_OBJECT: + break; + + case OP_CONST_4: + case OP_CONST_16: + case OP_CONST: + /* could be boolean, int, float, or a null reference */ + setRegisterType(workRegs, decInsn.vA, + dvmDetermineCat1Const((s4)decInsn.vB)); + break; + case OP_CONST_HIGH16: + /* could be boolean, int, float, or a null reference */ + setRegisterType(workRegs, decInsn.vA, + dvmDetermineCat1Const((s4) decInsn.vB << 16)); + break; + case OP_CONST_WIDE_16: + case OP_CONST_WIDE_32: + case OP_CONST_WIDE: + case OP_CONST_WIDE_HIGH16: + /* could be long or double; default to long and allow conversion */ + setRegisterType(workRegs, decInsn.vA, kRegTypeLongLo); + break; + case OP_CONST_STRING: + case OP_CONST_STRING_JUMBO: + case OP_CONST_CLASS: + setRegisterType(workRegs, decInsn.vA, kRegTypeReference); + break; + + case OP_MONITOR_ENTER: + case OP_MONITOR_EXIT: + break; + + case OP_CHECK_CAST: + setRegisterType(workRegs, decInsn.vA, kRegTypeReference); + break; + case OP_INSTANCE_OF: + /* result is boolean */ + setRegisterType(workRegs, decInsn.vA, kRegTypeBoolean); + break; + + case OP_ARRAY_LENGTH: + setRegisterType(workRegs, decInsn.vA, kRegTypeInteger); + break; + + case OP_NEW_INSTANCE: + case OP_NEW_ARRAY: + /* add the new uninitialized reference to the register ste */ + setRegisterType(workRegs, decInsn.vA, kRegTypeReference); + break; + case OP_FILLED_NEW_ARRAY: + case OP_FILLED_NEW_ARRAY_RANGE: + setRegisterType(workRegs, RESULT_REGISTER(insnRegCountPlus), + kRegTypeReference); + justSetResult = true; + break; + + case OP_CMPL_FLOAT: + case OP_CMPG_FLOAT: + setRegisterType(workRegs, decInsn.vA, kRegTypeBoolean); + break; + case OP_CMPL_DOUBLE: + case OP_CMPG_DOUBLE: + setRegisterType(workRegs, decInsn.vA, kRegTypeBoolean); + break; + case OP_CMP_LONG: + setRegisterType(workRegs, decInsn.vA, kRegTypeBoolean); + break; + + case OP_THROW: + case OP_GOTO: + case OP_GOTO_16: + case OP_GOTO_32: + case OP_PACKED_SWITCH: + case OP_SPARSE_SWITCH: + break; + + case OP_FILL_ARRAY_DATA: + break; + + case OP_IF_EQ: + case OP_IF_NE: + case OP_IF_LT: + case OP_IF_GE: + case OP_IF_GT: + case OP_IF_LE: + case OP_IF_EQZ: + case OP_IF_NEZ: + case OP_IF_LTZ: + case OP_IF_GEZ: + case OP_IF_GTZ: + case OP_IF_LEZ: + break; + + case OP_AGET: + tmpType = kRegTypeInteger; + goto aget_1nr_common; + case OP_AGET_BOOLEAN: + tmpType = kRegTypeBoolean; + goto aget_1nr_common; + case OP_AGET_BYTE: + tmpType = kRegTypeByte; + goto aget_1nr_common; + case OP_AGET_CHAR: + tmpType = kRegTypeChar; + goto aget_1nr_common; + case OP_AGET_SHORT: + tmpType = kRegTypeShort; + goto aget_1nr_common; +aget_1nr_common: + setRegisterType(workRegs, decInsn.vA, tmpType); + break; + + case OP_AGET_WIDE: + /* + * We know this is either long or double, and we don't really + * discriminate between those during verification, so we + * call it a long. + */ + setRegisterType(workRegs, decInsn.vA, kRegTypeLongLo); + break; + + case OP_AGET_OBJECT: + setRegisterType(workRegs, decInsn.vA, kRegTypeReference); + break; + + case OP_APUT: + case OP_APUT_BOOLEAN: + case OP_APUT_BYTE: + case OP_APUT_CHAR: + case OP_APUT_SHORT: + case OP_APUT_WIDE: + case OP_APUT_OBJECT: + break; + + case OP_IGET: + tmpType = kRegTypeInteger; + goto iget_1nr_common; + case OP_IGET_BOOLEAN: + tmpType = kRegTypeBoolean; + goto iget_1nr_common; + case OP_IGET_BYTE: + tmpType = kRegTypeByte; + goto iget_1nr_common; + case OP_IGET_CHAR: + tmpType = kRegTypeChar; + goto iget_1nr_common; + case OP_IGET_SHORT: + tmpType = kRegTypeShort; + goto iget_1nr_common; +iget_1nr_common: + setRegisterType(workRegs, decInsn.vA, tmpType); + break; + + case OP_IGET_WIDE: + setRegisterType(workRegs, decInsn.vA, kRegTypeLongLo); + break; + + case OP_IGET_OBJECT: + setRegisterType(workRegs, decInsn.vA, kRegTypeReference); + break; + + case OP_IPUT: + case OP_IPUT_BOOLEAN: + case OP_IPUT_BYTE: + case OP_IPUT_CHAR: + case OP_IPUT_SHORT: + case OP_IPUT_WIDE: + case OP_IPUT_OBJECT: + break; + + case OP_SGET: + tmpType = kRegTypeInteger; + goto sget_1nr_common; + case OP_SGET_BOOLEAN: + tmpType = kRegTypeBoolean; + goto sget_1nr_common; + case OP_SGET_BYTE: + tmpType = kRegTypeByte; + goto sget_1nr_common; + case OP_SGET_CHAR: + tmpType = kRegTypeChar; + goto sget_1nr_common; + case OP_SGET_SHORT: + tmpType = kRegTypeShort; + goto sget_1nr_common; +sget_1nr_common: + setRegisterType(workRegs, decInsn.vA, tmpType); + break; + + case OP_SGET_WIDE: + setRegisterType(workRegs, decInsn.vA, kRegTypeLongLo); + break; + + case OP_SGET_OBJECT: + setRegisterType(workRegs, decInsn.vA, kRegTypeReference); + break; + + case OP_SPUT: + case OP_SPUT_BOOLEAN: + case OP_SPUT_BYTE: + case OP_SPUT_CHAR: + case OP_SPUT_SHORT: + case OP_SPUT_WIDE: + case OP_SPUT_OBJECT: + break; + + case OP_INVOKE_VIRTUAL: + case OP_INVOKE_VIRTUAL_RANGE: + case OP_INVOKE_SUPER: + case OP_INVOKE_SUPER_RANGE: + { + Method* calledMethod; + + calledMethod = getInvokedMethod(meth, &decInsn, METHOD_VIRTUAL); + if (calledMethod == NULL) + goto bail; + setRegisterType(workRegs, RESULT_REGISTER(insnRegCountPlus), + getMethodReturnType(calledMethod)); + justSetResult = true; + } + break; + case OP_INVOKE_DIRECT: + case OP_INVOKE_DIRECT_RANGE: + { + Method* calledMethod; + + calledMethod = getInvokedMethod(meth, &decInsn, METHOD_DIRECT); + if (calledMethod == NULL) + goto bail; + setRegisterType(workRegs, RESULT_REGISTER(insnRegCountPlus), + getMethodReturnType(calledMethod)); + justSetResult = true; + } + break; + case OP_INVOKE_STATIC: + case OP_INVOKE_STATIC_RANGE: + { + Method* calledMethod; + + calledMethod = getInvokedMethod(meth, &decInsn, METHOD_STATIC); + if (calledMethod == NULL) + goto bail; + setRegisterType(workRegs, RESULT_REGISTER(insnRegCountPlus), + getMethodReturnType(calledMethod)); + justSetResult = true; + } + break; + case OP_INVOKE_INTERFACE: + case OP_INVOKE_INTERFACE_RANGE: + { + Method* absMethod; + + absMethod = getInvokedMethod(meth, &decInsn, METHOD_INTERFACE); + if (absMethod == NULL) + goto bail; + setRegisterType(workRegs, RESULT_REGISTER(insnRegCountPlus), + getMethodReturnType(absMethod)); + justSetResult = true; + } + break; + + case OP_NEG_INT: + case OP_NOT_INT: + setRegisterType(workRegs, decInsn.vA, kRegTypeInteger); + break; + case OP_NEG_LONG: + case OP_NOT_LONG: + setRegisterType(workRegs, decInsn.vA, kRegTypeLongLo); + break; + case OP_NEG_FLOAT: + setRegisterType(workRegs, decInsn.vA, kRegTypeFloat); + break; + case OP_NEG_DOUBLE: + setRegisterType(workRegs, decInsn.vA, kRegTypeDoubleLo); + break; + case OP_INT_TO_LONG: + setRegisterType(workRegs, decInsn.vA, kRegTypeLongLo); + break; + case OP_INT_TO_FLOAT: + setRegisterType(workRegs, decInsn.vA, kRegTypeFloat); + break; + case OP_INT_TO_DOUBLE: + setRegisterType(workRegs, decInsn.vA, kRegTypeDoubleLo); + break; + case OP_LONG_TO_INT: + setRegisterType(workRegs, decInsn.vA, kRegTypeInteger); + break; + case OP_LONG_TO_FLOAT: + setRegisterType(workRegs, decInsn.vA, kRegTypeFloat); + break; + case OP_LONG_TO_DOUBLE: + setRegisterType(workRegs, decInsn.vA, kRegTypeDoubleLo); + break; + case OP_FLOAT_TO_INT: + setRegisterType(workRegs, decInsn.vA, kRegTypeInteger); + break; + case OP_FLOAT_TO_LONG: + setRegisterType(workRegs, decInsn.vA, kRegTypeLongLo); + break; + case OP_FLOAT_TO_DOUBLE: + setRegisterType(workRegs, decInsn.vA, kRegTypeDoubleLo); + break; + case OP_DOUBLE_TO_INT: + setRegisterType(workRegs, decInsn.vA, kRegTypeInteger); + break; + case OP_DOUBLE_TO_LONG: + setRegisterType(workRegs, decInsn.vA, kRegTypeLongLo); + break; + case OP_DOUBLE_TO_FLOAT: + setRegisterType(workRegs, decInsn.vA, kRegTypeFloat); + break; + case OP_INT_TO_BYTE: + setRegisterType(workRegs, decInsn.vA, kRegTypeByte); + break; + case OP_INT_TO_CHAR: + setRegisterType(workRegs, decInsn.vA, kRegTypeChar); + break; + case OP_INT_TO_SHORT: + setRegisterType(workRegs, decInsn.vA, kRegTypeShort); + break; + + case OP_ADD_INT: + case OP_SUB_INT: + case OP_MUL_INT: + case OP_REM_INT: + case OP_DIV_INT: + case OP_SHL_INT: + case OP_SHR_INT: + case OP_USHR_INT: + case OP_AND_INT: + case OP_OR_INT: + case OP_XOR_INT: + setRegisterType(workRegs, decInsn.vA, kRegTypeInteger); + break; + case OP_ADD_LONG: + case OP_SUB_LONG: + case OP_MUL_LONG: + case OP_DIV_LONG: + case OP_REM_LONG: + case OP_AND_LONG: + case OP_OR_LONG: + case OP_XOR_LONG: + case OP_SHL_LONG: + case OP_SHR_LONG: + case OP_USHR_LONG: + setRegisterType(workRegs, decInsn.vA, kRegTypeLongLo); + break; + case OP_ADD_FLOAT: + case OP_SUB_FLOAT: + case OP_MUL_FLOAT: + case OP_DIV_FLOAT: + case OP_REM_FLOAT: + setRegisterType(workRegs, decInsn.vA, kRegTypeFloat); + break; + case OP_ADD_DOUBLE: + case OP_SUB_DOUBLE: + case OP_MUL_DOUBLE: + case OP_DIV_DOUBLE: + case OP_REM_DOUBLE: + setRegisterType(workRegs, decInsn.vA, kRegTypeDoubleLo); + break; + case OP_ADD_INT_2ADDR: + case OP_SUB_INT_2ADDR: + case OP_MUL_INT_2ADDR: + case OP_REM_INT_2ADDR: + case OP_SHL_INT_2ADDR: + case OP_SHR_INT_2ADDR: + case OP_USHR_INT_2ADDR: + case OP_AND_INT_2ADDR: + case OP_OR_INT_2ADDR: + case OP_XOR_INT_2ADDR: + case OP_DIV_INT_2ADDR: + setRegisterType(workRegs, decInsn.vA, kRegTypeInteger); + break; + case OP_ADD_LONG_2ADDR: + case OP_SUB_LONG_2ADDR: + case OP_MUL_LONG_2ADDR: + case OP_DIV_LONG_2ADDR: + case OP_REM_LONG_2ADDR: + case OP_AND_LONG_2ADDR: + case OP_OR_LONG_2ADDR: + case OP_XOR_LONG_2ADDR: + case OP_SHL_LONG_2ADDR: + case OP_SHR_LONG_2ADDR: + case OP_USHR_LONG_2ADDR: + setRegisterType(workRegs, decInsn.vA, kRegTypeLongLo); + break; + case OP_ADD_FLOAT_2ADDR: + case OP_SUB_FLOAT_2ADDR: + case OP_MUL_FLOAT_2ADDR: + case OP_DIV_FLOAT_2ADDR: + case OP_REM_FLOAT_2ADDR: + setRegisterType(workRegs, decInsn.vA, kRegTypeFloat); + break; + case OP_ADD_DOUBLE_2ADDR: + case OP_SUB_DOUBLE_2ADDR: + case OP_MUL_DOUBLE_2ADDR: + case OP_DIV_DOUBLE_2ADDR: + case OP_REM_DOUBLE_2ADDR: + setRegisterType(workRegs, decInsn.vA, kRegTypeDoubleLo); + break; + case OP_ADD_INT_LIT16: + case OP_RSUB_INT: + case OP_MUL_INT_LIT16: + case OP_DIV_INT_LIT16: + case OP_REM_INT_LIT16: + case OP_AND_INT_LIT16: + case OP_OR_INT_LIT16: + case OP_XOR_INT_LIT16: + case OP_ADD_INT_LIT8: + case OP_RSUB_INT_LIT8: + case OP_MUL_INT_LIT8: + case OP_DIV_INT_LIT8: + case OP_REM_INT_LIT8: + case OP_SHL_INT_LIT8: + case OP_SHR_INT_LIT8: + case OP_USHR_INT_LIT8: + case OP_AND_INT_LIT8: + case OP_OR_INT_LIT8: + case OP_XOR_INT_LIT8: + setRegisterType(workRegs, decInsn.vA, kRegTypeInteger); + break; + + + /* + * See comments in analysis/CodeVerify.c re: why some of these are + * annoying to deal with. In here, "annoying" turns into "impossible", + * since we make no effort to keep reference type info. + * + * Handling most of these would require retaining the field/method + * reference info that we discarded when the instructions were + * quickened. + */ + case OP_EXECUTE_INLINE: + case OP_INVOKE_DIRECT_EMPTY: + case OP_IGET_QUICK: + case OP_IGET_WIDE_QUICK: + case OP_IGET_OBJECT_QUICK: + case OP_IPUT_QUICK: + case OP_IPUT_WIDE_QUICK: + case OP_IPUT_OBJECT_QUICK: + case OP_INVOKE_VIRTUAL_QUICK: + case OP_INVOKE_VIRTUAL_QUICK_RANGE: + case OP_INVOKE_SUPER_QUICK: + case OP_INVOKE_SUPER_QUICK_RANGE: + dvmAbort(); // can't work + break; + + + /* these should never appear */ + case OP_UNUSED_3E: + case OP_UNUSED_3F: + case OP_UNUSED_40: + case OP_UNUSED_41: + case OP_UNUSED_42: + case OP_UNUSED_43: + case OP_UNUSED_73: + case OP_UNUSED_79: + case OP_UNUSED_7A: + case OP_UNUSED_E3: + case OP_UNUSED_E4: + case OP_UNUSED_E5: + case OP_UNUSED_E6: + case OP_UNUSED_E7: + case OP_UNUSED_E8: + case OP_UNUSED_E9: + case OP_UNUSED_EA: + case OP_UNUSED_EB: + case OP_UNUSED_EC: + case OP_UNUSED_ED: + case OP_UNUSED_EF: + case OP_UNUSED_F1: + case OP_UNUSED_FC: + case OP_UNUSED_FD: + case OP_UNUSED_FE: + case OP_UNUSED_FF: + dvmAbort(); + break; /* * DO NOT add a "default" clause here. Without it the compiler will @@ -563,7 +1218,7 @@ static bool handleInstruction(WorkState* pState, SRegType* workRegs, * the verifier. */ if (!justSetResult) { - int reg = RESULT_REGISTER(pState->insnRegCount); + int reg = RESULT_REGISTER(pState->insnRegCountPlus); workRegs[reg] = workRegs[reg+1] = kRegTypeUnknown; } @@ -585,7 +1240,7 @@ static bool handleInstruction(WorkState* pState, SRegType* workRegs, /* if not yet visited, or regs were updated, set "changed" */ if (!dvmInsnIsVisited(insnFlags, insnIdx+insnWidth) || compareRegisters(workRegs, entryRegs, - pState->insnRegCount) != 0) + pState->insnRegCountPlus) != 0) { dvmInsnSetChanged(insnFlags, insnIdx+insnWidth, true); } @@ -747,7 +1402,7 @@ static void updateRegisters(WorkState* pState, int nextInsn, { const Method* meth = pState->method; InsnFlags* insnFlags = pState->insnFlags; - const int insnRegCount = pState->insnRegCount; + const int insnRegCountPlus = pState->insnRegCountPlus; SRegType* targetRegs = getRegisterLine(pState, nextInsn); if (!dvmInsnIsVisitedOrChanged(insnFlags, nextInsn)) { @@ -759,7 +1414,7 @@ static void updateRegisters(WorkState* pState, int nextInsn, * just an optimization.) */ LOGVV("COPY into 0x%04x\n", nextInsn); - copyRegisters(targetRegs, workRegs, insnRegCount); + copyRegisters(targetRegs, workRegs, insnRegCountPlus); dvmInsnSetChanged(insnFlags, nextInsn, true); } else { /* merge registers, set Changed only if different */ @@ -767,7 +1422,7 @@ static void updateRegisters(WorkState* pState, int nextInsn, bool changed = false; int i; - for (i = 0; i < insnRegCount; i++) { + for (i = 0; i < insnRegCountPlus; i++) { targetRegs[i] = mergeTypes(targetRegs[i], workRegs[i], &changed); } |
