auto import from //branches/cupcake/...@127101
diff --git a/vm/analysis/CodeVerify.c b/vm/analysis/CodeVerify.c
index 0b8a94d..2c5e749 100644
--- a/vm/analysis/CodeVerify.c
+++ b/vm/analysis/CodeVerify.c
@@ -327,32 +327,6 @@
 }
 
 /*
- * Given a 32-bit constant, return the most-restricted RegType that can hold
- * the value.
- */
-static RegType determineCat1Const(s4 value)
-{
-    if (value < -32768)
-        return kRegTypeInteger;
-    else if (value < -128)
-        return kRegTypeShort;
-    else if (value < 0)
-        return kRegTypeByte;
-    else if (value == 0)
-        return kRegTypeZero;
-    else if (value == 1)
-        return kRegTypeOne;
-    else if (value < 128)
-        return kRegTypePosByte;
-    else if (value < 32768)
-        return kRegTypePosShort;
-    else if (value < 65536)
-        return kRegTypeChar;
-    else
-        return kRegTypeInteger;
-}
-
-/*
  * Convert a VM PrimitiveType enum value to the equivalent RegType value.
  */
 static RegType primitiveTypeToRegType(PrimitiveType primType)
@@ -923,7 +897,6 @@
 static RegType getMethodReturnType(const Method* meth)
 {
     RegType type;
-    bool okay = true;
     const char* descriptor = dexProtoGetReturnType(&meth->prototype);
 
     switch (*descriptor) {
@@ -957,6 +930,7 @@
     case 'L':
     case '[':
         {
+            bool okay = true;
             ClassObject* clazz =
                 lookupClassByDescriptor(meth, descriptor, &okay);
             assert(okay);
@@ -2455,7 +2429,7 @@
 
     /* make sure we're in the same class */
     if (meth->clazz != field->clazz) {
-        LOG_VFY_METH(meth, "VFY: can't modify final field %s.%\n",
+        LOG_VFY_METH(meth, "VFY: can't modify final field %s.%s\n",
             field->clazz->descriptor, field->name);
         *pOkay = false;
         return;
@@ -2716,6 +2690,54 @@
 
 
 /*
+ * Verify that the arguments in a filled-new-array instruction are valid.
+ *
+ * "resClass" is the class refered to by pDecInsn->vB.
+ */
+static void verifyFilledNewArrayRegs(const Method* meth,
+    const RegType* insnRegs, const int insnRegCount,
+    const DecodedInstruction* pDecInsn, ClassObject* resClass, bool isRange,
+    bool* pOkay)
+{
+    u4 argCount = pDecInsn->vA;
+    RegType expectedType;
+    PrimitiveType elemType;
+    unsigned int ui;
+
+    assert(dvmIsArrayClass(resClass));
+    elemType = resClass->elementClass->primitiveType;
+    if (elemType == PRIM_NOT) {
+        LOG_VFY("VFY: filled-new-array not yet supported on reference types\n");
+        *pOkay = false;
+        return;
+    }
+
+    expectedType = primitiveTypeToRegType(elemType);
+    //LOGI("filled-new-array: %s -> %d\n", resClass->descriptor, expectedType);
+
+    /*
+     * Verify each register.  If "argCount" is bad, verifyRegisterType()
+     * will run off the end of the list and fail.  It's legal, if silly,
+     * for argCount to be zero.
+     */
+    for (ui = 0; ui < argCount; ui++) {
+        u4 getReg;
+
+        if (isRange)
+            getReg = pDecInsn->vC + ui;
+        else
+            getReg = pDecInsn->arg[ui];
+
+        verifyRegisterType(insnRegs, insnRegCount, getReg, expectedType, pOkay);
+        if (!*pOkay) {
+            LOG_VFY("VFY: filled-new-array arg %u(%u) not valid\n", ui, getReg);
+            return;
+        }
+    }
+}
+
+
+/*
  * ===========================================================================
  *      Entry point and driver loop
  * ===========================================================================
@@ -3309,12 +3331,12 @@
     case OP_CONST:
         /* could be boolean, int, float, or a null reference */
         setRegisterType(workRegs, insnRegCount, decInsn.vA,
-            determineCat1Const((s4)decInsn.vB), &okay);
+            dvmDetermineCat1Const((s4)decInsn.vB), &okay);
         break;
     case OP_CONST_HIGH16:
         /* could be boolean, int, float, or a null reference */
         setRegisterType(workRegs, insnRegCount, decInsn.vA,
-            determineCat1Const((s4) decInsn.vB << 16), &okay);
+            dvmDetermineCat1Const((s4) decInsn.vB << 16), &okay);
         break;
     case OP_CONST_WIDE_16:
     case OP_CONST_WIDE_32:
@@ -3332,8 +3354,18 @@
         break;
     case OP_CONST_CLASS:
         assert(gDvm.classJavaLangClass != NULL);
-        setRegisterType(workRegs, insnRegCount, decInsn.vA,
-            regTypeFromClass(gDvm.classJavaLangClass), &okay);
+        /* make sure we can resolve the class; access check is important */
+        resClass = dvmOptResolveClass(meth->clazz, decInsn.vB);
+        if (resClass == NULL) {
+            const char* badClassDesc = dexStringByTypeIdx(pDexFile, decInsn.vB);
+            dvmLogUnableToResolveClass(badClassDesc, meth);
+            LOG_VFY("VFY: unable to resolve const-class %d (%s) in %s\n",
+                decInsn.vB, badClassDesc, meth->clazz->descriptor);
+            okay = false;
+        } else {
+            setRegisterType(workRegs, insnRegCount, decInsn.vA,
+                regTypeFromClass(gDvm.classJavaLangClass), &okay);
+        }
         break;
 
     case OP_MONITOR_ENTER:
@@ -3378,17 +3410,29 @@
         }
         break;
     case OP_INSTANCE_OF:
+        /* make sure we're checking a reference type */
         tmpType = getRegisterType(workRegs, insnRegCount, decInsn.vB, &okay);
         if (!okay)
             break;
         if (!regTypeIsReference(tmpType)) {
-            LOG_VFY("VFY: vB not a reference\n");
+            LOG_VFY("VFY: vB not a reference (%d)\n", tmpType);
             okay = false;
             break;
         }
-        /* result is boolean */
-        setRegisterType(workRegs, insnRegCount, decInsn.vA,
-            kRegTypeBoolean, &okay);
+
+        /* make sure we can resolve the class; access check is important */
+        resClass = dvmOptResolveClass(meth->clazz, decInsn.vC);
+        if (resClass == NULL) {
+            const char* badClassDesc = dexStringByTypeIdx(pDexFile, decInsn.vC);
+            dvmLogUnableToResolveClass(badClassDesc, meth);
+            LOG_VFY("VFY: unable to resolve instanceof %d (%s) in %s\n",
+                decInsn.vC, badClassDesc, meth->clazz->descriptor);
+            okay = false;
+        } else {
+            /* result is boolean */
+            setRegisterType(workRegs, insnRegCount, decInsn.vA,
+                kRegTypeBoolean, &okay);
+        }
         break;
 
     case OP_ARRAY_LENGTH:
@@ -3442,7 +3486,7 @@
     case OP_NEW_ARRAY:
         resClass = dvmOptResolveClass(meth->clazz, decInsn.vC);
         if (resClass == NULL) {
-            const char* badClassDesc = dexStringByTypeIdx(pDexFile, decInsn.vB);
+            const char* badClassDesc = dexStringByTypeIdx(pDexFile, decInsn.vC);
             dvmLogUnableToResolveClass(badClassDesc, meth);
             LOG_VFY("VFY: unable to resolve new-array %d (%s) in %s\n",
                 decInsn.vC, badClassDesc, meth->clazz->descriptor);
@@ -3451,6 +3495,9 @@
             LOG_VFY("VFY: new-array on non-array class\n");
             okay = false;
         } else {
+            /* make sure "size" register is valid type */
+            verifyRegisterType(workRegs, insnRegCount, decInsn.vB,
+                kRegTypeInteger, &okay);
             /* set register type to array class */
             setRegisterType(workRegs, insnRegCount, decInsn.vA,
                 regTypeFromClass(resClass), &okay);
@@ -3458,7 +3505,6 @@
         break;
     case OP_FILLED_NEW_ARRAY:
     case OP_FILLED_NEW_ARRAY_RANGE:
-        /* (decInsn.vA == 0) is silly, but not illegal */
         resClass = dvmOptResolveClass(meth->clazz, decInsn.vB);
         if (resClass == NULL) {
             const char* badClassDesc = dexStringByTypeIdx(pDexFile, decInsn.vB);
@@ -3470,13 +3516,11 @@
             LOG_VFY("VFY: filled-new-array on non-array class\n");
             okay = false;
         } else {
-            /*
-             * TODO: verify decInsn.vA range
-             * TODO: if resClass is array of references, verify the registers
-             * in the argument list against the array type.
-             * TODO: if resClass is array of primitives, verify that the
-             * contents of the registers are appropriate.
-             */
+            bool isRange = (decInsn.opCode == OP_FILLED_NEW_ARRAY_RANGE);
+
+            /* check the arguments to the instruction */
+            verifyFilledNewArrayRegs(meth, workRegs, insnRegCount, &decInsn,
+                resClass, isRange, &okay);
             /* filled-array result goes into "result" register */
             setResultRegisterType(workRegs, insnRegCount,
                 regTypeFromClass(resClass), &okay);
@@ -3802,6 +3846,7 @@
             if (!okay)
                 break;
 
+            /* get the class of the array we're pulling an object from */
             resClass = getClassFromRegister(workRegs, insnRegCount,
                             decInsn.vB, &okay);
             if (!okay)
@@ -3811,7 +3856,7 @@
 
                 assert(resClass != NULL);
                 if (!dvmIsArrayClass(resClass)) {
-                    LOG_VFY("VFY: aget-object on non-ref array class\n");
+                    LOG_VFY("VFY: aget-object on non-array class\n");
                     okay = false;
                     break;
                 }
@@ -3826,9 +3871,14 @@
                     assert(resClass->arrayDim > 1);
                     elementClass = dvmFindArrayClass(&resClass->descriptor[1],
                                         resClass->classLoader);
-                } else {
+                } else if (resClass->descriptor[1] == 'L') {
                     assert(resClass->arrayDim == 1);
                     elementClass = resClass->elementClass;
+                } else {
+                    LOG_VFY("VFY: aget-object on non-ref array class (%s)\n",
+                        resClass->descriptor);
+                    okay = false;
+                    break;
                 }
 
                 dstType = regTypeFromClass(elementClass);
@@ -4655,7 +4705,7 @@
     case OP_INVOKE_INTERFACE:
     case OP_INVOKE_INTERFACE_RANGE:
         {
-            RegType thisType, returnType;
+            RegType /*thisType,*/ returnType;
             Method* absMethod;
             bool isRange;
 
@@ -4666,6 +4716,7 @@
             if (!okay)
                 break;
 
+#if 0       /* can't do this here, fails on dalvik test 052-verifier-fun */
             /*
              * Get the type of the "this" arg, which should always be an
              * interface class.  Because we don't do a full merge on
@@ -4676,7 +4727,6 @@
             if (!okay)
                 break;
 
-#if 0       /* can't do this here, fails on dalvik test 052-verifier-fun */
             if (thisType == kRegTypeZero) {
                 /* null pointer always passes (and always fails at runtime) */
             } else {
@@ -4934,10 +4984,40 @@
         break;
 
 
+    /*
+     * Verifying "quickened" instructions is tricky, because we have
+     * discarded the original field/method information.  The byte offsets
+     * and vtable indices only have meaning in the context of an object
+     * instance.
+     *
+     * If a piece of code declares a local reference variable, assigns
+     * null to it, and then issues a virtual method call on it, we
+     * cannot evaluate the method call during verification.  This situation
+     * isn't hard to handle, since we know the call will always result in an
+     * NPE, and the arguments and return value don't matter.  Any code that
+     * depends on the result of the method call is inaccessible, so the
+     * fact that we can't fully verify anything that comes after the bad
+     * call is not a problem.
+     *
+     * We must also consider the case of multiple code paths, only some of
+     * which involve a null reference.  We can completely verify the method
+     * if we sidestep the results of executing with a null reference.
+     * For example, if on the first pass through the code we try to do a
+     * virtual method invocation through a null ref, we have to skip the
+     * method checks and have the method return a "wildcard" type (which
+     * merges with anything to become that other thing).  The move-result
+     * will tell us if it's a reference, single-word numeric, or double-word
+     * value.  We continue to perform the verification, and at the end of
+     * the function any invocations that were never fully exercised are
+     * marked as null-only.
+     *
+     * We would do something similar for the field accesses.  The field's
+     * type, once known, can be used to recover the width of short integers.
+     * If the object reference was null, the field-get returns the "wildcard"
+     * type, which is acceptable for any operation.
+     */
     case OP_EXECUTE_INLINE:
     case OP_INVOKE_DIRECT_EMPTY:
-        okay = false;               // TODO - implement optimized opcodes
-        break;
     case OP_IGET_QUICK:
     case OP_IGET_WIDE_QUICK:
     case OP_IGET_OBJECT_QUICK:
@@ -4948,7 +5028,7 @@
     case OP_INVOKE_VIRTUAL_QUICK_RANGE:
     case OP_INVOKE_SUPER_QUICK:
     case OP_INVOKE_SUPER_QUICK_RANGE:
-        okay = false;               // TODO - implement optimized opcodes
+        okay = false;
         break;
 
     /* these should never appear */
diff --git a/vm/analysis/DexOptimize.c b/vm/analysis/DexOptimize.c
index 90e4c6f..09199db 100644
--- a/vm/analysis/DexOptimize.c
+++ b/vm/analysis/DexOptimize.c
@@ -1657,7 +1657,7 @@
     bool allowed = dvmCheckClassAccess(referrer, resClass);
     untweakLoader(referrer, resClass);
     if (!allowed) {
-        LOGI("DexOpt: resolve class illegal access: %s -> %s\n",
+        LOGW("DexOpt: resolve class illegal access: %s -> %s\n",
             referrer->descriptor, resClass->descriptor);
         return NULL;
     }
diff --git a/vm/analysis/DexVerify.c b/vm/analysis/DexVerify.c
index f78133b..5a3e8bd 100644
--- a/vm/analysis/DexVerify.c
+++ b/vm/analysis/DexVerify.c
@@ -331,13 +331,20 @@
  */
 static bool checkNewInstance(const Method* meth, int insnIdx)
 {
-    DexFile* pDexFile = meth->clazz->pDvmDex->pDexFile;
+    DvmDex* pDvmDex = meth->clazz->pDvmDex;
     DecodedInstruction decInsn;
     const char* classDescriptor;
+    u4 idx;
 
     decodeInstruction(meth, insnIdx, &decInsn);
-    classDescriptor = dexStringByTypeIdx(pDexFile, decInsn.vB); // 2nd item
+    idx = decInsn.vB;       // 2nd item
+    if (idx >= pDvmDex->pHeader->typeIdsSize) {
+        LOG_VFY_METH(meth, "VFY: bad type index %d (max %d)\n",
+            idx, pDvmDex->pHeader->typeIdsSize);
+        return false;
+    }
 
+    classDescriptor = dexStringByTypeIdx(pDvmDex->pDexFile, idx);
     if (classDescriptor[0] != 'L') {
         LOG_VFY_METH(meth, "VFY: can't call new-instance on type '%s'\n",
             classDescriptor);
@@ -354,12 +361,20 @@
  */
 static bool checkNewArray(const Method* meth, int insnIdx)
 {
-    DexFile* pDexFile = meth->clazz->pDvmDex->pDexFile;
+    DvmDex* pDvmDex = meth->clazz->pDvmDex;
     DecodedInstruction decInsn;
     const char* classDescriptor;
+    u4 idx;
 
     decodeInstruction(meth, insnIdx, &decInsn);
-    classDescriptor = dexStringByTypeIdx(pDexFile, decInsn.vC); // 3rd item
+    idx = decInsn.vC;       // 3rd item
+    if (idx >= pDvmDex->pHeader->typeIdsSize) {
+        LOG_VFY_METH(meth, "VFY: bad type index %d (max %d)\n",
+            idx, pDvmDex->pHeader->typeIdsSize);
+        return false;
+    }
+
+    classDescriptor = dexStringByTypeIdx(pDvmDex->pDexFile, idx);
 
     int bracketCount = 0;
     const char* cp = classDescriptor;
@@ -589,7 +604,7 @@
             break;
 
         case OP_FILLED_NEW_ARRAY:
-            if (!checkTypeIndex(meth, i, false))
+            if (!checkTypeIndex(meth, i, true))
                 return false;
             break;
         case OP_FILLED_NEW_ARRAY_RANGE:
diff --git a/vm/analysis/RegisterMap.c b/vm/analysis/RegisterMap.c
index 8e0054e..eb243af 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 @@
 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 @@
  * 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 @@
      * 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 @@
 
     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 @@
     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 @@
     while (*ccp != 0) {
         switch (*ccp) {
         case 'L':
-        case '[':
+        //case '[':
             *pCurReg++ = kRegTypeReference;
             break;
         case 'Z':
@@ -386,7 +393,7 @@
 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 @@
         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 @@
              */
             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 @@
 }
 
 /*
+ * 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 @@
      * 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 @@
      */
     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 @@
      * 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 @@
             /* 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 @@
 {
     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 @@
          * 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 @@
         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);
         }
 
diff --git a/vm/analysis/RegisterMap.h b/vm/analysis/RegisterMap.h
index d431aa7..07071d2 100644
--- a/vm/analysis/RegisterMap.h
+++ b/vm/analysis/RegisterMap.h
@@ -15,17 +15,21 @@
  */
 
 /*
- * Register map declaration.
+ * Declaration of register map data structure and related functions.
  */
 #ifndef _DALVIK_REGISTERMAP
 #define _DALVIK_REGISTERMAP
 
+/*
+ * This is a single variable-size structure.  It may be allocated on the
+ * heap or mapped out of a DEX file.
+ */
 typedef struct RegisterMap {
     /* header */
     char    addrWidth;      /* bytes per address, 1 or 2 */
     char    regWidth;       /* bytes per register line, 1+ */
-    char    pad0;
-    char    pad1;
+
+    /* char pad0, pad1; */
 
     /* entries start here; 32-bit align guaranteed */
     u4      entries[1];
diff --git a/vm/analysis/VerifySubs.c b/vm/analysis/VerifySubs.c
index 77134a7..8dcc6f8 100644
--- a/vm/analysis/VerifySubs.c
+++ b/vm/analysis/VerifySubs.c
@@ -195,6 +195,7 @@
     const int insnCount = dvmGetMethodInsnsSize(meth);
     const u2* insns = meth->insns + curOffset;
     const u2* switchInsns;
+    u2 expectedSignature;
     int switchCount, tableSize;
     int offsetToSwitch, offsetToKeys, offsetToTargets, targ;
     int offset, absOffset;
@@ -229,13 +230,22 @@
         /* 0=sig, 1=count, 2/3=firstKey */
         offsetToTargets = 4;
         offsetToKeys = -1;
+        expectedSignature = kPackedSwitchSignature;
     } else {
         /* 0=sig, 1=count, 2..count*2 = keys */
         offsetToKeys = 2;
         offsetToTargets = 2 + 2*switchCount;
+        expectedSignature = kSparseSwitchSignature;
     }
     tableSize = offsetToTargets + switchCount*2;
 
+    if (switchInsns[0] != expectedSignature) {
+        LOG_VFY_METH(meth,
+            "VFY: wrong signature for switch table (0x%04x, wanted 0x%04x)\n",
+            switchInsns[0], expectedSignature);
+        return false;
+    }
+
     /* make sure the end of the switch is in range */
     if (curOffset + offsetToSwitch + tableSize > insnCount) {
         LOG_VFY_METH(meth,
@@ -368,6 +378,9 @@
 /*
  * Show a relatively human-readable message describing the failure to
  * resolve a class.
+ *
+ * TODO: this is somewhat misleading when resolution fails because of
+ * illegal access rather than nonexistent class.
  */
 void dvmLogUnableToResolveClass(const char* missingClassDescr,
     const Method* meth)
@@ -434,4 +447,29 @@
     return true;
 }
 
+/*
+ * Given a 32-bit constant, return the most-restricted RegType enum entry
+ * that can hold the value.
+ */
+char dvmDetermineCat1Const(s4 value)
+{
+    if (value < -32768)
+        return kRegTypeInteger;
+    else if (value < -128)
+        return kRegTypeShort;
+    else if (value < 0)
+        return kRegTypeByte;
+    else if (value == 0)
+        return kRegTypeZero;
+    else if (value == 1)
+        return kRegTypeOne;
+    else if (value < 128)
+        return kRegTypePosByte;
+    else if (value < 32768)
+        return kRegTypePosShort;
+    else if (value < 65536)
+        return kRegTypeChar;
+    else
+        return kRegTypeInteger;
+}
 
diff --git a/vm/analysis/VerifySubs.h b/vm/analysis/VerifySubs.h
index 4a317d4..4d5b57c 100644
--- a/vm/analysis/VerifySubs.h
+++ b/vm/analysis/VerifySubs.h
@@ -67,4 +67,7 @@
 bool dvmGetBranchTarget(const Method* meth, InsnFlags* insnFlags,
     int curOffset, int* pOffset, bool* pConditional);
 
+/* return a RegType enumeration value that "value" just fits into */
+char dvmDetermineCat1Const(s4 value);
+
 #endif /*_DALVIK_VERIFYSUBS*/