Home | History | Annotate | Download | only in Analysis
      1 /*
      2  * [The "BSD licence"]
      3  * Copyright (c) 2010 Ben Gruver (JesusFreke)
      4  * All rights reserved.
      5  *
      6  * Redistribution and use in source and binary forms, with or without
      7  * modification, are permitted provided that the following conditions
      8  * are met:
      9  * 1. Redistributions of source code must retain the above copyright
     10  *    notice, this list of conditions and the following disclaimer.
     11  * 2. Redistributions in binary form must reproduce the above copyright
     12  *    notice, this list of conditions and the following disclaimer in the
     13  *    documentation and/or other materials provided with the distribution.
     14  * 3. The name of the author may not be used to endorse or promote products
     15  *    derived from this software without specific prior written permission.
     16  *
     17  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
     18  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
     19  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
     20  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
     21  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
     22  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
     23  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
     24  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     25  * INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
     26  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     27  */
     28 
     29 package org.jf.dexlib.Code.Analysis;
     30 
     31 import org.jf.dexlib.*;
     32 import org.jf.dexlib.Code.*;
     33 import org.jf.dexlib.Code.Format.*;
     34 import org.jf.dexlib.Util.AccessFlags;
     35 import org.jf.dexlib.Util.ExceptionWithContext;
     36 import org.jf.dexlib.Util.SparseArray;
     37 
     38 import java.util.BitSet;
     39 import java.util.EnumSet;
     40 import java.util.List;
     41 
     42 /**
     43  * The MethodAnalyzer performs several functions. It "analyzes" the instructions and infers the register types
     44  * for each register, it can deodex odexed instructions, and it can verify the bytecode. The analysis and verification
     45  * are done in two separate passes, because the analysis has to process instructions multiple times in some cases, and
     46  * there's no need to perform the verification multiple times, so we wait until the method is fully analyzed and then
     47  * verify it.
     48  *
     49  * Before calling the analyze() method, you must have initialized the ClassPath by calling
     50  * ClassPath.InitializeClassPath
     51  */
     52 public class MethodAnalyzer {
     53     private final ClassDataItem.EncodedMethod encodedMethod;
     54 
     55     private final DeodexUtil deodexUtil;
     56 
     57     private SparseArray<AnalyzedInstruction> instructions;
     58 
     59     private static final int NOT_ANALYZED = 0;
     60     private static final int ANALYZED = 1;
     61     private static final int VERIFIED = 2;
     62     private int analyzerState = NOT_ANALYZED;
     63 
     64     private BitSet analyzedInstructions;
     65 
     66     private ValidationException validationException = null;
     67 
     68     //This is a dummy instruction that occurs immediately before the first real instruction. We can initialize the
     69     //register types for this instruction to the parameter types, in order to have them propagate to all of its
     70     //successors, e.g. the first real instruction, the first instructions in any exception handlers covering the first
     71     //instruction, etc.
     72     private AnalyzedInstruction startOfMethod;
     73 
     74     public MethodAnalyzer(ClassDataItem.EncodedMethod encodedMethod, boolean deodex) {
     75         if (encodedMethod == null) {
     76             throw new IllegalArgumentException("encodedMethod cannot be null");
     77         }
     78         if (encodedMethod.codeItem == null || encodedMethod.codeItem.getInstructions().length == 0) {
     79             throw new IllegalArgumentException("The method has no code");
     80         }
     81         this.encodedMethod = encodedMethod;
     82 
     83         if (deodex) {
     84             this.deodexUtil = new DeodexUtil(encodedMethod.method.getDexFile());
     85         } else {
     86             this.deodexUtil = null;
     87         }
     88 
     89         //override AnalyzedInstruction and provide custom implementations of some of the methods, so that we don't
     90         //have to handle the case this special case of instruction being null, in the main class
     91         startOfMethod = new AnalyzedInstruction(null, -1, encodedMethod.codeItem.getRegisterCount()) {
     92             public boolean setsRegister() {
     93                 return false;
     94             }
     95 
     96             @Override
     97             public boolean setsWideRegister() {
     98                 return false;
     99             }
    100 
    101             @Override
    102             public boolean setsRegister(int registerNumber) {
    103                 return false;
    104             }
    105 
    106             @Override
    107             public int getDestinationRegister() {
    108                 assert false;
    109                 return -1;
    110             };
    111         };
    112 
    113         buildInstructionList();
    114 
    115         analyzedInstructions = new BitSet(instructions.size());
    116     }
    117 
    118     public boolean isAnalyzed() {
    119         return analyzerState >= ANALYZED;
    120     }
    121 
    122     public boolean isVerified() {
    123         return analyzerState == VERIFIED;
    124     }
    125 
    126     public void analyze() {
    127         assert encodedMethod != null;
    128         assert encodedMethod.codeItem != null;
    129 
    130         if (analyzerState >= ANALYZED) {
    131             //the instructions have already been analyzed, so there is nothing to do
    132             return;
    133         }
    134 
    135         CodeItem codeItem = encodedMethod.codeItem;
    136         MethodIdItem methodIdItem = encodedMethod.method;
    137 
    138         int totalRegisters = codeItem.getRegisterCount();
    139         int parameterRegisters = methodIdItem.getPrototype().getParameterRegisterCount();
    140 
    141         int nonParameterRegisters = totalRegisters - parameterRegisters;
    142 
    143         for (AnalyzedInstruction instruction: instructions.getValues()) {
    144             instruction.dead = true;
    145         }
    146 
    147         //if this isn't a static method, determine which register is the "this" register and set the type to the
    148         //current class
    149         if ((encodedMethod.accessFlags & AccessFlags.STATIC.getValue()) == 0) {
    150             nonParameterRegisters--;
    151             int thisRegister = totalRegisters - parameterRegisters - 1;
    152 
    153             //if this is a constructor, then set the "this" register to an uninitialized reference of the current class
    154             if ((encodedMethod.accessFlags & AccessFlags.CONSTRUCTOR.getValue()) != 0) {
    155                 setPostRegisterTypeAndPropagateChanges(startOfMethod, thisRegister,
    156                         RegisterType.getRegisterType(RegisterType.Category.UninitThis,
    157                             ClassPath.getClassDef(methodIdItem.getContainingClass())));
    158             } else {
    159                 setPostRegisterTypeAndPropagateChanges(startOfMethod, thisRegister,
    160                         RegisterType.getRegisterType(RegisterType.Category.Reference,
    161                             ClassPath.getClassDef(methodIdItem.getContainingClass())));
    162             }
    163         }
    164 
    165         TypeListItem parameters = methodIdItem.getPrototype().getParameters();
    166         if (parameters != null) {
    167             RegisterType[] parameterTypes = getParameterTypes(parameters, parameterRegisters);
    168             for (int i=0; i<parameterTypes.length; i++) {
    169                 RegisterType registerType = parameterTypes[i];
    170                 int registerNum = (totalRegisters - parameterRegisters) + i;
    171                 setPostRegisterTypeAndPropagateChanges(startOfMethod, registerNum, registerType);
    172             }
    173         }
    174 
    175         RegisterType uninit = RegisterType.getRegisterType(RegisterType.Category.Uninit, null);
    176         for (int i=0; i<nonParameterRegisters; i++) {
    177             setPostRegisterTypeAndPropagateChanges(startOfMethod, i, uninit);
    178         }
    179 
    180         BitSet instructionsToAnalyze = new BitSet(instructions.size());
    181 
    182         //make sure all of the "first instructions" are marked for processing
    183         for (AnalyzedInstruction successor: startOfMethod.successors) {
    184             instructionsToAnalyze.set(successor.instructionIndex);
    185         }
    186 
    187         BitSet undeodexedInstructions = new BitSet(instructions.size());
    188 
    189         do {
    190             boolean didSomething = false;
    191 
    192             while (!instructionsToAnalyze.isEmpty()) {
    193                 for(int i=instructionsToAnalyze.nextSetBit(0); i>=0; i=instructionsToAnalyze.nextSetBit(i+1)) {
    194                     instructionsToAnalyze.clear(i);
    195                     if (analyzedInstructions.get(i)) {
    196                         continue;
    197                     }
    198                     AnalyzedInstruction instructionToAnalyze = instructions.valueAt(i);
    199                     instructionToAnalyze.dead = false;
    200                     try {
    201                         if (instructionToAnalyze.originalInstruction.opcode.odexOnly()) {
    202                             //if we had deodexed an odex instruction in a previous pass, we might have more specific
    203                             //register information now, so let's restore the original odexed instruction and
    204                             //re-deodex it
    205                             instructionToAnalyze.restoreOdexedInstruction();
    206                         }
    207 
    208                         if (!analyzeInstruction(instructionToAnalyze)) {
    209                             undeodexedInstructions.set(i);
    210                             continue;
    211                         } else {
    212                             didSomething = true;
    213                             undeodexedInstructions.clear(i);
    214                         }
    215                     } catch (ValidationException ex) {
    216                         this.validationException = ex;
    217                         int codeAddress = getInstructionAddress(instructionToAnalyze);
    218                         ex.setCodeAddress(codeAddress);
    219                         ex.addContext(String.format("opcode: %s", instructionToAnalyze.instruction.opcode.name));
    220                         ex.addContext(String.format("CodeAddress: %d", codeAddress));
    221                         ex.addContext(String.format("Method: %s", encodedMethod.method.getMethodString()));
    222                         break;
    223                     }
    224 
    225                     analyzedInstructions.set(instructionToAnalyze.getInstructionIndex());
    226 
    227                     for (AnalyzedInstruction successor: instructionToAnalyze.successors) {
    228                         instructionsToAnalyze.set(successor.getInstructionIndex());
    229                     }
    230                 }
    231                 if (validationException != null) {
    232                     break;
    233                 }
    234             }
    235 
    236             if (!didSomething) {
    237                 break;
    238             }
    239 
    240             if (!undeodexedInstructions.isEmpty()) {
    241                 for (int i=undeodexedInstructions.nextSetBit(0); i>=0; i=undeodexedInstructions.nextSetBit(i+1)) {
    242                     instructionsToAnalyze.set(i);
    243                 }
    244             }
    245         } while (true);
    246 
    247         for (int i=0; i<instructions.size(); i++) {
    248             AnalyzedInstruction instruction = instructions.valueAt(i);
    249 
    250             int objectRegisterNumber;
    251             switch (instruction.getInstruction().getFormat()) {
    252                 case Format22cs:
    253                     objectRegisterNumber = ((Instruction22cs)instruction.instruction).getRegisterB();
    254                     break;
    255                 case Format35ms:
    256                     objectRegisterNumber = ((Instruction35ms)instruction.instruction).getRegisterD();
    257                     break;
    258                 case Format3rms:
    259                     objectRegisterNumber = ((Instruction3rms)instruction.instruction).getStartRegister();
    260                     break;
    261                 default:
    262                     continue;
    263             }
    264 
    265             instruction.setDeodexedInstruction(new UnresolvedOdexInstruction(instruction.instruction,
    266                     objectRegisterNumber));
    267         }
    268 
    269         analyzerState = ANALYZED;
    270     }
    271 
    272     public void verify() {
    273         if (analyzerState < ANALYZED) {
    274             throw new ExceptionWithContext("You must call analyze() before calling verify().");
    275         }
    276 
    277         if (analyzerState == VERIFIED) {
    278             //we've already verified the bytecode. nothing to do
    279             return;
    280         }
    281 
    282         BitSet instructionsToVerify = new BitSet(instructions.size());
    283         BitSet verifiedInstructions = new BitSet(instructions.size());
    284 
    285         //make sure all of the "first instructions" are marked for processing
    286         for (AnalyzedInstruction successor: startOfMethod.successors) {
    287             instructionsToVerify.set(successor.instructionIndex);
    288         }
    289 
    290         while (!instructionsToVerify.isEmpty()) {
    291             for (int i=instructionsToVerify.nextSetBit(0); i>=0; i=instructionsToVerify.nextSetBit(i+1)) {
    292                 instructionsToVerify.clear(i);
    293                 if (verifiedInstructions.get(i)) {
    294                     continue;
    295                 }
    296                 AnalyzedInstruction instructionToVerify = instructions.valueAt(i);
    297                 try {
    298                     verifyInstruction(instructionToVerify);
    299                 } catch (ValidationException ex) {
    300                     this.validationException = ex;
    301                     int codeAddress = getInstructionAddress(instructionToVerify);
    302                     ex.setCodeAddress(codeAddress);
    303                     ex.addContext(String.format("opcode: %s", instructionToVerify.instruction.opcode.name));
    304                     ex.addContext(String.format("CodeAddress: %d", codeAddress));
    305                     ex.addContext(String.format("Method: %s", encodedMethod.method.getMethodString()));
    306                     break;
    307                 }
    308 
    309                 verifiedInstructions.set(instructionToVerify.getInstructionIndex());
    310 
    311                 for (AnalyzedInstruction successor: instructionToVerify.successors) {
    312                     instructionsToVerify.set(successor.getInstructionIndex());
    313                 }
    314             }
    315             if (validationException != null) {
    316                 break;
    317             }
    318         }
    319 
    320         analyzerState = VERIFIED;
    321     }
    322 
    323     private int getThisRegister() {
    324         assert (encodedMethod.accessFlags & AccessFlags.STATIC.getValue()) == 0;
    325 
    326         CodeItem codeItem = encodedMethod.codeItem;
    327         assert codeItem != null;
    328 
    329         MethodIdItem methodIdItem = encodedMethod.method;
    330         assert methodIdItem != null;
    331 
    332         int totalRegisters = codeItem.getRegisterCount();
    333         if (totalRegisters == 0) {
    334             throw new ValidationException("A non-static method must have at least 1 register");
    335         }
    336 
    337         int parameterRegisters = methodIdItem.getPrototype().getParameterRegisterCount();
    338 
    339         return totalRegisters - parameterRegisters - 1;
    340     }
    341 
    342     private boolean isInstanceConstructor() {
    343         return (encodedMethod.accessFlags & AccessFlags.STATIC.getValue()) == 0 &&
    344                (encodedMethod.accessFlags & AccessFlags.CONSTRUCTOR.getValue()) != 0;
    345     }
    346 
    347     private boolean isStaticConstructor() {
    348         return (encodedMethod.accessFlags & AccessFlags.STATIC.getValue()) != 0 &&
    349                (encodedMethod.accessFlags & AccessFlags.CONSTRUCTOR.getValue()) != 0;
    350     }
    351 
    352     public AnalyzedInstruction getStartOfMethod() {
    353         return startOfMethod;
    354     }
    355 
    356     /**
    357      * @return a read-only list containing the instructions for tihs method.
    358      */
    359     public List<AnalyzedInstruction> getInstructions() {
    360         return instructions.getValues();
    361     }
    362 
    363     public ClassDataItem.EncodedMethod getMethod() {
    364         return this.encodedMethod;
    365     }
    366 
    367     public ValidationException getValidationException() {
    368         return validationException;
    369     }
    370 
    371     private static RegisterType[] getParameterTypes(TypeListItem typeListItem, int parameterRegisterCount) {
    372         assert typeListItem != null;
    373         assert parameterRegisterCount == typeListItem.getRegisterCount();
    374 
    375         RegisterType[] registerTypes = new RegisterType[parameterRegisterCount];
    376 
    377         int registerNum = 0;
    378         for (TypeIdItem type: typeListItem.getTypes()) {
    379             if (type.getRegisterCount() == 2) {
    380                 registerTypes[registerNum++] = RegisterType.getWideRegisterTypeForTypeIdItem(type, true);
    381                 registerTypes[registerNum++] = RegisterType.getWideRegisterTypeForTypeIdItem(type, false);
    382             } else {
    383                 registerTypes[registerNum++] = RegisterType.getRegisterTypeForTypeIdItem(type);
    384             }
    385         }
    386 
    387         return registerTypes;
    388     }
    389 
    390     public int getInstructionAddress(AnalyzedInstruction instruction) {
    391         return instructions.keyAt(instruction.instructionIndex);
    392     }
    393 
    394     private void setDestinationRegisterTypeAndPropagateChanges(AnalyzedInstruction analyzedInstruction,
    395                                                                RegisterType registerType) {
    396         setPostRegisterTypeAndPropagateChanges(analyzedInstruction, analyzedInstruction.getDestinationRegister(),
    397                 registerType);
    398     }
    399 
    400     private void setPostRegisterTypeAndPropagateChanges(AnalyzedInstruction analyzedInstruction, int registerNumber,
    401                                                 RegisterType registerType) {
    402 
    403         BitSet changedInstructions = new BitSet(instructions.size());
    404 
    405         if (!analyzedInstruction.setPostRegisterType(registerNumber, registerType)) {
    406             return;
    407         }
    408 
    409         propagateRegisterToSuccessors(analyzedInstruction, registerNumber, changedInstructions);
    410 
    411         //Using a for loop inside the while loop optimizes for the common case of the successors of an instruction
    412         //occurring after the instruction. Any successors that occur prior to the instruction will be picked up on
    413         //the next iteration of the while loop.
    414         //This could also be done recursively, but in large methods it would likely cause very deep recursion,
    415         //which requires the user to specify a larger stack size. This isn't really a problem, but it is slightly
    416         //annoying.
    417         while (!changedInstructions.isEmpty()) {
    418             for (int instructionIndex=changedInstructions.nextSetBit(0);
    419                      instructionIndex>=0;
    420                      instructionIndex=changedInstructions.nextSetBit(instructionIndex+1)) {
    421 
    422                 changedInstructions.clear(instructionIndex);
    423 
    424                 propagateRegisterToSuccessors(instructions.valueAt(instructionIndex), registerNumber,
    425                         changedInstructions);
    426             }
    427         }
    428 
    429         if (registerType.category == RegisterType.Category.LongLo) {
    430             checkWidePair(registerNumber, analyzedInstruction);
    431             setPostRegisterTypeAndPropagateChanges(analyzedInstruction, registerNumber+1,
    432                     RegisterType.getRegisterType(RegisterType.Category.LongHi, null));
    433         } else if (registerType.category == RegisterType.Category.DoubleLo) {
    434             checkWidePair(registerNumber, analyzedInstruction);
    435             setPostRegisterTypeAndPropagateChanges(analyzedInstruction, registerNumber+1,
    436                     RegisterType.getRegisterType(RegisterType.Category.DoubleHi, null));
    437         }
    438     }
    439 
    440     private void propagateRegisterToSuccessors(AnalyzedInstruction instruction, int registerNumber,
    441                                                BitSet changedInstructions) {
    442         RegisterType postRegisterType = instruction.getPostInstructionRegisterType(registerNumber);
    443         for (AnalyzedInstruction successor: instruction.successors) {
    444             if (successor.mergeRegister(registerNumber, postRegisterType, analyzedInstructions)) {
    445                 changedInstructions.set(successor.instructionIndex);
    446             }
    447         }
    448     }
    449 
    450     private void buildInstructionList() {
    451         assert encodedMethod != null;
    452         assert encodedMethod.codeItem != null;
    453         int registerCount = encodedMethod.codeItem.getRegisterCount();
    454 
    455         Instruction[] insns = encodedMethod.codeItem.getInstructions();
    456 
    457         instructions = new SparseArray<AnalyzedInstruction>(insns.length);
    458 
    459         //first, create all the instructions and populate the instructionAddresses array
    460         int currentCodeAddress = 0;
    461         for (int i=0; i<insns.length; i++) {
    462             instructions.append(currentCodeAddress, new AnalyzedInstruction(insns[i], i, registerCount));
    463             assert instructions.indexOfKey(currentCodeAddress) == i;
    464             currentCodeAddress += insns[i].getSize(currentCodeAddress);
    465         }
    466 
    467         //next, populate the exceptionHandlers array. The array item for each instruction that can throw an exception
    468         //and is covered by a try block should be set to a list of the first instructions of each exception handler
    469         //for the try block covering the instruction
    470         CodeItem.TryItem[] tries = encodedMethod.codeItem.getTries();
    471         int triesIndex = 0;
    472         CodeItem.TryItem currentTry = null;
    473         AnalyzedInstruction[] currentExceptionHandlers = null;
    474         AnalyzedInstruction[][] exceptionHandlers = new AnalyzedInstruction[insns.length][];
    475 
    476         if (tries != null) {
    477             for (int i=0; i<instructions.size(); i++) {
    478                 AnalyzedInstruction instruction = instructions.valueAt(i);
    479                 Opcode instructionOpcode = instruction.instruction.opcode;
    480                 currentCodeAddress = getInstructionAddress(instruction);
    481 
    482                 //check if we have gone past the end of the current try
    483                 if (currentTry != null) {
    484                     if (currentTry.getStartCodeAddress() + currentTry.getTryLength() <= currentCodeAddress) {
    485                         currentTry = null;
    486                         triesIndex++;
    487                     }
    488                 }
    489 
    490                 //check if the next try is applicable yet
    491                 if (currentTry == null && triesIndex < tries.length) {
    492                     CodeItem.TryItem tryItem = tries[triesIndex];
    493                     if (tryItem.getStartCodeAddress() <= currentCodeAddress) {
    494                         assert(tryItem.getStartCodeAddress() + tryItem.getTryLength() > currentCodeAddress);
    495 
    496                         currentTry = tryItem;
    497 
    498                         currentExceptionHandlers = buildExceptionHandlerArray(tryItem);
    499                     }
    500                 }
    501 
    502                 //if we're inside a try block, and the instruction can throw an exception, then add the exception handlers
    503                 //for the current instruction
    504                 if (currentTry != null && instructionOpcode.canThrow()) {
    505                     exceptionHandlers[i] = currentExceptionHandlers;
    506                 }
    507             }
    508         }
    509 
    510         //finally, populate the successors and predecessors for each instruction. We start at the fake "StartOfMethod"
    511         //instruction and follow the execution path. Any unreachable code won't have any predecessors or successors,
    512         //and no reachable code will have an unreachable predessor or successor
    513         assert instructions.size() > 0;
    514         BitSet instructionsToProcess = new BitSet(insns.length);
    515 
    516         addPredecessorSuccessor(startOfMethod, instructions.valueAt(0), exceptionHandlers, instructionsToProcess);
    517         while (!instructionsToProcess.isEmpty()) {
    518             int currentInstructionIndex = instructionsToProcess.nextSetBit(0);
    519             instructionsToProcess.clear(currentInstructionIndex);
    520 
    521             AnalyzedInstruction instruction = instructions.valueAt(currentInstructionIndex);
    522             Opcode instructionOpcode = instruction.instruction.opcode;
    523             int instructionCodeAddress = getInstructionAddress(instruction);
    524 
    525             if (instruction.instruction.opcode.canContinue()) {
    526                 if (instruction.instruction.opcode != Opcode.NOP ||
    527                     !instruction.instruction.getFormat().variableSizeFormat) {
    528 
    529                     if (currentInstructionIndex == instructions.size() - 1) {
    530                         throw new ValidationException("Execution can continue past the last instruction");
    531                     }
    532 
    533                     AnalyzedInstruction nextInstruction = instructions.valueAt(currentInstructionIndex+1);
    534                     addPredecessorSuccessor(instruction, nextInstruction, exceptionHandlers, instructionsToProcess);
    535                 }
    536             }
    537 
    538             if (instruction.instruction instanceof OffsetInstruction) {
    539                 OffsetInstruction offsetInstruction = (OffsetInstruction)instruction.instruction;
    540 
    541                 if (instructionOpcode == Opcode.PACKED_SWITCH || instructionOpcode == Opcode.SPARSE_SWITCH) {
    542                     MultiOffsetInstruction switchDataInstruction =
    543                             (MultiOffsetInstruction)instructions.get(instructionCodeAddress +
    544                                     offsetInstruction.getTargetAddressOffset()).instruction;
    545                     for (int targetAddressOffset: switchDataInstruction.getTargets()) {
    546                         AnalyzedInstruction targetInstruction = instructions.get(instructionCodeAddress +
    547                                 targetAddressOffset);
    548 
    549                         addPredecessorSuccessor(instruction, targetInstruction, exceptionHandlers,
    550                                 instructionsToProcess);
    551                     }
    552                 } else {
    553                     int targetAddressOffset = offsetInstruction.getTargetAddressOffset();
    554                     AnalyzedInstruction targetInstruction = instructions.get(instructionCodeAddress +
    555                             targetAddressOffset);
    556                     addPredecessorSuccessor(instruction, targetInstruction, exceptionHandlers, instructionsToProcess);
    557                 }
    558             }
    559         }
    560     }
    561 
    562     private void addPredecessorSuccessor(AnalyzedInstruction predecessor, AnalyzedInstruction successor,
    563                                                 AnalyzedInstruction[][] exceptionHandlers,
    564                                                 BitSet instructionsToProcess) {
    565         addPredecessorSuccessor(predecessor, successor, exceptionHandlers, instructionsToProcess, false);
    566     }
    567 
    568     private void addPredecessorSuccessor(AnalyzedInstruction predecessor, AnalyzedInstruction successor,
    569                                                 AnalyzedInstruction[][] exceptionHandlers,
    570                                                 BitSet instructionsToProcess, boolean allowMoveException) {
    571 
    572         if (!allowMoveException && successor.instruction.opcode == Opcode.MOVE_EXCEPTION) {
    573             throw new ValidationException("Execution can pass from the " + predecessor.instruction.opcode.name +
    574                     " instruction at code address 0x" + Integer.toHexString(getInstructionAddress(predecessor)) +
    575                     " to the move-exception instruction at address 0x" +
    576                     Integer.toHexString(getInstructionAddress(successor)));
    577         }
    578 
    579         if (!successor.addPredecessor(predecessor)) {
    580             return;
    581         }
    582 
    583         predecessor.addSuccessor(successor);
    584         instructionsToProcess.set(successor.getInstructionIndex());
    585 
    586 
    587         //if the successor can throw an instruction, then we need to add the exception handlers as additional
    588         //successors to the predecessor (and then apply this same logic recursively if needed)
    589         //Technically, we should handle the monitor-exit instruction as a special case. The exception is actually
    590         //thrown *after* the instruction executes, instead of "before" the instruction executes, lke for any other
    591         //instruction. But since it doesn't modify any registers, we can treat it like any other instruction.
    592         AnalyzedInstruction[] exceptionHandlersForSuccessor = exceptionHandlers[successor.instructionIndex];
    593         if (exceptionHandlersForSuccessor != null) {
    594             //the item for this instruction in exceptionHandlersForSuccessor should only be set if this instruction
    595             //can throw an exception
    596             assert successor.instruction.opcode.canThrow();
    597 
    598             for (AnalyzedInstruction exceptionHandler: exceptionHandlersForSuccessor) {
    599                 addPredecessorSuccessor(predecessor, exceptionHandler, exceptionHandlers, instructionsToProcess, true);
    600             }
    601         }
    602     }
    603 
    604     private AnalyzedInstruction[] buildExceptionHandlerArray(CodeItem.TryItem tryItem) {
    605         int exceptionHandlerCount = tryItem.encodedCatchHandler.handlers.length;
    606         int catchAllHandler = tryItem.encodedCatchHandler.getCatchAllHandlerAddress();
    607         if (catchAllHandler != -1) {
    608             exceptionHandlerCount++;
    609         }
    610 
    611         AnalyzedInstruction[] exceptionHandlers = new AnalyzedInstruction[exceptionHandlerCount];
    612         for (int i=0; i<tryItem.encodedCatchHandler.handlers.length; i++) {
    613             exceptionHandlers[i] = instructions.get(tryItem.encodedCatchHandler.handlers[i].getHandlerAddress());
    614         }
    615 
    616         if (catchAllHandler != -1) {
    617             exceptionHandlers[exceptionHandlers.length - 1] = instructions.get(catchAllHandler);
    618         }
    619 
    620         return exceptionHandlers;
    621     }
    622 
    623     /**
    624      * @return false if analyzedInstruction is an odex instruction that couldn't be deodexed, due to its
    625      * object register being null
    626      */
    627     private boolean analyzeInstruction(AnalyzedInstruction analyzedInstruction) {
    628         Instruction instruction = analyzedInstruction.instruction;
    629 
    630         switch (instruction.opcode) {
    631             case NOP:
    632                 return true;
    633             case MOVE:
    634             case MOVE_FROM16:
    635             case MOVE_16:
    636             case MOVE_WIDE:
    637             case MOVE_WIDE_FROM16:
    638             case MOVE_WIDE_16:
    639             case MOVE_OBJECT:
    640             case MOVE_OBJECT_FROM16:
    641             case MOVE_OBJECT_16:
    642                 analyzeMove(analyzedInstruction);
    643                 return true;
    644             case MOVE_RESULT:
    645             case MOVE_RESULT_WIDE:
    646             case MOVE_RESULT_OBJECT:
    647                 analyzeMoveResult(analyzedInstruction);
    648                 return true;
    649             case MOVE_EXCEPTION:
    650                 analyzeMoveException(analyzedInstruction);
    651                 return true;
    652             case RETURN_VOID:
    653             case RETURN:
    654             case RETURN_WIDE:
    655             case RETURN_OBJECT:
    656                 return true;
    657             case CONST_4:
    658             case CONST_16:
    659             case CONST:
    660                 analyzeConst(analyzedInstruction);
    661                 return true;
    662             case CONST_HIGH16:
    663                 analyzeConstHigh16(analyzedInstruction);
    664                 return true;
    665             case CONST_WIDE_16:
    666             case CONST_WIDE_32:
    667             case CONST_WIDE:
    668             case CONST_WIDE_HIGH16:
    669                 analyzeWideConst(analyzedInstruction);
    670                 return true;
    671             case CONST_STRING:
    672             case CONST_STRING_JUMBO:
    673                 analyzeConstString(analyzedInstruction);
    674                 return true;
    675             case CONST_CLASS:
    676                 analyzeConstClass(analyzedInstruction);
    677                 return true;
    678             case MONITOR_ENTER:
    679             case MONITOR_EXIT:
    680                 return true;
    681             case CHECK_CAST:
    682                 analyzeCheckCast(analyzedInstruction);
    683                 return true;
    684             case INSTANCE_OF:
    685                 analyzeInstanceOf(analyzedInstruction);
    686                 return true;
    687             case ARRAY_LENGTH:
    688                 analyzeArrayLength(analyzedInstruction);
    689                 return true;
    690             case NEW_INSTANCE:
    691                 analyzeNewInstance(analyzedInstruction);
    692                 return true;
    693             case NEW_ARRAY:
    694                 analyzeNewArray(analyzedInstruction);
    695                 return true;
    696             case FILLED_NEW_ARRAY:
    697             case FILLED_NEW_ARRAY_RANGE:
    698                 return true;
    699             case FILL_ARRAY_DATA:
    700                 analyzeArrayDataOrSwitch(analyzedInstruction);
    701             case THROW:
    702             case GOTO:
    703             case GOTO_16:
    704             case GOTO_32:
    705                 return true;
    706             case PACKED_SWITCH:
    707             case SPARSE_SWITCH:
    708                 analyzeArrayDataOrSwitch(analyzedInstruction);
    709                 return true;
    710             case CMPL_FLOAT:
    711             case CMPG_FLOAT:
    712             case CMPL_DOUBLE:
    713             case CMPG_DOUBLE:
    714             case CMP_LONG:
    715                 analyzeFloatWideCmp(analyzedInstruction);
    716                 return true;
    717             case IF_EQ:
    718             case IF_NE:
    719             case IF_LT:
    720             case IF_GE:
    721             case IF_GT:
    722             case IF_LE:
    723             case IF_EQZ:
    724             case IF_NEZ:
    725             case IF_LTZ:
    726             case IF_GEZ:
    727             case IF_GTZ:
    728             case IF_LEZ:
    729                 return true;
    730             case AGET:
    731                 analyze32BitPrimitiveAget(analyzedInstruction, RegisterType.Category.Integer);
    732                 return true;
    733             case AGET_BOOLEAN:
    734                 analyze32BitPrimitiveAget(analyzedInstruction, RegisterType.Category.Boolean);
    735                 return true;
    736             case AGET_BYTE:
    737                 analyze32BitPrimitiveAget(analyzedInstruction, RegisterType.Category.Byte);
    738                 return true;
    739             case AGET_CHAR:
    740                 analyze32BitPrimitiveAget(analyzedInstruction, RegisterType.Category.Char);
    741                 return true;
    742             case AGET_SHORT:
    743                 analyze32BitPrimitiveAget(analyzedInstruction, RegisterType.Category.Short);
    744                 return true;
    745             case AGET_WIDE:
    746                 analyzeAgetWide(analyzedInstruction);
    747                 return true;
    748             case AGET_OBJECT:
    749                 analyzeAgetObject(analyzedInstruction);
    750                 return true;
    751             case APUT:
    752             case APUT_BOOLEAN:
    753             case APUT_BYTE:
    754             case APUT_CHAR:
    755             case APUT_SHORT:
    756             case APUT_WIDE:
    757             case APUT_OBJECT:
    758                 return true;
    759             case IGET:
    760                 analyze32BitPrimitiveIget(analyzedInstruction, RegisterType.Category.Integer);
    761                 return true;
    762             case IGET_BOOLEAN:
    763                 analyze32BitPrimitiveIget(analyzedInstruction, RegisterType.Category.Boolean);
    764                 return true;
    765             case IGET_BYTE:
    766                 analyze32BitPrimitiveIget(analyzedInstruction, RegisterType.Category.Byte);
    767                 return true;
    768             case IGET_CHAR:
    769                 analyze32BitPrimitiveIget(analyzedInstruction, RegisterType.Category.Char);
    770                 return true;
    771             case IGET_SHORT:
    772                 analyze32BitPrimitiveIget(analyzedInstruction, RegisterType.Category.Short);
    773                 return true;
    774             case IGET_WIDE:
    775             case IGET_OBJECT:
    776                 analyzeIgetWideObject(analyzedInstruction);
    777                 return true;
    778             case IPUT:
    779             case IPUT_BOOLEAN:
    780             case IPUT_BYTE:
    781             case IPUT_CHAR:
    782             case IPUT_SHORT:
    783             case IPUT_WIDE:
    784             case IPUT_OBJECT:
    785                 return true;
    786             case SGET:
    787                 analyze32BitPrimitiveSget(analyzedInstruction, RegisterType.Category.Integer);
    788                 return true;
    789             case SGET_BOOLEAN:
    790                 analyze32BitPrimitiveSget(analyzedInstruction, RegisterType.Category.Boolean);
    791                 return true;
    792             case SGET_BYTE:
    793                 analyze32BitPrimitiveSget(analyzedInstruction, RegisterType.Category.Byte);
    794                 return true;
    795             case SGET_CHAR:
    796                 analyze32BitPrimitiveSget(analyzedInstruction, RegisterType.Category.Char);
    797                 return true;
    798             case SGET_SHORT:
    799                 analyze32BitPrimitiveSget(analyzedInstruction, RegisterType.Category.Short);
    800                 return true;
    801             case SGET_WIDE:
    802             case SGET_OBJECT:
    803                 analyzeSgetWideObject(analyzedInstruction);
    804                 return true;
    805             case SPUT:
    806             case SPUT_BOOLEAN:
    807             case SPUT_BYTE:
    808             case SPUT_CHAR:
    809             case SPUT_SHORT:
    810             case SPUT_WIDE:
    811             case SPUT_OBJECT:
    812                 return true;
    813             case INVOKE_VIRTUAL:
    814             case INVOKE_SUPER:
    815                 return true;
    816             case INVOKE_DIRECT:
    817                 analyzeInvokeDirect(analyzedInstruction);
    818                 return true;
    819             case INVOKE_STATIC:
    820             case INVOKE_INTERFACE:
    821             case INVOKE_VIRTUAL_RANGE:
    822             case INVOKE_SUPER_RANGE:
    823                 return true;
    824             case INVOKE_DIRECT_RANGE:
    825                 analyzeInvokeDirectRange(analyzedInstruction);
    826                 return true;
    827             case INVOKE_STATIC_RANGE:
    828             case INVOKE_INTERFACE_RANGE:
    829                 return true;
    830             case NEG_INT:
    831             case NOT_INT:
    832                 analyzeUnaryOp(analyzedInstruction, RegisterType.Category.Integer);
    833                 return true;
    834             case NEG_LONG:
    835             case NOT_LONG:
    836                 analyzeUnaryOp(analyzedInstruction, RegisterType.Category.LongLo);
    837                 return true;
    838             case NEG_FLOAT:
    839                 analyzeUnaryOp(analyzedInstruction, RegisterType.Category.Float);
    840                 return true;
    841             case NEG_DOUBLE:
    842                 analyzeUnaryOp(analyzedInstruction, RegisterType.Category.DoubleLo);
    843                 return true;
    844             case INT_TO_LONG:
    845                 analyzeUnaryOp(analyzedInstruction, RegisterType.Category.LongLo);
    846                 return true;
    847             case INT_TO_FLOAT:
    848                 analyzeUnaryOp(analyzedInstruction, RegisterType.Category.Float);
    849                 return true;
    850             case INT_TO_DOUBLE:
    851                 analyzeUnaryOp(analyzedInstruction, RegisterType.Category.DoubleLo);
    852                 return true;
    853             case LONG_TO_INT:
    854             case DOUBLE_TO_INT:
    855                 analyzeUnaryOp(analyzedInstruction, RegisterType.Category.Integer);
    856                 return true;
    857             case LONG_TO_FLOAT:
    858             case DOUBLE_TO_FLOAT:
    859                 analyzeUnaryOp(analyzedInstruction, RegisterType.Category.Float);
    860                 return true;
    861             case LONG_TO_DOUBLE:
    862                 analyzeUnaryOp(analyzedInstruction, RegisterType.Category.DoubleLo);
    863                 return true;
    864             case FLOAT_TO_INT:
    865                 analyzeUnaryOp(analyzedInstruction, RegisterType.Category.Integer);
    866                 return true;
    867             case FLOAT_TO_LONG:
    868                 analyzeUnaryOp(analyzedInstruction, RegisterType.Category.LongLo);
    869                 return true;
    870             case FLOAT_TO_DOUBLE:
    871                 analyzeUnaryOp(analyzedInstruction, RegisterType.Category.DoubleLo);
    872                 return true;
    873             case DOUBLE_TO_LONG:
    874                 analyzeUnaryOp(analyzedInstruction, RegisterType.Category.LongLo);
    875                 return true;
    876             case INT_TO_BYTE:
    877                 analyzeUnaryOp(analyzedInstruction, RegisterType.Category.Byte);
    878                 return true;
    879             case INT_TO_CHAR:
    880                 analyzeUnaryOp(analyzedInstruction, RegisterType.Category.Char);
    881                 return true;
    882             case INT_TO_SHORT:
    883                 analyzeUnaryOp(analyzedInstruction, RegisterType.Category.Short);
    884                 return true;
    885             case ADD_INT:
    886             case SUB_INT:
    887             case MUL_INT:
    888             case DIV_INT:
    889             case REM_INT:
    890             case SHL_INT:
    891             case SHR_INT:
    892             case USHR_INT:
    893                 analyzeBinaryOp(analyzedInstruction, RegisterType.Category.Integer, false);
    894                 return true;
    895             case AND_INT:
    896             case OR_INT:
    897             case XOR_INT:
    898                 analyzeBinaryOp(analyzedInstruction, RegisterType.Category.Integer, true);
    899                 return true;
    900             case ADD_LONG:
    901             case SUB_LONG:
    902             case MUL_LONG:
    903             case DIV_LONG:
    904             case REM_LONG:
    905             case AND_LONG:
    906             case OR_LONG:
    907             case XOR_LONG:
    908             case SHL_LONG:
    909             case SHR_LONG:
    910             case USHR_LONG:
    911                 analyzeBinaryOp(analyzedInstruction, RegisterType.Category.LongLo, false);
    912                 return true;
    913             case ADD_FLOAT:
    914             case SUB_FLOAT:
    915             case MUL_FLOAT:
    916             case DIV_FLOAT:
    917             case REM_FLOAT:
    918                 analyzeBinaryOp(analyzedInstruction, RegisterType.Category.Float, false);
    919                 return true;
    920             case ADD_DOUBLE:
    921             case SUB_DOUBLE:
    922             case MUL_DOUBLE:
    923             case DIV_DOUBLE:
    924             case REM_DOUBLE:
    925                 analyzeBinaryOp(analyzedInstruction, RegisterType.Category.DoubleLo, false);
    926                 return true;
    927             case ADD_INT_2ADDR:
    928             case SUB_INT_2ADDR:
    929             case MUL_INT_2ADDR:
    930             case DIV_INT_2ADDR:
    931             case REM_INT_2ADDR:
    932             case SHL_INT_2ADDR:
    933             case SHR_INT_2ADDR:
    934             case USHR_INT_2ADDR:
    935                 analyzeBinary2AddrOp(analyzedInstruction, RegisterType.Category.Integer, false);
    936                 return true;
    937             case AND_INT_2ADDR:
    938             case OR_INT_2ADDR:
    939             case XOR_INT_2ADDR:
    940                 analyzeBinary2AddrOp(analyzedInstruction, RegisterType.Category.Integer, true);
    941                 return true;
    942             case ADD_LONG_2ADDR:
    943             case SUB_LONG_2ADDR:
    944             case MUL_LONG_2ADDR:
    945             case DIV_LONG_2ADDR:
    946             case REM_LONG_2ADDR:
    947             case AND_LONG_2ADDR:
    948             case OR_LONG_2ADDR:
    949             case XOR_LONG_2ADDR:
    950             case SHL_LONG_2ADDR:
    951             case SHR_LONG_2ADDR:
    952             case USHR_LONG_2ADDR:
    953                 analyzeBinary2AddrOp(analyzedInstruction, RegisterType.Category.LongLo, false);
    954                 return true;
    955             case ADD_FLOAT_2ADDR:
    956             case SUB_FLOAT_2ADDR:
    957             case MUL_FLOAT_2ADDR:
    958             case DIV_FLOAT_2ADDR:
    959             case REM_FLOAT_2ADDR:
    960                 analyzeBinary2AddrOp(analyzedInstruction, RegisterType.Category.Float, false);
    961                 return true;
    962             case ADD_DOUBLE_2ADDR:
    963             case SUB_DOUBLE_2ADDR:
    964             case MUL_DOUBLE_2ADDR:
    965             case DIV_DOUBLE_2ADDR:
    966             case REM_DOUBLE_2ADDR:
    967                 analyzeBinary2AddrOp(analyzedInstruction, RegisterType.Category.DoubleLo, false);
    968                 return true;
    969             case ADD_INT_LIT16:
    970             case RSUB_INT:
    971             case MUL_INT_LIT16:
    972             case DIV_INT_LIT16:
    973             case REM_INT_LIT16:
    974                 analyzeLiteralBinaryOp(analyzedInstruction, RegisterType.Category.Integer, false);
    975                 return true;
    976             case AND_INT_LIT16:
    977             case OR_INT_LIT16:
    978             case XOR_INT_LIT16:
    979                 analyzeLiteralBinaryOp(analyzedInstruction, RegisterType.Category.Integer, true);
    980                 return true;
    981             case ADD_INT_LIT8:
    982             case RSUB_INT_LIT8:
    983             case MUL_INT_LIT8:
    984             case DIV_INT_LIT8:
    985             case REM_INT_LIT8:
    986             case SHL_INT_LIT8:
    987                 analyzeLiteralBinaryOp(analyzedInstruction, RegisterType.Category.Integer, false);
    988                 return true;
    989             case AND_INT_LIT8:
    990             case OR_INT_LIT8:
    991             case XOR_INT_LIT8:
    992                 analyzeLiteralBinaryOp(analyzedInstruction, RegisterType.Category.Integer, true);
    993                 return true;
    994             case SHR_INT_LIT8:
    995                 analyzeLiteralBinaryOp(analyzedInstruction, getDestTypeForLiteralShiftRight(analyzedInstruction, true),
    996                         false);
    997                 return true;
    998             case USHR_INT_LIT8:
    999                 analyzeLiteralBinaryOp(analyzedInstruction, getDestTypeForLiteralShiftRight(analyzedInstruction, false),
   1000                         false);
   1001                 return true;
   1002 
   1003             /*odexed instructions*/
   1004             case IGET_VOLATILE:
   1005             case IPUT_VOLATILE:
   1006             case SGET_VOLATILE:
   1007             case SPUT_VOLATILE:
   1008             case IGET_OBJECT_VOLATILE:
   1009             case IGET_WIDE_VOLATILE:
   1010             case IPUT_WIDE_VOLATILE:
   1011             case SGET_WIDE_VOLATILE:
   1012             case SPUT_WIDE_VOLATILE:
   1013                 analyzePutGetVolatile(analyzedInstruction);
   1014                 return true;
   1015             case EXECUTE_INLINE:
   1016                 analyzeExecuteInline(analyzedInstruction);
   1017                 return true;
   1018             case EXECUTE_INLINE_RANGE:
   1019                 analyzeExecuteInlineRange(analyzedInstruction);
   1020                 return true;
   1021             case INVOKE_DIRECT_EMPTY:
   1022                 analyzeInvokeDirectEmpty(analyzedInstruction);
   1023                 return true;
   1024             case IGET_QUICK:
   1025             case IGET_WIDE_QUICK:
   1026             case IGET_OBJECT_QUICK:
   1027             case IPUT_QUICK:
   1028             case IPUT_WIDE_QUICK:
   1029             case IPUT_OBJECT_QUICK:
   1030                 return analyzeIputIgetQuick(analyzedInstruction);
   1031             case INVOKE_VIRTUAL_QUICK:
   1032                 return analyzeInvokeVirtualQuick(analyzedInstruction, false, false);
   1033             case INVOKE_SUPER_QUICK:
   1034                 return analyzeInvokeVirtualQuick(analyzedInstruction, true, false);
   1035             case INVOKE_VIRTUAL_QUICK_RANGE:
   1036                 return analyzeInvokeVirtualQuick(analyzedInstruction, false, true);
   1037             case INVOKE_SUPER_QUICK_RANGE:
   1038                 return analyzeInvokeVirtualQuick(analyzedInstruction, true, true);
   1039             case IPUT_OBJECT_VOLATILE:
   1040             case SGET_OBJECT_VOLATILE:
   1041             case SPUT_OBJECT_VOLATILE:
   1042                 analyzePutGetVolatile(analyzedInstruction);
   1043                 return true;
   1044             default:
   1045                 assert false;
   1046                 return true;
   1047         }
   1048     }
   1049 
   1050 
   1051         private void verifyInstruction(AnalyzedInstruction analyzedInstruction) {
   1052         Instruction instruction = analyzedInstruction.instruction;
   1053 
   1054         switch (instruction.opcode) {
   1055             case NOP:
   1056                 return;
   1057             case MOVE:
   1058             case MOVE_FROM16:
   1059             case MOVE_16:
   1060                 verifyMove(analyzedInstruction, Primitive32BitCategories);
   1061                 return;
   1062             case MOVE_WIDE:
   1063             case MOVE_WIDE_FROM16:
   1064             case MOVE_WIDE_16:
   1065                 verifyMove(analyzedInstruction, WideLowCategories);
   1066                 return;
   1067             case MOVE_OBJECT:
   1068             case MOVE_OBJECT_FROM16:
   1069             case MOVE_OBJECT_16:
   1070                 verifyMove(analyzedInstruction, ReferenceOrUninitCategories);
   1071                 return;
   1072             case MOVE_RESULT:
   1073                 verifyMoveResult(analyzedInstruction, Primitive32BitCategories);
   1074                 return;
   1075             case MOVE_RESULT_WIDE:
   1076                 verifyMoveResult(analyzedInstruction, WideLowCategories);
   1077                 return;
   1078             case MOVE_RESULT_OBJECT:
   1079                 verifyMoveResult(analyzedInstruction, ReferenceCategories);
   1080                 return;
   1081             case MOVE_EXCEPTION:
   1082                 verifyMoveException(analyzedInstruction);
   1083                 return;
   1084             case RETURN_VOID:
   1085                 verifyReturnVoid(analyzedInstruction);
   1086                 return;
   1087             case RETURN:
   1088                 verifyReturn(analyzedInstruction, Primitive32BitCategories);
   1089                 return;
   1090             case RETURN_WIDE:
   1091                 verifyReturn(analyzedInstruction, WideLowCategories);
   1092                 return;
   1093             case RETURN_OBJECT:
   1094                 verifyReturn(analyzedInstruction, ReferenceCategories);
   1095                 return;
   1096             case CONST_4:
   1097             case CONST_16:
   1098             case CONST:
   1099             case CONST_HIGH16:
   1100             case CONST_WIDE_16:
   1101             case CONST_WIDE_32:
   1102             case CONST_WIDE:
   1103             case CONST_WIDE_HIGH16:
   1104             case CONST_STRING:
   1105             case CONST_STRING_JUMBO:
   1106                 return;
   1107             case CONST_CLASS:
   1108                 verifyConstClass(analyzedInstruction);
   1109                 return;
   1110             case MONITOR_ENTER:
   1111             case MONITOR_EXIT:
   1112                 verifyMonitor(analyzedInstruction);
   1113                 return;
   1114             case CHECK_CAST:
   1115                 verifyCheckCast(analyzedInstruction);
   1116                 return;
   1117             case INSTANCE_OF:
   1118                 verifyInstanceOf(analyzedInstruction);
   1119                 return;
   1120             case ARRAY_LENGTH:
   1121                 verifyArrayLength(analyzedInstruction);
   1122                 return;
   1123             case NEW_INSTANCE:
   1124                 verifyNewInstance(analyzedInstruction);
   1125                 return;
   1126             case NEW_ARRAY:
   1127                 verifyNewArray(analyzedInstruction);
   1128                 return;
   1129             case FILLED_NEW_ARRAY:
   1130                 verifyFilledNewArray(analyzedInstruction);
   1131                 return;
   1132             case FILLED_NEW_ARRAY_RANGE:
   1133                 verifyFilledNewArrayRange(analyzedInstruction);
   1134                 return;
   1135             case FILL_ARRAY_DATA:
   1136                 verifyFillArrayData(analyzedInstruction);
   1137                 return;
   1138             case THROW:
   1139                 verifyThrow(analyzedInstruction);
   1140                 return;
   1141             case GOTO:
   1142             case GOTO_16:
   1143             case GOTO_32:
   1144                 return;
   1145             case PACKED_SWITCH:
   1146                 verifySwitch(analyzedInstruction, Format.PackedSwitchData);
   1147                 return;
   1148             case SPARSE_SWITCH:
   1149                 verifySwitch(analyzedInstruction, Format.SparseSwitchData);
   1150                 return;
   1151             case CMPL_FLOAT:
   1152             case CMPG_FLOAT:
   1153                 verifyFloatWideCmp(analyzedInstruction, Primitive32BitCategories);
   1154                 return;
   1155             case CMPL_DOUBLE:
   1156             case CMPG_DOUBLE:
   1157             case CMP_LONG:
   1158                 verifyFloatWideCmp(analyzedInstruction, WideLowCategories);
   1159                 return;
   1160             case IF_EQ:
   1161             case IF_NE:
   1162                 verifyIfEqNe(analyzedInstruction);
   1163                 return;
   1164             case IF_LT:
   1165             case IF_GE:
   1166             case IF_GT:
   1167             case IF_LE:
   1168                 verifyIf(analyzedInstruction);
   1169                 return;
   1170             case IF_EQZ:
   1171             case IF_NEZ:
   1172                 verifyIfEqzNez(analyzedInstruction);
   1173                 return;
   1174             case IF_LTZ:
   1175             case IF_GEZ:
   1176             case IF_GTZ:
   1177             case IF_LEZ:
   1178                 verifyIfz(analyzedInstruction);
   1179                 return;
   1180             case AGET:
   1181                 verify32BitPrimitiveAget(analyzedInstruction, RegisterType.Category.Integer);
   1182                 return;
   1183             case AGET_BOOLEAN:
   1184                 verify32BitPrimitiveAget(analyzedInstruction, RegisterType.Category.Boolean);
   1185                 return;
   1186             case AGET_BYTE:
   1187                 verify32BitPrimitiveAget(analyzedInstruction, RegisterType.Category.Byte);
   1188                 return;
   1189             case AGET_CHAR:
   1190                 verify32BitPrimitiveAget(analyzedInstruction, RegisterType.Category.Char);
   1191                 return;
   1192             case AGET_SHORT:
   1193                 verify32BitPrimitiveAget(analyzedInstruction, RegisterType.Category.Short);
   1194                 return;
   1195             case AGET_WIDE:
   1196                 verifyAgetWide(analyzedInstruction);
   1197                 return;
   1198             case AGET_OBJECT:
   1199                 verifyAgetObject(analyzedInstruction);
   1200                 return;
   1201             case APUT:
   1202                 verify32BitPrimitiveAput(analyzedInstruction, RegisterType.Category.Integer);
   1203                 return;
   1204             case APUT_BOOLEAN:
   1205                 verify32BitPrimitiveAput(analyzedInstruction, RegisterType.Category.Boolean);
   1206                 return;
   1207             case APUT_BYTE:
   1208                 verify32BitPrimitiveAput(analyzedInstruction, RegisterType.Category.Byte);
   1209                 return;
   1210             case APUT_CHAR:
   1211                 verify32BitPrimitiveAput(analyzedInstruction, RegisterType.Category.Char);
   1212                 return;
   1213             case APUT_SHORT:
   1214                 verify32BitPrimitiveAput(analyzedInstruction, RegisterType.Category.Short);
   1215                 return;
   1216             case APUT_WIDE:
   1217                 verifyAputWide(analyzedInstruction);
   1218                 return;
   1219             case APUT_OBJECT:
   1220                 verifyAputObject(analyzedInstruction);
   1221                 return;
   1222             case IGET:
   1223                 verify32BitPrimitiveIget(analyzedInstruction, RegisterType.Category.Integer);
   1224                 return;
   1225             case IGET_BOOLEAN:
   1226                 verify32BitPrimitiveIget(analyzedInstruction, RegisterType.Category.Boolean);
   1227                 return;
   1228             case IGET_BYTE:
   1229                 verify32BitPrimitiveIget(analyzedInstruction, RegisterType.Category.Byte);
   1230                 return;
   1231             case IGET_CHAR:
   1232                 verify32BitPrimitiveIget(analyzedInstruction, RegisterType.Category.Char);
   1233                 return;
   1234             case IGET_SHORT:
   1235                 verify32BitPrimitiveIget(analyzedInstruction, RegisterType.Category.Short);
   1236                 return;
   1237             case IGET_WIDE:
   1238                 verifyIgetWide(analyzedInstruction);
   1239                 return;
   1240             case IGET_OBJECT:
   1241                 verifyIgetObject(analyzedInstruction);
   1242                 return;
   1243             case IPUT:
   1244                 verify32BitPrimitiveIput(analyzedInstruction, RegisterType.Category.Integer);
   1245                 return;
   1246             case IPUT_BOOLEAN:
   1247                 verify32BitPrimitiveIput(analyzedInstruction, RegisterType.Category.Boolean);
   1248                 return;
   1249             case IPUT_BYTE:
   1250                 verify32BitPrimitiveIput(analyzedInstruction, RegisterType.Category.Byte);
   1251                 return;
   1252             case IPUT_CHAR:
   1253                 verify32BitPrimitiveIput(analyzedInstruction, RegisterType.Category.Char);
   1254                 return;
   1255             case IPUT_SHORT:
   1256                 verify32BitPrimitiveIput(analyzedInstruction, RegisterType.Category.Short);
   1257                 return;
   1258             case IPUT_WIDE:
   1259                 verifyIputWide(analyzedInstruction);
   1260                 return;
   1261             case IPUT_OBJECT:
   1262                 verifyIputObject(analyzedInstruction);
   1263                 return;
   1264             case SGET:
   1265                 verify32BitPrimitiveSget(analyzedInstruction, RegisterType.Category.Integer);
   1266                 return;
   1267             case SGET_BOOLEAN:
   1268                 verify32BitPrimitiveSget(analyzedInstruction, RegisterType.Category.Boolean);
   1269                 return;
   1270             case SGET_BYTE:
   1271                 verify32BitPrimitiveSget(analyzedInstruction, RegisterType.Category.Byte);
   1272                 return;
   1273             case SGET_CHAR:
   1274                 verify32BitPrimitiveSget(analyzedInstruction, RegisterType.Category.Char);
   1275                 return;
   1276             case SGET_SHORT:
   1277                 verify32BitPrimitiveSget(analyzedInstruction, RegisterType.Category.Short);
   1278                 return;
   1279             case SGET_WIDE:
   1280                 verifySgetWide(analyzedInstruction);
   1281                 return;
   1282             case SGET_OBJECT:
   1283                 verifySgetObject(analyzedInstruction);
   1284                 return;
   1285             case SPUT:
   1286                 verify32BitPrimitiveSput(analyzedInstruction, RegisterType.Category.Integer);
   1287                 return;
   1288             case SPUT_BOOLEAN:
   1289                 verify32BitPrimitiveSput(analyzedInstruction, RegisterType.Category.Boolean);
   1290                 return;
   1291             case SPUT_BYTE:
   1292                 verify32BitPrimitiveSput(analyzedInstruction, RegisterType.Category.Byte);
   1293                 return;
   1294             case SPUT_CHAR:
   1295                 verify32BitPrimitiveSput(analyzedInstruction, RegisterType.Category.Char);
   1296                 return;
   1297             case SPUT_SHORT:
   1298                 verify32BitPrimitiveSput(analyzedInstruction, RegisterType.Category.Short);
   1299                 return;
   1300             case SPUT_WIDE:
   1301                 verifySputWide(analyzedInstruction);
   1302                 return;
   1303             case SPUT_OBJECT:
   1304                 verifySputObject(analyzedInstruction);
   1305                 return;
   1306             case INVOKE_VIRTUAL:
   1307                 verifyInvoke(analyzedInstruction, INVOKE_VIRTUAL);
   1308                 return;
   1309             case INVOKE_SUPER:
   1310                 verifyInvoke(analyzedInstruction, INVOKE_SUPER);
   1311                 return;
   1312             case INVOKE_DIRECT:
   1313                 verifyInvoke(analyzedInstruction, INVOKE_DIRECT);
   1314                 return;
   1315             case INVOKE_STATIC:
   1316                 verifyInvoke(analyzedInstruction, INVOKE_STATIC);
   1317                 return;
   1318             case INVOKE_INTERFACE:
   1319                 verifyInvoke(analyzedInstruction, INVOKE_INTERFACE);
   1320                 return;
   1321             case INVOKE_VIRTUAL_RANGE:
   1322                 verifyInvokeRange(analyzedInstruction, INVOKE_VIRTUAL);
   1323                 return;
   1324             case INVOKE_SUPER_RANGE:
   1325                 verifyInvokeRange(analyzedInstruction, INVOKE_SUPER);
   1326                 return;
   1327             case INVOKE_DIRECT_RANGE:
   1328                 verifyInvokeRange(analyzedInstruction, INVOKE_DIRECT);
   1329                 return;
   1330             case INVOKE_STATIC_RANGE:
   1331                 verifyInvokeRange(analyzedInstruction, INVOKE_STATIC);
   1332                 return;
   1333             case INVOKE_INTERFACE_RANGE:
   1334                 verifyInvokeRange(analyzedInstruction, INVOKE_INTERFACE);
   1335                 return;
   1336             case NEG_INT:
   1337             case NOT_INT:
   1338                 verifyUnaryOp(analyzedInstruction, Primitive32BitCategories);
   1339                 return;
   1340             case NEG_LONG:
   1341             case NOT_LONG:
   1342                 verifyUnaryOp(analyzedInstruction, WideLowCategories);
   1343                 return;
   1344             case NEG_FLOAT:
   1345                 verifyUnaryOp(analyzedInstruction, Primitive32BitCategories);
   1346                 return;
   1347             case NEG_DOUBLE:
   1348                 verifyUnaryOp(analyzedInstruction, WideLowCategories);
   1349                 return;
   1350             case INT_TO_LONG:
   1351                 verifyUnaryOp(analyzedInstruction, Primitive32BitCategories);
   1352                 return;
   1353             case INT_TO_FLOAT:
   1354                 verifyUnaryOp(analyzedInstruction, Primitive32BitCategories);
   1355                 return;
   1356             case INT_TO_DOUBLE:
   1357                 verifyUnaryOp(analyzedInstruction, Primitive32BitCategories);
   1358                 return;
   1359             case LONG_TO_INT:
   1360             case DOUBLE_TO_INT:
   1361                 verifyUnaryOp(analyzedInstruction, WideLowCategories);
   1362                 return;
   1363             case LONG_TO_FLOAT:
   1364             case DOUBLE_TO_FLOAT:
   1365                 verifyUnaryOp(analyzedInstruction, WideLowCategories);
   1366                 return;
   1367             case LONG_TO_DOUBLE:
   1368                 verifyUnaryOp(analyzedInstruction, WideLowCategories);
   1369                 return;
   1370             case FLOAT_TO_INT:
   1371                 verifyUnaryOp(analyzedInstruction, Primitive32BitCategories);
   1372                 return;
   1373             case FLOAT_TO_LONG:
   1374                 verifyUnaryOp(analyzedInstruction, Primitive32BitCategories);
   1375                 return;
   1376             case FLOAT_TO_DOUBLE:
   1377                 verifyUnaryOp(analyzedInstruction, Primitive32BitCategories);
   1378                 return;
   1379             case DOUBLE_TO_LONG:
   1380                 verifyUnaryOp(analyzedInstruction, WideLowCategories);
   1381                 return;
   1382             case INT_TO_BYTE:
   1383                 verifyUnaryOp(analyzedInstruction, Primitive32BitCategories);
   1384                 return;
   1385             case INT_TO_CHAR:
   1386                 verifyUnaryOp(analyzedInstruction, Primitive32BitCategories);
   1387                 return;
   1388             case INT_TO_SHORT:
   1389                 verifyUnaryOp(analyzedInstruction, Primitive32BitCategories);
   1390                 return;
   1391             case ADD_INT:
   1392             case SUB_INT:
   1393             case MUL_INT:
   1394             case DIV_INT:
   1395             case REM_INT:
   1396             case SHL_INT:
   1397             case SHR_INT:
   1398             case USHR_INT:
   1399             case AND_INT:
   1400             case OR_INT:
   1401             case XOR_INT:
   1402                 verifyBinaryOp(analyzedInstruction, Primitive32BitCategories, Primitive32BitCategories);
   1403                 return;
   1404             case ADD_LONG:
   1405             case SUB_LONG:
   1406             case MUL_LONG:
   1407             case DIV_LONG:
   1408             case REM_LONG:
   1409             case AND_LONG:
   1410             case OR_LONG:
   1411             case XOR_LONG:
   1412                 verifyBinaryOp(analyzedInstruction, WideLowCategories, WideLowCategories);
   1413                 return;
   1414             case SHL_LONG:
   1415             case SHR_LONG:
   1416             case USHR_LONG:
   1417                 verifyBinaryOp(analyzedInstruction, WideLowCategories, Primitive32BitCategories);
   1418                 return;
   1419             case ADD_FLOAT:
   1420             case SUB_FLOAT:
   1421             case MUL_FLOAT:
   1422             case DIV_FLOAT:
   1423             case REM_FLOAT:
   1424                 verifyBinaryOp(analyzedInstruction, Primitive32BitCategories, Primitive32BitCategories);
   1425                 return;
   1426             case ADD_DOUBLE:
   1427             case SUB_DOUBLE:
   1428             case MUL_DOUBLE:
   1429             case DIV_DOUBLE:
   1430             case REM_DOUBLE:
   1431                 verifyBinaryOp(analyzedInstruction, WideLowCategories, WideLowCategories);
   1432                 return;
   1433             case ADD_INT_2ADDR:
   1434             case SUB_INT_2ADDR:
   1435             case MUL_INT_2ADDR:
   1436             case DIV_INT_2ADDR:
   1437             case REM_INT_2ADDR:
   1438             case SHL_INT_2ADDR:
   1439             case SHR_INT_2ADDR:
   1440             case USHR_INT_2ADDR:
   1441             case AND_INT_2ADDR:
   1442             case OR_INT_2ADDR:
   1443             case XOR_INT_2ADDR:
   1444                 verifyBinary2AddrOp(analyzedInstruction, Primitive32BitCategories, Primitive32BitCategories);
   1445                 return;
   1446             case ADD_LONG_2ADDR:
   1447             case SUB_LONG_2ADDR:
   1448             case MUL_LONG_2ADDR:
   1449             case DIV_LONG_2ADDR:
   1450             case REM_LONG_2ADDR:
   1451             case AND_LONG_2ADDR:
   1452             case OR_LONG_2ADDR:
   1453             case XOR_LONG_2ADDR:
   1454                 verifyBinary2AddrOp(analyzedInstruction, WideLowCategories, WideLowCategories);
   1455                 return;
   1456             case SHL_LONG_2ADDR:
   1457             case SHR_LONG_2ADDR:
   1458             case USHR_LONG_2ADDR:
   1459                 verifyBinary2AddrOp(analyzedInstruction, WideLowCategories, Primitive32BitCategories);
   1460                 return;
   1461             case ADD_FLOAT_2ADDR:
   1462             case SUB_FLOAT_2ADDR:
   1463             case MUL_FLOAT_2ADDR:
   1464             case DIV_FLOAT_2ADDR:
   1465             case REM_FLOAT_2ADDR:
   1466                 verifyBinary2AddrOp(analyzedInstruction, Primitive32BitCategories, Primitive32BitCategories);
   1467                 return;
   1468             case ADD_DOUBLE_2ADDR:
   1469             case SUB_DOUBLE_2ADDR:
   1470             case MUL_DOUBLE_2ADDR:
   1471             case DIV_DOUBLE_2ADDR:
   1472             case REM_DOUBLE_2ADDR:
   1473                 verifyBinary2AddrOp(analyzedInstruction, WideLowCategories, WideLowCategories);
   1474                 return;
   1475             case ADD_INT_LIT16:
   1476             case RSUB_INT:
   1477             case MUL_INT_LIT16:
   1478             case DIV_INT_LIT16:
   1479             case REM_INT_LIT16:
   1480                 verifyLiteralBinaryOp(analyzedInstruction);
   1481                 return;
   1482             case AND_INT_LIT16:
   1483             case OR_INT_LIT16:
   1484             case XOR_INT_LIT16:
   1485                 verifyLiteralBinaryOp(analyzedInstruction);
   1486                 return;
   1487             case ADD_INT_LIT8:
   1488             case RSUB_INT_LIT8:
   1489             case MUL_INT_LIT8:
   1490             case DIV_INT_LIT8:
   1491             case REM_INT_LIT8:
   1492             case SHL_INT_LIT8:
   1493                 verifyLiteralBinaryOp(analyzedInstruction);
   1494                 return;
   1495             case AND_INT_LIT8:
   1496             case OR_INT_LIT8:
   1497             case XOR_INT_LIT8:
   1498                 verifyLiteralBinaryOp(analyzedInstruction);
   1499                 return;
   1500             case SHR_INT_LIT8:
   1501                 verifyLiteralBinaryOp(analyzedInstruction);
   1502                 return;
   1503             case USHR_INT_LIT8:
   1504                 verifyLiteralBinaryOp(analyzedInstruction);
   1505                 return;
   1506             case IGET_VOLATILE:
   1507             case IPUT_VOLATILE:
   1508             case SGET_VOLATILE:
   1509             case SPUT_VOLATILE:
   1510             case IGET_OBJECT_VOLATILE:
   1511             case IGET_WIDE_VOLATILE:
   1512             case IPUT_WIDE_VOLATILE:
   1513             case SGET_WIDE_VOLATILE:
   1514             case SPUT_WIDE_VOLATILE:
   1515             case EXECUTE_INLINE:
   1516             case EXECUTE_INLINE_RANGE:
   1517             case INVOKE_DIRECT_EMPTY:
   1518             case IGET_QUICK:
   1519             case IGET_WIDE_QUICK:
   1520             case IGET_OBJECT_QUICK:
   1521             case IPUT_QUICK:
   1522             case IPUT_WIDE_QUICK:
   1523             case IPUT_OBJECT_QUICK:
   1524             case INVOKE_VIRTUAL_QUICK:
   1525             case INVOKE_SUPER_QUICK:
   1526             case INVOKE_VIRTUAL_QUICK_RANGE:
   1527             case INVOKE_SUPER_QUICK_RANGE:
   1528             case IPUT_OBJECT_VOLATILE:
   1529             case SGET_OBJECT_VOLATILE:
   1530             case SPUT_OBJECT_VOLATILE:
   1531                 //TODO: throw validation exception?
   1532             default:
   1533                 assert false;
   1534                 return;
   1535         }
   1536     }
   1537 
   1538     private static final EnumSet<RegisterType.Category> Primitive32BitCategories = EnumSet.of(
   1539             RegisterType.Category.Null,
   1540             RegisterType.Category.One,
   1541             RegisterType.Category.Boolean,
   1542             RegisterType.Category.Byte,
   1543             RegisterType.Category.PosByte,
   1544             RegisterType.Category.Short,
   1545             RegisterType.Category.PosShort,
   1546             RegisterType.Category.Char,
   1547             RegisterType.Category.Integer,
   1548             RegisterType.Category.Float);
   1549 
   1550     private static final EnumSet<RegisterType.Category> WideLowCategories = EnumSet.of(
   1551             RegisterType.Category.LongLo,
   1552             RegisterType.Category.DoubleLo);
   1553 
   1554     private static final EnumSet<RegisterType.Category> WideHighCategories = EnumSet.of(
   1555             RegisterType.Category.LongHi,
   1556             RegisterType.Category.DoubleHi);
   1557 
   1558     private static final EnumSet<RegisterType.Category> ReferenceCategories = EnumSet.of(
   1559             RegisterType.Category.Null,
   1560             RegisterType.Category.Reference);
   1561 
   1562     private static final EnumSet<RegisterType.Category> ReferenceOrUninitThisCategories = EnumSet.of(
   1563             RegisterType.Category.Null,
   1564             RegisterType.Category.UninitThis,
   1565             RegisterType.Category.Reference);
   1566 
   1567     private static final EnumSet<RegisterType.Category> ReferenceOrUninitCategories = EnumSet.of(
   1568             RegisterType.Category.Null,
   1569             RegisterType.Category.UninitRef,
   1570             RegisterType.Category.UninitThis,
   1571             RegisterType.Category.Reference);
   1572 
   1573     private static final EnumSet<RegisterType.Category> ReferenceAndPrimitive32BitCategories = EnumSet.of(
   1574             RegisterType.Category.Null,
   1575             RegisterType.Category.One,
   1576             RegisterType.Category.Boolean,
   1577             RegisterType.Category.Byte,
   1578             RegisterType.Category.PosByte,
   1579             RegisterType.Category.Short,
   1580             RegisterType.Category.PosShort,
   1581             RegisterType.Category.Char,
   1582             RegisterType.Category.Integer,
   1583             RegisterType.Category.Float,
   1584             RegisterType.Category.Reference);
   1585 
   1586     private static final EnumSet<RegisterType.Category> BooleanCategories = EnumSet.of(
   1587             RegisterType.Category.Null,
   1588             RegisterType.Category.One,
   1589             RegisterType.Category.Boolean);
   1590 
   1591     private void analyzeMove(AnalyzedInstruction analyzedInstruction) {
   1592         TwoRegisterInstruction instruction = (TwoRegisterInstruction)analyzedInstruction.instruction;
   1593 
   1594         RegisterType sourceRegisterType = analyzedInstruction.getPreInstructionRegisterType(instruction.getRegisterB());
   1595         setDestinationRegisterTypeAndPropagateChanges(analyzedInstruction, sourceRegisterType);
   1596     }
   1597 
   1598     private void verifyMove(AnalyzedInstruction analyzedInstruction, EnumSet validCategories) {
   1599         TwoRegisterInstruction instruction = (TwoRegisterInstruction)analyzedInstruction.instruction;
   1600 
   1601         getAndCheckSourceRegister(analyzedInstruction, instruction.getRegisterB(), validCategories);
   1602     }
   1603 
   1604     private void analyzeMoveResult(AnalyzedInstruction analyzedInstruction) {
   1605         AnalyzedInstruction previousInstruction = instructions.valueAt(analyzedInstruction.instructionIndex-1);
   1606         if (!previousInstruction.instruction.opcode.setsResult()) {
   1607             throw new ValidationException(analyzedInstruction.instruction.opcode.name + " must occur after an " +
   1608                     "invoke-*/fill-new-array instruction");
   1609         }
   1610 
   1611         RegisterType resultRegisterType;
   1612         InstructionWithReference invokeInstruction = (InstructionWithReference)previousInstruction.instruction;
   1613         Item item = invokeInstruction.getReferencedItem();
   1614 
   1615         if (item.getItemType() == ItemType.TYPE_METHOD_ID_ITEM) {
   1616             resultRegisterType = RegisterType.getRegisterTypeForTypeIdItem(
   1617                     ((MethodIdItem)item).getPrototype().getReturnType());
   1618         } else {
   1619             assert item.getItemType() == ItemType.TYPE_TYPE_ID_ITEM;
   1620             resultRegisterType = RegisterType.getRegisterTypeForTypeIdItem((TypeIdItem)item);
   1621         }
   1622 
   1623         setDestinationRegisterTypeAndPropagateChanges(analyzedInstruction, resultRegisterType);
   1624     }
   1625 
   1626     private void verifyMoveResult(AnalyzedInstruction analyzedInstruction,
   1627                                      EnumSet<RegisterType.Category> allowedCategories) {
   1628         if (analyzedInstruction.instructionIndex == 0) {
   1629             throw new ValidationException(analyzedInstruction.instruction.opcode.name + " cannot be the first " +
   1630                     "instruction in a method. It must occur after an invoke-*/fill-new-array instruction");
   1631         }
   1632 
   1633         AnalyzedInstruction previousInstruction = instructions.valueAt(analyzedInstruction.instructionIndex-1);
   1634 
   1635         if (!previousInstruction.instruction.opcode.setsResult()) {
   1636             throw new ValidationException(analyzedInstruction.instruction.opcode.name + " must occur after an " +
   1637                     "invoke-*/fill-new-array instruction");
   1638         }
   1639 
   1640         //TODO: does dalvik allow a move-result after an invoke with a void return type?
   1641         RegisterType resultRegisterType;
   1642 
   1643         InstructionWithReference invokeInstruction = (InstructionWithReference)previousInstruction.getInstruction();
   1644         Item item = invokeInstruction.getReferencedItem();
   1645 
   1646         if (item instanceof MethodIdItem) {
   1647             resultRegisterType = RegisterType.getRegisterTypeForTypeIdItem(
   1648                     ((MethodIdItem)item).getPrototype().getReturnType());
   1649         } else {
   1650             assert item instanceof TypeIdItem;
   1651             resultRegisterType = RegisterType.getRegisterTypeForTypeIdItem((TypeIdItem)item);
   1652         }
   1653 
   1654         if (!allowedCategories.contains(resultRegisterType.category)) {
   1655             throw new ValidationException(String.format("Wrong move-result* instruction for return value %s",
   1656                     resultRegisterType.toString()));
   1657         }
   1658     }
   1659 
   1660     private void analyzeMoveException(AnalyzedInstruction analyzedInstruction) {
   1661         CodeItem.TryItem[] tries = encodedMethod.codeItem.getTries();
   1662         int instructionAddress = getInstructionAddress(analyzedInstruction);
   1663 
   1664         if (tries == null) {
   1665             throw new ValidationException("move-exception must be the first instruction in an exception handler block");
   1666         }
   1667 
   1668         RegisterType exceptionType = null;
   1669 
   1670         for (CodeItem.TryItem tryItem: encodedMethod.codeItem.getTries()) {
   1671             if (tryItem.encodedCatchHandler.getCatchAllHandlerAddress() == instructionAddress) {
   1672                 exceptionType = RegisterType.getRegisterType(RegisterType.Category.Reference,
   1673                         ClassPath.getClassDef("Ljava/lang/Throwable;"));
   1674                 break;
   1675             }
   1676             for (CodeItem.EncodedTypeAddrPair handler: tryItem.encodedCatchHandler.handlers) {
   1677                 if (handler.getHandlerAddress() == instructionAddress) {
   1678                     exceptionType = RegisterType.getRegisterTypeForTypeIdItem(handler.exceptionType)
   1679                             .merge(exceptionType);
   1680                 }
   1681             }
   1682         }
   1683 
   1684         if (exceptionType == null) {
   1685             throw new ValidationException("move-exception must be the first instruction in an exception handler block");
   1686         }
   1687 
   1688         setDestinationRegisterTypeAndPropagateChanges(analyzedInstruction, exceptionType);
   1689     }
   1690 
   1691     private void verifyMoveException(AnalyzedInstruction analyzedInstruction) {
   1692         CodeItem.TryItem[] tries = encodedMethod.codeItem.getTries();
   1693         int instructionAddress = getInstructionAddress(analyzedInstruction);
   1694 
   1695         if (tries == null) {
   1696             throw new ValidationException("move-exception must be the first instruction in an exception handler block");
   1697         }
   1698 
   1699         RegisterType exceptionType = null;
   1700 
   1701         for (CodeItem.TryItem tryItem: encodedMethod.codeItem.getTries()) {
   1702             if (tryItem.encodedCatchHandler.getCatchAllHandlerAddress() == instructionAddress) {
   1703                 exceptionType = RegisterType.getRegisterType(RegisterType.Category.Reference,
   1704                         ClassPath.getClassDef("Ljava/lang/Throwable;"));
   1705                 break;
   1706             }
   1707             for (CodeItem.EncodedTypeAddrPair handler: tryItem.encodedCatchHandler.handlers) {
   1708                 if (handler.getHandlerAddress() == instructionAddress) {
   1709                     exceptionType = RegisterType.getRegisterTypeForTypeIdItem(handler.exceptionType)
   1710                             .merge(exceptionType);
   1711                 }
   1712             }
   1713         }
   1714 
   1715         if (exceptionType == null) {
   1716             throw new ValidationException("move-exception must be the first instruction in an exception handler block");
   1717         }
   1718 
   1719         //TODO: check if the type is a throwable. Should we throw a ValidationException or print a warning? (does dalvik validate that it's a throwable? It doesn't in CodeVerify.c, but it might check in DexSwapVerify.c)
   1720         if (exceptionType.category != RegisterType.Category.Reference) {
   1721             throw new ValidationException(String.format("Exception type %s is not a reference type",
   1722                     exceptionType.toString()));
   1723         }
   1724     }
   1725 
   1726     private void verifyReturnVoid(AnalyzedInstruction analyzedInstruction) {
   1727         TypeIdItem returnType = encodedMethod.method.getPrototype().getReturnType();
   1728         if (returnType.getTypeDescriptor().charAt(0) != 'V') {
   1729             //TODO: could add which return-* variation should be used instead
   1730             throw new ValidationException("Cannot use return-void with a non-void return type (" +
   1731                 returnType.getTypeDescriptor() + ")");
   1732         }
   1733     }
   1734 
   1735     private void verifyReturn(AnalyzedInstruction analyzedInstruction, EnumSet validCategories) {
   1736         /*if (this.isInstanceConstructor()) {
   1737             checkConstructorReturn(analyzedInstruction);
   1738         }*/
   1739 
   1740         SingleRegisterInstruction instruction = (SingleRegisterInstruction)analyzedInstruction.instruction;
   1741         int returnRegister = instruction.getRegisterA();
   1742         RegisterType returnRegisterType = getAndCheckSourceRegister(analyzedInstruction, returnRegister,
   1743                 validCategories);
   1744 
   1745         TypeIdItem returnType = encodedMethod.method.getPrototype().getReturnType();
   1746         if (returnType.getTypeDescriptor().charAt(0) == 'V') {
   1747             throw new ValidationException("Cannot use return with a void return type. Use return-void instead");
   1748         }
   1749 
   1750         RegisterType methodReturnRegisterType = RegisterType.getRegisterTypeForTypeIdItem(returnType);
   1751 
   1752         if (!validCategories.contains(methodReturnRegisterType.category)) {
   1753             //TODO: could add which return-* variation should be used instead
   1754             throw new ValidationException(String.format("Cannot use %s with return type %s",
   1755                     analyzedInstruction.instruction.opcode.name, returnType.getTypeDescriptor()));
   1756         }
   1757 
   1758         if (validCategories == ReferenceCategories) {
   1759             if (methodReturnRegisterType.type.isInterface()) {
   1760                 if (returnRegisterType.category != RegisterType.Category.Null &&
   1761                     !returnRegisterType.type.implementsInterface(methodReturnRegisterType.type)) {
   1762                     //TODO: how to handle warnings?
   1763                 }
   1764             } else {
   1765                 if (returnRegisterType.category == RegisterType.Category.Reference &&
   1766                     !returnRegisterType.type.extendsClass(methodReturnRegisterType.type)) {
   1767 
   1768                     throw new ValidationException(String.format("The return value in register v%d (%s) is not " +
   1769                             "compatible with the method's return type %s", returnRegister,
   1770                             returnRegisterType.type.getClassType(), methodReturnRegisterType.type.getClassType()));
   1771                 }
   1772             }
   1773         }
   1774     }
   1775 
   1776     private void analyzeConst(AnalyzedInstruction analyzedInstruction) {
   1777         LiteralInstruction instruction = (LiteralInstruction)analyzedInstruction.instruction;
   1778 
   1779         RegisterType newDestinationRegisterType = RegisterType.getRegisterTypeForLiteral(instruction.getLiteral());
   1780 
   1781         //we assume that the literal value is a valid value for the given instruction type, because it's impossible
   1782         //to store an invalid literal with the instruction. so we don't need to check the type of the literal
   1783         setDestinationRegisterTypeAndPropagateChanges(analyzedInstruction, newDestinationRegisterType);
   1784     }
   1785 
   1786     private void analyzeConstHigh16(AnalyzedInstruction analyzedInstruction) {
   1787         //the literal value stored in the instruction is a 16-bit value. When shifted left by 16, it will always be an
   1788         //integer
   1789         setDestinationRegisterTypeAndPropagateChanges(analyzedInstruction,
   1790                 RegisterType.getRegisterType(RegisterType.Category.Integer, null));
   1791     }
   1792 
   1793     private void analyzeWideConst(AnalyzedInstruction analyzedInstruction) {
   1794         setDestinationRegisterTypeAndPropagateChanges(analyzedInstruction,
   1795                 RegisterType.getRegisterType(RegisterType.Category.LongLo, null));
   1796     }
   1797 
   1798     private void analyzeConstString(AnalyzedInstruction analyzedInstruction) {
   1799         ClassPath.ClassDef stringClassDef = ClassPath.getClassDef("Ljava/lang/String;");
   1800         RegisterType stringType = RegisterType.getRegisterType(RegisterType.Category.Reference, stringClassDef);
   1801         setDestinationRegisterTypeAndPropagateChanges(analyzedInstruction, stringType);
   1802     }
   1803 
   1804     private void analyzeConstClass(AnalyzedInstruction analyzedInstruction) {
   1805         ClassPath.ClassDef classClassDef = ClassPath.getClassDef("Ljava/lang/Class;");
   1806         RegisterType classType = RegisterType.getRegisterType(RegisterType.Category.Reference, classClassDef);
   1807 
   1808         setDestinationRegisterTypeAndPropagateChanges(analyzedInstruction, classType);
   1809     }
   1810 
   1811 
   1812     private void verifyConstClass(AnalyzedInstruction analyzedInstruction) {
   1813         ClassPath.ClassDef classClassDef = ClassPath.getClassDef("Ljava/lang/Class;");
   1814         RegisterType classType = RegisterType.getRegisterType(RegisterType.Category.Reference, classClassDef);
   1815 
   1816         InstructionWithReference instruction = (InstructionWithReference)analyzedInstruction.instruction;
   1817         Item item = instruction.getReferencedItem();
   1818         assert item.getItemType() == ItemType.TYPE_TYPE_ID_ITEM;
   1819 
   1820         //TODO: need to check class access
   1821         //make sure the referenced class is resolvable
   1822         ClassPath.getClassDef((TypeIdItem)item);
   1823     }
   1824 
   1825     private void verifyMonitor(AnalyzedInstruction analyzedInstruction) {
   1826         SingleRegisterInstruction instruction = (SingleRegisterInstruction)analyzedInstruction.instruction;
   1827         getAndCheckSourceRegister(analyzedInstruction, instruction.getRegisterA(), ReferenceCategories);
   1828     }
   1829 
   1830     private void analyzeCheckCast(AnalyzedInstruction analyzedInstruction) {
   1831         InstructionWithReference instruction = (InstructionWithReference)analyzedInstruction.instruction;
   1832 
   1833         Item item = instruction.getReferencedItem();
   1834         assert item.getItemType() == ItemType.TYPE_TYPE_ID_ITEM;
   1835 
   1836         RegisterType castRegisterType = RegisterType.getRegisterTypeForTypeIdItem((TypeIdItem)item);
   1837         setDestinationRegisterTypeAndPropagateChanges(analyzedInstruction, castRegisterType);
   1838     }
   1839 
   1840     private void verifyCheckCast(AnalyzedInstruction analyzedInstruction) {
   1841         {
   1842             //ensure the "source" register is a reference type
   1843             SingleRegisterInstruction instruction = (SingleRegisterInstruction)analyzedInstruction.instruction;
   1844 
   1845             RegisterType registerType = getAndCheckSourceRegister(analyzedInstruction, instruction.getRegisterA(),
   1846                     ReferenceCategories);
   1847         }
   1848 
   1849         {
   1850             //resolve and verify the class that we're casting to
   1851             InstructionWithReference instruction = (InstructionWithReference)analyzedInstruction.instruction;
   1852 
   1853             Item item = instruction.getReferencedItem();
   1854             assert item.getItemType() == ItemType.TYPE_TYPE_ID_ITEM;
   1855 
   1856             //TODO: need to check class access
   1857             RegisterType castRegisterType = RegisterType.getRegisterTypeForTypeIdItem((TypeIdItem)item);
   1858             if (castRegisterType.category != RegisterType.Category.Reference) {
   1859                 //TODO: verify that dalvik allows a non-reference type..
   1860                 //TODO: print a warning, but don't re-throw the exception. dalvik allows a non-reference type during validation (but throws an exception at runtime)
   1861             }
   1862         }
   1863     }
   1864 
   1865     private void analyzeInstanceOf(AnalyzedInstruction analyzedInstruction) {
   1866         setDestinationRegisterTypeAndPropagateChanges(analyzedInstruction,
   1867                 RegisterType.getRegisterType(RegisterType.Category.Boolean, null));
   1868     }
   1869 
   1870     private void verifyInstanceOf(AnalyzedInstruction analyzedInstruction) {
   1871         {
   1872             //ensure the register that is being checks is a reference type
   1873             TwoRegisterInstruction instruction = (TwoRegisterInstruction)analyzedInstruction.instruction;
   1874 
   1875             getAndCheckSourceRegister(analyzedInstruction, instruction.getRegisterB(), ReferenceCategories);
   1876         }
   1877 
   1878         {
   1879             //resolve and verify the class that we're checking against
   1880             InstructionWithReference instruction = (InstructionWithReference)analyzedInstruction.instruction;
   1881 
   1882             Item item = instruction.getReferencedItem();
   1883             assert  item.getItemType() == ItemType.TYPE_TYPE_ID_ITEM;
   1884             RegisterType registerType = RegisterType.getRegisterTypeForTypeIdItem((TypeIdItem)item);
   1885             if (registerType.category != RegisterType.Category.Reference) {
   1886                 throw new ValidationException(String.format("Cannot use instance-of with a non-reference type %s",
   1887                         registerType.toString()));
   1888             }
   1889 
   1890             //TODO: is it valid to use an array type?
   1891             //TODO: could probably do an even more sophisticated check, where we check the possible register types against the specified type. In some cases, we could determine that it always fails, and print a warning to that effect.
   1892         }
   1893     }
   1894 
   1895     private void analyzeArrayLength(AnalyzedInstruction analyzedInstruction) {
   1896         setDestinationRegisterTypeAndPropagateChanges(analyzedInstruction,
   1897                 RegisterType.getRegisterType(RegisterType.Category.Integer, null));
   1898     }
   1899 
   1900     private void verifyArrayLength(AnalyzedInstruction analyzedInstruction) {
   1901         TwoRegisterInstruction instruction = (TwoRegisterInstruction)analyzedInstruction.instruction;
   1902 
   1903         int arrayRegisterNumber = instruction.getRegisterB();
   1904         RegisterType arrayRegisterType = getAndCheckSourceRegister(analyzedInstruction, arrayRegisterNumber,
   1905                 ReferenceCategories);
   1906 
   1907         if (arrayRegisterType.type != null) {
   1908             if (arrayRegisterType.type.getClassType().charAt(0) != '[') {
   1909                 throw new ValidationException(String.format("Cannot use array-length with non-array type %s",
   1910                         arrayRegisterType.type.getClassType()));
   1911             }
   1912             assert arrayRegisterType.type instanceof ClassPath.ArrayClassDef;
   1913         }
   1914     }
   1915 
   1916     private void analyzeNewInstance(AnalyzedInstruction analyzedInstruction) {
   1917         InstructionWithReference instruction = (InstructionWithReference)analyzedInstruction.instruction;
   1918 
   1919         int register = ((SingleRegisterInstruction)analyzedInstruction.instruction).getRegisterA();
   1920         RegisterType destRegisterType = analyzedInstruction.getPostInstructionRegisterType(register);
   1921         if (destRegisterType.category != RegisterType.Category.Unknown) {
   1922             assert destRegisterType.category == RegisterType.Category.UninitRef;
   1923 
   1924             //the post-instruction destination register will only be set if we have already analyzed this instruction
   1925             //at least once. If this is the case, then the uninit reference has already been propagated to all
   1926             //successors and nothing else needs to be done.
   1927             return;
   1928         }
   1929 
   1930         Item item = instruction.getReferencedItem();
   1931         assert item.getItemType() == ItemType.TYPE_TYPE_ID_ITEM;
   1932 
   1933         RegisterType classType = RegisterType.getRegisterTypeForTypeIdItem((TypeIdItem)item);
   1934 
   1935         setDestinationRegisterTypeAndPropagateChanges(analyzedInstruction,
   1936                 RegisterType.getUnitializedReference(classType.type));
   1937     }
   1938 
   1939     private void verifyNewInstance(AnalyzedInstruction analyzedInstruction) {
   1940         InstructionWithReference instruction = (InstructionWithReference)analyzedInstruction.instruction;
   1941 
   1942         int register = ((SingleRegisterInstruction)analyzedInstruction.instruction).getRegisterA();
   1943         RegisterType destRegisterType = analyzedInstruction.postRegisterMap[register];
   1944         if (destRegisterType.category != RegisterType.Category.Unknown) {
   1945             assert destRegisterType.category == RegisterType.Category.UninitRef;
   1946 
   1947             //the "post-instruction" destination register will only be set if we've gone over
   1948             //this instruction at least once before. If this is the case, then we need to check
   1949             //all the other registers, and make sure that none of them contain the same
   1950             //uninitialized reference that is in the destination register.
   1951 
   1952             for (int i=0; i<analyzedInstruction.postRegisterMap.length; i++) {
   1953                 if (i==register) {
   1954                     continue;
   1955                 }
   1956 
   1957                 if (analyzedInstruction.getPreInstructionRegisterType(i) == destRegisterType) {
   1958                     throw new ValidationException(String.format("Register v%d contains an uninitialized reference " +
   1959                             "that was created by this new-instance instruction.", i));
   1960                 }
   1961             }
   1962 
   1963             return;
   1964         }
   1965 
   1966         Item item = instruction.getReferencedItem();
   1967         assert item.getItemType() == ItemType.TYPE_TYPE_ID_ITEM;
   1968 
   1969         //TODO: need to check class access
   1970         RegisterType classType = RegisterType.getRegisterTypeForTypeIdItem((TypeIdItem)item);
   1971         if (classType.category != RegisterType.Category.Reference) {
   1972             throw new ValidationException(String.format("Cannot use new-instance with a non-reference type %s",
   1973                     classType.toString()));
   1974         }
   1975 
   1976         if (((TypeIdItem)item).getTypeDescriptor().charAt(0) == '[') {
   1977             throw new ValidationException("Cannot use array type \"" + ((TypeIdItem)item).getTypeDescriptor() +
   1978                     "\" with new-instance. Use new-array instead.");
   1979         }
   1980     }
   1981 
   1982     private void analyzeNewArray(AnalyzedInstruction analyzedInstruction) {
   1983         InstructionWithReference instruction = (InstructionWithReference)analyzedInstruction.instruction;
   1984 
   1985         Item item = instruction.getReferencedItem();
   1986         assert item.getItemType() == ItemType.TYPE_TYPE_ID_ITEM;
   1987 
   1988         RegisterType arrayType = RegisterType.getRegisterTypeForTypeIdItem((TypeIdItem)item);
   1989         assert arrayType.type instanceof ClassPath.ArrayClassDef;
   1990 
   1991         setDestinationRegisterTypeAndPropagateChanges(analyzedInstruction, arrayType);
   1992     }
   1993 
   1994     private void verifyNewArray(AnalyzedInstruction analyzedInstruction) {
   1995         {
   1996             TwoRegisterInstruction instruction = (TwoRegisterInstruction)analyzedInstruction.instruction;
   1997             getAndCheckSourceRegister(analyzedInstruction, instruction.getRegisterB(), Primitive32BitCategories);
   1998         }
   1999 
   2000         InstructionWithReference instruction = (InstructionWithReference)analyzedInstruction.instruction;
   2001 
   2002         Item item = instruction.getReferencedItem();
   2003         assert item.getItemType() == ItemType.TYPE_TYPE_ID_ITEM;
   2004 
   2005         RegisterType arrayType = RegisterType.getRegisterTypeForTypeIdItem((TypeIdItem)item);
   2006         assert arrayType.type instanceof ClassPath.ArrayClassDef;
   2007 
   2008         if (arrayType.category != RegisterType.Category.Reference) {
   2009             throw new ValidationException(String.format("Cannot use new-array with a non-reference type %s",
   2010                     arrayType.toString()));
   2011         }
   2012         if (arrayType.type.getClassType().charAt(0) != '[') {
   2013             throw new ValidationException("Cannot use non-array type \"" + arrayType.type.getClassType() +
   2014                     "\" with new-array. Use new-instance instead.");
   2015         }
   2016     }
   2017 
   2018     private void verifyFilledNewArrayCommon(AnalyzedInstruction analyzedInstruction,
   2019                                                RegisterIterator registerIterator) {
   2020         InstructionWithReference instruction = (InstructionWithReference)analyzedInstruction.instruction;
   2021 
   2022         RegisterType arrayType;
   2023         RegisterType arrayImmediateElementType;
   2024 
   2025         Item item = instruction.getReferencedItem();
   2026         assert  item.getItemType() == ItemType.TYPE_TYPE_ID_ITEM;
   2027 
   2028         ClassPath.ClassDef classDef = ClassPath.getClassDef((TypeIdItem)item);
   2029 
   2030         if (classDef.getClassType().charAt(0) != '[') {
   2031             throw new ValidationException("Cannot use non-array type \"" + classDef.getClassType() +
   2032                 "\" with new-array. Use new-instance instead.");
   2033         }
   2034 
   2035         ClassPath.ArrayClassDef arrayClassDef = (ClassPath.ArrayClassDef)classDef;
   2036         arrayType = RegisterType.getRegisterType(RegisterType.Category.Reference, classDef);
   2037         arrayImmediateElementType = RegisterType.getRegisterTypeForType(
   2038                 arrayClassDef.getImmediateElementClass().getClassType());
   2039         String baseElementType = arrayClassDef.getBaseElementClass().getClassType();
   2040         if (baseElementType.charAt(0) == 'J' || baseElementType.charAt(0) == 'D') {
   2041             throw new ValidationException("Cannot use filled-new-array to create an array of wide values " +
   2042                     "(long or double)");
   2043         }
   2044 
   2045         do {
   2046             int register = registerIterator.getRegister();
   2047             RegisterType elementType = analyzedInstruction.getPreInstructionRegisterType(register);
   2048             assert elementType != null;
   2049 
   2050             if (!elementType.canBeAssignedTo(arrayImmediateElementType)) {
   2051                 throw new ValidationException("Register v" + Integer.toString(register) + " is of type " +
   2052                         elementType.toString() + " and is incompatible with the array type " +
   2053                         arrayType.type.getClassType());
   2054             }
   2055         } while (registerIterator.moveNext());
   2056     }
   2057 
   2058     private void verifyFilledNewArray(AnalyzedInstruction analyzedInstruction) {
   2059         FiveRegisterInstruction instruction = (FiveRegisterInstruction)analyzedInstruction.instruction;
   2060         verifyFilledNewArrayCommon(analyzedInstruction, new Format35cRegisterIterator(instruction));
   2061     }
   2062 
   2063     private void verifyFilledNewArrayRange(AnalyzedInstruction analyzedInstruction) {
   2064         RegisterRangeInstruction instruction = (RegisterRangeInstruction)analyzedInstruction.instruction;
   2065 
   2066         //instruction.getStartRegister() and instruction.getRegCount() both return an int value, but are actually
   2067         //unsigned 16 bit values, so we don't have to worry about overflowing an int when adding them together
   2068         if (instruction.getStartRegister() + instruction.getRegCount() >= 1<<16) {
   2069             throw new ValidationException(String.format("Invalid register range {v%d .. v%d}. The ending register " +
   2070                     "is larger than the largest allowed register of v65535.",
   2071                     instruction.getStartRegister(),
   2072                     instruction.getStartRegister() + instruction.getRegCount() - 1));
   2073         }
   2074 
   2075         verifyFilledNewArrayCommon(analyzedInstruction, new Format3rcRegisterIterator(instruction));
   2076     }
   2077 
   2078     private void verifyFillArrayData(AnalyzedInstruction analyzedInstruction) {
   2079         SingleRegisterInstruction instruction = (SingleRegisterInstruction)analyzedInstruction.instruction;
   2080 
   2081         int register = instruction.getRegisterA();
   2082         RegisterType registerType = analyzedInstruction.getPreInstructionRegisterType(register);
   2083         assert registerType != null;
   2084 
   2085         if (registerType.category == RegisterType.Category.Null) {
   2086             return;
   2087         }
   2088 
   2089         if (registerType.category != RegisterType.Category.Reference) {
   2090             throw new ValidationException(String.format("Cannot use fill-array-data with non-array register v%d of " +
   2091                     "type %s", register, registerType.toString()));
   2092         }
   2093 
   2094         assert registerType.type instanceof ClassPath.ArrayClassDef;
   2095         ClassPath.ArrayClassDef arrayClassDef = (ClassPath.ArrayClassDef)registerType.type;
   2096 
   2097         if (arrayClassDef.getArrayDimensions() != 1) {
   2098             throw new ValidationException(String.format("Cannot use fill-array-data with array type %s. It can only " +
   2099                     "be used with a one-dimensional array of primitives.", arrayClassDef.getClassType()));
   2100         }
   2101 
   2102         int elementWidth;
   2103         switch (arrayClassDef.getBaseElementClass().getClassType().charAt(0)) {
   2104             case 'Z':
   2105             case 'B':
   2106                 elementWidth = 1;
   2107                 break;
   2108             case 'C':
   2109             case 'S':
   2110                 elementWidth = 2;
   2111                 break;
   2112             case 'I':
   2113             case 'F':
   2114                 elementWidth = 4;
   2115                 break;
   2116             case 'J':
   2117             case 'D':
   2118                 elementWidth = 8;
   2119                 break;
   2120             default:
   2121                 throw new ValidationException(String.format("Cannot use fill-array-data with array type %s. It can " +
   2122                         "only be used with a one-dimensional array of primitives.", arrayClassDef.getClassType()));
   2123         }
   2124 
   2125 
   2126         int arrayDataAddressOffset = ((OffsetInstruction)analyzedInstruction.instruction).getTargetAddressOffset();
   2127         int arrayDataCodeAddress = getInstructionAddress(analyzedInstruction) + arrayDataAddressOffset;
   2128         AnalyzedInstruction arrayDataInstruction = this.instructions.get(arrayDataCodeAddress);
   2129         if (arrayDataInstruction == null || arrayDataInstruction.instruction.getFormat() != Format.ArrayData) {
   2130             throw new ValidationException(String.format("Could not find an array data structure at code address 0x%x",
   2131                     arrayDataCodeAddress));
   2132         }
   2133 
   2134         ArrayDataPseudoInstruction arrayDataPseudoInstruction =
   2135                 (ArrayDataPseudoInstruction)arrayDataInstruction.instruction;
   2136 
   2137         if (elementWidth != arrayDataPseudoInstruction.getElementWidth()) {
   2138             throw new ValidationException(String.format("The array data at code address 0x%x does not have the " +
   2139                     "correct element width for array type %s. Expecting element width %d, got element width %d.",
   2140                     arrayDataCodeAddress, arrayClassDef.getClassType(), elementWidth,
   2141                     arrayDataPseudoInstruction.getElementWidth()));
   2142         }
   2143     }
   2144 
   2145     private void verifyThrow(AnalyzedInstruction analyzedInstruction) {
   2146         int register = ((SingleRegisterInstruction)analyzedInstruction.instruction).getRegisterA();
   2147 
   2148         RegisterType registerType = analyzedInstruction.getPreInstructionRegisterType(register);
   2149         assert registerType != null;
   2150 
   2151         if (registerType.category == RegisterType.Category.Null) {
   2152             return;
   2153         }
   2154 
   2155         if (registerType.category != RegisterType.Category.Reference) {
   2156             throw new ValidationException(String.format("Cannot use throw with non-reference type %s in register v%d",
   2157                     registerType.toString(), register));
   2158         }
   2159 
   2160         assert registerType.type != null;
   2161 
   2162         if (!registerType.type.extendsClass(ClassPath.getClassDef("Ljava/lang/Throwable;"))) {
   2163             throw new ValidationException(String.format("Cannot use throw with non-throwable type %s in register v%d",
   2164                     registerType.type.getClassType(), register));
   2165         }
   2166     }
   2167 
   2168     private void analyzeArrayDataOrSwitch(AnalyzedInstruction analyzedInstruction) {
   2169         int dataAddressOffset = ((OffsetInstruction)analyzedInstruction.instruction).getTargetAddressOffset();
   2170 
   2171         int dataCodeAddress = this.getInstructionAddress(analyzedInstruction) + dataAddressOffset;
   2172         AnalyzedInstruction dataAnalyzedInstruction = instructions.get(dataCodeAddress);
   2173 
   2174         if (dataAnalyzedInstruction != null) {
   2175             dataAnalyzedInstruction.dead = false;
   2176 
   2177             //if there is a preceding nop, it's deadness should be the same
   2178             AnalyzedInstruction priorInstruction =
   2179                     instructions.valueAt(dataAnalyzedInstruction.getInstructionIndex()-1);
   2180             if (priorInstruction.getInstruction().opcode == Opcode.NOP &&
   2181                     !priorInstruction.getInstruction().getFormat().variableSizeFormat) {
   2182 
   2183                 priorInstruction.dead = false;
   2184             }
   2185         }
   2186     }
   2187 
   2188     private void verifySwitch(AnalyzedInstruction analyzedInstruction, Format expectedSwitchDataFormat) {
   2189         int register = ((SingleRegisterInstruction)analyzedInstruction.instruction).getRegisterA();
   2190         int switchCodeAddressOffset = ((OffsetInstruction)analyzedInstruction.instruction).getTargetAddressOffset();
   2191 
   2192         getAndCheckSourceRegister(analyzedInstruction, register, Primitive32BitCategories);
   2193 
   2194         int switchDataCodeAddress = this.getInstructionAddress(analyzedInstruction) + switchCodeAddressOffset;
   2195         AnalyzedInstruction switchDataAnalyzedInstruction = instructions.get(switchDataCodeAddress);
   2196 
   2197         if (switchDataAnalyzedInstruction == null ||
   2198             switchDataAnalyzedInstruction.instruction.getFormat() != expectedSwitchDataFormat) {
   2199             throw new ValidationException(String.format("There is no %s structure at code address 0x%x",
   2200                     expectedSwitchDataFormat.name(), switchDataCodeAddress));
   2201         }
   2202     }
   2203 
   2204     private void analyzeFloatWideCmp(AnalyzedInstruction analyzedInstruction) {
   2205         setDestinationRegisterTypeAndPropagateChanges(analyzedInstruction,
   2206                 RegisterType.getRegisterType(RegisterType.Category.Byte, null));
   2207     }
   2208 
   2209     private void verifyFloatWideCmp(AnalyzedInstruction analyzedInstruction, EnumSet validCategories) {
   2210         ThreeRegisterInstruction instruction = (ThreeRegisterInstruction)analyzedInstruction.instruction;
   2211 
   2212         getAndCheckSourceRegister(analyzedInstruction, instruction.getRegisterB(), validCategories);
   2213         getAndCheckSourceRegister(analyzedInstruction, instruction.getRegisterC(), validCategories);
   2214     }
   2215 
   2216     private void verifyIfEqNe(AnalyzedInstruction analyzedInstruction) {
   2217         TwoRegisterInstruction instruction = (TwoRegisterInstruction)analyzedInstruction.instruction;
   2218 
   2219         RegisterType registerType1 = analyzedInstruction.getPreInstructionRegisterType(instruction.getRegisterA());
   2220         assert registerType1 != null;
   2221 
   2222         RegisterType registerType2 = analyzedInstruction.getPreInstructionRegisterType(instruction.getRegisterB());
   2223         assert registerType2 != null;
   2224 
   2225         if (!(
   2226                 (ReferenceCategories.contains(registerType1.category) &&
   2227                 ReferenceCategories.contains(registerType2.category))
   2228                     ||
   2229                 (Primitive32BitCategories.contains(registerType1.category) &&
   2230                 Primitive32BitCategories.contains(registerType2.category))
   2231               )) {
   2232 
   2233             throw new ValidationException(String.format("%s cannot be used on registers of dissimilar types %s and " +
   2234                     "%s. They must both be a reference type or a primitive 32 bit type.",
   2235                     analyzedInstruction.instruction.opcode.name, registerType1.toString(), registerType2.toString()));
   2236         }
   2237     }
   2238 
   2239     private void verifyIf(AnalyzedInstruction analyzedInstruction) {
   2240         TwoRegisterInstruction instruction = (TwoRegisterInstruction)analyzedInstruction.instruction;
   2241 
   2242         getAndCheckSourceRegister(analyzedInstruction, instruction.getRegisterA(), Primitive32BitCategories);
   2243         getAndCheckSourceRegister(analyzedInstruction, instruction.getRegisterB(), Primitive32BitCategories);
   2244     }
   2245 
   2246     private void verifyIfEqzNez(AnalyzedInstruction analyzedInstruction) {
   2247         SingleRegisterInstruction instruction = (SingleRegisterInstruction)analyzedInstruction.instruction;
   2248 
   2249         getAndCheckSourceRegister(analyzedInstruction, instruction.getRegisterA(),
   2250                 ReferenceAndPrimitive32BitCategories);
   2251     }
   2252 
   2253     private void verifyIfz(AnalyzedInstruction analyzedInstruction) {
   2254         SingleRegisterInstruction instruction = (SingleRegisterInstruction)analyzedInstruction.instruction;
   2255 
   2256         getAndCheckSourceRegister(analyzedInstruction, instruction.getRegisterA(), Primitive32BitCategories);
   2257     }
   2258 
   2259     private void analyze32BitPrimitiveAget(AnalyzedInstruction analyzedInstruction,
   2260                                              RegisterType.Category instructionCategory) {
   2261         setDestinationRegisterTypeAndPropagateChanges(analyzedInstruction,
   2262                 RegisterType.getRegisterType(instructionCategory, null));
   2263     }
   2264 
   2265     private void verify32BitPrimitiveAget(AnalyzedInstruction analyzedInstruction,
   2266                                              RegisterType.Category instructionCategory) {
   2267         ThreeRegisterInstruction instruction = (ThreeRegisterInstruction)analyzedInstruction.instruction;
   2268 
   2269         getAndCheckSourceRegister(analyzedInstruction, instruction.getRegisterC(), Primitive32BitCategories);
   2270 
   2271         RegisterType arrayRegisterType = analyzedInstruction.getPreInstructionRegisterType(instruction.getRegisterB());
   2272         assert arrayRegisterType != null;
   2273 
   2274         if (arrayRegisterType.category != RegisterType.Category.Null) {
   2275             if (arrayRegisterType.category != RegisterType.Category.Reference) {
   2276                 throw new ValidationException(String.format("Cannot use %s with non-array type %s",
   2277                         analyzedInstruction.instruction.opcode.name, arrayRegisterType.category.toString()));
   2278             }
   2279 
   2280             assert arrayRegisterType.type != null;
   2281             if (arrayRegisterType.type.getClassType().charAt(0) != '[') {
   2282                 throw new ValidationException(String.format("Cannot use %s with non-array type %s",
   2283                         analyzedInstruction.instruction.opcode.name, arrayRegisterType.type.getClassType()));
   2284             }
   2285 
   2286             assert arrayRegisterType.type instanceof ClassPath.ArrayClassDef;
   2287             ClassPath.ArrayClassDef arrayClassDef = (ClassPath.ArrayClassDef)arrayRegisterType.type;
   2288 
   2289             if (arrayClassDef.getArrayDimensions() != 1) {
   2290                 throw new ValidationException(String.format("Cannot use %s with multi-dimensional array type %s",
   2291                         analyzedInstruction.instruction.opcode.name, arrayRegisterType.type.getClassType()));
   2292             }
   2293 
   2294             RegisterType arrayBaseType =
   2295                     RegisterType.getRegisterTypeForType(arrayClassDef.getBaseElementClass().getClassType());
   2296             if (!checkArrayFieldAssignment(arrayBaseType.category, instructionCategory)) {
   2297                 throw new ValidationException(String.format("Cannot use %s with array type %s. Incorrect array type " +
   2298                         "for the instruction.", analyzedInstruction.instruction.opcode.name,
   2299                         arrayRegisterType.type.getClassType()));
   2300             }
   2301         }
   2302     }
   2303 
   2304     private void analyzeAgetWide(AnalyzedInstruction analyzedInstruction) {
   2305         ThreeRegisterInstruction instruction = (ThreeRegisterInstruction)analyzedInstruction.instruction;
   2306 
   2307         RegisterType arrayRegisterType = analyzedInstruction.getPreInstructionRegisterType(instruction.getRegisterB());
   2308         assert arrayRegisterType != null;
   2309 
   2310         if (arrayRegisterType.category != RegisterType.Category.Null) {
   2311             assert arrayRegisterType.type != null;
   2312             if (arrayRegisterType.type.getClassType().charAt(0) != '[') {
   2313                 throw new ValidationException(String.format("Cannot use aget-wide with non-array type %s",
   2314                         arrayRegisterType.type.getClassType()));
   2315             }
   2316 
   2317             assert arrayRegisterType.type instanceof ClassPath.ArrayClassDef;
   2318             ClassPath.ArrayClassDef arrayClassDef = (ClassPath.ArrayClassDef)arrayRegisterType.type;
   2319 
   2320             char arrayBaseType = arrayClassDef.getBaseElementClass().getClassType().charAt(0);
   2321             if (arrayBaseType == 'J') {
   2322                 setDestinationRegisterTypeAndPropagateChanges(analyzedInstruction,
   2323                         RegisterType.getRegisterType(RegisterType.Category.LongLo, null));
   2324             } else if (arrayBaseType == 'D') {
   2325                 setDestinationRegisterTypeAndPropagateChanges(analyzedInstruction,
   2326                         RegisterType.getRegisterType(RegisterType.Category.DoubleLo, null));
   2327             } else {
   2328                 throw new ValidationException(String.format("Cannot use aget-wide with array type %s. Incorrect " +
   2329                         "array type for the instruction.", arrayRegisterType.type.getClassType()));
   2330             }
   2331         } else {
   2332             setDestinationRegisterTypeAndPropagateChanges(analyzedInstruction,
   2333                         RegisterType.getRegisterType(RegisterType.Category.LongLo, null));
   2334         }
   2335     }
   2336 
   2337     private void verifyAgetWide(AnalyzedInstruction analyzedInstruction) {
   2338         ThreeRegisterInstruction instruction = (ThreeRegisterInstruction)analyzedInstruction.instruction;
   2339 
   2340         getAndCheckSourceRegister(analyzedInstruction, instruction.getRegisterC(), Primitive32BitCategories);
   2341 
   2342         RegisterType arrayRegisterType = analyzedInstruction.getPreInstructionRegisterType(instruction.getRegisterB());
   2343         assert arrayRegisterType != null;
   2344 
   2345         if (arrayRegisterType.category != RegisterType.Category.Null) {
   2346             if (arrayRegisterType.category != RegisterType.Category.Reference) {
   2347                 throw new ValidationException(String.format("Cannot use aget-wide with non-array type %s",
   2348                         arrayRegisterType.category.toString()));
   2349             }
   2350 
   2351             assert arrayRegisterType.type != null;
   2352             if (arrayRegisterType.type.getClassType().charAt(0) != '[') {
   2353                 throw new ValidationException(String.format("Cannot use aget-wide with non-array type %s",
   2354                         arrayRegisterType.type.getClassType()));
   2355             }
   2356 
   2357             assert arrayRegisterType.type instanceof ClassPath.ArrayClassDef;
   2358             ClassPath.ArrayClassDef arrayClassDef = (ClassPath.ArrayClassDef)arrayRegisterType.type;
   2359 
   2360             if (arrayClassDef.getArrayDimensions() != 1) {
   2361                 throw new ValidationException(String.format("Cannot use aget-wide with multi-dimensional array type %s",
   2362                         arrayRegisterType.type.getClassType()));
   2363             }
   2364 
   2365             char arrayBaseType = arrayClassDef.getBaseElementClass().getClassType().charAt(0);
   2366             if (arrayBaseType != 'J' && arrayBaseType != 'D') {
   2367                 throw new ValidationException(String.format("Cannot use aget-wide with array type %s. Incorrect " +
   2368                         "array type for the instruction.", arrayRegisterType.type.getClassType()));
   2369             }
   2370         }
   2371     }
   2372 
   2373     private void analyzeAgetObject(AnalyzedInstruction analyzedInstruction) {
   2374         ThreeRegisterInstruction instruction = (ThreeRegisterInstruction)analyzedInstruction.instruction;
   2375 
   2376         RegisterType arrayRegisterType = analyzedInstruction.getPreInstructionRegisterType(instruction.getRegisterB());
   2377         assert arrayRegisterType != null;
   2378 
   2379         if (arrayRegisterType.category != RegisterType.Category.Null) {
   2380             assert arrayRegisterType.type != null;
   2381             if (arrayRegisterType.type.getClassType().charAt(0) != '[') {
   2382                 throw new ValidationException(String.format("Cannot use aget-object with non-array type %s",
   2383                         arrayRegisterType.type.getClassType()));
   2384             }
   2385 
   2386             assert arrayRegisterType.type instanceof ClassPath.ArrayClassDef;
   2387             ClassPath.ArrayClassDef arrayClassDef = (ClassPath.ArrayClassDef)arrayRegisterType.type;
   2388 
   2389             ClassPath.ClassDef elementClassDef = arrayClassDef.getImmediateElementClass();
   2390             char elementTypePrefix = elementClassDef.getClassType().charAt(0);
   2391             if (elementTypePrefix != 'L' && elementTypePrefix != '[') {
   2392                 throw new ValidationException(String.format("Cannot use aget-object with array type %s. Incorrect " +
   2393                         "array type for the instruction.", arrayRegisterType.type.getClassType()));
   2394             }
   2395 
   2396             setDestinationRegisterTypeAndPropagateChanges(analyzedInstruction,
   2397                     RegisterType.getRegisterType(RegisterType.Category.Reference, elementClassDef));
   2398         } else {
   2399             setDestinationRegisterTypeAndPropagateChanges(analyzedInstruction,
   2400                     RegisterType.getRegisterType(RegisterType.Category.Null, null));
   2401         }
   2402     }
   2403 
   2404     private void verifyAgetObject(AnalyzedInstruction analyzedInstruction) {
   2405         ThreeRegisterInstruction instruction = (ThreeRegisterInstruction)analyzedInstruction.instruction;
   2406 
   2407         getAndCheckSourceRegister(analyzedInstruction, instruction.getRegisterC(), Primitive32BitCategories);
   2408 
   2409         RegisterType arrayRegisterType = analyzedInstruction.getPreInstructionRegisterType(instruction.getRegisterB());
   2410         assert arrayRegisterType != null;
   2411 
   2412         if (arrayRegisterType.category != RegisterType.Category.Null) {
   2413             if (arrayRegisterType.category != RegisterType.Category.Reference) {
   2414                 throw new ValidationException(String.format("Cannot use aget-object with non-array type %s",
   2415                         arrayRegisterType.category.toString()));
   2416             }
   2417 
   2418             assert arrayRegisterType.type != null;
   2419             if (arrayRegisterType.type.getClassType().charAt(0) != '[') {
   2420                 throw new ValidationException(String.format("Cannot use aget-object with non-array type %s",
   2421                         arrayRegisterType.type.getClassType()));
   2422             }
   2423 
   2424             assert arrayRegisterType.type instanceof ClassPath.ArrayClassDef;
   2425             ClassPath.ArrayClassDef arrayClassDef = (ClassPath.ArrayClassDef)arrayRegisterType.type;
   2426 
   2427             ClassPath.ClassDef elementClassDef = arrayClassDef.getImmediateElementClass();
   2428             char elementTypePrefix = elementClassDef.getClassType().charAt(0);
   2429             if (elementTypePrefix != 'L' && elementTypePrefix != '[') {
   2430                 throw new ValidationException(String.format("Cannot use aget-object with array type %s. Incorrect " +
   2431                         "array type for the instruction.", arrayRegisterType.type.getClassType()));
   2432             }
   2433         }
   2434     }
   2435 
   2436     private void verify32BitPrimitiveAput(AnalyzedInstruction analyzedInstruction,
   2437                                              RegisterType.Category instructionCategory) {
   2438         ThreeRegisterInstruction instruction = (ThreeRegisterInstruction)analyzedInstruction.instruction;
   2439 
   2440         getAndCheckSourceRegister(analyzedInstruction, instruction.getRegisterC(), Primitive32BitCategories);
   2441 
   2442         RegisterType sourceRegisterType = analyzedInstruction.getPreInstructionRegisterType(instruction.getRegisterA());
   2443         assert sourceRegisterType != null;
   2444         RegisterType instructionRegisterType = RegisterType.getRegisterType(instructionCategory, null);
   2445         if (!sourceRegisterType.canBeAssignedTo(instructionRegisterType)) {
   2446             throw new ValidationException(String.format("Cannot use %s with source register type %s.",
   2447                     analyzedInstruction.instruction.opcode.name, sourceRegisterType.toString()));
   2448         }
   2449 
   2450 
   2451         RegisterType arrayRegisterType = analyzedInstruction.getPreInstructionRegisterType(instruction.getRegisterB());
   2452         assert arrayRegisterType != null;
   2453 
   2454         if (arrayRegisterType.category != RegisterType.Category.Null) {
   2455             if (arrayRegisterType.category != RegisterType.Category.Reference) {
   2456                 throw new ValidationException(String.format("Cannot use %s with non-array type %s",
   2457                         analyzedInstruction.instruction.opcode.name, arrayRegisterType.category.toString()));
   2458             }
   2459 
   2460             assert arrayRegisterType.type != null;
   2461             if (arrayRegisterType.type.getClassType().charAt(0) != '[') {
   2462                 throw new ValidationException(String.format("Cannot use %s with non-array type %s",
   2463                         analyzedInstruction.instruction.opcode.name, arrayRegisterType.type.getClassType()));
   2464             }
   2465 
   2466             assert arrayRegisterType.type instanceof ClassPath.ArrayClassDef;
   2467             ClassPath.ArrayClassDef arrayClassDef = (ClassPath.ArrayClassDef)arrayRegisterType.type;
   2468 
   2469             if (arrayClassDef.getArrayDimensions() != 1) {
   2470                 throw new ValidationException(String.format("Cannot use %s with multi-dimensional array type %s",
   2471                         analyzedInstruction.instruction.opcode.name, arrayRegisterType.type.getClassType()));
   2472             }
   2473 
   2474             RegisterType arrayBaseType =
   2475                     RegisterType.getRegisterTypeForType(arrayClassDef.getBaseElementClass().getClassType());
   2476             if (!checkArrayFieldAssignment(arrayBaseType.category, instructionCategory)) {
   2477                 throw new ValidationException(String.format("Cannot use %s with array type %s. Incorrect array type " +
   2478                         "for the instruction.", analyzedInstruction.instruction.opcode.name,
   2479                         arrayRegisterType.type.getClassType()));
   2480             }
   2481         }
   2482     }
   2483 
   2484     private void verifyAputWide(AnalyzedInstruction analyzedInstruction) {
   2485         ThreeRegisterInstruction instruction = (ThreeRegisterInstruction)analyzedInstruction.instruction;
   2486 
   2487         getAndCheckSourceRegister(analyzedInstruction, instruction.getRegisterC(), Primitive32BitCategories);
   2488         getAndCheckSourceRegister(analyzedInstruction, instruction.getRegisterA(), WideLowCategories);
   2489 
   2490         RegisterType arrayRegisterType = analyzedInstruction.getPreInstructionRegisterType(instruction.getRegisterB());
   2491         assert arrayRegisterType != null;
   2492 
   2493         if (arrayRegisterType.category != RegisterType.Category.Null) {
   2494             if (arrayRegisterType.category != RegisterType.Category.Reference) {
   2495                 throw new ValidationException(String.format("Cannot use aput-wide with non-array type %s",
   2496                         arrayRegisterType.category.toString()));
   2497             }
   2498 
   2499             assert arrayRegisterType.type != null;
   2500             if (arrayRegisterType.type.getClassType().charAt(0) != '[') {
   2501                 throw new ValidationException(String.format("Cannot use aput-wide with non-array type %s",
   2502                         arrayRegisterType.type.getClassType()));
   2503             }
   2504 
   2505             assert arrayRegisterType.type instanceof ClassPath.ArrayClassDef;
   2506             ClassPath.ArrayClassDef arrayClassDef = (ClassPath.ArrayClassDef)arrayRegisterType.type;
   2507 
   2508             if (arrayClassDef.getArrayDimensions() != 1) {
   2509                 throw new ValidationException(String.format("Cannot use aput-wide with multi-dimensional array type %s",
   2510                         arrayRegisterType.type.getClassType()));
   2511             }
   2512 
   2513             char arrayBaseType = arrayClassDef.getBaseElementClass().getClassType().charAt(0);
   2514             if (arrayBaseType != 'J' && arrayBaseType != 'D') {
   2515                 throw new ValidationException(String.format("Cannot use aput-wide with array type %s. Incorrect " +
   2516                         "array type for the instruction.", arrayRegisterType.type.getClassType()));
   2517             }
   2518         }
   2519     }
   2520 
   2521     private void verifyAputObject(AnalyzedInstruction analyzedInstruction) {
   2522         ThreeRegisterInstruction instruction = (ThreeRegisterInstruction)analyzedInstruction.instruction;
   2523 
   2524         getAndCheckSourceRegister(analyzedInstruction, instruction.getRegisterC(), Primitive32BitCategories);
   2525 
   2526         RegisterType sourceRegisterType = analyzedInstruction.getPreInstructionRegisterType(instruction.getRegisterA());
   2527         assert sourceRegisterType != null;
   2528 
   2529         //TODO: ensure sourceRegisterType is a Reference type?
   2530 
   2531         RegisterType arrayRegisterType = analyzedInstruction.getPreInstructionRegisterType(instruction.getRegisterB());
   2532         assert arrayRegisterType != null;
   2533 
   2534         if (arrayRegisterType.category != RegisterType.Category.Null) {
   2535             //don't check the source type against the array type, just make sure it is an array of reference types
   2536 
   2537             if (arrayRegisterType.category != RegisterType.Category.Reference) {
   2538                 throw new ValidationException(String.format("Cannot use aget-object with non-array type %s",
   2539                         arrayRegisterType.category.toString()));
   2540             }
   2541 
   2542             assert arrayRegisterType.type != null;
   2543             if (arrayRegisterType.type.getClassType().charAt(0) != '[') {
   2544                 throw new ValidationException(String.format("Cannot use aget-object with non-array type %s",
   2545                         arrayRegisterType.type.getClassType()));
   2546             }
   2547 
   2548             assert arrayRegisterType.type instanceof ClassPath.ArrayClassDef;
   2549             ClassPath.ArrayClassDef arrayClassDef = (ClassPath.ArrayClassDef)arrayRegisterType.type;
   2550 
   2551             ClassPath.ClassDef elementClassDef = arrayClassDef.getImmediateElementClass();
   2552             char elementTypePrefix = elementClassDef.getClassType().charAt(0);
   2553             if (elementTypePrefix != 'L' && elementTypePrefix != '[') {
   2554                 throw new ValidationException(String.format("Cannot use aget-object with array type %s. Incorrect " +
   2555                         "array type for the instruction.", arrayRegisterType.type.getClassType()));
   2556             }
   2557         }
   2558     }
   2559 
   2560     private void analyze32BitPrimitiveIget(AnalyzedInstruction analyzedInstruction,
   2561                                              RegisterType.Category instructionCategory) {
   2562         setDestinationRegisterTypeAndPropagateChanges(analyzedInstruction,
   2563                 RegisterType.getRegisterType(instructionCategory, null));
   2564     }
   2565 
   2566     private void verify32BitPrimitiveIget(AnalyzedInstruction analyzedInstruction,
   2567                                              RegisterType.Category instructionCategory) {
   2568         TwoRegisterInstruction instruction = (TwoRegisterInstruction)analyzedInstruction.instruction;
   2569 
   2570         RegisterType objectRegisterType = getAndCheckSourceRegister(analyzedInstruction, instruction.getRegisterB(),
   2571                 ReferenceOrUninitThisCategories);
   2572 
   2573         //TODO: check access
   2574         Item referencedItem = ((InstructionWithReference)analyzedInstruction.instruction).getReferencedItem();
   2575         assert referencedItem instanceof FieldIdItem;
   2576         FieldIdItem field = (FieldIdItem)referencedItem;
   2577 
   2578         if (objectRegisterType.category != RegisterType.Category.Null &&
   2579             !objectRegisterType.type.extendsClass(ClassPath.getClassDef(field.getContainingClass()))) {
   2580             throw new ValidationException(String.format("Cannot access field %s through type %s",
   2581                     field.getFieldString(), objectRegisterType.type.getClassType()));
   2582         }
   2583 
   2584         RegisterType fieldType = RegisterType.getRegisterTypeForTypeIdItem(field.getFieldType());
   2585 
   2586         if (!checkArrayFieldAssignment(fieldType.category, instructionCategory)) {
   2587                 throw new ValidationException(String.format("Cannot use %s with field %s. Incorrect field type " +
   2588                         "for the instruction.", analyzedInstruction.instruction.opcode.name,
   2589                         field.getFieldString()));
   2590         }
   2591     }
   2592 
   2593     private void analyzeIgetWideObject(AnalyzedInstruction analyzedInstruction) {
   2594         TwoRegisterInstruction instruction = (TwoRegisterInstruction)analyzedInstruction.instruction;
   2595 
   2596         Item referencedItem = ((InstructionWithReference)analyzedInstruction.instruction).getReferencedItem();
   2597         assert referencedItem instanceof FieldIdItem;
   2598         FieldIdItem field = (FieldIdItem)referencedItem;
   2599 
   2600         RegisterType fieldType = RegisterType.getRegisterTypeForTypeIdItem(field.getFieldType());
   2601         setDestinationRegisterTypeAndPropagateChanges(analyzedInstruction, fieldType);
   2602     }
   2603 
   2604     private void verifyIgetWide(AnalyzedInstruction analyzedInstruction) {
   2605         TwoRegisterInstruction instruction = (TwoRegisterInstruction)analyzedInstruction.instruction;
   2606 
   2607         RegisterType objectRegisterType = getAndCheckSourceRegister(analyzedInstruction, instruction.getRegisterB(),
   2608                 ReferenceOrUninitThisCategories);
   2609 
   2610         //TODO: check access
   2611         Item referencedItem = ((InstructionWithReference)analyzedInstruction.instruction).getReferencedItem();
   2612         assert referencedItem instanceof FieldIdItem;
   2613         FieldIdItem field = (FieldIdItem)referencedItem;
   2614 
   2615         if (objectRegisterType.category != RegisterType.Category.Null &&
   2616             !objectRegisterType.type.extendsClass(ClassPath.getClassDef(field.getContainingClass()))) {
   2617             throw new ValidationException(String.format("Cannot access field %s through type %s",
   2618                     field.getFieldString(), objectRegisterType.type.getClassType()));
   2619         }
   2620 
   2621         RegisterType fieldType = RegisterType.getRegisterTypeForTypeIdItem(field.getFieldType());
   2622 
   2623         if (!WideLowCategories.contains(fieldType.category)) {
   2624             throw new ValidationException(String.format("Cannot use %s with field %s. Incorrect field type " +
   2625                     "for the instruction.", analyzedInstruction.instruction.opcode.name,
   2626                     field.getFieldString()));
   2627         }
   2628     }
   2629 
   2630     private void verifyIgetObject(AnalyzedInstruction analyzedInstruction) {
   2631         TwoRegisterInstruction instruction = (TwoRegisterInstruction)analyzedInstruction.instruction;
   2632 
   2633         RegisterType objectRegisterType = getAndCheckSourceRegister(analyzedInstruction, instruction.getRegisterB(),
   2634                 ReferenceOrUninitThisCategories);
   2635 
   2636         //TODO: check access
   2637         Item referencedItem = ((InstructionWithReference)analyzedInstruction.instruction).getReferencedItem();
   2638         assert referencedItem instanceof FieldIdItem;
   2639         FieldIdItem field = (FieldIdItem)referencedItem;
   2640 
   2641         if (objectRegisterType.category != RegisterType.Category.Null &&
   2642             !objectRegisterType.type.extendsClass(ClassPath.getClassDef(field.getContainingClass()))) {
   2643             throw new ValidationException(String.format("Cannot access field %s through type %s",
   2644                     field.getFieldString(), objectRegisterType.type.getClassType()));
   2645         }
   2646 
   2647         RegisterType fieldType = RegisterType.getRegisterTypeForTypeIdItem(field.getFieldType());
   2648 
   2649         if (fieldType.category != RegisterType.Category.Reference) {
   2650             throw new ValidationException(String.format("Cannot use %s with field %s. Incorrect field type " +
   2651                         "for the instruction.", analyzedInstruction.instruction.opcode.name,
   2652                         field.getFieldString()));
   2653         }
   2654     }
   2655 
   2656     private void verify32BitPrimitiveIput(AnalyzedInstruction analyzedInstruction,
   2657                                              RegisterType.Category instructionCategory) {
   2658         TwoRegisterInstruction instruction = (TwoRegisterInstruction)analyzedInstruction.instruction;
   2659 
   2660         RegisterType objectRegisterType = getAndCheckSourceRegister(analyzedInstruction, instruction.getRegisterB(),
   2661                 ReferenceOrUninitThisCategories);
   2662 
   2663         RegisterType sourceRegisterType = analyzedInstruction.getPreInstructionRegisterType(instruction.getRegisterA());
   2664         assert sourceRegisterType != null;
   2665 
   2666         //per CodeVerify.c in dalvik:
   2667         //java generates synthetic functions that write byte values into boolean fields
   2668         if (sourceRegisterType.category == RegisterType.Category.Byte &&
   2669             instructionCategory == RegisterType.Category.Boolean) {
   2670 
   2671             sourceRegisterType = RegisterType.getRegisterType(RegisterType.Category.Boolean, null);
   2672         }
   2673 
   2674         RegisterType instructionRegisterType = RegisterType.getRegisterType(instructionCategory, null);
   2675         if (!sourceRegisterType.canBeAssignedTo(instructionRegisterType)) {
   2676             throw new ValidationException(String.format("Cannot use %s with source register type %s.",
   2677                     analyzedInstruction.instruction.opcode.name, sourceRegisterType.toString()));
   2678         }
   2679 
   2680 
   2681         //TODO: check access
   2682         Item referencedItem = ((InstructionWithReference)analyzedInstruction.instruction).getReferencedItem();
   2683         assert referencedItem instanceof FieldIdItem;
   2684         FieldIdItem field = (FieldIdItem)referencedItem;
   2685 
   2686         if (objectRegisterType.category != RegisterType.Category.Null &&
   2687             !objectRegisterType.type.extendsClass(ClassPath.getClassDef(field.getContainingClass()))) {
   2688             throw new ValidationException(String.format("Cannot access field %s through type %s",
   2689                     field.getFieldString(), objectRegisterType.type.getClassType()));
   2690         }
   2691 
   2692         RegisterType fieldType = RegisterType.getRegisterTypeForTypeIdItem(field.getFieldType());
   2693 
   2694         if (!checkArrayFieldAssignment(fieldType.category, instructionCategory)) {
   2695                 throw new ValidationException(String.format("Cannot use %s with field %s. Incorrect field type " +
   2696                         "for the instruction.", analyzedInstruction.instruction.opcode.name,
   2697                         field.getFieldString()));
   2698         }
   2699     }
   2700 
   2701     private void verifyIputWide(AnalyzedInstruction analyzedInstruction) {
   2702         TwoRegisterInstruction instruction = (TwoRegisterInstruction)analyzedInstruction.instruction;
   2703 
   2704         RegisterType objectRegisterType = getAndCheckSourceRegister(analyzedInstruction, instruction.getRegisterB(),
   2705                 ReferenceOrUninitThisCategories);
   2706 
   2707         getAndCheckSourceRegister(analyzedInstruction, instruction.getRegisterA(), WideLowCategories);
   2708 
   2709         //TODO: check access
   2710         Item referencedItem = ((InstructionWithReference)analyzedInstruction.instruction).getReferencedItem();
   2711         assert referencedItem instanceof FieldIdItem;
   2712         FieldIdItem field = (FieldIdItem)referencedItem;
   2713 
   2714         if (objectRegisterType.category != RegisterType.Category.Null &&
   2715                 !objectRegisterType.type.extendsClass(ClassPath.getClassDef(field.getContainingClass()))) {
   2716             throw new ValidationException(String.format("Cannot access field %s through type %s",
   2717                     field.getFieldString(), objectRegisterType.type.getClassType()));
   2718         }
   2719 
   2720         RegisterType fieldType = RegisterType.getRegisterTypeForTypeIdItem(field.getFieldType());
   2721 
   2722         if (!WideLowCategories.contains(fieldType.category)) {
   2723             throw new ValidationException(String.format("Cannot use %s with field %s. Incorrect field type " +
   2724                     "for the instruction.", analyzedInstruction.instruction.opcode.name,
   2725                     field.getFieldString()));
   2726         }
   2727     }
   2728 
   2729     private void verifyIputObject(AnalyzedInstruction analyzedInstruction) {
   2730         TwoRegisterInstruction instruction = (TwoRegisterInstruction)analyzedInstruction.instruction;
   2731 
   2732         RegisterType objectRegisterType = getAndCheckSourceRegister(analyzedInstruction, instruction.getRegisterB(),
   2733                 ReferenceOrUninitThisCategories);
   2734 
   2735         RegisterType sourceRegisterType = getAndCheckSourceRegister(analyzedInstruction, instruction.getRegisterA(),
   2736                 ReferenceCategories);
   2737 
   2738         //TODO: check access
   2739         Item referencedItem = ((InstructionWithReference)analyzedInstruction.instruction).getReferencedItem();
   2740         assert referencedItem instanceof FieldIdItem;
   2741         FieldIdItem field = (FieldIdItem)referencedItem;
   2742 
   2743         if (objectRegisterType.category != RegisterType.Category.Null &&
   2744             !objectRegisterType.type.extendsClass(ClassPath.getClassDef(field.getContainingClass()))) {
   2745             throw new ValidationException(String.format("Cannot access field %s through type %s",
   2746                     field.getFieldString(), objectRegisterType.type.getClassType()));
   2747         }
   2748 
   2749         RegisterType fieldType = RegisterType.getRegisterTypeForTypeIdItem(field.getFieldType());
   2750 
   2751         if (fieldType.category != RegisterType.Category.Reference) {
   2752             throw new ValidationException(String.format("Cannot use %s with field %s. Incorrect field type " +
   2753                         "for the instruction.", analyzedInstruction.instruction.opcode.name,
   2754                         field.getFieldString()));
   2755         }
   2756 
   2757         if (sourceRegisterType.category != RegisterType.Category.Null &&
   2758             !fieldType.type.isInterface() &&
   2759             !sourceRegisterType.type.extendsClass(fieldType.type)) {
   2760 
   2761             throw new ValidationException(String.format("Cannot store a value of type %s into a field of type %s",
   2762                     sourceRegisterType.type.getClassType(), fieldType.type.getClassType()));
   2763         }
   2764     }
   2765 
   2766     private void analyze32BitPrimitiveSget(AnalyzedInstruction analyzedInstruction,
   2767                                              RegisterType.Category instructionCategory) {
   2768         setDestinationRegisterTypeAndPropagateChanges(analyzedInstruction,
   2769                 RegisterType.getRegisterType(instructionCategory, null));
   2770     }
   2771 
   2772     private void verify32BitPrimitiveSget(AnalyzedInstruction analyzedInstruction,
   2773                                              RegisterType.Category instructionCategory) {
   2774         //TODO: check access
   2775         Item referencedItem = ((InstructionWithReference)analyzedInstruction.instruction).getReferencedItem();
   2776         assert referencedItem instanceof FieldIdItem;
   2777         FieldIdItem field = (FieldIdItem)referencedItem;
   2778 
   2779         RegisterType fieldType = RegisterType.getRegisterTypeForTypeIdItem(field.getFieldType());
   2780 
   2781         if (!checkArrayFieldAssignment(fieldType.category, instructionCategory)) {
   2782                 throw new ValidationException(String.format("Cannot use %s with field %s. Incorrect field type " +
   2783                         "for the instruction.", analyzedInstruction.instruction.opcode.name,
   2784                         field.getFieldString()));
   2785         }
   2786     }
   2787 
   2788     private void analyzeSgetWideObject(AnalyzedInstruction analyzedInstruction) {
   2789         Item referencedItem = ((InstructionWithReference)analyzedInstruction.instruction).getReferencedItem();
   2790         assert referencedItem instanceof FieldIdItem;
   2791         FieldIdItem field = (FieldIdItem)referencedItem;
   2792 
   2793         RegisterType fieldType = RegisterType.getRegisterTypeForTypeIdItem(field.getFieldType());
   2794         setDestinationRegisterTypeAndPropagateChanges(analyzedInstruction, fieldType);
   2795     }
   2796 
   2797     private void verifySgetWide(AnalyzedInstruction analyzedInstruction) {
   2798         //TODO: check access
   2799         Item referencedItem = ((InstructionWithReference)analyzedInstruction.instruction).getReferencedItem();
   2800         assert referencedItem instanceof FieldIdItem;
   2801         FieldIdItem field = (FieldIdItem)referencedItem;
   2802 
   2803         RegisterType fieldType = RegisterType.getRegisterTypeForTypeIdItem(field.getFieldType());
   2804 
   2805 
   2806         if (fieldType.category != RegisterType.Category.LongLo &&
   2807             fieldType.category != RegisterType.Category.DoubleLo) {
   2808 
   2809             throw new ValidationException(String.format("Cannot use %s with field %s. Incorrect field type " +
   2810                     "for the instruction.", analyzedInstruction.instruction.opcode.name,
   2811                     field.getFieldString()));
   2812         }
   2813     }
   2814 
   2815     private void verifySgetObject(AnalyzedInstruction analyzedInstruction) {
   2816         //TODO: check access
   2817         Item referencedItem = ((InstructionWithReference)analyzedInstruction.instruction).getReferencedItem();
   2818         assert referencedItem instanceof FieldIdItem;
   2819         FieldIdItem field = (FieldIdItem)referencedItem;
   2820 
   2821         RegisterType fieldType = RegisterType.getRegisterTypeForTypeIdItem(field.getFieldType());
   2822 
   2823         if (fieldType.category != RegisterType.Category.Reference) {
   2824                 throw new ValidationException(String.format("Cannot use %s with field %s. Incorrect field type " +
   2825                         "for the instruction.", analyzedInstruction.instruction.opcode.name,
   2826                         field.getFieldString()));
   2827         }
   2828     }
   2829 
   2830     private void verify32BitPrimitiveSput(AnalyzedInstruction analyzedInstruction,
   2831                                              RegisterType.Category instructionCategory) {
   2832         SingleRegisterInstruction instruction = (SingleRegisterInstruction)analyzedInstruction.instruction;
   2833 
   2834         RegisterType sourceRegisterType = analyzedInstruction.getPreInstructionRegisterType(instruction.getRegisterA());
   2835         assert sourceRegisterType != null;
   2836 
   2837         //per CodeVerify.c in dalvik:
   2838         //java generates synthetic functions that write byte values into boolean fields
   2839         if (sourceRegisterType.category == RegisterType.Category.Byte &&
   2840             instructionCategory == RegisterType.Category.Boolean) {
   2841 
   2842             sourceRegisterType = RegisterType.getRegisterType(RegisterType.Category.Boolean, null);
   2843         }
   2844 
   2845         RegisterType instructionRegisterType = RegisterType.getRegisterType(instructionCategory, null);
   2846         if (!sourceRegisterType.canBeAssignedTo(instructionRegisterType)) {
   2847             throw new ValidationException(String.format("Cannot use %s with source register type %s.",
   2848                     analyzedInstruction.instruction.opcode.name, sourceRegisterType.toString()));
   2849         }
   2850 
   2851         //TODO: check access
   2852         Item referencedItem = ((InstructionWithReference)analyzedInstruction.instruction).getReferencedItem();
   2853         assert referencedItem instanceof FieldIdItem;
   2854         FieldIdItem field = (FieldIdItem)referencedItem;
   2855 
   2856         RegisterType fieldType = RegisterType.getRegisterTypeForTypeIdItem(field.getFieldType());
   2857 
   2858         if (!checkArrayFieldAssignment(fieldType.category, instructionCategory)) {
   2859                 throw new ValidationException(String.format("Cannot use %s with field %s. Incorrect field type " +
   2860                         "for the instruction.", analyzedInstruction.instruction.opcode.name,
   2861                         field.getFieldString()));
   2862         }
   2863     }
   2864 
   2865     private void verifySputWide(AnalyzedInstruction analyzedInstruction) {
   2866         SingleRegisterInstruction instruction = (SingleRegisterInstruction)analyzedInstruction.instruction;
   2867 
   2868 
   2869         getAndCheckSourceRegister(analyzedInstruction, instruction.getRegisterA(), WideLowCategories);
   2870 
   2871         //TODO: check access
   2872         Item referencedItem = ((InstructionWithReference)analyzedInstruction.instruction).getReferencedItem();
   2873         assert referencedItem instanceof FieldIdItem;
   2874         FieldIdItem field = (FieldIdItem)referencedItem;
   2875 
   2876         RegisterType fieldType = RegisterType.getRegisterTypeForTypeIdItem(field.getFieldType());
   2877 
   2878         if (!WideLowCategories.contains(fieldType.category)) {
   2879                 throw new ValidationException(String.format("Cannot use %s with field %s. Incorrect field type " +
   2880                         "for the instruction.", analyzedInstruction.instruction.opcode.name,
   2881                         field.getFieldString()));
   2882         }
   2883     }
   2884 
   2885     private void verifySputObject(AnalyzedInstruction analyzedInstruction) {
   2886         SingleRegisterInstruction instruction = (SingleRegisterInstruction)analyzedInstruction.instruction;
   2887 
   2888         RegisterType sourceRegisterType = getAndCheckSourceRegister(analyzedInstruction, instruction.getRegisterA(),
   2889                 ReferenceCategories);
   2890 
   2891         //TODO: check access
   2892         Item referencedItem = ((InstructionWithReference)analyzedInstruction.instruction).getReferencedItem();
   2893         assert referencedItem instanceof FieldIdItem;
   2894         FieldIdItem field = (FieldIdItem)referencedItem;
   2895 
   2896         RegisterType fieldType = RegisterType.getRegisterTypeForTypeIdItem(field.getFieldType());
   2897 
   2898         if (fieldType.category != RegisterType.Category.Reference) {
   2899             throw new ValidationException(String.format("Cannot use %s with field %s. Incorrect field type " +
   2900                         "for the instruction.", analyzedInstruction.instruction.opcode.name,
   2901                         field.getFieldString()));
   2902         }
   2903 
   2904         if (sourceRegisterType.category != RegisterType.Category.Null &&
   2905             !fieldType.type.isInterface() &&
   2906             !sourceRegisterType.type.extendsClass(fieldType.type)) {
   2907 
   2908             throw new ValidationException(String.format("Cannot store a value of type %s into a field of type %s",
   2909                     sourceRegisterType.type.getClassType(), fieldType.type.getClassType()));
   2910         }
   2911     }
   2912 
   2913     private void analyzeInvokeDirect(AnalyzedInstruction analyzedInstruction) {
   2914         FiveRegisterInstruction instruction = (FiveRegisterInstruction)analyzedInstruction.instruction;
   2915         analyzeInvokeDirectCommon(analyzedInstruction, new Format35cRegisterIterator(instruction));
   2916     }
   2917 
   2918     private void verifyInvoke(AnalyzedInstruction analyzedInstruction, int invokeType) {
   2919         FiveRegisterInstruction instruction = (FiveRegisterInstruction)analyzedInstruction.instruction;
   2920         verifyInvokeCommon(analyzedInstruction, false, invokeType, new Format35cRegisterIterator(instruction));
   2921     }
   2922 
   2923     private void analyzeInvokeDirectRange(AnalyzedInstruction analyzedInstruction) {
   2924         RegisterRangeInstruction instruction = (RegisterRangeInstruction)analyzedInstruction.instruction;
   2925         analyzeInvokeDirectCommon(analyzedInstruction, new Format3rcRegisterIterator(instruction));
   2926     }
   2927 
   2928     private void verifyInvokeRange(AnalyzedInstruction analyzedInstruction, int invokeType) {
   2929         RegisterRangeInstruction instruction = (RegisterRangeInstruction)analyzedInstruction.instruction;
   2930         verifyInvokeCommon(analyzedInstruction, true, invokeType, new Format3rcRegisterIterator(instruction));
   2931     }
   2932 
   2933     private static final int INVOKE_VIRTUAL = 0x01;
   2934     private static final int INVOKE_SUPER = 0x02;
   2935     private static final int INVOKE_DIRECT = 0x04;
   2936     private static final int INVOKE_INTERFACE = 0x08;
   2937     private static final int INVOKE_STATIC = 0x10;
   2938 
   2939     private void analyzeInvokeDirectCommon(AnalyzedInstruction analyzedInstruction, RegisterIterator registers) {
   2940         //the only time that an invoke instruction changes a register type is when using invoke-direct on a
   2941         //constructor (<init>) method, which changes the uninitialized reference (and any register that the same
   2942         //uninit reference has been copied to) to an initialized reference
   2943 
   2944         InstructionWithReference instruction = (InstructionWithReference)analyzedInstruction.instruction;
   2945 
   2946         Item item = instruction.getReferencedItem();
   2947         assert item.getItemType() == ItemType.TYPE_METHOD_ID_ITEM;
   2948         MethodIdItem methodIdItem = (MethodIdItem)item;
   2949 
   2950         if (!methodIdItem.getMethodName().getStringValue().equals("<init>")) {
   2951             return;
   2952         }
   2953 
   2954         RegisterType objectRegisterType;
   2955         //the object register is always the first register
   2956         int objectRegister = registers.getRegister();
   2957 
   2958         objectRegisterType = analyzedInstruction.getPreInstructionRegisterType(objectRegister);
   2959         assert objectRegisterType != null;
   2960 
   2961         if (objectRegisterType.category != RegisterType.Category.UninitRef &&
   2962                 objectRegisterType.category != RegisterType.Category.UninitThis) {
   2963             return;
   2964         }
   2965 
   2966         setPostRegisterTypeAndPropagateChanges(analyzedInstruction, objectRegister,
   2967                 RegisterType.getRegisterType(RegisterType.Category.Reference, objectRegisterType.type));
   2968 
   2969         for (int i=0; i<analyzedInstruction.postRegisterMap.length; i++) {
   2970             RegisterType postInstructionRegisterType = analyzedInstruction.postRegisterMap[i];
   2971             if (postInstructionRegisterType.category == RegisterType.Category.Unknown) {
   2972                 RegisterType preInstructionRegisterType =
   2973                         analyzedInstruction.getPreInstructionRegisterType(i);
   2974 
   2975                 if (preInstructionRegisterType.category == RegisterType.Category.UninitRef ||
   2976                     preInstructionRegisterType.category == RegisterType.Category.UninitThis) {
   2977 
   2978                     RegisterType registerType;
   2979                     if (preInstructionRegisterType == objectRegisterType) {
   2980                         registerType = analyzedInstruction.postRegisterMap[objectRegister];
   2981                     } else {
   2982                         registerType = preInstructionRegisterType;
   2983                     }
   2984 
   2985                     setPostRegisterTypeAndPropagateChanges(analyzedInstruction, i, registerType);
   2986                 }
   2987             }
   2988         }
   2989     }
   2990 
   2991     private void verifyInvokeCommon(AnalyzedInstruction analyzedInstruction, boolean isRange, int invokeType,
   2992                                        RegisterIterator registers) {
   2993         InstructionWithReference instruction = (InstructionWithReference)analyzedInstruction.instruction;
   2994 
   2995         //TODO: check access
   2996 
   2997         Item item = instruction.getReferencedItem();
   2998         assert item.getItemType() == ItemType.TYPE_METHOD_ID_ITEM;
   2999         MethodIdItem methodIdItem = (MethodIdItem)item;
   3000 
   3001         TypeIdItem methodClass = methodIdItem.getContainingClass();
   3002         boolean isInit = false;
   3003 
   3004         if (methodIdItem.getMethodName().getStringValue().charAt(0) == '<') {
   3005             if ((invokeType & INVOKE_DIRECT) != 0) {
   3006                 isInit = true;
   3007             } else {
   3008                 throw new ValidationException(String.format("Cannot call constructor %s with %s",
   3009                         methodIdItem.getMethodString(), analyzedInstruction.instruction.opcode.name));
   3010             }
   3011         }
   3012 
   3013         ClassPath.ClassDef methodClassDef = ClassPath.getClassDef(methodClass);
   3014         if ((invokeType & INVOKE_INTERFACE) != 0) {
   3015             if (!methodClassDef.isInterface()) {
   3016                 throw new ValidationException(String.format("Cannot call method %s with %s. %s is not an interface " +
   3017                         "class.", methodIdItem.getMethodString(), analyzedInstruction.instruction.opcode.name,
   3018                         methodClassDef.getClassType()));
   3019             }
   3020         } else {
   3021             if (methodClassDef.isInterface()) {
   3022                 throw new ValidationException(String.format("Cannot call method %s with %s. %s is an interface class." +
   3023                         " Use invoke-interface or invoke-interface/range instead.", methodIdItem.getMethodString(),
   3024                         analyzedInstruction.instruction.opcode.name, methodClassDef.getClassType()));
   3025             }
   3026         }
   3027 
   3028         if ((invokeType & INVOKE_SUPER) != 0) {
   3029             ClassPath.ClassDef currentMethodClassDef = ClassPath.getClassDef(encodedMethod.method.getContainingClass());
   3030             if (currentMethodClassDef.getSuperclass() == null) {
   3031                 throw new ValidationException(String.format("Cannot call method %s with %s. %s has no superclass",
   3032                         methodIdItem.getMethodString(), analyzedInstruction.instruction.opcode.name,
   3033                         methodClassDef.getSuperclass().getClassType()));
   3034             }
   3035 
   3036             if (!currentMethodClassDef.getSuperclass().extendsClass(methodClassDef)) {
   3037                 throw new ValidationException(String.format("Cannot call method %s with %s. %s is not an ancestor " +
   3038                         "of the current class %s", methodIdItem.getMethodString(),
   3039                         analyzedInstruction.instruction.opcode.name, methodClass.getTypeDescriptor(),
   3040                         encodedMethod.method.getContainingClass().getTypeDescriptor()));
   3041             }
   3042 
   3043             if (!currentMethodClassDef.getSuperclass().hasVirtualMethod(methodIdItem.getVirtualMethodString())) {
   3044                 throw new ValidationException(String.format("Cannot call method %s with %s. The superclass %s has" +
   3045                         "no such method", methodIdItem.getMethodString(),
   3046                         analyzedInstruction.instruction.opcode.name, methodClassDef.getSuperclass().getClassType()));
   3047             }
   3048         }
   3049 
   3050         assert isRange || registers.getCount() <= 5;
   3051 
   3052         TypeListItem typeListItem = methodIdItem.getPrototype().getParameters();
   3053         int methodParameterRegisterCount;
   3054         if (typeListItem == null) {
   3055             methodParameterRegisterCount = 0;
   3056         } else {
   3057             methodParameterRegisterCount = typeListItem.getRegisterCount();
   3058         }
   3059 
   3060         if ((invokeType & INVOKE_STATIC) == 0) {
   3061             methodParameterRegisterCount++;
   3062         }
   3063 
   3064         if (methodParameterRegisterCount != registers.getCount()) {
   3065             throw new ValidationException(String.format("The number of registers does not match the number of " +
   3066                     "parameters for method %s. Expecting %d registers, got %d.", methodIdItem.getMethodString(),
   3067                     methodParameterRegisterCount + 1, registers.getCount()));
   3068         }
   3069 
   3070         RegisterType objectRegisterType = null;
   3071         int objectRegister = 0;
   3072         if ((invokeType & INVOKE_STATIC) == 0) {
   3073             objectRegister = registers.getRegister();
   3074             registers.moveNext();
   3075 
   3076             objectRegisterType = analyzedInstruction.getPreInstructionRegisterType(objectRegister);
   3077             assert objectRegisterType != null;
   3078             if (objectRegisterType.category == RegisterType.Category.UninitRef ||
   3079                     objectRegisterType.category == RegisterType.Category.UninitThis) {
   3080 
   3081                 if (!isInit) {
   3082                     throw new ValidationException(String.format("Cannot invoke non-<init> method %s on uninitialized " +
   3083                             "reference type %s", methodIdItem.getMethodString(),
   3084                             objectRegisterType.type.getClassType()));
   3085                 }
   3086             } else if (objectRegisterType.category == RegisterType.Category.Reference) {
   3087                 if (isInit) {
   3088                     throw new ValidationException(String.format("Cannot invoke %s on initialized reference type %s",
   3089                             methodIdItem.getMethodString(), objectRegisterType.type.getClassType()));
   3090                 }
   3091             } else if (objectRegisterType.category == RegisterType.Category.Null) {
   3092                 if (isInit) {
   3093                     throw new ValidationException(String.format("Cannot invoke %s on a null reference",
   3094                             methodIdItem.getMethodString()));
   3095                 }
   3096             }
   3097             else {
   3098                 throw new ValidationException(String.format("Cannot invoke %s on non-reference type %s",
   3099                         methodIdItem.getMethodString(), objectRegisterType.toString()));
   3100             }
   3101 
   3102             if (isInit) {
   3103                 if (objectRegisterType.type.getSuperclass() == methodClassDef) {
   3104                     if (!encodedMethod.method.getMethodName().getStringValue().equals("<init>")) {
   3105                         throw new ValidationException(String.format("Cannot call %s on type %s. The object type must " +
   3106                                 "match the method type exactly", methodIdItem.getMethodString(),
   3107                                 objectRegisterType.type.getClassType()));
   3108                     }
   3109                 }
   3110             }
   3111 
   3112             if ((invokeType & INVOKE_INTERFACE) == 0 && objectRegisterType.category != RegisterType.Category.Null &&
   3113                     !objectRegisterType.type.extendsClass(methodClassDef)) {
   3114 
   3115                throw new ValidationException(String.format("Cannot call method %s on an object of type %s, which " +
   3116                        "does not extend %s.", methodIdItem.getMethodString(), objectRegisterType.type.getClassType(),
   3117                         methodClassDef.getClassType()));
   3118             }
   3119         }
   3120 
   3121         if (typeListItem != null) {
   3122             List<TypeIdItem> parameterTypes = typeListItem.getTypes();
   3123             int parameterTypeIndex = 0;
   3124             while (!registers.pastEnd()) {
   3125                 assert parameterTypeIndex < parameterTypes.size();
   3126                 RegisterType parameterType =
   3127                         RegisterType.getRegisterTypeForTypeIdItem(parameterTypes.get(parameterTypeIndex));
   3128 
   3129                 int register = registers.getRegister();
   3130 
   3131                 RegisterType parameterRegisterType;
   3132                 if (WideLowCategories.contains(parameterType.category)) {
   3133                     parameterRegisterType = getAndCheckSourceRegister(analyzedInstruction, register, WideLowCategories);
   3134 
   3135                     if (!registers.moveNext()) {
   3136                         throw new ValidationException(String.format("No 2nd register specified for wide register pair v%d",
   3137                                 parameterTypeIndex+1));
   3138                     }
   3139                     int nextRegister = registers.getRegister();
   3140 
   3141                     if (nextRegister != register + 1) {
   3142                         throw new ValidationException(String.format("Invalid wide register pair (v%d, v%d). Registers " +
   3143                                 "must be consecutive.", register, nextRegister));
   3144                     }
   3145                 } else {
   3146                     parameterRegisterType = analyzedInstruction.getPreInstructionRegisterType(register);
   3147                 }
   3148 
   3149                 assert parameterRegisterType != null;
   3150 
   3151                 if (!parameterRegisterType.canBeAssignedTo(parameterType)) {
   3152                     throw new ValidationException(
   3153                             String.format("Invalid register type %s for parameter %d %s.",
   3154                                     parameterRegisterType.toString(), parameterTypeIndex+1,
   3155                                     parameterType.toString()));
   3156                 }
   3157 
   3158                 parameterTypeIndex++;
   3159                 registers.moveNext();
   3160             }
   3161         }
   3162     }
   3163 
   3164     private void analyzeUnaryOp(AnalyzedInstruction analyzedInstruction, RegisterType.Category destRegisterCategory) {
   3165         setDestinationRegisterTypeAndPropagateChanges(analyzedInstruction,
   3166                 RegisterType.getRegisterType(destRegisterCategory, null));
   3167     }
   3168 
   3169     private void verifyUnaryOp(AnalyzedInstruction analyzedInstruction, EnumSet validSourceCategories) {
   3170         TwoRegisterInstruction instruction = (TwoRegisterInstruction)analyzedInstruction.instruction;
   3171 
   3172         getAndCheckSourceRegister(analyzedInstruction, instruction.getRegisterB(), validSourceCategories);
   3173     }
   3174 
   3175     private void analyzeBinaryOp(AnalyzedInstruction analyzedInstruction, RegisterType.Category destRegisterCategory,
   3176                                 boolean checkForBoolean) {
   3177         if (checkForBoolean) {
   3178             ThreeRegisterInstruction instruction = (ThreeRegisterInstruction)analyzedInstruction.instruction;
   3179 
   3180             RegisterType source1RegisterType =
   3181                     analyzedInstruction.getPreInstructionRegisterType(instruction.getRegisterB());
   3182             RegisterType source2RegisterType =
   3183                     analyzedInstruction.getPreInstructionRegisterType(instruction.getRegisterC());
   3184 
   3185             if (BooleanCategories.contains(source1RegisterType.category) &&
   3186                 BooleanCategories.contains(source2RegisterType.category)) {
   3187 
   3188                 destRegisterCategory = RegisterType.Category.Boolean;
   3189             }
   3190         }
   3191 
   3192         setDestinationRegisterTypeAndPropagateChanges(analyzedInstruction,
   3193                 RegisterType.getRegisterType(destRegisterCategory, null));
   3194     }
   3195 
   3196     private void verifyBinaryOp(AnalyzedInstruction analyzedInstruction, EnumSet validSource1Categories,
   3197                                 EnumSet validSource2Categories) {
   3198         ThreeRegisterInstruction instruction = (ThreeRegisterInstruction)analyzedInstruction.instruction;
   3199 
   3200         getAndCheckSourceRegister(analyzedInstruction, instruction.getRegisterB(), validSource1Categories);
   3201         getAndCheckSourceRegister(analyzedInstruction, instruction.getRegisterC(), validSource2Categories);
   3202     }
   3203 
   3204     private void analyzeBinary2AddrOp(AnalyzedInstruction analyzedInstruction,
   3205                                       RegisterType.Category destRegisterCategory, boolean checkForBoolean) {
   3206         if (checkForBoolean) {
   3207             TwoRegisterInstruction instruction = (TwoRegisterInstruction)analyzedInstruction.instruction;
   3208 
   3209             RegisterType source1RegisterType =
   3210                     analyzedInstruction.getPreInstructionRegisterType(instruction.getRegisterA());
   3211             RegisterType source2RegisterType =
   3212                     analyzedInstruction.getPreInstructionRegisterType(instruction.getRegisterB());
   3213 
   3214             if (BooleanCategories.contains(source1RegisterType.category) &&
   3215                 BooleanCategories.contains(source2RegisterType.category)) {
   3216 
   3217                 destRegisterCategory = RegisterType.Category.Boolean;
   3218             }
   3219         }
   3220 
   3221         setDestinationRegisterTypeAndPropagateChanges(analyzedInstruction,
   3222                 RegisterType.getRegisterType(destRegisterCategory, null));
   3223     }
   3224 
   3225     private void verifyBinary2AddrOp(AnalyzedInstruction analyzedInstruction, EnumSet validSource1Categories,
   3226                                 EnumSet validSource2Categories) {
   3227         TwoRegisterInstruction instruction = (TwoRegisterInstruction)analyzedInstruction.instruction;
   3228 
   3229         getAndCheckSourceRegister(analyzedInstruction, instruction.getRegisterA(), validSource1Categories);
   3230         getAndCheckSourceRegister(analyzedInstruction, instruction.getRegisterB(), validSource2Categories);
   3231     }
   3232 
   3233     private void analyzeLiteralBinaryOp(AnalyzedInstruction analyzedInstruction,
   3234                                         RegisterType.Category destRegisterCategory, boolean checkForBoolean) {
   3235         if (checkForBoolean) {
   3236             TwoRegisterInstruction instruction = (TwoRegisterInstruction)analyzedInstruction.instruction;
   3237 
   3238             RegisterType sourceRegisterType =
   3239                     analyzedInstruction.getPreInstructionRegisterType(instruction.getRegisterB());
   3240 
   3241             if (BooleanCategories.contains(sourceRegisterType.category)) {
   3242                 long literal = ((LiteralInstruction)analyzedInstruction.instruction).getLiteral();
   3243                 if (literal == 0 || literal == 1) {
   3244                     destRegisterCategory = RegisterType.Category.Boolean;
   3245                 }
   3246             }
   3247         }
   3248 
   3249         setDestinationRegisterTypeAndPropagateChanges(analyzedInstruction,
   3250                 RegisterType.getRegisterType(destRegisterCategory, null));
   3251     }
   3252 
   3253     private void verifyLiteralBinaryOp(AnalyzedInstruction analyzedInstruction) {
   3254         TwoRegisterInstruction instruction = (TwoRegisterInstruction)analyzedInstruction.instruction;
   3255 
   3256         getAndCheckSourceRegister(analyzedInstruction, instruction.getRegisterB(), Primitive32BitCategories);
   3257     }
   3258 
   3259     private RegisterType.Category getDestTypeForLiteralShiftRight(AnalyzedInstruction analyzedInstruction,
   3260                                                                   boolean signedShift) {
   3261         TwoRegisterInstruction instruction = (TwoRegisterInstruction)analyzedInstruction.instruction;
   3262 
   3263         RegisterType sourceRegisterType = getAndCheckSourceRegister(analyzedInstruction, instruction.getRegisterB(),
   3264                 Primitive32BitCategories);
   3265         long literalShift = ((LiteralInstruction)analyzedInstruction.instruction).getLiteral();
   3266 
   3267         if (literalShift == 0) {
   3268             return sourceRegisterType.category;
   3269         }
   3270 
   3271         RegisterType.Category destRegisterCategory;
   3272         if (!signedShift) {
   3273             destRegisterCategory = RegisterType.Category.Integer;
   3274         } else {
   3275             destRegisterCategory = sourceRegisterType.category;
   3276         }
   3277 
   3278         if (literalShift >= 32) {
   3279             //TODO: add warning
   3280             return destRegisterCategory;
   3281         }
   3282 
   3283         switch (sourceRegisterType.category) {
   3284             case Integer:
   3285             case Float:
   3286                 if (!signedShift) {
   3287                     if (literalShift > 24) {
   3288                         return RegisterType.Category.PosByte;
   3289                     }
   3290                     if (literalShift >= 16) {
   3291                         return RegisterType.Category.Char;
   3292                     }
   3293                 } else {
   3294                     if (literalShift >= 24) {
   3295                         return RegisterType.Category.Byte;
   3296                     }
   3297                     if (literalShift >= 16) {
   3298                         return RegisterType.Category.Short;
   3299                     }
   3300                 }
   3301                 break;
   3302             case Short:
   3303                 if (signedShift && literalShift >= 8) {
   3304                     return RegisterType.Category.Byte;
   3305                 }
   3306                 break;
   3307             case PosShort:
   3308                 if (literalShift >= 8) {
   3309                     return RegisterType.Category.PosByte;
   3310                 }
   3311                 break;
   3312             case Char:
   3313                 if (literalShift > 8) {
   3314                     return RegisterType.Category.PosByte;
   3315                 }
   3316                 break;
   3317             case Byte:
   3318                 break;
   3319             case PosByte:
   3320                 return RegisterType.Category.PosByte;
   3321             case Null:
   3322             case One:
   3323             case Boolean:
   3324                 return RegisterType.Category.Null;
   3325             default:
   3326                 assert false;
   3327         }
   3328 
   3329         return destRegisterCategory;
   3330     }
   3331 
   3332 
   3333     private void analyzeExecuteInline(AnalyzedInstruction analyzedInstruction) {
   3334         if (deodexUtil == null) {
   3335             throw new ValidationException("Cannot analyze an odexed instruction unless we are deodexing");
   3336         }
   3337 
   3338         Instruction35ms instruction = (Instruction35ms)analyzedInstruction.instruction;
   3339 
   3340         DeodexUtil.InlineMethod inlineMethod = deodexUtil.lookupInlineMethod(analyzedInstruction);
   3341         MethodIdItem inlineMethodIdItem = inlineMethod.getMethodIdItem();
   3342         if (inlineMethodIdItem == null) {
   3343             throw new ValidationException(String.format("Cannot load inline method with index %d",
   3344                     instruction.getMethodIndex()));
   3345         }
   3346 
   3347         Opcode deodexedOpcode = null;
   3348         switch (inlineMethod.methodType) {
   3349             case DeodexUtil.Direct:
   3350                 deodexedOpcode = Opcode.INVOKE_DIRECT;
   3351                 break;
   3352             case DeodexUtil.Static:
   3353                 deodexedOpcode = Opcode.INVOKE_STATIC;
   3354                 break;
   3355             case DeodexUtil.Virtual:
   3356                 deodexedOpcode = Opcode.INVOKE_VIRTUAL;
   3357                 break;
   3358             default:
   3359                 assert false;
   3360         }
   3361 
   3362         Instruction35c deodexedInstruction = new Instruction35c(deodexedOpcode, instruction.getRegCount(),
   3363                 instruction.getRegisterD(), instruction.getRegisterE(), instruction.getRegisterF(),
   3364                 instruction.getRegisterG(), instruction.getRegisterA(), inlineMethodIdItem);
   3365 
   3366         analyzedInstruction.setDeodexedInstruction(deodexedInstruction);
   3367 
   3368         analyzeInstruction(analyzedInstruction);
   3369     }
   3370 
   3371     private void analyzeExecuteInlineRange(AnalyzedInstruction analyzedInstruction) {
   3372         if (deodexUtil == null) {
   3373             throw new ValidationException("Cannot analyze an odexed instruction unless we are deodexing");
   3374         }
   3375 
   3376         Instruction3rms instruction = (Instruction3rms)analyzedInstruction.instruction;
   3377 
   3378         DeodexUtil.InlineMethod inlineMethod = deodexUtil.lookupInlineMethod(analyzedInstruction);
   3379         MethodIdItem inlineMethodIdItem = inlineMethod.getMethodIdItem();
   3380         if (inlineMethodIdItem == null) {
   3381             throw new ValidationException(String.format("Cannot load inline method with index %d",
   3382                     instruction.getMethodIndex()));
   3383         }
   3384 
   3385         Opcode deodexedOpcode = null;
   3386         switch (inlineMethod.methodType) {
   3387             case DeodexUtil.Direct:
   3388                 deodexedOpcode = Opcode.INVOKE_DIRECT_RANGE;
   3389                 break;
   3390             case DeodexUtil.Static:
   3391                 deodexedOpcode = Opcode.INVOKE_STATIC_RANGE;
   3392                 break;
   3393             case DeodexUtil.Virtual:
   3394                 deodexedOpcode = Opcode.INVOKE_VIRTUAL_RANGE;
   3395                 break;
   3396             default:
   3397                 assert false;
   3398         }
   3399 
   3400         Instruction3rc deodexedInstruction = new Instruction3rc(deodexedOpcode, instruction.getRegCount(),
   3401                 instruction.getStartRegister(), inlineMethodIdItem);
   3402 
   3403         analyzedInstruction.setDeodexedInstruction(deodexedInstruction);
   3404 
   3405         analyzeInstruction(analyzedInstruction);
   3406     }
   3407 
   3408     private void analyzeInvokeDirectEmpty(AnalyzedInstruction analyzedInstruction) {
   3409         Instruction35s instruction = (Instruction35s)analyzedInstruction.instruction;
   3410 
   3411         Instruction35c deodexedInstruction = new Instruction35c(Opcode.INVOKE_DIRECT, instruction.getRegCount(),
   3412                 instruction.getRegisterD(), instruction.getRegisterE(), instruction.getRegisterF(),
   3413                 instruction.getRegisterG(), instruction.getRegisterA(), instruction.getReferencedItem());
   3414 
   3415         analyzedInstruction.setDeodexedInstruction(deodexedInstruction);
   3416 
   3417         analyzeInstruction(analyzedInstruction);
   3418     }
   3419 
   3420     private boolean analyzeIputIgetQuick(AnalyzedInstruction analyzedInstruction) {
   3421         Instruction22cs instruction = (Instruction22cs)analyzedInstruction.instruction;
   3422 
   3423         int fieldOffset = instruction.getFieldOffset();
   3424         RegisterType objectRegisterType = getAndCheckSourceRegister(analyzedInstruction, instruction.getRegisterB(),
   3425                 ReferenceOrUninitCategories);
   3426 
   3427         if (objectRegisterType.category == RegisterType.Category.Null) {
   3428             return false;
   3429         }
   3430 
   3431         FieldIdItem fieldIdItem = deodexUtil.lookupField(objectRegisterType.type, fieldOffset);
   3432         if (fieldIdItem == null) {
   3433             throw new ValidationException(String.format("Could not resolve the field in class %s at offset %d",
   3434                     objectRegisterType.type.getClassType(), fieldOffset));
   3435         }
   3436 
   3437         String fieldType = fieldIdItem.getFieldType().getTypeDescriptor();
   3438 
   3439         Opcode opcode = OdexedFieldInstructionMapper.getAndCheckDeodexedOpcodeForOdexedOpcode(fieldType, instruction.opcode);
   3440 
   3441         Instruction22c deodexedInstruction = new Instruction22c(opcode, (byte)instruction.getRegisterA(),
   3442                 (byte)instruction.getRegisterB(), fieldIdItem);
   3443         analyzedInstruction.setDeodexedInstruction(deodexedInstruction);
   3444 
   3445         analyzeInstruction(analyzedInstruction);
   3446 
   3447         return true;
   3448     }
   3449 
   3450     private boolean analyzeInvokeVirtualQuick(AnalyzedInstruction analyzedInstruction, boolean isSuper,
   3451                                               boolean isRange) {
   3452         int methodIndex;
   3453         int objectRegister;
   3454 
   3455 
   3456         if (isRange) {
   3457             Instruction3rms instruction = (Instruction3rms)analyzedInstruction.instruction;
   3458             methodIndex = instruction.getMethodIndex();
   3459             objectRegister = instruction.getStartRegister();
   3460         } else {
   3461             Instruction35ms instruction = (Instruction35ms)analyzedInstruction.instruction;
   3462             methodIndex = instruction.getMethodIndex();
   3463             objectRegister = instruction.getRegisterD();
   3464         }
   3465 
   3466         RegisterType objectRegisterType = getAndCheckSourceRegister(analyzedInstruction, objectRegister,
   3467                 ReferenceOrUninitCategories);
   3468 
   3469         if (objectRegisterType.category == RegisterType.Category.Null) {
   3470             return false;
   3471         }
   3472 
   3473         MethodIdItem methodIdItem = null;
   3474         if (isSuper) {
   3475             ClassPath.ClassDef classDef = ClassPath.getClassDef(this.encodedMethod.method.getContainingClass(), false);
   3476             assert classDef != null;
   3477 
   3478             if (classDef.getSuperclass() != null) {
   3479                 methodIdItem = deodexUtil.lookupVirtualMethod(classDef.getSuperclass(), methodIndex);
   3480             }
   3481 
   3482             if (methodIdItem == null) {
   3483                 //it's possible that the pre-odexed instruction had used the method from the current class instead
   3484                 //of from the superclass (although the superclass method is still what would actually be called).
   3485                 //And so the MethodIdItem for the superclass method may not be in the dex file. Let's try to get the
   3486                 //MethodIdItem for the method in the current class instead
   3487                 methodIdItem = deodexUtil.lookupVirtualMethod(classDef, methodIndex);
   3488             }
   3489         } else{
   3490             methodIdItem = deodexUtil.lookupVirtualMethod(objectRegisterType.type, methodIndex);
   3491         }
   3492 
   3493         if (methodIdItem == null) {
   3494             throw new ValidationException(String.format("Could not resolve the method in class %s at index %d",
   3495                     objectRegisterType.type.getClassType(), methodIndex));
   3496         }
   3497 
   3498 
   3499         Instruction deodexedInstruction;
   3500         if (isRange) {
   3501             Instruction3rms instruction = (Instruction3rms)analyzedInstruction.instruction;
   3502             Opcode opcode;
   3503             if (isSuper) {
   3504                 opcode = Opcode.INVOKE_SUPER_RANGE;
   3505             } else {
   3506                 opcode = Opcode.INVOKE_VIRTUAL_RANGE;
   3507             }
   3508 
   3509             deodexedInstruction = new Instruction3rc(opcode, instruction.getRegCount(),
   3510                     instruction.getStartRegister(), methodIdItem);
   3511         } else {
   3512             Instruction35ms instruction = (Instruction35ms)analyzedInstruction.instruction;
   3513             Opcode opcode;
   3514             if (isSuper) {
   3515                 opcode = Opcode.INVOKE_SUPER;
   3516             } else {
   3517                 opcode = Opcode.INVOKE_VIRTUAL;
   3518             }
   3519 
   3520             deodexedInstruction = new Instruction35c(opcode, instruction.getRegCount(),
   3521                     instruction.getRegisterD(), instruction.getRegisterE(), instruction.getRegisterF(),
   3522                     instruction.getRegisterG(), instruction.getRegisterA(), methodIdItem);
   3523         }
   3524 
   3525         analyzedInstruction.setDeodexedInstruction(deodexedInstruction);
   3526         analyzeInstruction(analyzedInstruction);
   3527 
   3528         return true;
   3529     }
   3530 
   3531     private boolean analyzePutGetVolatile(AnalyzedInstruction analyzedInstruction) {
   3532         FieldIdItem fieldIdItem =
   3533                 (FieldIdItem)(((InstructionWithReference)analyzedInstruction.instruction).getReferencedItem());
   3534 
   3535         String fieldType = fieldIdItem.getFieldType().getTypeDescriptor();
   3536 
   3537         Opcode opcode = OdexedFieldInstructionMapper.getAndCheckDeodexedOpcodeForOdexedOpcode(fieldType,
   3538                 analyzedInstruction.instruction.opcode);
   3539 
   3540         Instruction deodexedInstruction;
   3541 
   3542         if (analyzedInstruction.instruction.opcode.isOdexedStaticVolatile()) {
   3543             SingleRegisterInstruction instruction = (SingleRegisterInstruction)analyzedInstruction.instruction;
   3544 
   3545             deodexedInstruction = new Instruction21c(opcode, (byte)instruction.getRegisterA(),
   3546                 fieldIdItem);
   3547         } else {
   3548             TwoRegisterInstruction instruction = (TwoRegisterInstruction)analyzedInstruction.instruction;
   3549 
   3550             deodexedInstruction = new Instruction22c(opcode, (byte)instruction.getRegisterA(),
   3551                 (byte)instruction.getRegisterB(), fieldIdItem);
   3552         }
   3553 
   3554         analyzedInstruction.setDeodexedInstruction(deodexedInstruction);
   3555         analyzeInstruction(analyzedInstruction);
   3556 
   3557         return true;
   3558     }
   3559 
   3560     private static boolean checkArrayFieldAssignment(RegisterType.Category arrayFieldCategory,
   3561                                                   RegisterType.Category instructionCategory) {
   3562         if (arrayFieldCategory == instructionCategory) {
   3563             return true;
   3564         }
   3565 
   3566         if ((arrayFieldCategory == RegisterType.Category.Integer &&
   3567              instructionCategory == RegisterType.Category.Float) ||
   3568             (arrayFieldCategory == RegisterType.Category.Float &&
   3569              instructionCategory == RegisterType.Category.Integer)) {
   3570             return true;
   3571         }
   3572         return false;
   3573     }
   3574 
   3575     private static RegisterType getAndCheckSourceRegister(AnalyzedInstruction analyzedInstruction, int registerNumber,
   3576                                             EnumSet validCategories) {
   3577         assert registerNumber >= 0 && registerNumber < analyzedInstruction.postRegisterMap.length;
   3578 
   3579         RegisterType registerType = analyzedInstruction.getPreInstructionRegisterType(registerNumber);
   3580         assert registerType != null;
   3581 
   3582         checkRegister(registerType, registerNumber, validCategories);
   3583 
   3584         if (validCategories == WideLowCategories) {
   3585             checkRegister(registerType, registerNumber, WideLowCategories);
   3586             checkWidePair(registerNumber, analyzedInstruction);
   3587 
   3588             RegisterType secondRegisterType = analyzedInstruction.getPreInstructionRegisterType(registerNumber + 1);
   3589             assert secondRegisterType != null;
   3590             checkRegister(secondRegisterType, registerNumber+1, WideHighCategories);
   3591         }
   3592 
   3593         return registerType;
   3594     }
   3595 
   3596     private static void checkRegister(RegisterType registerType, int registerNumber, EnumSet validCategories) {
   3597         if (!validCategories.contains(registerType.category)) {
   3598             throw new ValidationException(String.format("Invalid register type %s for register v%d.",
   3599                     registerType.toString(), registerNumber));
   3600         }
   3601     }
   3602 
   3603     private static void checkWidePair(int registerNumber, AnalyzedInstruction analyzedInstruction) {
   3604         if (registerNumber + 1 >= analyzedInstruction.postRegisterMap.length) {
   3605             throw new ValidationException(String.format("v%d cannot be used as the first register in a wide register" +
   3606                     "pair because it is the last register.", registerNumber));
   3607         }
   3608     }
   3609 
   3610     private static interface RegisterIterator {
   3611         int getRegister();
   3612         boolean moveNext();
   3613         int getCount();
   3614         boolean pastEnd();
   3615     }
   3616 
   3617     private static class Format35cRegisterIterator implements RegisterIterator {
   3618         private final int registerCount;
   3619         private final int[] registers;
   3620         private int currentRegister = 0;
   3621 
   3622         public Format35cRegisterIterator(FiveRegisterInstruction instruction) {
   3623             registerCount = instruction.getRegCount();
   3624             registers = new int[]{instruction.getRegisterD(), instruction.getRegisterE(),
   3625                                   instruction.getRegisterF(), instruction.getRegisterG(),
   3626                                   instruction.getRegisterA()};
   3627         }
   3628 
   3629         public int getRegister() {
   3630             return registers[currentRegister];
   3631         }
   3632 
   3633         public boolean moveNext() {
   3634             currentRegister++;
   3635             return !pastEnd();
   3636         }
   3637 
   3638         public int getCount() {
   3639             return registerCount;
   3640         }
   3641 
   3642         public boolean pastEnd() {
   3643             return currentRegister >= registerCount;
   3644         }
   3645     }
   3646 
   3647     private static class Format3rcRegisterIterator implements RegisterIterator {
   3648         private final int startRegister;
   3649         private final int registerCount;
   3650         private int currentRegister = 0;
   3651 
   3652         public Format3rcRegisterIterator(RegisterRangeInstruction instruction) {
   3653             startRegister = instruction.getStartRegister();
   3654             registerCount = instruction.getRegCount();
   3655         }
   3656 
   3657         public int getRegister() {
   3658             return startRegister + currentRegister;
   3659         }
   3660 
   3661         public boolean moveNext() {
   3662             currentRegister++;
   3663             return !pastEnd();
   3664         }
   3665 
   3666         public int getCount() {
   3667             return registerCount;
   3668         }
   3669 
   3670         public boolean pastEnd() {
   3671             return currentRegister >= registerCount;
   3672         }
   3673     }
   3674 }
   3675