MethodAnalyzer.java revision e3478f4fd4a52a6dbbcc46b389ad7c8fcc1135ab
1f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)/*
2f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) * Copyright 2013, Google Inc.
3f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) * All rights reserved.
4f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) *
5f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) * Redistribution and use in source and binary forms, with or without
6f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) * modification, are permitted provided that the following conditions are
7f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) * met:
8f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) *
9f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) *     * Redistributions of source code must retain the above copyright
10f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) * notice, this list of conditions and the following disclaimer.
11f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) *     * Redistributions in binary form must reproduce the above
12f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) * copyright notice, this list of conditions and the following disclaimer
13f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) * in the documentation and/or other materials provided with the
14f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) * distribution.
15f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) *     * Neither the name of Google Inc. nor the names of its
16f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) * contributors may be used to endorse or promote products derived from
17f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) * this software without specific prior written permission.
18f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) *
195d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
205d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
215d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
225d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
235d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
245d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
255d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
265d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
275d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
285d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
295d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
305d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) */
315d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
325d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)package org.jf.dexlib2.analysis;
33f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
34f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)import com.google.common.collect.ImmutableList;
35f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)import org.jf.dexlib2.Opcode;
36f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)import org.jf.dexlib2.iface.*;
37f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)import org.jf.dexlib2.iface.instruction.*;
38f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)import org.jf.dexlib2.iface.instruction.formats.*;
39f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)import org.jf.dexlib2.iface.reference.FieldReference;
40f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)import org.jf.dexlib2.iface.reference.MethodReference;
41f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)import org.jf.dexlib2.iface.reference.Reference;
42f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)import org.jf.dexlib2.iface.reference.TypeReference;
435d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)import org.jf.dexlib2.immutable.instruction.*;
44f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)import org.jf.dexlib2.util.MethodUtil;
45f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)import org.jf.dexlib2.util.ReferenceUtil;
46f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)import org.jf.dexlib2.util.TypeUtils;
47f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)import org.jf.util.BitSetUtils;
485d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)import org.jf.util.ExceptionWithContext;
49f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)import org.jf.util.SparseArray;
50f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
51f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)import javax.annotation.Nonnull;
52f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)import javax.annotation.Nullable;
535d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)import java.util.BitSet;
54f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)import java.util.List;
55f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
56f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)/**
57f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) * The MethodAnalyzer performs several functions. It "analyzes" the instructions and infers the register types
585d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) * for each register, it can deodex odexed instructions, and it can verify the bytecode. The analysis and verification
59f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) * are done in two separate passes, because the analysis has to process instructions multiple times in some cases, and
60f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) * there's no need to perform the verification multiple times, so we wait until the method is fully analyzed and then
61f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) * verify it.
62f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) *
635d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) * Before calling the analyze() method, you must have initialized the ClassPath by calling
64f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) * ClassPath.InitializeClassPath
65f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) */
66f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)public class MethodAnalyzer {
67f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    @Nonnull private final Method method;
685d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    @Nonnull private final MethodImplementation methodImpl;
69f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
70f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    @Nonnull private final ClassPath classPath;
71f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    @Nullable private final InlineMethodResolver inlineResolver;
725d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
735d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    // This contains all the AnalyzedInstruction instances, keyed by the code unit address of the instruction
745d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    @Nonnull private final SparseArray<AnalyzedInstruction> analyzedInstructions =
755d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)            new SparseArray<AnalyzedInstruction>(0);
765d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
775d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    // Which instructions have been analyzed, keyed by instruction index
785d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    @Nonnull private final BitSet analyzedState;
795d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
805d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    @Nullable private AnalysisException analysisException = null;
815d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
825d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    //This is a dummy instruction that occurs immediately before the first real instruction. We can initialize the
835d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    //register types for this instruction to the parameter types, in order to have them propagate to all of its
845d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    //successors, e.g. the first real instruction, the first instructions in any exception handlers covering the first
855d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    //instruction, etc.
865d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    private final AnalyzedInstruction startOfMethod;
875d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
885d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    public MethodAnalyzer(@Nonnull ClassPath classPath, @Nonnull Method method,
895d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                          @Nullable InlineMethodResolver inlineResolver) {
905d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        this.classPath = classPath;
915d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        this.inlineResolver = inlineResolver;
925d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
935d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        this.method = method;
945d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
955d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        MethodImplementation methodImpl = method.getImplementation();
965d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        if (methodImpl == null) {
975d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)            throw new IllegalArgumentException("The method has no implementation");
985d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        }
995d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1005d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        this.methodImpl = methodImpl;
1015d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1025d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        //override AnalyzedInstruction and provide custom implementations of some of the methods, so that we don't
1035d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        //have to handle the case this special case of instruction being null, in the main class
1045d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        startOfMethod = new AnalyzedInstruction(null, -1, methodImpl.getRegisterCount()) {
1055d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)            public boolean setsRegister() {
1065d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                return false;
1075d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)            }
1085d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1095d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)            @Override
1105d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)            public boolean setsWideRegister() {
1115d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                return false;
1125d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)            }
1135d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1145d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)            @Override
1155d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)            public boolean setsRegister(int registerNumber) {
1165d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                return false;
1175d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)            }
1185d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1195d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)            @Override
1205d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)            public int getDestinationRegister() {
1215d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                assert false;
1225d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                return -1;
1235d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)            }
1245d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        };
1255d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1265d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        buildInstructionList();
1275d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1285d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        analyzedState = new BitSet(analyzedInstructions.size());
1295d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        analyze();
1305d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    }
1315d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1325d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    private void analyze() {
1335d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        Method method = this.method;
1345d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        MethodImplementation methodImpl = this.methodImpl;
1355d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1365d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        int totalRegisters = methodImpl.getRegisterCount();
1375d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        int parameterRegisters = MethodUtil.getParameterRegisterCount(method);
1385d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1395d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        int nonParameterRegisters = totalRegisters - parameterRegisters;
1405d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1415d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        //if this isn't a static method, determine which register is the "this" register and set the type to the
1425d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        //current class
1435d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        if (!MethodUtil.isStatic(method)) {
1445d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)            nonParameterRegisters--;
1455d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)            int thisRegister = totalRegisters - parameterRegisters;
1465d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1475d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)            //if this is a constructor, then set the "this" register to an uninitialized reference of the current class
1485d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)            if (MethodUtil.isConstructor(method)) {
1495d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                setPostRegisterTypeAndPropagateChanges(startOfMethod, thisRegister,
1505d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                        RegisterType.getRegisterType(RegisterType.UNINIT,
1515d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                classPath.getClass(method.getDefiningClass())));
1525d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)            } else {
1535d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                setPostRegisterTypeAndPropagateChanges(startOfMethod, thisRegister,
1545d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                        RegisterType.getRegisterType(RegisterType.REFERENCE,
1555d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                classPath.getClass(method.getDefiningClass())));
1565d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)            }
1575d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1585d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)            propagateParameterTypes(totalRegisters-parameterRegisters+1);
1595d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        } else {
1605d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)            propagateParameterTypes(totalRegisters-parameterRegisters);
1615d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        }
1625d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1635d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        RegisterType uninit = RegisterType.getRegisterType(RegisterType.UNINIT, null);
1645d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        for (int i=0; i<nonParameterRegisters; i++) {
1655d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)            setPostRegisterTypeAndPropagateChanges(startOfMethod, i, uninit);
1665d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        }
1675d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1685d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        BitSet instructionsToAnalyze = new BitSet(analyzedInstructions.size());
1695d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1705d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        //make sure all of the "first instructions" are marked for processing
1715d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        for (AnalyzedInstruction successor: startOfMethod.successors) {
1725d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)            instructionsToAnalyze.set(successor.instructionIndex);
1735d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        }
1745d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1755d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        BitSet undeodexedInstructions = new BitSet(analyzedInstructions.size());
1765d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1775d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        do {
1785d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)            boolean didSomething = false;
1795d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1805d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)            while (!instructionsToAnalyze.isEmpty()) {
1815d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                for(int i=instructionsToAnalyze.nextSetBit(0); i>=0; i=instructionsToAnalyze.nextSetBit(i+1)) {
1825d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                    instructionsToAnalyze.clear(i);
1835d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                    if (analyzedState.get(i)) {
1845d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                        continue;
1855d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                    }
1865d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                    AnalyzedInstruction instructionToAnalyze = analyzedInstructions.valueAt(i);
1875d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                    try {
1885d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                        if (instructionToAnalyze.originalInstruction.getOpcode().odexOnly()) {
1895d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                            //if we had deodexed an odex instruction in a previous pass, we might have more specific
1905d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                            //register information now, so let's restore the original odexed instruction and
1915d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                            //re-deodex it
1925d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                            instructionToAnalyze.restoreOdexedInstruction();
1935d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                        }
1945d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1955d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                        if (!analyzeInstruction(instructionToAnalyze)) {
1965d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                            undeodexedInstructions.set(i);
1975d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                            continue;
1985d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                        } else {
1995d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                            didSomething = true;
2005d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                            undeodexedInstructions.clear(i);
2015d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                        }
2025d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                    } catch (AnalysisException ex) {
2035d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                        this.analysisException = ex;
2045d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                        int codeAddress = getInstructionAddress(instructionToAnalyze);
2055d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                        ex.addContext(String.format("opcode: %s", instructionToAnalyze.instruction.getOpcode().name));
2065d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                        ex.addContext(String.format("code address: %d", codeAddress));
2075d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                        ex.addContext(String.format("method: %s", ReferenceUtil.getReferenceString(method)));
2085d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                        break;
2095d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                    }
2105d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
2115d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                    analyzedState.set(instructionToAnalyze.getInstructionIndex());
2125d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
2135d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                    for (AnalyzedInstruction successor: instructionToAnalyze.successors) {
2145d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                        instructionsToAnalyze.set(successor.getInstructionIndex());
2155d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                    }
2165d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                }
2175d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                if (analysisException != null) {
2185d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                    break;
2195d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                }
2205d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)            }
2215d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
2225d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)            if (!didSomething) {
2235d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                break;
2245d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)            }
2255d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
2265d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)            if (!undeodexedInstructions.isEmpty()) {
2275d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                for (int i=undeodexedInstructions.nextSetBit(0); i>=0; i=undeodexedInstructions.nextSetBit(i+1)) {
2285d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                    instructionsToAnalyze.set(i);
2295d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                }
2305d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)            }
2315d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        } while (true);
2325d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
2335d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        //Now, go through and fix up any unresolvable odex instructions. These are usually odex instructions
2345d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        //that operate on a null register, and thus always throw an NPE. They can also be any sort of odex instruction
2355d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        //that occurs after an unresolvable odex instruction. We deodex if possible, or replace with an
2365d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        //UnresolvableOdexInstruction
2375d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        for (int i=0; i< analyzedInstructions.size(); i++) {
2385d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)            AnalyzedInstruction analyzedInstruction = analyzedInstructions.valueAt(i);
2395d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
2405d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)            Instruction instruction = analyzedInstruction.getInstruction();
2415d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
2425d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)            if (instruction.getOpcode().odexOnly()) {
2435d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                int objectRegisterNumber;
2445d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                switch (instruction.getOpcode().format) {
2455d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                    case Format10x:
2465d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                        analyzeReturnVoidBarrier(analyzedInstruction, false);
2475d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                        continue;
2485d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                    case Format21c:
2495d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                    case Format22c:
2505d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                        analyzePutGetVolatile(analyzedInstruction, false);
2515d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                        continue;
2525d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                    case Format35c:
2535d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                        analyzeInvokeDirectEmpty(analyzedInstruction, false);
2545d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                        continue;
2555d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                    case Format3rc:
2565d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                        analyzeInvokeObjectInitRange(analyzedInstruction, false);
2575d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                        continue;
2585d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                    case Format22cs:
2595d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                        objectRegisterNumber = ((Instruction22cs)instruction).getRegisterB();
2605d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                        break;
2615d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                    case Format35mi:
2625d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                    case Format35ms:
2635d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                        objectRegisterNumber = ((FiveRegisterInstruction)instruction).getRegisterD();
2645d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                        break;
2655d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                    case Format3rmi:
2665d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                    case Format3rms:
2675d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                        objectRegisterNumber = ((RegisterRangeInstruction)instruction).getStartRegister();
2685d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                        break;
2695d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                    default:
2705d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                        continue;
2715d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                }
2725d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
2735d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                analyzedInstruction.setDeodexedInstruction(
2745d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                        new UnresolvedOdexInstruction(instruction, objectRegisterNumber));
2755d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)            }
2765d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        }
2775d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    }
2785d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
2795d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    private void propagateParameterTypes(int parameterStartRegister) {
2805d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        int i=0;
2815d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        for (MethodParameter parameter: method.getParameters()) {
2825d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)            if (TypeUtils.isWideType(parameter)) {
2835d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                setPostRegisterTypeAndPropagateChanges(startOfMethod, parameterStartRegister + i++,
2845d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                        RegisterType.getWideRegisterType(parameter, true));
2855d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                setPostRegisterTypeAndPropagateChanges(startOfMethod, parameterStartRegister + i++,
2865d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                        RegisterType.getWideRegisterType(parameter, false));
2875d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)            } else {
2885d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                setPostRegisterTypeAndPropagateChanges(startOfMethod, parameterStartRegister + i++,
2895d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                        RegisterType.getRegisterType(classPath, parameter));
2905d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)            }
2915d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        }
2925d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
2935d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    }
2945d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
2955d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    public int getInstructionAddress(@Nonnull AnalyzedInstruction instruction) {
2965d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        return analyzedInstructions.keyAt(instruction.instructionIndex);
2975d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    }
2985d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
2995d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    private void setDestinationRegisterTypeAndPropagateChanges(@Nonnull AnalyzedInstruction analyzedInstruction,
3005d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                                               @Nonnull RegisterType registerType) {
3015d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        setPostRegisterTypeAndPropagateChanges(analyzedInstruction, analyzedInstruction.getDestinationRegister(),
3025d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                registerType);
3035d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    }
3045d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
3055d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    private void setPostRegisterTypeAndPropagateChanges(@Nonnull AnalyzedInstruction analyzedInstruction,
3065d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                                        int registerNumber, @Nonnull RegisterType registerType) {
3075d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
3085d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        BitSet changedInstructions = new BitSet(analyzedInstructions.size());
3095d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
3105d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        if (!analyzedInstruction.setPostRegisterType(registerNumber, registerType)) {
3115d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)            return;
3125d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        }
3135d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
3145d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        propagateRegisterToSuccessors(analyzedInstruction, registerNumber, changedInstructions);
3155d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
3165d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        //Using a for loop inside the while loop optimizes for the common case of the successors of an instruction
3175d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        //occurring after the instruction. Any successors that occur prior to the instruction will be picked up on
3185d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        //the next iteration of the while loop.
3195d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        //This could also be done recursively, but in large methods it would likely cause very deep recursion,
3205d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        //which requires the user to specify a larger stack size. This isn't really a problem, but it is slightly
3215d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        //annoying.
3225d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        while (!changedInstructions.isEmpty()) {
3235d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)            for (int instructionIndex=changedInstructions.nextSetBit(0);
3245d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                     instructionIndex>=0;
3255d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                     instructionIndex=changedInstructions.nextSetBit(instructionIndex+1)) {
3265d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
3275d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                changedInstructions.clear(instructionIndex);
3285d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
3295d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                propagateRegisterToSuccessors(analyzedInstructions.valueAt(instructionIndex), registerNumber,
3305d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                        changedInstructions);
3315d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)            }
3325d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        }
3335d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
3345d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        if (registerType.category == RegisterType.LONG_LO) {
3355d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)            checkWidePair(registerNumber, analyzedInstruction);
3365d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)            setPostRegisterTypeAndPropagateChanges(analyzedInstruction, registerNumber+1, RegisterType.LONG_HI_TYPE);
3375d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        } else if (registerType.category == RegisterType.DOUBLE_LO) {
3385d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)            checkWidePair(registerNumber, analyzedInstruction);
3395d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)            setPostRegisterTypeAndPropagateChanges(analyzedInstruction, registerNumber+1, RegisterType.DOUBLE_HI_TYPE);
3405d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        }
3415d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    }
3425d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
3435d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    private void propagateRegisterToSuccessors(@Nonnull AnalyzedInstruction instruction, int registerNumber,
3445d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                               @Nonnull BitSet changedInstructions) {
3455d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        RegisterType postRegisterType = instruction.getPostInstructionRegisterType(registerNumber);
3465d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        for (AnalyzedInstruction successor: instruction.successors) {
3475d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)            if (successor.mergeRegister(registerNumber, postRegisterType, analyzedState)) {
3485d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                changedInstructions.set(successor.instructionIndex);
3495d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)            }
3505d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        }
3515d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    }
3525d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
3535d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    private void buildInstructionList() {
3545d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        int registerCount = methodImpl.getRegisterCount();
3555d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
3565d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        ImmutableList<Instruction> instructions = ImmutableList.copyOf(methodImpl.getInstructions());
3575d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
3585d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        analyzedInstructions.ensureCapacity(instructions.size());
3595d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
3605d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        //first, create all the instructions and populate the instructionAddresses array
3615d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        int currentCodeAddress = 0;
3625d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        for (int i=0; i<instructions.size(); i++) {
3635d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)            Instruction instruction = instructions.get(i);
3645d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)            analyzedInstructions.append(currentCodeAddress, new AnalyzedInstruction(instruction, i, registerCount));
3655d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)            assert analyzedInstructions.indexOfKey(currentCodeAddress) == i;
3665d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)            currentCodeAddress += instruction.getCodeUnits();
3675d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        }
3685d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
3695d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        //next, populate the exceptionHandlers array. The array item for each instruction that can throw an exception
3705d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        //and is covered by a try block should be set to a list of the first instructions of each exception handler
3715d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        //for the try block covering the instruction
3725d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        List<? extends TryBlock> tries = methodImpl.getTryBlocks();
3735d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        int triesIndex = 0;
3745d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        TryBlock currentTry = null;
3755d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        AnalyzedInstruction[] currentExceptionHandlers = null;
3765d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        AnalyzedInstruction[][] exceptionHandlers = new AnalyzedInstruction[instructions.size()][];
3775d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
3785d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        if (tries != null) {
3795d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)            for (int i=0; i< analyzedInstructions.size(); i++) {
3805d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                AnalyzedInstruction instruction = analyzedInstructions.valueAt(i);
3815d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                Opcode instructionOpcode = instruction.instruction.getOpcode();
382f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)                currentCodeAddress = getInstructionAddress(instruction);
383f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
384f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)                //check if we have gone past the end of the current try
385                if (currentTry != null) {
386                    if (currentTry.getStartCodeAddress() + currentTry.getCodeUnitCount()  <= currentCodeAddress) {
387                        currentTry = null;
388                        triesIndex++;
389                    }
390                }
391
392                //check if the next try is applicable yet
393                if (currentTry == null && triesIndex < tries.size()) {
394                    TryBlock tryBlock = tries.get(triesIndex);
395                    if (tryBlock.getStartCodeAddress() <= currentCodeAddress) {
396                        assert(tryBlock.getStartCodeAddress() + tryBlock.getCodeUnitCount() > currentCodeAddress);
397
398                        currentTry = tryBlock;
399
400                        currentExceptionHandlers = buildExceptionHandlerArray(tryBlock);
401                    }
402                }
403
404                //if we're inside a try block, and the instruction can throw an exception, then add the exception handlers
405                //for the current instruction
406                if (currentTry != null && instructionOpcode.canThrow()) {
407                    exceptionHandlers[i] = currentExceptionHandlers;
408                }
409            }
410        }
411
412        //finally, populate the successors and predecessors for each instruction. We start at the fake "StartOfMethod"
413        //instruction and follow the execution path. Any unreachable code won't have any predecessors or successors,
414        //and no reachable code will have an unreachable predessor or successor
415        assert analyzedInstructions.size() > 0;
416        BitSet instructionsToProcess = new BitSet(instructions.size());
417
418        addPredecessorSuccessor(startOfMethod, analyzedInstructions.valueAt(0), exceptionHandlers, instructionsToProcess);
419        while (!instructionsToProcess.isEmpty()) {
420            int currentInstructionIndex = instructionsToProcess.nextSetBit(0);
421            instructionsToProcess.clear(currentInstructionIndex);
422
423            AnalyzedInstruction instruction = analyzedInstructions.valueAt(currentInstructionIndex);
424            Opcode instructionOpcode = instruction.instruction.getOpcode();
425            int instructionCodeAddress = getInstructionAddress(instruction);
426
427            if (instruction.instruction.getOpcode().canContinue()) {
428                if (currentInstructionIndex == analyzedInstructions.size() - 1) {
429                    throw new AnalysisException("Execution can continue past the last instruction");
430                }
431
432                AnalyzedInstruction nextInstruction = analyzedInstructions.valueAt(currentInstructionIndex+1);
433                addPredecessorSuccessor(instruction, nextInstruction, exceptionHandlers, instructionsToProcess);
434            }
435
436            if (instruction.instruction instanceof OffsetInstruction) {
437                OffsetInstruction offsetInstruction = (OffsetInstruction)instruction.instruction;
438
439                if (instructionOpcode == Opcode.PACKED_SWITCH || instructionOpcode == Opcode.SPARSE_SWITCH) {
440                    SwitchPayload switchPayload = (SwitchPayload)analyzedInstructions.get(instructionCodeAddress +
441                                    offsetInstruction.getCodeOffset()).instruction;
442                    for (SwitchElement switchElement: switchPayload.getSwitchElements()) {
443                        AnalyzedInstruction targetInstruction = analyzedInstructions.get(instructionCodeAddress +
444                                switchElement.getOffset());
445
446                        addPredecessorSuccessor(instruction, targetInstruction, exceptionHandlers,
447                                instructionsToProcess);
448                    }
449                } else {
450                    int targetAddressOffset = offsetInstruction.getCodeOffset();
451                    AnalyzedInstruction targetInstruction = analyzedInstructions.get(instructionCodeAddress +
452                            targetAddressOffset);
453                    addPredecessorSuccessor(instruction, targetInstruction, exceptionHandlers, instructionsToProcess);
454                }
455            }
456        }
457    }
458
459    private void addPredecessorSuccessor(@Nonnull AnalyzedInstruction predecessor,
460                                         @Nonnull AnalyzedInstruction successor,
461                                         @Nonnull AnalyzedInstruction[][] exceptionHandlers,
462                                         @Nonnull BitSet instructionsToProcess) {
463        addPredecessorSuccessor(predecessor, successor, exceptionHandlers, instructionsToProcess, false);
464    }
465
466    private void addPredecessorSuccessor(@Nonnull AnalyzedInstruction predecessor,
467                                         @Nonnull AnalyzedInstruction successor,
468                                         @Nonnull AnalyzedInstruction[][] exceptionHandlers,
469                                         @Nonnull BitSet instructionsToProcess, boolean allowMoveException) {
470
471        if (!allowMoveException && successor.instruction.getOpcode() == Opcode.MOVE_EXCEPTION) {
472            throw new AnalysisException("Execution can pass from the " + predecessor.instruction.getOpcode().name +
473                    " instruction at code address 0x" + Integer.toHexString(getInstructionAddress(predecessor)) +
474                    " to the move-exception instruction at address 0x" +
475                    Integer.toHexString(getInstructionAddress(successor)));
476        }
477
478        if (!successor.addPredecessor(predecessor)) {
479            return;
480        }
481
482        predecessor.addSuccessor(successor);
483        instructionsToProcess.set(successor.getInstructionIndex());
484
485
486        //if the successor can throw an instruction, then we need to add the exception handlers as additional
487        //successors to the predecessor (and then apply this same logic recursively if needed)
488        //Technically, we should handle the monitor-exit instruction as a special case. The exception is actually
489        //thrown *after* the instruction executes, instead of "before" the instruction executes, lke for any other
490        //instruction. But since it doesn't modify any registers, we can treat it like any other instruction.
491        AnalyzedInstruction[] exceptionHandlersForSuccessor = exceptionHandlers[successor.instructionIndex];
492        if (exceptionHandlersForSuccessor != null) {
493            //the item for this instruction in exceptionHandlersForSuccessor should only be set if this instruction
494            //can throw an exception
495            assert successor.instruction.getOpcode().canThrow();
496
497            for (AnalyzedInstruction exceptionHandler: exceptionHandlersForSuccessor) {
498                addPredecessorSuccessor(predecessor, exceptionHandler, exceptionHandlers, instructionsToProcess, true);
499            }
500        }
501    }
502
503    @Nonnull
504    private AnalyzedInstruction[] buildExceptionHandlerArray(@Nonnull TryBlock tryBlock) {
505        List<? extends ExceptionHandler> exceptionHandlers = tryBlock.getExceptionHandlers();
506
507        AnalyzedInstruction[] handlerInstructions = new AnalyzedInstruction[exceptionHandlers.size()];
508        for (int i=0; i<exceptionHandlers.size(); i++) {
509            handlerInstructions[i] = analyzedInstructions.get(exceptionHandlers.get(i).getHandlerCodeAddress());
510        }
511
512        return handlerInstructions;
513    }
514
515    /**
516     * @return false if analyzedInstruction is an odex instruction that couldn't be deodexed, due to its
517     * object register being null
518     */
519    private boolean analyzeInstruction(@Nonnull AnalyzedInstruction analyzedInstruction) {
520        Instruction instruction = analyzedInstruction.instruction;
521
522        switch (instruction.getOpcode()) {
523            case NOP:
524                return true;
525            case MOVE:
526            case MOVE_FROM16:
527            case MOVE_16:
528            case MOVE_WIDE:
529            case MOVE_WIDE_FROM16:
530            case MOVE_WIDE_16:
531            case MOVE_OBJECT:
532            case MOVE_OBJECT_FROM16:
533            case MOVE_OBJECT_16:
534                analyzeMove(analyzedInstruction);
535                return true;
536            case MOVE_RESULT:
537            case MOVE_RESULT_WIDE:
538            case MOVE_RESULT_OBJECT:
539                analyzeMoveResult(analyzedInstruction);
540                return true;
541            case MOVE_EXCEPTION:
542                analyzeMoveException(analyzedInstruction);
543                return true;
544            case RETURN_VOID:
545            case RETURN:
546            case RETURN_WIDE:
547            case RETURN_OBJECT:
548                return true;
549            case RETURN_VOID_BARRIER:
550                analyzeReturnVoidBarrier(analyzedInstruction);
551                return true;
552            case CONST_4:
553            case CONST_16:
554            case CONST:
555            case CONST_HIGH16:
556                analyzeConst(analyzedInstruction);
557                return true;
558            case CONST_WIDE_16:
559            case CONST_WIDE_32:
560            case CONST_WIDE:
561            case CONST_WIDE_HIGH16:
562                analyzeWideConst(analyzedInstruction);
563                return true;
564            case CONST_STRING:
565            case CONST_STRING_JUMBO:
566                analyzeConstString(analyzedInstruction);
567                return true;
568            case CONST_CLASS:
569                analyzeConstClass(analyzedInstruction);
570                return true;
571            case MONITOR_ENTER:
572            case MONITOR_EXIT:
573                return true;
574            case CHECK_CAST:
575                analyzeCheckCast(analyzedInstruction);
576                return true;
577            case INSTANCE_OF:
578                analyzeInstanceOf(analyzedInstruction);
579                return true;
580            case ARRAY_LENGTH:
581                analyzeArrayLength(analyzedInstruction);
582                return true;
583            case NEW_INSTANCE:
584                analyzeNewInstance(analyzedInstruction);
585                return true;
586            case NEW_ARRAY:
587                analyzeNewArray(analyzedInstruction);
588                return true;
589            case FILLED_NEW_ARRAY:
590            case FILLED_NEW_ARRAY_RANGE:
591                return true;
592            case FILL_ARRAY_DATA:
593                return true;
594            case THROW:
595            case GOTO:
596            case GOTO_16:
597            case GOTO_32:
598                return true;
599            case PACKED_SWITCH:
600            case SPARSE_SWITCH:
601                return true;
602            case CMPL_FLOAT:
603            case CMPG_FLOAT:
604            case CMPL_DOUBLE:
605            case CMPG_DOUBLE:
606            case CMP_LONG:
607                analyzeFloatWideCmp(analyzedInstruction);
608                return true;
609            case IF_EQ:
610            case IF_NE:
611            case IF_LT:
612            case IF_GE:
613            case IF_GT:
614            case IF_LE:
615            case IF_EQZ:
616            case IF_NEZ:
617            case IF_LTZ:
618            case IF_GEZ:
619            case IF_GTZ:
620            case IF_LEZ:
621                return true;
622            case AGET:
623                analyze32BitPrimitiveAget(analyzedInstruction, RegisterType.INTEGER_TYPE);
624                return true;
625            case AGET_BOOLEAN:
626                analyze32BitPrimitiveAget(analyzedInstruction, RegisterType.BOOLEAN_TYPE);
627                return true;
628            case AGET_BYTE:
629                analyze32BitPrimitiveAget(analyzedInstruction, RegisterType.BYTE_TYPE);
630                return true;
631            case AGET_CHAR:
632                analyze32BitPrimitiveAget(analyzedInstruction, RegisterType.CHAR_TYPE);
633                return true;
634            case AGET_SHORT:
635                analyze32BitPrimitiveAget(analyzedInstruction, RegisterType.SHORT_TYPE);
636                return true;
637            case AGET_WIDE:
638                analyzeAgetWide(analyzedInstruction);
639                return true;
640            case AGET_OBJECT:
641                analyzeAgetObject(analyzedInstruction);
642                return true;
643            case APUT:
644            case APUT_BOOLEAN:
645            case APUT_BYTE:
646            case APUT_CHAR:
647            case APUT_SHORT:
648            case APUT_WIDE:
649            case APUT_OBJECT:
650                return true;
651            case IGET:
652                analyze32BitPrimitiveIgetSget(analyzedInstruction, RegisterType.INTEGER_TYPE);
653                return true;
654            case IGET_BOOLEAN:
655                analyze32BitPrimitiveIgetSget(analyzedInstruction, RegisterType.BOOLEAN_TYPE);
656                return true;
657            case IGET_BYTE:
658                analyze32BitPrimitiveIgetSget(analyzedInstruction, RegisterType.BYTE_TYPE);
659                return true;
660            case IGET_CHAR:
661                analyze32BitPrimitiveIgetSget(analyzedInstruction, RegisterType.CHAR_TYPE);
662                return true;
663            case IGET_SHORT:
664                analyze32BitPrimitiveIgetSget(analyzedInstruction, RegisterType.SHORT_TYPE);
665                return true;
666            case IGET_WIDE:
667            case IGET_OBJECT:
668                analyzeIgetSgetWideObject(analyzedInstruction);
669                return true;
670            case IPUT:
671            case IPUT_BOOLEAN:
672            case IPUT_BYTE:
673            case IPUT_CHAR:
674            case IPUT_SHORT:
675            case IPUT_WIDE:
676            case IPUT_OBJECT:
677                return true;
678            case SGET:
679                analyze32BitPrimitiveIgetSget(analyzedInstruction, RegisterType.INTEGER_TYPE);
680                return true;
681            case SGET_BOOLEAN:
682                analyze32BitPrimitiveIgetSget(analyzedInstruction, RegisterType.BOOLEAN_TYPE);
683                return true;
684            case SGET_BYTE:
685                analyze32BitPrimitiveIgetSget(analyzedInstruction, RegisterType.BYTE_TYPE);
686                return true;
687            case SGET_CHAR:
688                analyze32BitPrimitiveIgetSget(analyzedInstruction, RegisterType.CHAR_TYPE);
689                return true;
690            case SGET_SHORT:
691                analyze32BitPrimitiveIgetSget(analyzedInstruction, RegisterType.SHORT_TYPE);
692                return true;
693            case SGET_WIDE:
694            case SGET_OBJECT:
695                analyzeIgetSgetWideObject(analyzedInstruction);
696                return true;
697            case SPUT:
698            case SPUT_BOOLEAN:
699            case SPUT_BYTE:
700            case SPUT_CHAR:
701            case SPUT_SHORT:
702            case SPUT_WIDE:
703            case SPUT_OBJECT:
704                return true;
705            case INVOKE_VIRTUAL:
706            case INVOKE_SUPER:
707                return true;
708            case INVOKE_DIRECT:
709                analyzeInvokeDirect(analyzedInstruction);
710                return true;
711            case INVOKE_STATIC:
712            case INVOKE_INTERFACE:
713            case INVOKE_VIRTUAL_RANGE:
714            case INVOKE_SUPER_RANGE:
715                return true;
716            case INVOKE_DIRECT_RANGE:
717                analyzeInvokeDirectRange(analyzedInstruction);
718                return true;
719            case INVOKE_STATIC_RANGE:
720            case INVOKE_INTERFACE_RANGE:
721                return true;
722            case NEG_INT:
723            case NOT_INT:
724                analyzeUnaryOp(analyzedInstruction, RegisterType.INTEGER_TYPE);
725                return true;
726            case NEG_LONG:
727            case NOT_LONG:
728                analyzeUnaryOp(analyzedInstruction, RegisterType.LONG_LO_TYPE);
729                return true;
730            case NEG_FLOAT:
731                analyzeUnaryOp(analyzedInstruction, RegisterType.FLOAT_TYPE);
732                return true;
733            case NEG_DOUBLE:
734                analyzeUnaryOp(analyzedInstruction, RegisterType.DOUBLE_LO_TYPE);
735                return true;
736            case INT_TO_LONG:
737                analyzeUnaryOp(analyzedInstruction, RegisterType.LONG_LO_TYPE);
738                return true;
739            case INT_TO_FLOAT:
740                analyzeUnaryOp(analyzedInstruction, RegisterType.FLOAT_TYPE);
741                return true;
742            case INT_TO_DOUBLE:
743                analyzeUnaryOp(analyzedInstruction, RegisterType.DOUBLE_LO_TYPE);
744                return true;
745            case LONG_TO_INT:
746            case DOUBLE_TO_INT:
747                analyzeUnaryOp(analyzedInstruction, RegisterType.INTEGER_TYPE);
748                return true;
749            case LONG_TO_FLOAT:
750            case DOUBLE_TO_FLOAT:
751                analyzeUnaryOp(analyzedInstruction, RegisterType.FLOAT_TYPE);
752                return true;
753            case LONG_TO_DOUBLE:
754                analyzeUnaryOp(analyzedInstruction, RegisterType.DOUBLE_LO_TYPE);
755                return true;
756            case FLOAT_TO_INT:
757                analyzeUnaryOp(analyzedInstruction, RegisterType.INTEGER_TYPE);
758                return true;
759            case FLOAT_TO_LONG:
760                analyzeUnaryOp(analyzedInstruction, RegisterType.LONG_LO_TYPE);
761                return true;
762            case FLOAT_TO_DOUBLE:
763                analyzeUnaryOp(analyzedInstruction, RegisterType.DOUBLE_LO_TYPE);
764                return true;
765            case DOUBLE_TO_LONG:
766                analyzeUnaryOp(analyzedInstruction, RegisterType.LONG_LO_TYPE);
767                return true;
768            case INT_TO_BYTE:
769                analyzeUnaryOp(analyzedInstruction, RegisterType.BYTE_TYPE);
770                return true;
771            case INT_TO_CHAR:
772                analyzeUnaryOp(analyzedInstruction, RegisterType.CHAR_TYPE);
773                return true;
774            case INT_TO_SHORT:
775                analyzeUnaryOp(analyzedInstruction, RegisterType.SHORT_TYPE);
776                return true;
777            case ADD_INT:
778            case SUB_INT:
779            case MUL_INT:
780            case DIV_INT:
781            case REM_INT:
782            case SHL_INT:
783            case SHR_INT:
784            case USHR_INT:
785                analyzeBinaryOp(analyzedInstruction, RegisterType.INTEGER_TYPE, false);
786                return true;
787            case AND_INT:
788            case OR_INT:
789            case XOR_INT:
790                analyzeBinaryOp(analyzedInstruction, RegisterType.INTEGER_TYPE, true);
791                return true;
792            case ADD_LONG:
793            case SUB_LONG:
794            case MUL_LONG:
795            case DIV_LONG:
796            case REM_LONG:
797            case AND_LONG:
798            case OR_LONG:
799            case XOR_LONG:
800            case SHL_LONG:
801            case SHR_LONG:
802            case USHR_LONG:
803                analyzeBinaryOp(analyzedInstruction, RegisterType.LONG_LO_TYPE, false);
804                return true;
805            case ADD_FLOAT:
806            case SUB_FLOAT:
807            case MUL_FLOAT:
808            case DIV_FLOAT:
809            case REM_FLOAT:
810                analyzeBinaryOp(analyzedInstruction, RegisterType.FLOAT_TYPE, false);
811                return true;
812            case ADD_DOUBLE:
813            case SUB_DOUBLE:
814            case MUL_DOUBLE:
815            case DIV_DOUBLE:
816            case REM_DOUBLE:
817                analyzeBinaryOp(analyzedInstruction, RegisterType.DOUBLE_LO_TYPE, false);
818                return true;
819            case ADD_INT_2ADDR:
820            case SUB_INT_2ADDR:
821            case MUL_INT_2ADDR:
822            case DIV_INT_2ADDR:
823            case REM_INT_2ADDR:
824            case SHL_INT_2ADDR:
825            case SHR_INT_2ADDR:
826            case USHR_INT_2ADDR:
827                analyzeBinary2AddrOp(analyzedInstruction, RegisterType.INTEGER_TYPE, false);
828                return true;
829            case AND_INT_2ADDR:
830            case OR_INT_2ADDR:
831            case XOR_INT_2ADDR:
832                analyzeBinary2AddrOp(analyzedInstruction, RegisterType.INTEGER_TYPE, true);
833                return true;
834            case ADD_LONG_2ADDR:
835            case SUB_LONG_2ADDR:
836            case MUL_LONG_2ADDR:
837            case DIV_LONG_2ADDR:
838            case REM_LONG_2ADDR:
839            case AND_LONG_2ADDR:
840            case OR_LONG_2ADDR:
841            case XOR_LONG_2ADDR:
842            case SHL_LONG_2ADDR:
843            case SHR_LONG_2ADDR:
844            case USHR_LONG_2ADDR:
845                analyzeBinary2AddrOp(analyzedInstruction, RegisterType.LONG_LO_TYPE, false);
846                return true;
847            case ADD_FLOAT_2ADDR:
848            case SUB_FLOAT_2ADDR:
849            case MUL_FLOAT_2ADDR:
850            case DIV_FLOAT_2ADDR:
851            case REM_FLOAT_2ADDR:
852                analyzeBinary2AddrOp(analyzedInstruction, RegisterType.FLOAT_TYPE, false);
853                return true;
854            case ADD_DOUBLE_2ADDR:
855            case SUB_DOUBLE_2ADDR:
856            case MUL_DOUBLE_2ADDR:
857            case DIV_DOUBLE_2ADDR:
858            case REM_DOUBLE_2ADDR:
859                analyzeBinary2AddrOp(analyzedInstruction, RegisterType.DOUBLE_LO_TYPE, false);
860                return true;
861            case ADD_INT_LIT16:
862            case RSUB_INT:
863            case MUL_INT_LIT16:
864            case DIV_INT_LIT16:
865            case REM_INT_LIT16:
866                analyzeLiteralBinaryOp(analyzedInstruction, RegisterType.INTEGER_TYPE, false);
867                return true;
868            case AND_INT_LIT16:
869            case OR_INT_LIT16:
870            case XOR_INT_LIT16:
871                analyzeLiteralBinaryOp(analyzedInstruction, RegisterType.INTEGER_TYPE, true);
872                return true;
873            case ADD_INT_LIT8:
874            case RSUB_INT_LIT8:
875            case MUL_INT_LIT8:
876            case DIV_INT_LIT8:
877            case REM_INT_LIT8:
878            case SHL_INT_LIT8:
879                analyzeLiteralBinaryOp(analyzedInstruction, RegisterType.INTEGER_TYPE, false);
880                return true;
881            case AND_INT_LIT8:
882            case OR_INT_LIT8:
883            case XOR_INT_LIT8:
884                analyzeLiteralBinaryOp(analyzedInstruction, RegisterType.INTEGER_TYPE, true);
885                return true;
886            case SHR_INT_LIT8:
887                analyzeLiteralBinaryOp(analyzedInstruction, getDestTypeForLiteralShiftRight(analyzedInstruction, true),
888                        false);
889                return true;
890            case USHR_INT_LIT8:
891                analyzeLiteralBinaryOp(analyzedInstruction, getDestTypeForLiteralShiftRight(analyzedInstruction, false),
892                        false);
893                return true;
894
895            /*odexed instructions*/
896            case IGET_VOLATILE:
897            case IPUT_VOLATILE:
898            case SGET_VOLATILE:
899            case SPUT_VOLATILE:
900            case IGET_OBJECT_VOLATILE:
901            case IGET_WIDE_VOLATILE:
902            case IPUT_WIDE_VOLATILE:
903            case SGET_WIDE_VOLATILE:
904            case SPUT_WIDE_VOLATILE:
905                analyzePutGetVolatile(analyzedInstruction);
906                return true;
907            case THROW_VERIFICATION_ERROR:
908                return true;
909            case EXECUTE_INLINE:
910                analyzeExecuteInline(analyzedInstruction);
911                return true;
912            case EXECUTE_INLINE_RANGE:
913                analyzeExecuteInlineRange(analyzedInstruction);
914                return true;
915            case INVOKE_DIRECT_EMPTY:
916                analyzeInvokeDirectEmpty(analyzedInstruction);
917                return true;
918            case INVOKE_OBJECT_INIT_RANGE:
919                analyzeInvokeObjectInitRange(analyzedInstruction);
920                return true;
921            case IGET_QUICK:
922            case IGET_WIDE_QUICK:
923            case IGET_OBJECT_QUICK:
924            case IPUT_QUICK:
925            case IPUT_WIDE_QUICK:
926            case IPUT_OBJECT_QUICK:
927                return analyzeIputIgetQuick(analyzedInstruction);
928            case INVOKE_VIRTUAL_QUICK:
929                return analyzeInvokeVirtualQuick(analyzedInstruction, false, false);
930            case INVOKE_SUPER_QUICK:
931                return analyzeInvokeVirtualQuick(analyzedInstruction, true, false);
932            case INVOKE_VIRTUAL_QUICK_RANGE:
933                return analyzeInvokeVirtualQuick(analyzedInstruction, false, true);
934            case INVOKE_SUPER_QUICK_RANGE:
935                return analyzeInvokeVirtualQuick(analyzedInstruction, true, true);
936            case IPUT_OBJECT_VOLATILE:
937            case SGET_OBJECT_VOLATILE:
938            case SPUT_OBJECT_VOLATILE:
939                analyzePutGetVolatile(analyzedInstruction);
940                return true;
941            default:
942                assert false;
943                return true;
944        }
945    }
946
947    private static final BitSet Primitive32BitCategories = BitSetUtils.bitSetOfIndexes(
948            RegisterType.NULL,
949            RegisterType.ONE,
950            RegisterType.BOOLEAN,
951            RegisterType.BYTE,
952            RegisterType.POS_BYTE,
953            RegisterType.SHORT,
954            RegisterType.POS_SHORT,
955            RegisterType.CHAR,
956            RegisterType.INTEGER,
957            RegisterType.FLOAT);
958
959    private static final BitSet WideLowCategories = BitSetUtils.bitSetOfIndexes(
960            RegisterType.LONG_LO,
961            RegisterType.DOUBLE_LO);
962
963    private static final BitSet WideHighCategories = BitSetUtils.bitSetOfIndexes(
964            RegisterType.LONG_HI,
965            RegisterType.DOUBLE_HI);
966
967    private static final BitSet ReferenceOrUninitCategories = BitSetUtils.bitSetOfIndexes(
968            RegisterType.NULL,
969            RegisterType.UNINIT_REF,
970            RegisterType.UNINIT_THIS,
971            RegisterType.REFERENCE);
972
973    private static final BitSet BooleanCategories = BitSetUtils.bitSetOfIndexes(
974            RegisterType.NULL,
975            RegisterType.ONE,
976            RegisterType.BOOLEAN);
977
978    private void analyzeMove(@Nonnull AnalyzedInstruction analyzedInstruction) {
979        TwoRegisterInstruction instruction = (TwoRegisterInstruction)analyzedInstruction.instruction;
980
981        RegisterType sourceRegisterType = analyzedInstruction.getPreInstructionRegisterType(instruction.getRegisterB());
982        setDestinationRegisterTypeAndPropagateChanges(analyzedInstruction, sourceRegisterType);
983    }
984
985    private void analyzeMoveResult(@Nonnull AnalyzedInstruction analyzedInstruction) {
986        AnalyzedInstruction previousInstruction = analyzedInstructions.valueAt(analyzedInstruction.instructionIndex-1);
987        if (!previousInstruction.instruction.getOpcode().setsResult()) {
988            throw new AnalysisException(analyzedInstruction.instruction.getOpcode().name + " must occur after an " +
989                    "invoke-*/fill-new-array instruction");
990        }
991
992        RegisterType resultRegisterType;
993        ReferenceInstruction invokeInstruction = (ReferenceInstruction)previousInstruction.instruction;
994        Reference reference = invokeInstruction.getReference();
995
996        if (reference instanceof MethodReference) {
997            resultRegisterType = RegisterType.getRegisterType(classPath, ((MethodReference)reference).getReturnType());
998        } else {
999            resultRegisterType = RegisterType.getRegisterType(classPath, (TypeReference)reference);
1000        }
1001
1002        setDestinationRegisterTypeAndPropagateChanges(analyzedInstruction, resultRegisterType);
1003    }
1004
1005    private void analyzeMoveException(@Nonnull AnalyzedInstruction analyzedInstruction) {
1006        int instructionAddress = getInstructionAddress(analyzedInstruction);
1007
1008        RegisterType exceptionType = RegisterType.UNKNOWN_TYPE;
1009
1010        for (TryBlock tryBlock: methodImpl.getTryBlocks()) {
1011            for (ExceptionHandler handler: tryBlock.getExceptionHandlers()) {
1012
1013                if (handler.getHandlerCodeAddress() == instructionAddress) {
1014                    String type = handler.getExceptionType();
1015                    if (type == null) {
1016                        exceptionType = RegisterType.getRegisterType(RegisterType.REFERENCE,
1017                                classPath.getClass("Ljava/lang/Throwable;"));
1018                    } else {
1019                        exceptionType = RegisterType.getRegisterType(RegisterType.REFERENCE, classPath.getClass(type))
1020                                .merge(exceptionType);
1021                    }
1022                }
1023            }
1024        }
1025
1026        if (exceptionType.category == RegisterType.UNKNOWN) {
1027            throw new AnalysisException("move-exception must be the first instruction in an exception handler block");
1028        }
1029
1030        setDestinationRegisterTypeAndPropagateChanges(analyzedInstruction, exceptionType);
1031    }
1032
1033    private void analyzeReturnVoidBarrier(AnalyzedInstruction analyzedInstruction) {
1034        analyzeReturnVoidBarrier(analyzedInstruction, true);
1035    }
1036
1037    private void analyzeReturnVoidBarrier(@Nonnull AnalyzedInstruction analyzedInstruction, boolean analyzeResult) {
1038        Instruction10x deodexedInstruction = new ImmutableInstruction10x(Opcode.RETURN_VOID);
1039
1040        analyzedInstruction.setDeodexedInstruction(deodexedInstruction);
1041
1042        if (analyzeResult) {
1043            analyzeInstruction(analyzedInstruction);
1044        }
1045    }
1046
1047    private void analyzeConst(@Nonnull AnalyzedInstruction analyzedInstruction) {
1048        NarrowLiteralInstruction instruction = (NarrowLiteralInstruction)analyzedInstruction.instruction;
1049
1050        //we assume that the literal value is a valid value for the given instruction type, because it's impossible
1051        //to store an invalid literal with the instruction. so we don't need to check the type of the literal
1052        setDestinationRegisterTypeAndPropagateChanges(analyzedInstruction,
1053                RegisterType.getRegisterTypeForLiteral(instruction.getNarrowLiteral()));
1054    }
1055
1056    private void analyzeWideConst(@Nonnull AnalyzedInstruction analyzedInstruction) {
1057        setDestinationRegisterTypeAndPropagateChanges(analyzedInstruction, RegisterType.LONG_LO_TYPE);
1058    }
1059
1060    private void analyzeConstString(@Nonnull AnalyzedInstruction analyzedInstruction) {
1061        TypeProto stringClass = classPath.getClass("Ljava/lang/String;");
1062        RegisterType stringType = RegisterType.getRegisterType(RegisterType.REFERENCE, stringClass);
1063        setDestinationRegisterTypeAndPropagateChanges(analyzedInstruction, stringType);
1064    }
1065
1066    private void analyzeConstClass(@Nonnull AnalyzedInstruction analyzedInstruction) {
1067        TypeProto classClass = classPath.getClass("Ljava/lang/Class;");
1068        RegisterType classType = RegisterType.getRegisterType(RegisterType.REFERENCE, classClass);
1069        setDestinationRegisterTypeAndPropagateChanges(analyzedInstruction, classType);
1070    }
1071
1072    private void analyzeCheckCast(@Nonnull AnalyzedInstruction analyzedInstruction) {
1073        ReferenceInstruction instruction = (ReferenceInstruction)analyzedInstruction.instruction;
1074        TypeReference reference = (TypeReference)instruction.getReference();
1075        RegisterType castRegisterType = RegisterType.getRegisterType(classPath, reference);
1076        setDestinationRegisterTypeAndPropagateChanges(analyzedInstruction, castRegisterType);
1077    }
1078
1079    private void analyzeInstanceOf(@Nonnull AnalyzedInstruction analyzedInstruction) {
1080        setDestinationRegisterTypeAndPropagateChanges(analyzedInstruction, RegisterType.BOOLEAN_TYPE);
1081    }
1082
1083    private void analyzeArrayLength(@Nonnull AnalyzedInstruction analyzedInstruction) {
1084        setDestinationRegisterTypeAndPropagateChanges(analyzedInstruction, RegisterType.INTEGER_TYPE);
1085    }
1086
1087    private void analyzeNewInstance(@Nonnull AnalyzedInstruction analyzedInstruction) {
1088        ReferenceInstruction instruction = (ReferenceInstruction)analyzedInstruction.instruction;
1089
1090        int register = ((OneRegisterInstruction)analyzedInstruction.instruction).getRegisterA();
1091        RegisterType destRegisterType = analyzedInstruction.getPostInstructionRegisterType(register);
1092        if (destRegisterType.category != RegisterType.UNKNOWN) {
1093            //the post-instruction destination register will only be set if we have already analyzed this instruction
1094            //at least once. If this is the case, then the uninit reference has already been propagated to all
1095            //successors and nothing else needs to be done.
1096            assert destRegisterType.category == RegisterType.UNINIT_REF;
1097            return;
1098        }
1099
1100        TypeReference typeReference = (TypeReference)instruction.getReference();
1101
1102        RegisterType classType = RegisterType.getRegisterType(classPath, typeReference);
1103
1104        setDestinationRegisterTypeAndPropagateChanges(analyzedInstruction,
1105                RegisterType.getRegisterType(RegisterType.UNINIT_REF, classType.type));
1106    }
1107
1108    private void analyzeNewArray(@Nonnull AnalyzedInstruction analyzedInstruction) {
1109        ReferenceInstruction instruction = (ReferenceInstruction)analyzedInstruction.instruction;
1110
1111        TypeReference type = (TypeReference)instruction.getReference();
1112        if (type.getType().charAt(0) != '[') {
1113            throw new AnalysisException("new-array used with non-array type");
1114        }
1115
1116        RegisterType arrayType = RegisterType.getRegisterType(classPath, type);
1117
1118        setDestinationRegisterTypeAndPropagateChanges(analyzedInstruction, arrayType);
1119    }
1120
1121    private void analyzeFloatWideCmp(@Nonnull AnalyzedInstruction analyzedInstruction) {
1122        setDestinationRegisterTypeAndPropagateChanges(analyzedInstruction, RegisterType.BYTE_TYPE);
1123    }
1124
1125    private void analyze32BitPrimitiveAget(@Nonnull AnalyzedInstruction analyzedInstruction,
1126                                           @Nonnull RegisterType registerType) {
1127        setDestinationRegisterTypeAndPropagateChanges(analyzedInstruction, registerType);
1128    }
1129
1130    private void analyzeAgetWide(@Nonnull AnalyzedInstruction analyzedInstruction) {
1131        ThreeRegisterInstruction instruction = (ThreeRegisterInstruction)analyzedInstruction.instruction;
1132
1133        RegisterType arrayRegisterType = analyzedInstruction.getPreInstructionRegisterType(instruction.getRegisterB());
1134        if (arrayRegisterType.category != RegisterType.NULL) {
1135            if (arrayRegisterType.category != RegisterType.REFERENCE ||
1136                    !(arrayRegisterType.type instanceof ArrayProto)) {
1137                throw new AnalysisException("aget-wide used with non-array register: %s", arrayRegisterType.toString());
1138            }
1139            ArrayProto arrayProto = (ArrayProto)arrayRegisterType.type;
1140
1141            if (arrayProto.dimensions != 1) {
1142                throw new AnalysisException("aget-wide used with multi-dimensional array: %s",
1143                        arrayRegisterType.toString());
1144            }
1145
1146            char arrayBaseType = arrayProto.getElementType().charAt(0);
1147            if (arrayBaseType == 'J') {
1148                setDestinationRegisterTypeAndPropagateChanges(analyzedInstruction, RegisterType.LONG_LO_TYPE);
1149            } else if (arrayBaseType == 'D') {
1150                setDestinationRegisterTypeAndPropagateChanges(analyzedInstruction, RegisterType.DOUBLE_LO_TYPE);
1151            } else {
1152                throw new AnalysisException("aget-wide used with narrow array: %s", arrayRegisterType);
1153            }
1154        } else {
1155            // If the array register is null, we can assume that the destination register was meant to be a wide type.
1156            // This is the same behavior as dalvik's verifier
1157            setDestinationRegisterTypeAndPropagateChanges(analyzedInstruction, RegisterType.LONG_LO_TYPE);
1158        }
1159    }
1160
1161    private void analyzeAgetObject(@Nonnull AnalyzedInstruction analyzedInstruction) {
1162        ThreeRegisterInstruction instruction = (ThreeRegisterInstruction)analyzedInstruction.instruction;
1163
1164        RegisterType arrayRegisterType = analyzedInstruction.getPreInstructionRegisterType(instruction.getRegisterB());
1165        if (arrayRegisterType.category != RegisterType.NULL) {
1166            if (arrayRegisterType.category != RegisterType.REFERENCE ||
1167                    !(arrayRegisterType.type instanceof ArrayProto)) {
1168                throw new AnalysisException("aget-object used with non-array register: %s",
1169                        arrayRegisterType.toString());
1170            }
1171
1172            ArrayProto arrayProto = (ArrayProto)arrayRegisterType.type;
1173
1174            String elementType = arrayProto.getImmediateElementType();
1175
1176            setDestinationRegisterTypeAndPropagateChanges(analyzedInstruction,
1177                    RegisterType.getRegisterType(RegisterType.REFERENCE, classPath.getClass(elementType)));
1178        } else {
1179            // If the array register is null, we can assume that the destination register was meant to be a reference
1180            // type, so we set the destination to NULL. This is the same behavior as dalvik's verifier
1181            setDestinationRegisterTypeAndPropagateChanges(analyzedInstruction, RegisterType.NULL_TYPE);
1182        }
1183    }
1184
1185    private void analyze32BitPrimitiveIgetSget(@Nonnull AnalyzedInstruction analyzedInstruction,
1186                                               @Nonnull RegisterType registerType) {
1187        setDestinationRegisterTypeAndPropagateChanges(analyzedInstruction, registerType);
1188    }
1189
1190    private void analyzeIgetSgetWideObject(@Nonnull AnalyzedInstruction analyzedInstruction) {
1191        ReferenceInstruction referenceInstruction = (ReferenceInstruction)analyzedInstruction.instruction;
1192
1193        FieldReference fieldReference = (FieldReference)referenceInstruction.getReference();
1194
1195        RegisterType fieldType = RegisterType.getRegisterType(classPath, fieldReference.getType());
1196        setDestinationRegisterTypeAndPropagateChanges(analyzedInstruction, fieldType);
1197    }
1198
1199    private void analyzeInvokeDirect(@Nonnull AnalyzedInstruction analyzedInstruction) {
1200        FiveRegisterInstruction instruction = (FiveRegisterInstruction)analyzedInstruction.instruction;
1201        analyzeInvokeDirectCommon(analyzedInstruction, instruction.getRegisterC());
1202    }
1203
1204    private void analyzeInvokeDirectRange(@Nonnull AnalyzedInstruction analyzedInstruction) {
1205        RegisterRangeInstruction instruction = (RegisterRangeInstruction)analyzedInstruction.instruction;
1206        analyzeInvokeDirectCommon(analyzedInstruction, instruction.getStartRegister());
1207    }
1208
1209    private void analyzeInvokeDirectCommon(@Nonnull AnalyzedInstruction analyzedInstruction, int objectRegister) {
1210        //the only time that an invoke instruction changes a register type is when using invoke-direct on a
1211        //constructor (<init>) method, which changes the uninitialized reference (and any register that the same
1212        //uninit reference has been copied to) to an initialized reference
1213
1214        ReferenceInstruction instruction = (ReferenceInstruction)analyzedInstruction.instruction;
1215
1216        MethodReference methodReference = (MethodReference)instruction.getReference();
1217
1218        if (!methodReference.getName().equals("<init>")) {
1219            return;
1220        }
1221
1222        RegisterType objectRegisterType = analyzedInstruction.getPreInstructionRegisterType(objectRegister);
1223
1224        if (objectRegisterType.category != RegisterType.UNINIT_REF &&
1225                objectRegisterType.category != RegisterType.UNINIT_THIS) {
1226            return;
1227        }
1228
1229        setPostRegisterTypeAndPropagateChanges(analyzedInstruction, objectRegister,
1230                RegisterType.getRegisterType(RegisterType.REFERENCE, objectRegisterType.type));
1231
1232        for (int i=0; i<analyzedInstruction.postRegisterMap.length; i++) {
1233            RegisterType postInstructionRegisterType = analyzedInstruction.postRegisterMap[i];
1234            if (postInstructionRegisterType.category == RegisterType.UNKNOWN) {
1235                RegisterType preInstructionRegisterType =
1236                        analyzedInstruction.getPreInstructionRegisterType(i);
1237
1238                if (preInstructionRegisterType.category == RegisterType.UNINIT_REF ||
1239                        preInstructionRegisterType.category == RegisterType.UNINIT_THIS) {
1240                    RegisterType registerType;
1241                    if (preInstructionRegisterType == objectRegisterType) {
1242                        registerType = analyzedInstruction.postRegisterMap[objectRegister];
1243                    } else {
1244                        registerType = preInstructionRegisterType;
1245                    }
1246
1247                    setPostRegisterTypeAndPropagateChanges(analyzedInstruction, i, registerType);
1248                }
1249            }
1250        }
1251    }
1252
1253    private void analyzeUnaryOp(@Nonnull AnalyzedInstruction analyzedInstruction,
1254                                @Nonnull RegisterType destRegisterType) {
1255        setDestinationRegisterTypeAndPropagateChanges(analyzedInstruction, destRegisterType);
1256    }
1257
1258    private void analyzeBinaryOp(@Nonnull AnalyzedInstruction analyzedInstruction,
1259                                 @Nonnull RegisterType destRegisterType, boolean checkForBoolean) {
1260        if (checkForBoolean) {
1261            ThreeRegisterInstruction instruction = (ThreeRegisterInstruction)analyzedInstruction.instruction;
1262
1263            RegisterType source1RegisterType =
1264                    analyzedInstruction.getPreInstructionRegisterType(instruction.getRegisterB());
1265            RegisterType source2RegisterType =
1266                    analyzedInstruction.getPreInstructionRegisterType(instruction.getRegisterC());
1267
1268            if (BooleanCategories.get(source1RegisterType.category) &&
1269                    BooleanCategories.get(source2RegisterType.category)) {
1270                destRegisterType = RegisterType.BOOLEAN_TYPE;
1271            }
1272        }
1273
1274        setDestinationRegisterTypeAndPropagateChanges(analyzedInstruction, destRegisterType);
1275    }
1276
1277    private void analyzeBinary2AddrOp(@Nonnull AnalyzedInstruction analyzedInstruction,
1278                                      @Nonnull RegisterType destRegisterType, boolean checkForBoolean) {
1279        if (checkForBoolean) {
1280            TwoRegisterInstruction instruction = (TwoRegisterInstruction)analyzedInstruction.instruction;
1281
1282            RegisterType source1RegisterType =
1283                    analyzedInstruction.getPreInstructionRegisterType(instruction.getRegisterA());
1284            RegisterType source2RegisterType =
1285                    analyzedInstruction.getPreInstructionRegisterType(instruction.getRegisterB());
1286
1287            if (BooleanCategories.get(source1RegisterType.category) &&
1288                    BooleanCategories.get(source2RegisterType.category)) {
1289                destRegisterType = RegisterType.BOOLEAN_TYPE;
1290            }
1291        }
1292
1293        setDestinationRegisterTypeAndPropagateChanges(analyzedInstruction, destRegisterType);
1294    }
1295
1296    private void analyzeLiteralBinaryOp(@Nonnull AnalyzedInstruction analyzedInstruction,
1297                                        @Nonnull RegisterType destRegisterType, boolean checkForBoolean) {
1298        if (checkForBoolean) {
1299            TwoRegisterInstruction instruction = (TwoRegisterInstruction)analyzedInstruction.instruction;
1300
1301            RegisterType sourceRegisterType =
1302                    analyzedInstruction.getPreInstructionRegisterType(instruction.getRegisterB());
1303
1304            if (BooleanCategories.get(sourceRegisterType.category)) {
1305                int literal = ((NarrowLiteralInstruction)analyzedInstruction.instruction).getNarrowLiteral();
1306                if (literal == 0 || literal == 1) {
1307                    destRegisterType = RegisterType.BOOLEAN_TYPE;
1308                }
1309            }
1310        }
1311
1312        setDestinationRegisterTypeAndPropagateChanges(analyzedInstruction, destRegisterType);
1313    }
1314
1315    private RegisterType getDestTypeForLiteralShiftRight(@Nonnull AnalyzedInstruction analyzedInstruction, boolean signedShift) {
1316        TwoRegisterInstruction instruction = (TwoRegisterInstruction)analyzedInstruction.instruction;
1317
1318        RegisterType sourceRegisterType = getAndCheckSourceRegister(analyzedInstruction, instruction.getRegisterB(),
1319                Primitive32BitCategories);
1320        long literalShift = ((NarrowLiteralInstruction)analyzedInstruction.instruction).getNarrowLiteral();
1321
1322        if (literalShift == 0) {
1323            return sourceRegisterType;
1324        }
1325
1326        RegisterType destRegisterType;
1327        if (!signedShift) {
1328            destRegisterType = RegisterType.INTEGER_TYPE;
1329        } else {
1330            destRegisterType = sourceRegisterType;
1331        }
1332
1333        literalShift = literalShift & 0x1f;
1334
1335        switch (sourceRegisterType.category) {
1336            case RegisterType.INTEGER:
1337            case RegisterType.FLOAT:
1338                if (!signedShift) {
1339                    if (literalShift > 24) {
1340                        return RegisterType.POS_BYTE_TYPE;
1341                    }
1342                    if (literalShift >= 16) {
1343                        return RegisterType.CHAR_TYPE;
1344                    }
1345                } else {
1346                    if (literalShift >= 24) {
1347                        return RegisterType.BYTE_TYPE;
1348                    }
1349                    if (literalShift >= 16) {
1350                        return RegisterType.SHORT_TYPE;
1351                    }
1352                }
1353                break;
1354            case RegisterType.SHORT:
1355                if (signedShift && literalShift >= 8) {
1356                    return RegisterType.BYTE_TYPE;
1357                }
1358                break;
1359            case RegisterType.POS_SHORT:
1360                if (literalShift >= 8) {
1361                    return RegisterType.POS_BYTE_TYPE;
1362                }
1363                break;
1364            case RegisterType.CHAR:
1365                if (literalShift > 8) {
1366                    return RegisterType.POS_BYTE_TYPE;
1367                }
1368                break;
1369            case RegisterType.BYTE:
1370                break;
1371            case RegisterType.POS_BYTE:
1372                return RegisterType.POS_BYTE_TYPE;
1373            case RegisterType.NULL:
1374            case RegisterType.ONE:
1375            case RegisterType.BOOLEAN:
1376                return RegisterType.NULL_TYPE;
1377            default:
1378                assert false;
1379        }
1380
1381        return destRegisterType;
1382    }
1383
1384
1385    private void analyzeExecuteInline(@Nonnull AnalyzedInstruction analyzedInstruction) {
1386        if (inlineResolver == null) {
1387            throw new AnalysisException("Cannot analyze an odexed instruction unless we are deodexing");
1388        }
1389
1390        Instruction35mi instruction = (Instruction35mi)analyzedInstruction.instruction;
1391        Method resolvedMethod = inlineResolver.resolveExecuteInline(analyzedInstruction);
1392
1393        Opcode deodexedOpcode;
1394        switch (resolvedMethod.getAccessFlags()) {
1395            case InlineMethodResolver.DIRECT:
1396                deodexedOpcode = Opcode.INVOKE_DIRECT;
1397                break;
1398            case InlineMethodResolver.STATIC:
1399                deodexedOpcode = Opcode.INVOKE_STATIC;
1400                break;
1401            case InlineMethodResolver.VIRTUAL:
1402                deodexedOpcode = Opcode.INVOKE_VIRTUAL;
1403                break;
1404            default:
1405                throw new ExceptionWithContext("Unexpected access flags on resolved inline method: %d, %s",
1406                        resolvedMethod.getAccessFlags(), ReferenceUtil.getReferenceString(resolvedMethod));
1407        }
1408
1409        Instruction35c deodexedInstruction = new ImmutableInstruction35c(deodexedOpcode, instruction.getRegisterCount(),
1410                instruction.getRegisterC(), instruction.getRegisterD(), instruction.getRegisterE(),
1411                instruction.getRegisterF(), instruction.getRegisterG(), resolvedMethod);
1412
1413        analyzedInstruction.setDeodexedInstruction(deodexedInstruction);
1414        analyzeInstruction(analyzedInstruction);
1415    }
1416
1417    private void analyzeExecuteInlineRange(@Nonnull AnalyzedInstruction analyzedInstruction) {
1418        if (inlineResolver == null) {
1419            throw new AnalysisException("Cannot analyze an odexed instruction unless we are deodexing");
1420        }
1421
1422        Instruction3rmi instruction = (Instruction3rmi)analyzedInstruction.instruction;
1423        Method resolvedMethod = inlineResolver.resolveExecuteInline(analyzedInstruction);
1424
1425        Opcode deodexedOpcode = null;
1426        switch (resolvedMethod.getAccessFlags()) {
1427            case InlineMethodResolver.DIRECT:
1428                deodexedOpcode = Opcode.INVOKE_DIRECT_RANGE;
1429                break;
1430            case InlineMethodResolver.STATIC:
1431                deodexedOpcode = Opcode.INVOKE_STATIC_RANGE;
1432                break;
1433            case InlineMethodResolver.VIRTUAL:
1434                deodexedOpcode = Opcode.INVOKE_VIRTUAL_RANGE;
1435                break;
1436            default:
1437                assert false;
1438        }
1439
1440        Instruction3rc deodexedInstruction = new ImmutableInstruction3rc(deodexedOpcode, instruction.getRegisterCount(),
1441                instruction.getStartRegister(), resolvedMethod);
1442
1443        analyzedInstruction.setDeodexedInstruction(deodexedInstruction);
1444        analyzeInstruction(analyzedInstruction);
1445    }
1446
1447    private void analyzeInvokeDirectEmpty(@Nonnull AnalyzedInstruction analyzedInstruction) {
1448        analyzeInvokeDirectEmpty(analyzedInstruction, true);
1449    }
1450
1451    private void analyzeInvokeDirectEmpty(@Nonnull AnalyzedInstruction analyzedInstruction, boolean analyzeResult) {
1452        Instruction35c instruction = (Instruction35c)analyzedInstruction.instruction;
1453
1454        Instruction35c deodexedInstruction = new ImmutableInstruction35c(Opcode.INVOKE_DIRECT,
1455                instruction.getRegisterCount(), instruction.getRegisterC(), instruction.getRegisterD(),
1456                instruction.getRegisterE(), instruction.getRegisterF(), instruction.getRegisterG(),
1457                instruction.getReference());
1458
1459        analyzedInstruction.setDeodexedInstruction(deodexedInstruction);
1460
1461        if (analyzeResult) {
1462            analyzeInstruction(analyzedInstruction);
1463        }
1464    }
1465
1466    private void analyzeInvokeObjectInitRange(@Nonnull AnalyzedInstruction analyzedInstruction) {
1467        analyzeInvokeObjectInitRange(analyzedInstruction, true);
1468    }
1469
1470    private void analyzeInvokeObjectInitRange(@Nonnull AnalyzedInstruction analyzedInstruction, boolean analyzeResult) {
1471        Instruction3rc instruction = (Instruction3rc)analyzedInstruction.instruction;
1472
1473        Instruction3rc deodexedInstruction = new ImmutableInstruction3rc(Opcode.INVOKE_DIRECT_RANGE,
1474                instruction.getRegisterCount(), instruction.getStartRegister(), instruction.getReference());
1475
1476        analyzedInstruction.setDeodexedInstruction(deodexedInstruction);
1477
1478        if (analyzeResult) {
1479            analyzeInstruction(analyzedInstruction);
1480        }
1481    }
1482
1483    private boolean analyzeIputIgetQuick(@Nonnull AnalyzedInstruction analyzedInstruction) {
1484        Instruction22cs instruction = (Instruction22cs)analyzedInstruction.instruction;
1485
1486        int fieldOffset = instruction.getFieldOffset();
1487        RegisterType objectRegisterType = getAndCheckSourceRegister(analyzedInstruction, instruction.getRegisterB(),
1488                ReferenceOrUninitCategories);
1489
1490        if (objectRegisterType.category == RegisterType.NULL) {
1491            return false;
1492        }
1493
1494        TypeProto registerTypeProto = objectRegisterType.type;
1495        assert registerTypeProto != null;
1496
1497        TypeProto classTypeProto = classPath.getClass(registerTypeProto.getType());
1498        FieldReference field = classTypeProto.getFieldByOffset(fieldOffset);
1499
1500        if (field == null) {
1501            throw new AnalysisException("Could not resolve the field in class %s at offset %d",
1502                    objectRegisterType.type.getType(), fieldOffset);
1503        }
1504
1505        String fieldType = field.getType();
1506
1507        Opcode opcode = OdexedFieldInstructionMapper.getAndCheckDeodexedOpcodeForOdexedOpcode(fieldType,
1508                instruction.getOpcode());
1509
1510        Instruction22c deodexedInstruction = new ImmutableInstruction22c(opcode, (byte)instruction.getRegisterA(),
1511                (byte)instruction.getRegisterB(), field);
1512        analyzedInstruction.setDeodexedInstruction(deodexedInstruction);
1513
1514        analyzeInstruction(analyzedInstruction);
1515
1516        return true;
1517    }
1518
1519    private boolean analyzeInvokeVirtualQuick(@Nonnull AnalyzedInstruction analyzedInstruction, boolean isSuper,
1520                                              boolean isRange) {
1521        int methodIndex;
1522        int objectRegister;
1523
1524        if (isRange) {
1525            Instruction3rms instruction = (Instruction3rms)analyzedInstruction.instruction;
1526            methodIndex = instruction.getVtableIndex();
1527            objectRegister = instruction.getStartRegister();
1528        } else {
1529            Instruction35ms instruction = (Instruction35ms)analyzedInstruction.instruction;
1530            methodIndex = instruction.getVtableIndex();
1531            objectRegister = instruction.getRegisterD();
1532        }
1533
1534        RegisterType objectRegisterType = getAndCheckSourceRegister(analyzedInstruction, objectRegister,
1535                ReferenceOrUninitCategories);
1536        TypeProto objectRegisterTypeProto = objectRegisterType.type;
1537        assert objectRegisterTypeProto != null;
1538
1539        if (objectRegisterType.category == RegisterType.NULL) {
1540            return false;
1541        }
1542
1543        MethodReference resolvedMethod;
1544        if (isSuper) {
1545            // invoke-super is only used for the same class that we're currently in
1546            TypeProto typeProto = classPath.getClass(method.getDefiningClass());
1547            TypeProto superType;
1548
1549            String superclassType = typeProto.getSuperclass();
1550            if (superclassType != null) {
1551                superType = classPath.getClass(superclassType);
1552            } else {
1553                // This is either java.lang.Object, or an UnknownClassProto
1554                superType = typeProto;
1555            }
1556
1557            resolvedMethod = superType.getMethodByVtableIndex(methodIndex);
1558        } else{
1559            resolvedMethod = objectRegisterTypeProto.getMethodByVtableIndex(methodIndex);
1560        }
1561
1562        if (resolvedMethod == null) {
1563            throw new AnalysisException("Could not resolve the method in class %s at index %d",
1564                    objectRegisterType.type.getType(), methodIndex);
1565        }
1566
1567        Instruction deodexedInstruction;
1568        if (isRange) {
1569            Instruction3rms instruction = (Instruction3rms)analyzedInstruction.instruction;
1570            Opcode opcode;
1571            if (isSuper) {
1572                opcode = Opcode.INVOKE_SUPER_RANGE;
1573            } else {
1574                opcode = Opcode.INVOKE_VIRTUAL_RANGE;
1575            }
1576
1577            deodexedInstruction = new ImmutableInstruction3rc(opcode, instruction.getRegisterCount(),
1578                    instruction.getStartRegister(), resolvedMethod);
1579        } else {
1580            Instruction35ms instruction = (Instruction35ms)analyzedInstruction.instruction;
1581            Opcode opcode;
1582            if (isSuper) {
1583                opcode = Opcode.INVOKE_SUPER;
1584            } else {
1585                opcode = Opcode.INVOKE_VIRTUAL;
1586            }
1587
1588            deodexedInstruction = new ImmutableInstruction35c(opcode, instruction.getRegisterCount(),
1589                    instruction.getRegisterC(), instruction.getRegisterD(), instruction.getRegisterE(),
1590                    instruction.getRegisterF(), instruction.getRegisterG(), resolvedMethod);
1591        }
1592
1593        analyzedInstruction.setDeodexedInstruction(deodexedInstruction);
1594        analyzeInstruction(analyzedInstruction);
1595
1596        return true;
1597    }
1598
1599    private boolean analyzePutGetVolatile(@Nonnull AnalyzedInstruction analyzedInstruction) {
1600        return analyzePutGetVolatile(analyzedInstruction, true);
1601    }
1602
1603    private boolean analyzePutGetVolatile(@Nonnull AnalyzedInstruction analyzedInstruction, boolean analyzeResult) {
1604        FieldReference field = (FieldReference)((ReferenceInstruction)analyzedInstruction.instruction).getReference();
1605        String fieldType = field.getType();
1606
1607        Opcode originalOpcode = analyzedInstruction.instruction.getOpcode();
1608
1609        Opcode opcode = OdexedFieldInstructionMapper.getAndCheckDeodexedOpcodeForOdexedOpcode(fieldType,
1610                originalOpcode);
1611
1612        Instruction deodexedInstruction;
1613
1614        if (originalOpcode.isOdexedStaticVolatile()) {
1615            OneRegisterInstruction instruction = (OneRegisterInstruction)analyzedInstruction.instruction;
1616            deodexedInstruction = new ImmutableInstruction21c(opcode, instruction.getRegisterA(), field);
1617        } else {
1618            TwoRegisterInstruction instruction = (TwoRegisterInstruction)analyzedInstruction.instruction;
1619
1620            deodexedInstruction = new ImmutableInstruction22c(opcode, instruction.getRegisterA(),
1621                    instruction.getRegisterB(), field);
1622        }
1623
1624        analyzedInstruction.setDeodexedInstruction(deodexedInstruction);
1625
1626        if (analyzeResult) {
1627            analyzeInstruction(analyzedInstruction);
1628        }
1629        return true;
1630    }
1631
1632    @Nonnull
1633    private static RegisterType getAndCheckSourceRegister(@Nonnull AnalyzedInstruction analyzedInstruction,
1634                                                          int registerNumber, BitSet validCategories) {
1635        assert registerNumber >= 0 && registerNumber < analyzedInstruction.postRegisterMap.length;
1636
1637        RegisterType registerType = analyzedInstruction.getPreInstructionRegisterType(registerNumber);
1638
1639        checkRegister(registerType, registerNumber, validCategories);
1640
1641        if (validCategories == WideLowCategories) {
1642            checkRegister(registerType, registerNumber, WideLowCategories);
1643            checkWidePair(registerNumber, analyzedInstruction);
1644
1645            RegisterType secondRegisterType = analyzedInstruction.getPreInstructionRegisterType(registerNumber + 1);
1646            checkRegister(secondRegisterType, registerNumber+1, WideHighCategories);
1647        }
1648
1649        return registerType;
1650    }
1651
1652    private static void checkRegister(RegisterType registerType, int registerNumber, BitSet validCategories) {
1653        if (!validCategories.get(registerType.category)) {
1654            throw new AnalysisException(String.format("Invalid register type %s for register v%d.",
1655                    registerType.toString(), registerNumber));
1656        }
1657    }
1658
1659    private static void checkWidePair(int registerNumber, AnalyzedInstruction analyzedInstruction) {
1660        if (registerNumber + 1 >= analyzedInstruction.postRegisterMap.length) {
1661            throw new AnalysisException(String.format("v%d cannot be used as the first register in a wide register" +
1662                    "pair because it is the last register.", registerNumber));
1663        }
1664    }
1665}