MethodAnalyzer.java revision cda44f70cfebfae4875cd77455a171075aebac4d
1d27ca7f7a61cfbe60e1c490bf645257d7d59fd39JesusFreke@JesusFreke.compackage org.jf.dexlib.Code.Analysis;
2d27ca7f7a61cfbe60e1c490bf645257d7d59fd39JesusFreke@JesusFreke.com
3fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.comimport org.jf.dexlib.*;
4fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.comimport org.jf.dexlib.Code.*;
5472d3ea58455ebf43d21819b2701fad98b5a0f9cJesusFreke@JesusFreke.comimport org.jf.dexlib.Code.Format.ArrayDataPseudoInstruction;
6472d3ea58455ebf43d21819b2701fad98b5a0f9cJesusFreke@JesusFreke.comimport org.jf.dexlib.Code.Format.Format;
7fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.comimport org.jf.dexlib.Util.*;
8d27ca7f7a61cfbe60e1c490bf645257d7d59fd39JesusFreke@JesusFreke.com
9fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.comimport java.util.*;
10d27ca7f7a61cfbe60e1c490bf645257d7d59fd39JesusFreke@JesusFreke.com
11d27ca7f7a61cfbe60e1c490bf645257d7d59fd39JesusFreke@JesusFreke.compublic class MethodAnalyzer {
12d27ca7f7a61cfbe60e1c490bf645257d7d59fd39JesusFreke@JesusFreke.com    private final ClassDataItem.EncodedMethod encodedMethod;
13d27ca7f7a61cfbe60e1c490bf645257d7d59fd39JesusFreke@JesusFreke.com
14fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com    private SparseArray<AnalyzedInstruction> instructions;
15fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com
16fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com    private boolean analyzed = false;
17d27ca7f7a61cfbe60e1c490bf645257d7d59fd39JesusFreke@JesusFreke.com
18d27ca7f7a61cfbe60e1c490bf645257d7d59fd39JesusFreke@JesusFreke.com    //This is a dummy instruction that occurs immediately before the first real instruction. We can initialize the
19d27ca7f7a61cfbe60e1c490bf645257d7d59fd39JesusFreke@JesusFreke.com    //register types for this instruction to the parameter types, in order to have them propagate to all of its
20d27ca7f7a61cfbe60e1c490bf645257d7d59fd39JesusFreke@JesusFreke.com    //successors, e.g. the first real instruction, the first instructions in any exception handlers covering the first
21d27ca7f7a61cfbe60e1c490bf645257d7d59fd39JesusFreke@JesusFreke.com    //instruction, etc.
22d27ca7f7a61cfbe60e1c490bf645257d7d59fd39JesusFreke@JesusFreke.com    private AnalyzedInstruction startOfMethod;
23d27ca7f7a61cfbe60e1c490bf645257d7d59fd39JesusFreke@JesusFreke.com
24d27ca7f7a61cfbe60e1c490bf645257d7d59fd39JesusFreke@JesusFreke.com    public MethodAnalyzer(ClassDataItem.EncodedMethod encodedMethod) {
25d27ca7f7a61cfbe60e1c490bf645257d7d59fd39JesusFreke@JesusFreke.com        if (encodedMethod == null) {
26d27ca7f7a61cfbe60e1c490bf645257d7d59fd39JesusFreke@JesusFreke.com            throw new IllegalArgumentException("encodedMethod cannot be null");
27d27ca7f7a61cfbe60e1c490bf645257d7d59fd39JesusFreke@JesusFreke.com        }
28fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        if (encodedMethod.codeItem == null || encodedMethod.codeItem.getInstructions().length == 0) {
29d27ca7f7a61cfbe60e1c490bf645257d7d59fd39JesusFreke@JesusFreke.com            throw new IllegalArgumentException("The method has no code");
30d27ca7f7a61cfbe60e1c490bf645257d7d59fd39JesusFreke@JesusFreke.com        }
31d27ca7f7a61cfbe60e1c490bf645257d7d59fd39JesusFreke@JesusFreke.com        this.encodedMethod = encodedMethod;
32d27ca7f7a61cfbe60e1c490bf645257d7d59fd39JesusFreke@JesusFreke.com        buildInstructionList();
33fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com
34fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        //override AnalyzedInstruction and provide custom implementations of some of the methods, so that we don't
35fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        //have to handle the case this special case of instruction being null, in the main class
36fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        startOfMethod = new AnalyzedInstruction(null, -1, encodedMethod.codeItem.getRegisterCount()) {
37fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com            public boolean setsRegister() {
38fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com                return false;
39fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com            }
40fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com
41fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com            @Override
42fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com            public boolean setsWideRegister() {
43fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com                return false;
44fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com            }
45fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com
46fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com            @Override
47fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com            public boolean setsRegister(int registerNumber) {
48fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com                return false;
49fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com            }
50fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com
51fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com            @Override
52fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com            public int getDestinationRegister() {
53fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com                assert false;
54fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com                return -1;
55fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com            };
56fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        };
57d27ca7f7a61cfbe60e1c490bf645257d7d59fd39JesusFreke@JesusFreke.com    }
58d27ca7f7a61cfbe60e1c490bf645257d7d59fd39JesusFreke@JesusFreke.com
59d27ca7f7a61cfbe60e1c490bf645257d7d59fd39JesusFreke@JesusFreke.com    public AnalyzedInstruction[] analyze() {
60fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        assert encodedMethod != null;
61fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        assert encodedMethod.codeItem != null;
62fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com
63fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        if (analyzed) {
64fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com            return makeInstructionArray();
65fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        }
66fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com
67fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        CodeItem codeItem = encodedMethod.codeItem;
68fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        MethodIdItem methodIdItem = encodedMethod.method;
69fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com
70fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        int totalRegisters = codeItem.getRegisterCount();
71fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        int parameterRegisters = methodIdItem.getPrototype().getParameterRegisterCount();
72fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com
73fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        //if this isn't a static method, determine which register is the "this" register and set the type to the
74fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        //current class
75fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        if ((encodedMethod.accessFlags & AccessFlags.STATIC.getValue()) == 0) {
76fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com            int thisRegister = totalRegisters - parameterRegisters - 1;
77fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com
78fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com            //if this is a constructor, then set the "this" register to an uninitialized reference of the current class
79fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com            if ((encodedMethod.accessFlags & AccessFlags.CONSTRUCTOR.getValue()) != 0) {
80fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com                //TODO: it would probably make more sense to validate this somewhere else, and just put an assert here. Also, need to do a similar check for static constructor
81fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com                if (!encodedMethod.method.getMethodName().equals("<init>")) {
82fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com                    throw new ValidationException("The constructor flag can only be used with an <init> method.");
83fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com                }
84fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com
85fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com                setRegisterTypeAndPropagateChanges(startOfMethod, thisRegister,
86fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com                        RegisterType.getRegisterType(RegisterType.Category.UninitRef,
87fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com                            ClassPath.getClassDef(methodIdItem.getContainingClass())));
88fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com            } else {
89fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com                if (encodedMethod.method.getMethodName().equals("<init>")) {
90fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com                    throw new ValidationException("An <init> method must have the \"constructor\" access flag");
91fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com                }
92fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com
93fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com                setRegisterTypeAndPropagateChanges(startOfMethod, thisRegister,
94fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com                        RegisterType.getRegisterType(RegisterType.Category.Reference,
95fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com                            ClassPath.getClassDef(methodIdItem.getContainingClass())));
96fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com            }
97fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        }
98fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com
99fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        TypeListItem parameters = methodIdItem.getPrototype().getParameters();
100fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        if (parameters != null) {
101fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com            RegisterType[] parameterTypes = getParameterTypes(parameters, parameterRegisters);
102fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com            for (int i=0; i<parameterTypes.length; i++) {
103fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com                RegisterType registerType = parameterTypes[i];
104fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com                int registerNum = (totalRegisters - parameterRegisters) + i;
105fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com                setRegisterTypeAndPropagateChanges(startOfMethod, registerNum, registerType);
106fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com            }
107fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        }
108fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com
109fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        analyzed = true;
110fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        return makeInstructionArray();
111fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com    }
112fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com
113fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com    private int getThisRegister() {
114fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        assert (encodedMethod.accessFlags & AccessFlags.STATIC.getValue()) == 0;
115fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com
116fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        CodeItem codeItem = encodedMethod.codeItem;
117fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        assert codeItem != null;
118fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com
119fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        MethodIdItem methodIdItem = encodedMethod.method;
120fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        assert methodIdItem != null;
121fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com
122fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        int totalRegisters = codeItem.getRegisterCount();
123fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        if (totalRegisters == 0) {
124fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com            throw new ValidationException("A non-static method must have at least 1 register");
125fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        }
126fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com
127fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        int parameterRegisters = methodIdItem.getPrototype().getParameterRegisterCount();
128fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com
129fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        return totalRegisters - parameterRegisters - 1;
130fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com    }
131fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com
132fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com    private boolean isInstanceConstructor() {
133fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        return (encodedMethod.accessFlags & AccessFlags.STATIC.getValue()) == 0 &&
134fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com               (encodedMethod.accessFlags & AccessFlags.CONSTRUCTOR.getValue()) != 0;
135fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com    }
136fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com
137fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com    private boolean isStaticConstructor() {
138fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        return (encodedMethod.accessFlags & AccessFlags.STATIC.getValue()) != 0 &&
139fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com               (encodedMethod.accessFlags & AccessFlags.CONSTRUCTOR.getValue()) != 0;
140fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com    }
141fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com
142fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com    public AnalyzedInstruction[] makeInstructionArray() {
143fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        AnalyzedInstruction[] instructionArray = new AnalyzedInstruction[instructions.size()];
144fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        for (int i=0; i<instructions.size(); i++) {
145fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com            instructionArray[i] = instructions.valueAt(i);
146fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        }
147fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        return instructionArray;
148fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com    }
149fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com
150fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com    private static RegisterType[] getParameterTypes(TypeListItem typeListItem, int parameterRegisterCount) {
151fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        assert typeListItem != null;
152fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        assert parameterRegisterCount == typeListItem.getRegisterCount();
153fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com
154fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        RegisterType[] registerTypes = new RegisterType[parameterRegisterCount];
155fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com
156fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        int registerNum = 0;
157fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        for (TypeIdItem type: typeListItem.getTypes()) {
158fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com            if (type.getRegisterCount() == 2) {
159fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com                registerTypes[registerNum++] = RegisterType.getWideRegisterTypeForTypeIdItem(type, true);
160fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com                registerTypes[registerNum++] = RegisterType.getWideRegisterTypeForTypeIdItem(type, false);
161fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com            } else {
162fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com                registerTypes[registerNum] = RegisterType.getRegisterTypeForTypeIdItem(type);
163fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com            }
164fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        }
165fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com
166fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        return registerTypes;
167fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com    }
168fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com
169fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com    private int getInstructionAddress(AnalyzedInstruction instruction) {
170fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        return instructions.keyAt(instruction.instructionIndex);
171fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com    }
172fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com
173fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com    private void setWideDestinationRegisterTypeAndPropagateChanges(AnalyzedInstruction analyzedInstruction,
174fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com                                                                   RegisterType registerType) {
175fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        assert registerType.category == RegisterType.Category.LongLo ||
176fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com               registerType.category == RegisterType.Category.DoubleLo;
177fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com
178fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        checkWideDestinationPair(analyzedInstruction);
179fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com
180fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        setRegisterTypeAndPropagateChanges(analyzedInstruction, analyzedInstruction.getDestinationRegister(),
181fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com                registerType);
182fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        if (registerType.category == RegisterType.Category.LongLo) {
183fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com            setRegisterTypeAndPropagateChanges(analyzedInstruction, analyzedInstruction.getDestinationRegister() + 1,
184fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com                RegisterType.getRegisterType(RegisterType.Category.LongHi, null));
185fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        } else {
186fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com            setRegisterTypeAndPropagateChanges(analyzedInstruction, analyzedInstruction.getDestinationRegister() + 1,
187fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com                RegisterType.getRegisterType(RegisterType.Category.DoubleHi, null));
188fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        }
189fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com    }
190fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com
191fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com    private void setDestinationRegisterTypeAndPropagateChanges(AnalyzedInstruction analyzedInstruction,
192fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com                                                               RegisterType registerType) {
193fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        setRegisterTypeAndPropagateChanges(analyzedInstruction, analyzedInstruction.getDestinationRegister(),
194fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com                registerType);
195fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com    }
196fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com
197fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com    private void setRegisterTypeAndPropagateChanges(AnalyzedInstruction instruction, int registerNumber,
198fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com                                                RegisterType registerType) {
199fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com
200fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        BitSet changedInstructions = new BitSet(instructions.size());
201fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com
202fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        boolean changed = instruction.setPostRegisterType(registerNumber, registerType);
203fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com
204fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        if (!changed || instruction.setsRegister(registerNumber)) {
205fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com            return;
206fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        }
207fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com
208fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        propagateRegisterToSuccessors(instruction, registerNumber, changedInstructions);
209fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com
210fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        //using a for loop inside the while loop optimizes for the common case of the successors of an instruction
211fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        //occurring after the instruction. Any successors that occur prior to the instruction will be picked up on
212fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        //the next iteration of the while loop.
213fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        //this could also be done recursively, but in large methods it would likely cause very deep recursion,
214fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        //which would requires the user to specify a larger stack size. This isn't really a problem, but it is
215fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        //slightly annoying.
216fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        while (!changedInstructions.isEmpty()) {
217fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com            for (int instructionIndex=changedInstructions.nextSetBit(0);
218fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com                     instructionIndex>=0;
219fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com                     instructionIndex=changedInstructions.nextSetBit(instructionIndex)) {
220fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com
221fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com                changedInstructions.clear(instructionIndex);
222fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com
223fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com                propagateRegisterToSuccessors(instructions.valueAt(instructionIndex), registerNumber,
224fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com                        changedInstructions);
225fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com            }
226fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        }
227d27ca7f7a61cfbe60e1c490bf645257d7d59fd39JesusFreke@JesusFreke.com    }
228d27ca7f7a61cfbe60e1c490bf645257d7d59fd39JesusFreke@JesusFreke.com
229fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com    private void propagateRegisterToSuccessors(AnalyzedInstruction instruction, int registerNumber,
230fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com                                               BitSet changedInstructions) {
231fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        for (AnalyzedInstruction successor: instruction.successors) {
232fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com            if (!successor.setsRegister(registerNumber)) {
233fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com                RegisterType registerType = successor.getMergedRegisterTypeFromPredecessors(registerNumber);
234fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com
235fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com                if (successor.setPostRegisterType(registerNumber, registerType)) {
236fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com                    changedInstructions.set(successor.instructionIndex);
237fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com                }
238fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com            }
239fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        }
240fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com    }
241fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com
242fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com
243fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com
244d27ca7f7a61cfbe60e1c490bf645257d7d59fd39JesusFreke@JesusFreke.com    private void buildInstructionList() {
245d27ca7f7a61cfbe60e1c490bf645257d7d59fd39JesusFreke@JesusFreke.com        assert encodedMethod != null;
246d27ca7f7a61cfbe60e1c490bf645257d7d59fd39JesusFreke@JesusFreke.com        assert encodedMethod.codeItem != null;
247fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        int registerCount = encodedMethod.codeItem.getRegisterCount();
248d27ca7f7a61cfbe60e1c490bf645257d7d59fd39JesusFreke@JesusFreke.com
249fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        startOfMethod = new AnalyzedInstruction(null, -1, registerCount);
250d27ca7f7a61cfbe60e1c490bf645257d7d59fd39JesusFreke@JesusFreke.com
251d27ca7f7a61cfbe60e1c490bf645257d7d59fd39JesusFreke@JesusFreke.com        Instruction[] insns = encodedMethod.codeItem.getInstructions();
252d27ca7f7a61cfbe60e1c490bf645257d7d59fd39JesusFreke@JesusFreke.com
253fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        instructions = new SparseArray<AnalyzedInstruction>(insns.length);
254d27ca7f7a61cfbe60e1c490bf645257d7d59fd39JesusFreke@JesusFreke.com
255d27ca7f7a61cfbe60e1c490bf645257d7d59fd39JesusFreke@JesusFreke.com        //first, create all the instructions and populate the instructionAddresses array
256d27ca7f7a61cfbe60e1c490bf645257d7d59fd39JesusFreke@JesusFreke.com        int currentCodeAddress = 0;
257d27ca7f7a61cfbe60e1c490bf645257d7d59fd39JesusFreke@JesusFreke.com        for (int i=0; i<insns.length; i++) {
258fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com            instructions.append(currentCodeAddress, new AnalyzedInstruction(insns[i], i, registerCount));
259fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com            assert instructions.indexOfKey(currentCodeAddress) == i;
260d27ca7f7a61cfbe60e1c490bf645257d7d59fd39JesusFreke@JesusFreke.com            currentCodeAddress += insns[i].getSize(currentCodeAddress);
261d27ca7f7a61cfbe60e1c490bf645257d7d59fd39JesusFreke@JesusFreke.com        }
262d27ca7f7a61cfbe60e1c490bf645257d7d59fd39JesusFreke@JesusFreke.com
263d27ca7f7a61cfbe60e1c490bf645257d7d59fd39JesusFreke@JesusFreke.com        //next, populate the exceptionHandlers array. The array item for each instruction that can throw an exception
264d27ca7f7a61cfbe60e1c490bf645257d7d59fd39JesusFreke@JesusFreke.com        //and is covered by a try block should be set to a list of the first instructions of each exception handler
265d27ca7f7a61cfbe60e1c490bf645257d7d59fd39JesusFreke@JesusFreke.com        //for the try block covering the instruction
266d27ca7f7a61cfbe60e1c490bf645257d7d59fd39JesusFreke@JesusFreke.com        CodeItem.TryItem[] tries = encodedMethod.codeItem.getTries();
267d27ca7f7a61cfbe60e1c490bf645257d7d59fd39JesusFreke@JesusFreke.com        int triesIndex = 0;
268d27ca7f7a61cfbe60e1c490bf645257d7d59fd39JesusFreke@JesusFreke.com        CodeItem.TryItem currentTry = null;
269fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        AnalyzedInstruction[] currentExceptionHandlers = null;
270fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        AnalyzedInstruction[][] exceptionHandlers = new AnalyzedInstruction[insns.length][];
271d27ca7f7a61cfbe60e1c490bf645257d7d59fd39JesusFreke@JesusFreke.com
272fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        for (int i=0; i<instructions.size(); i++) {
273fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com            AnalyzedInstruction instruction = instructions.valueAt(i);
274d27ca7f7a61cfbe60e1c490bf645257d7d59fd39JesusFreke@JesusFreke.com            Opcode instructionOpcode = instruction.instruction.opcode;
275d27ca7f7a61cfbe60e1c490bf645257d7d59fd39JesusFreke@JesusFreke.com
276d27ca7f7a61cfbe60e1c490bf645257d7d59fd39JesusFreke@JesusFreke.com            //check if we have gone past the end of the current try
277d27ca7f7a61cfbe60e1c490bf645257d7d59fd39JesusFreke@JesusFreke.com            if (currentTry != null) {
278d27ca7f7a61cfbe60e1c490bf645257d7d59fd39JesusFreke@JesusFreke.com                if (currentTry.getStartCodeAddress() + currentTry.getTryLength() <= currentCodeAddress) {
279d27ca7f7a61cfbe60e1c490bf645257d7d59fd39JesusFreke@JesusFreke.com                    currentTry = null;
280d27ca7f7a61cfbe60e1c490bf645257d7d59fd39JesusFreke@JesusFreke.com                    triesIndex++;
281d27ca7f7a61cfbe60e1c490bf645257d7d59fd39JesusFreke@JesusFreke.com                }
282d27ca7f7a61cfbe60e1c490bf645257d7d59fd39JesusFreke@JesusFreke.com            }
283d27ca7f7a61cfbe60e1c490bf645257d7d59fd39JesusFreke@JesusFreke.com
284d27ca7f7a61cfbe60e1c490bf645257d7d59fd39JesusFreke@JesusFreke.com            //check if the next try is applicable yet
285d27ca7f7a61cfbe60e1c490bf645257d7d59fd39JesusFreke@JesusFreke.com            if (currentTry == null && triesIndex < tries.length) {
286d27ca7f7a61cfbe60e1c490bf645257d7d59fd39JesusFreke@JesusFreke.com                CodeItem.TryItem tryItem = tries[triesIndex];
287d27ca7f7a61cfbe60e1c490bf645257d7d59fd39JesusFreke@JesusFreke.com                if (tryItem.getStartCodeAddress() <= currentCodeAddress) {
288d27ca7f7a61cfbe60e1c490bf645257d7d59fd39JesusFreke@JesusFreke.com                    assert(tryItem.getStartCodeAddress() + tryItem.getTryLength() > currentCodeAddress);
289d27ca7f7a61cfbe60e1c490bf645257d7d59fd39JesusFreke@JesusFreke.com
290d27ca7f7a61cfbe60e1c490bf645257d7d59fd39JesusFreke@JesusFreke.com                    currentTry = tryItem;
291d27ca7f7a61cfbe60e1c490bf645257d7d59fd39JesusFreke@JesusFreke.com
292d27ca7f7a61cfbe60e1c490bf645257d7d59fd39JesusFreke@JesusFreke.com                    currentExceptionHandlers = buildExceptionHandlerArray(tryItem);
293d27ca7f7a61cfbe60e1c490bf645257d7d59fd39JesusFreke@JesusFreke.com                }
294d27ca7f7a61cfbe60e1c490bf645257d7d59fd39JesusFreke@JesusFreke.com            }
295d27ca7f7a61cfbe60e1c490bf645257d7d59fd39JesusFreke@JesusFreke.com
296d27ca7f7a61cfbe60e1c490bf645257d7d59fd39JesusFreke@JesusFreke.com            //if we're inside a try block, and the instruction can throw an exception, then add the exception handlers
297d27ca7f7a61cfbe60e1c490bf645257d7d59fd39JesusFreke@JesusFreke.com            //for the current instruction
298d27ca7f7a61cfbe60e1c490bf645257d7d59fd39JesusFreke@JesusFreke.com            if (currentTry != null && instructionOpcode.canThrow()) {
299d27ca7f7a61cfbe60e1c490bf645257d7d59fd39JesusFreke@JesusFreke.com                exceptionHandlers[i] = currentExceptionHandlers;
300d27ca7f7a61cfbe60e1c490bf645257d7d59fd39JesusFreke@JesusFreke.com            }
301d27ca7f7a61cfbe60e1c490bf645257d7d59fd39JesusFreke@JesusFreke.com        }
302d27ca7f7a61cfbe60e1c490bf645257d7d59fd39JesusFreke@JesusFreke.com
303d27ca7f7a61cfbe60e1c490bf645257d7d59fd39JesusFreke@JesusFreke.com        //finally, populate the successors and predecessors for each instruction
304fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        assert instructions.size() > 0;
305fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        addPredecessorSuccessor(startOfMethod, instructions.valueAt(0), exceptionHandlers);
306fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        startOfMethod.addSuccessor(instructions.valueAt(0));
307fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com
308fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        for (int i=0; i<instructions.size(); i++) {
309fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com            AnalyzedInstruction instruction = instructions.valueAt(i);
310d27ca7f7a61cfbe60e1c490bf645257d7d59fd39JesusFreke@JesusFreke.com            Opcode instructionOpcode = instruction.instruction.opcode;
311fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com            int instructionCodeAddress = getInstructionAddress(instruction);
312d27ca7f7a61cfbe60e1c490bf645257d7d59fd39JesusFreke@JesusFreke.com
313d27ca7f7a61cfbe60e1c490bf645257d7d59fd39JesusFreke@JesusFreke.com            if (instruction.instruction.opcode.canContinue()) {
314fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com                if (i == instructions.size() - 1) {
315d27ca7f7a61cfbe60e1c490bf645257d7d59fd39JesusFreke@JesusFreke.com                    throw new ValidationException("Execution can continue past the last instruction");
316d27ca7f7a61cfbe60e1c490bf645257d7d59fd39JesusFreke@JesusFreke.com                }
317fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com                AnalyzedInstruction nextInstruction = instructions.valueAt(i+1);
318fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com                addPredecessorSuccessor(instruction, nextInstruction, exceptionHandlers);
319d27ca7f7a61cfbe60e1c490bf645257d7d59fd39JesusFreke@JesusFreke.com            }
320d27ca7f7a61cfbe60e1c490bf645257d7d59fd39JesusFreke@JesusFreke.com
321d27ca7f7a61cfbe60e1c490bf645257d7d59fd39JesusFreke@JesusFreke.com            if (instruction instanceof OffsetInstruction) {
322d27ca7f7a61cfbe60e1c490bf645257d7d59fd39JesusFreke@JesusFreke.com                OffsetInstruction offsetInstruction = (OffsetInstruction)instruction;
323d27ca7f7a61cfbe60e1c490bf645257d7d59fd39JesusFreke@JesusFreke.com
324d27ca7f7a61cfbe60e1c490bf645257d7d59fd39JesusFreke@JesusFreke.com                if (instructionOpcode == Opcode.PACKED_SWITCH || instructionOpcode == Opcode.SPARSE_SWITCH) {
325d27ca7f7a61cfbe60e1c490bf645257d7d59fd39JesusFreke@JesusFreke.com                    MultiOffsetInstruction switchDataInstruction =
326fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com                            (MultiOffsetInstruction)instructions.get(instructionCodeAddress +
327d27ca7f7a61cfbe60e1c490bf645257d7d59fd39JesusFreke@JesusFreke.com                                    offsetInstruction.getTargetAddressOffset()).instruction;
328d27ca7f7a61cfbe60e1c490bf645257d7d59fd39JesusFreke@JesusFreke.com                    for (int targetAddressOffset: switchDataInstruction.getTargets()) {
329fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com                        AnalyzedInstruction targetInstruction = instructions.get(instructionCodeAddress +
330d27ca7f7a61cfbe60e1c490bf645257d7d59fd39JesusFreke@JesusFreke.com                                targetAddressOffset);
331d27ca7f7a61cfbe60e1c490bf645257d7d59fd39JesusFreke@JesusFreke.com
332fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com                        addPredecessorSuccessor(instruction, targetInstruction, exceptionHandlers);
333d27ca7f7a61cfbe60e1c490bf645257d7d59fd39JesusFreke@JesusFreke.com                    }
334d27ca7f7a61cfbe60e1c490bf645257d7d59fd39JesusFreke@JesusFreke.com                } else {
335d27ca7f7a61cfbe60e1c490bf645257d7d59fd39JesusFreke@JesusFreke.com                    int targetAddressOffset = offsetInstruction.getTargetAddressOffset();
336fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com                    AnalyzedInstruction targetInstruction = instructions.get(instructionCodeAddress +
337fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com                            targetAddressOffset);
338fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com                    addPredecessorSuccessor(instruction, targetInstruction, exceptionHandlers);
339d27ca7f7a61cfbe60e1c490bf645257d7d59fd39JesusFreke@JesusFreke.com                }
340d27ca7f7a61cfbe60e1c490bf645257d7d59fd39JesusFreke@JesusFreke.com            }
341d27ca7f7a61cfbe60e1c490bf645257d7d59fd39JesusFreke@JesusFreke.com        }
342d27ca7f7a61cfbe60e1c490bf645257d7d59fd39JesusFreke@JesusFreke.com    }
343d27ca7f7a61cfbe60e1c490bf645257d7d59fd39JesusFreke@JesusFreke.com
344d27ca7f7a61cfbe60e1c490bf645257d7d59fd39JesusFreke@JesusFreke.com    private void addPredecessorSuccessor(AnalyzedInstruction predecessor, AnalyzedInstruction successor,
345fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com                                                AnalyzedInstruction[][] exceptionHandlers) {
346fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        addPredecessorSuccessor(predecessor, successor, exceptionHandlers, false);
347fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com    }
348fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com
349fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com    private void addPredecessorSuccessor(AnalyzedInstruction predecessor, AnalyzedInstruction successor,
350fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com                                                AnalyzedInstruction[][] exceptionHandlers, boolean allowMoveException) {
351fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com
352fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        if (!allowMoveException && successor.instruction.opcode == Opcode.MOVE_EXCEPTION) {
353fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com            throw new ValidationException("Execution can pass from the " + predecessor.instruction.opcode.name +
354fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com                    " instruction at code address 0x" + Integer.toHexString(getInstructionAddress(predecessor)) +
355fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com                    " to the move-exception instruction at address 0x" +
356fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com                    Integer.toHexString(getInstructionAddress(successor)));
357fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        }
358d27ca7f7a61cfbe60e1c490bf645257d7d59fd39JesusFreke@JesusFreke.com
359d27ca7f7a61cfbe60e1c490bf645257d7d59fd39JesusFreke@JesusFreke.com        if (!predecessor.addSuccessor(successor)) {
360d27ca7f7a61cfbe60e1c490bf645257d7d59fd39JesusFreke@JesusFreke.com            //if predecessor already had successor as a successor, then there's nothing else to do
361d27ca7f7a61cfbe60e1c490bf645257d7d59fd39JesusFreke@JesusFreke.com            return;
362d27ca7f7a61cfbe60e1c490bf645257d7d59fd39JesusFreke@JesusFreke.com        }
363d27ca7f7a61cfbe60e1c490bf645257d7d59fd39JesusFreke@JesusFreke.com
364d27ca7f7a61cfbe60e1c490bf645257d7d59fd39JesusFreke@JesusFreke.com        successor.addPredecessor(predecessor);
365d27ca7f7a61cfbe60e1c490bf645257d7d59fd39JesusFreke@JesusFreke.com
366fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        //TODO: need to handle the case of monitor-exit as a special case - the exception is thrown *after* the instruction executes
367d27ca7f7a61cfbe60e1c490bf645257d7d59fd39JesusFreke@JesusFreke.com        //if the successor can throw an instruction, then we need to add the exception handlers as additional
368d27ca7f7a61cfbe60e1c490bf645257d7d59fd39JesusFreke@JesusFreke.com        //successors to the predecessor (and then apply this same logic recursively if needed)
369fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        AnalyzedInstruction[] exceptionHandlersForSuccessor = exceptionHandlers[successor.instructionIndex];
370d27ca7f7a61cfbe60e1c490bf645257d7d59fd39JesusFreke@JesusFreke.com        if (exceptionHandlersForSuccessor != null) {
371d27ca7f7a61cfbe60e1c490bf645257d7d59fd39JesusFreke@JesusFreke.com            //the item for this instruction in exceptionHandlersForSuccessor should only be set if this instruction
372d27ca7f7a61cfbe60e1c490bf645257d7d59fd39JesusFreke@JesusFreke.com            //can throw an exception
373d27ca7f7a61cfbe60e1c490bf645257d7d59fd39JesusFreke@JesusFreke.com            assert predecessor.instruction.opcode.canThrow();
374d27ca7f7a61cfbe60e1c490bf645257d7d59fd39JesusFreke@JesusFreke.com
375fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com            for (AnalyzedInstruction exceptionHandler: exceptionHandlersForSuccessor) {
376fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com                addPredecessorSuccessor(predecessor, exceptionHandler, exceptionHandlers, true);
377d27ca7f7a61cfbe60e1c490bf645257d7d59fd39JesusFreke@JesusFreke.com            }
378d27ca7f7a61cfbe60e1c490bf645257d7d59fd39JesusFreke@JesusFreke.com        }
379d27ca7f7a61cfbe60e1c490bf645257d7d59fd39JesusFreke@JesusFreke.com    }
380d27ca7f7a61cfbe60e1c490bf645257d7d59fd39JesusFreke@JesusFreke.com
381fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com    private AnalyzedInstruction[] buildExceptionHandlerArray(CodeItem.TryItem tryItem) {
382d27ca7f7a61cfbe60e1c490bf645257d7d59fd39JesusFreke@JesusFreke.com        int exceptionHandlerCount = tryItem.encodedCatchHandler.handlers.length;
383d27ca7f7a61cfbe60e1c490bf645257d7d59fd39JesusFreke@JesusFreke.com        int catchAllHandler = tryItem.encodedCatchHandler.getCatchAllHandlerAddress();
384d27ca7f7a61cfbe60e1c490bf645257d7d59fd39JesusFreke@JesusFreke.com        if (catchAllHandler != -1) {
385d27ca7f7a61cfbe60e1c490bf645257d7d59fd39JesusFreke@JesusFreke.com            exceptionHandlerCount++;
386d27ca7f7a61cfbe60e1c490bf645257d7d59fd39JesusFreke@JesusFreke.com        }
387d27ca7f7a61cfbe60e1c490bf645257d7d59fd39JesusFreke@JesusFreke.com
388fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        AnalyzedInstruction[] exceptionHandlers = new AnalyzedInstruction[exceptionHandlerCount];
389d27ca7f7a61cfbe60e1c490bf645257d7d59fd39JesusFreke@JesusFreke.com        for (int i=0; i<tryItem.encodedCatchHandler.handlers.length; i++) {
390fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com            exceptionHandlers[i] = instructions.get(tryItem.encodedCatchHandler.handlers[i].getHandlerAddress());
391d27ca7f7a61cfbe60e1c490bf645257d7d59fd39JesusFreke@JesusFreke.com        }
392d27ca7f7a61cfbe60e1c490bf645257d7d59fd39JesusFreke@JesusFreke.com
393d27ca7f7a61cfbe60e1c490bf645257d7d59fd39JesusFreke@JesusFreke.com        if (catchAllHandler != -1) {
394fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com            exceptionHandlers[exceptionHandlers.length - 1] = instructions.get(catchAllHandler);
395d27ca7f7a61cfbe60e1c490bf645257d7d59fd39JesusFreke@JesusFreke.com        }
396d27ca7f7a61cfbe60e1c490bf645257d7d59fd39JesusFreke@JesusFreke.com
397d27ca7f7a61cfbe60e1c490bf645257d7d59fd39JesusFreke@JesusFreke.com        return exceptionHandlers;
398d27ca7f7a61cfbe60e1c490bf645257d7d59fd39JesusFreke@JesusFreke.com    }
399d27ca7f7a61cfbe60e1c490bf645257d7d59fd39JesusFreke@JesusFreke.com
400fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com    private boolean setDestinationRegisterTypeForInstruction(AnalyzedInstruction analyzedInstruction) {
401fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        Instruction instruction = analyzedInstruction.instruction;
402fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com
403fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        switch (instruction.opcode) {
404fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com            case NOP:
405fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com                return true;
406fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com            case MOVE:
407fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com            case MOVE_FROM16:
408fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com            case MOVE_16:
409fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com                return handleMove(analyzedInstruction, Primitive32BitCategories);
410fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com            case MOVE_WIDE:
411fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com            case MOVE_WIDE_FROM16:
412fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com            case MOVE_WIDE_16:
413fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com                return handleMoveWide(analyzedInstruction);
414fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com            case MOVE_OBJECT:
415fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com            case MOVE_OBJECT_FROM16:
416fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com            case MOVE_OBJECT_16:
417fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com                return handleMove(analyzedInstruction, ReferenceCategories);
418fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com            case MOVE_RESULT:
419fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com                return handleMoveResult(analyzedInstruction, Primitive32BitCategories);
420fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com            case MOVE_RESULT_WIDE:
421fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com                return handleMoveResult(analyzedInstruction, WideLowCategories);
422fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com            case MOVE_RESULT_OBJECT:
423fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com                return handleMoveResult(analyzedInstruction, ReferenceCategories);
424fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com            case MOVE_EXCEPTION:
425fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com                return handleMoveException(analyzedInstruction);
426fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com            case RETURN_VOID:
427fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com                return handleReturnVoid(analyzedInstruction);
428fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com            case RETURN:
429fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com                return handleReturn(analyzedInstruction);
430fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com            case RETURN_WIDE:
431fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com                return handleReturnWide(analyzedInstruction);
432fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com            case RETURN_OBJECT:
433fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com                return handleReturnObject(analyzedInstruction);
434fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com            case CONST_4:
435fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com            case CONST_16:
436fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com            case CONST:
437fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com                return handleConst(analyzedInstruction);
438fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com            case CONST_HIGH16:
439fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com                return handleConstHigh16(analyzedInstruction);
440fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com            case CONST_WIDE_16:
441fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com            case CONST_WIDE_32:
442fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com            case CONST_WIDE:
443fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com            case CONST_WIDE_HIGH16:
444fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com                return handleWideConst(analyzedInstruction);
445fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com            case CONST_STRING:
446fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com            case CONST_STRING_JUMBO:
447fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com                return handleConstString(analyzedInstruction);
448fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com            case CONST_CLASS:
449fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com                return handleConstClass(analyzedInstruction);
450fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com            case MONITOR_ENTER:
451fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com            case MONITOR_EXIT:
452fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com                return handleMonitor(analyzedInstruction);
453fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com            case CHECK_CAST:
454fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com                return handleCheckCast(analyzedInstruction);
455fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com            case INSTANCE_OF:
456fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com                return handleInstanceOf(analyzedInstruction);
457fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com            case ARRAY_LENGTH:
458fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com                return handleArrayLength(analyzedInstruction);
459fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com            case NEW_INSTANCE:
460fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com                return handleNewInstance(analyzedInstruction);
461fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com            case NEW_ARRAY:
462fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com                return handleNewArray(analyzedInstruction);
4639e5dd85d837501e84e18617fc136c8203ab1f183JesusFreke@JesusFreke.com            case FILLED_NEW_ARRAY:
4649e5dd85d837501e84e18617fc136c8203ab1f183JesusFreke@JesusFreke.com                return handleFilledNewArray(analyzedInstruction);
465ac8785e5d550c2ec7c7d02dd2990f859a78c111cJesusFreke@JesusFreke.com            case FILLED_NEW_ARRAY_RANGE:
466ac8785e5d550c2ec7c7d02dd2990f859a78c111cJesusFreke@JesusFreke.com                return handleFilledNewArrayRange(analyzedInstruction);
467472d3ea58455ebf43d21819b2701fad98b5a0f9cJesusFreke@JesusFreke.com            case FILL_ARRAY_DATA:
468472d3ea58455ebf43d21819b2701fad98b5a0f9cJesusFreke@JesusFreke.com                return handleFillArrayData(analyzedInstruction);
469ed140ca3e4fa66a03970affb3415a9fe2a924312JesusFreke@JesusFreke.com            case THROW:
470ed140ca3e4fa66a03970affb3415a9fe2a924312JesusFreke@JesusFreke.com                return handleThrow(analyzedInstruction);
471898edda7cea48c02687bb71804a98cfd6e260b89JesusFreke@JesusFreke.com            case GOTO:
472898edda7cea48c02687bb71804a98cfd6e260b89JesusFreke@JesusFreke.com            case GOTO_16:
473898edda7cea48c02687bb71804a98cfd6e260b89JesusFreke@JesusFreke.com            case GOTO_32:
474898edda7cea48c02687bb71804a98cfd6e260b89JesusFreke@JesusFreke.com                //nothing to do
475898edda7cea48c02687bb71804a98cfd6e260b89JesusFreke@JesusFreke.com                return true;
476cda44f70cfebfae4875cd77455a171075aebac4dJesusFreke@JesusFreke.com            case PACKED_SWITCH:
477cda44f70cfebfae4875cd77455a171075aebac4dJesusFreke@JesusFreke.com                return handleSwitch(analyzedInstruction, Format.PackedSwitchData);
478cda44f70cfebfae4875cd77455a171075aebac4dJesusFreke@JesusFreke.com            case SPARSE_SWITCH:
479cda44f70cfebfae4875cd77455a171075aebac4dJesusFreke@JesusFreke.com                return handleSwitch(analyzedInstruction, Format.SparseSwitchData);
480fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        }
481fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        assert false;
482fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        return false;
483fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com    }
484fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com
485fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com    private static final EnumSet<RegisterType.Category> Primitive32BitCategories = EnumSet.of(
486fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com            RegisterType.Category.Null,
487fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com            RegisterType.Category.Boolean,
488fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com            RegisterType.Category.Byte,
489fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com            RegisterType.Category.Short,
490fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com            RegisterType.Category.Char,
491fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com            RegisterType.Category.Integer,
492fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com            RegisterType.Category.Float);
493fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com
494fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com    private static final EnumSet<RegisterType.Category> WideLowCategories = EnumSet.of(
495fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com            RegisterType.Category.LongLo,
496fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com            RegisterType.Category.DoubleLo);
497fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com
498fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com    private static final EnumSet<RegisterType.Category> WideHighCategories = EnumSet.of(
499fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com            RegisterType.Category.LongHi,
500fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com            RegisterType.Category.DoubleHi);
501fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com
502fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com    private static final EnumSet<RegisterType.Category> ReferenceCategories = EnumSet.of(
503fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com            RegisterType.Category.Null,
504fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com            RegisterType.Category.Reference);
505fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com
506fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com    private boolean handleMove(AnalyzedInstruction analyzedInstruction,
507fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com                               EnumSet<RegisterType.Category> allowedCategories) {
508fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        TwoRegisterInstruction instruction = (TwoRegisterInstruction)analyzedInstruction.instruction;
509fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com
510fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        //get the "pre-instruction" register type for the source register
511fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        RegisterType sourceRegisterType = analyzedInstruction.getPreInstructionRegisterType(instruction.getRegisterB());
512fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        assert sourceRegisterType != null;
513fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com
514fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        if (sourceRegisterType.category == RegisterType.Category.Unknown) {
515fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com            //we don't know the source register type yet, so we can't verify it. Return false, and we'll come back later
516fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com            return false;
517fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        }
518d27ca7f7a61cfbe60e1c490bf645257d7d59fd39JesusFreke@JesusFreke.com
519fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        checkRegister(sourceRegisterType, allowedCategories);
520d27ca7f7a61cfbe60e1c490bf645257d7d59fd39JesusFreke@JesusFreke.com
521fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        setDestinationRegisterTypeAndPropagateChanges(analyzedInstruction, sourceRegisterType);
522fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        return true;
523fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com    }
524fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com
525fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com    private boolean handleMoveWide(AnalyzedInstruction analyzedInstruction) {
526fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        TwoRegisterInstruction instruction = (TwoRegisterInstruction)analyzedInstruction.instruction;
527fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com
528fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        RegisterType sourceRegisterType = getAndCheckWideSourcePair(analyzedInstruction,
529fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com                instruction.getRegisterB());
530fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        assert sourceRegisterType != null;
531fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com
532fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        if (sourceRegisterType.category == RegisterType.Category.Unknown) {
533fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com            //we don't know the source register type yet, so we can't verify it. Return false, and we'll come back later
534fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com            return false;
535fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        }
536fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com
537fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        checkWideDestinationPair(analyzedInstruction);
538fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com
539fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        setDestinationRegisterTypeAndPropagateChanges(analyzedInstruction, sourceRegisterType);
540fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        return true;
541fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com    }
542fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com
543fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com    private boolean handleMoveResult(AnalyzedInstruction analyzedInstruction,
544fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com                                     EnumSet<RegisterType.Category> allowedCategories) {
545fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com
546fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        //TODO: handle the case when the previous instruction is an odexed instruction
547fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com
548fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        if (analyzedInstruction.instructionIndex == 0) {
549fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com            throw new ValidationException(analyzedInstruction.instruction.opcode.name + " cannot be the first " +
550fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com                    "instruction in a method. It must occur after an invoke-*/fill-new-array instruction");
551fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        }
552fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com
553fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        AnalyzedInstruction previousInstruction = instructions.valueAt(analyzedInstruction.instructionIndex-1);
554fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com
555fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        if (!previousInstruction.instruction.opcode.setsResult()) {
556fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com            throw new ValidationException(analyzedInstruction.instruction.opcode.name + " must occur after an " +
557fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com                    "invoke-*/fill-new-array instruction");
558fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        }
559fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com
560fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        if (analyzedInstruction.instruction.opcode.setsWideRegister()) {
561fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com            checkWideDestinationPair(analyzedInstruction);
562fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        }
563fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com
564fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        //TODO: does dalvik allow a move-result after an invoke with a void return type?
565fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        RegisterType destinationRegisterType;
566fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com
567fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        InstructionWithReference invokeInstruction = (InstructionWithReference)previousInstruction.instruction;
568fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        Item item = invokeInstruction.getReferencedItem();
569fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com
570fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        if (item instanceof MethodIdItem) {
571fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com            destinationRegisterType = RegisterType.getRegisterTypeForTypeIdItem(
572fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com                    ((MethodIdItem)item).getPrototype().getReturnType());
573fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        } else {
574fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com            assert item instanceof TypeIdItem;
575fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com            destinationRegisterType = RegisterType.getRegisterTypeForTypeIdItem((TypeIdItem)item);
576fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        }
577fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com
578fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        checkRegister(destinationRegisterType, allowedCategories);
579fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        setDestinationRegisterTypeAndPropagateChanges(analyzedInstruction, destinationRegisterType);
580fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        return true;
581fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com    }
582fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com
583fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com    private boolean handleMoveException(AnalyzedInstruction analyzedInstruction) {
584fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        CodeItem.TryItem[] tries = encodedMethod.codeItem.getTries();
585fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        int instructionAddress = getInstructionAddress(analyzedInstruction);
586fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com
587fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        if (tries == null) {
588fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com            throw new ValidationException("move-exception must be the first instruction in an exception handler block");
589fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        }
590fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com
591fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        RegisterType exceptionType = null;
592fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com
593fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        for (CodeItem.TryItem tryItem: encodedMethod.codeItem.getTries()) {
594fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com            if (tryItem.encodedCatchHandler.getCatchAllHandlerAddress() == instructionAddress) {
595fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com                exceptionType = RegisterType.getRegisterType(RegisterType.Category.Reference,
596fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com                        ClassPath.getClassDef("Ljava/lang/Throwable;"));
597fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com                break;
598fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com            }
599fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com            for (CodeItem.EncodedTypeAddrPair handler: tryItem.encodedCatchHandler.handlers) {
600fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com                if (handler.getHandlerAddress() == instructionAddress) {
601fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com                    exceptionType = RegisterType.getRegisterTypeForTypeIdItem(handler.exceptionType)
602fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com                            .merge(exceptionType);
603fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com                }
604fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com            }
605fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        }
606fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com
607fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        //TODO: check if the type is a throwable. Should we throw a ValidationException or print a warning? (does dalvik validate that it's a throwable? It doesn't in CodeVerify.c, but it might check in DexSwapVerify.c)
608fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        checkRegister(exceptionType, ReferenceCategories);
609fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        setDestinationRegisterTypeAndPropagateChanges(analyzedInstruction, exceptionType);
610fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        return true;
611fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com    }
612fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com
613fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com    private boolean checkConstructorReturn(AnalyzedInstruction analyzedInstruction) {
614fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        assert this.isInstanceConstructor();
615fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com
616fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        //if we're in an instance constructor (an <init> method), then the superclass <init> must have been called.
617fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        //When execution enters the method, the "this" register is set as an uninitialized reference to the containing
618fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        //class. Once the superclass' <init> is called, the "this" register is upgraded to a full-blown reference type,
619fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        //so we need to ensure that the "this" register isn't an uninitialized reference
620fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com
621fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        int thisRegister = getThisRegister();
622fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        RegisterType thisRegisterType = analyzedInstruction.postRegisterMap[thisRegister];
623fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com
624fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        if (thisRegisterType.category == RegisterType.Category.Unknown) {
625fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com            //we don't have enough information yet, so return false. We'll come back later
626fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com            return false;
627fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        }
628fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        if (thisRegisterType.category == RegisterType.Category.UninitRef) {
629fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com            throw new ValidationException("Returning from constructor without calling the superclass' <init>");
630fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        }
631fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        assert thisRegisterType.category == RegisterType.Category.Reference;
632fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        assert thisRegisterType.type == ClassPath.getClassDef(encodedMethod.method.getContainingClass());
633fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        return true;
634fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com    }
635fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com
636fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com    private boolean handleReturnVoid(AnalyzedInstruction analyzedInstruction) {
637fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        if (this.isInstanceConstructor()) {
638fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com            if (!checkConstructorReturn(analyzedInstruction)) {
639fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com                return false;
640fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com            }
641fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        }
642fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com
643fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        TypeIdItem returnType = encodedMethod.method.getPrototype().getReturnType();
644fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        if (returnType.getTypeDescriptor().charAt(0) != 'V') {
645fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com            //TODO: could add which return-* variation should be used instead
646fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com            throw new ValidationException("Cannot use return-void with a non-void return type (" +
647fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com                returnType.getTypeDescriptor() + ")");
648fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        }
649fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        return true;
650fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com    }
651fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com
652fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com    private boolean handleReturn(AnalyzedInstruction analyzedInstruction) {
653fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        if (this.isInstanceConstructor()) {
654fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com            if (!checkConstructorReturn(analyzedInstruction)) {
655fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com                return false;
656fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com            }
657fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        }
658fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com
659fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        SingleRegisterInstruction instruction = (SingleRegisterInstruction)analyzedInstruction.instruction;
660fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        RegisterType returnRegisterType = analyzedInstruction.postRegisterMap[instruction.getRegisterA()];
661fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com
662fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        if (returnRegisterType.category == RegisterType.Category.Unknown) {
663fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com            return false;
664fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        }
665fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com
666fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        checkRegister(returnRegisterType, Primitive32BitCategories);
667fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com
668fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        TypeIdItem returnType = encodedMethod.method.getPrototype().getReturnType();
669fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        if (returnType.getTypeDescriptor().charAt(0) == 'V') {
670fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com            throw new ValidationException("Cannot use return with a void return type. Use return-void instead");
671fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        }
672fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com
673fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        RegisterType registerType = RegisterType.getRegisterTypeForTypeIdItem(returnType);
674fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com
675fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        if (!Primitive32BitCategories.contains(registerType.category)) {
676fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com            //TODO: could add which return-* variation should be used instead
677fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com            throw new ValidationException("Cannot use return with return type " + returnType.getTypeDescriptor());
678fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        }
679fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com
680fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com
681fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        return true;
682fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com    }
683fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com
684fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com    private boolean handleReturnWide(AnalyzedInstruction analyzedInstruction) {
685fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        if (this.isInstanceConstructor()) {
686fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com            if (!checkConstructorReturn(analyzedInstruction)) {
687fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com                return false;
688fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com            }
689fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        }
690fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com
691fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        SingleRegisterInstruction instruction = (SingleRegisterInstruction)analyzedInstruction.instruction;
692fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        RegisterType returnType = getAndCheckWideSourcePair(analyzedInstruction, instruction.getRegisterA());
693fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com
694fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        if (returnType.category == RegisterType.Category.Unknown) {
695fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com            return false;
696fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        }
697fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com
698fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com
699fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        TypeIdItem returnTypeIdItem = encodedMethod.method.getPrototype().getReturnType();
700fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        if (returnTypeIdItem.getTypeDescriptor().charAt(0) == 'V') {
701fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com            throw new ValidationException("Cannot use return-wide with a void return type. Use return-void instead");
702fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        }
703fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com
704fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        returnType = RegisterType.getRegisterTypeForTypeIdItem(returnTypeIdItem);
705fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        if (!WideLowCategories.contains(returnType.category)) {
706fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com            //TODO: could add which return-* variation should be used instead
707fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com            throw new ValidationException("Cannot use return-wide with return type " +
708fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com                    returnTypeIdItem.getTypeDescriptor());
709fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        }
710fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com
711fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        return true;
712fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com    }
713fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com
714fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com    private boolean handleReturnObject(AnalyzedInstruction analyzedInstruction) {
715fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        if (this.isInstanceConstructor()) {
716fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com            if (!checkConstructorReturn(analyzedInstruction)) {
717fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com                return false;
718fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com            }
719fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        }
720fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com
721fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        SingleRegisterInstruction instruction = (SingleRegisterInstruction)analyzedInstruction.instruction;
722fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        int returnRegister = instruction.getRegisterA();
723fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        RegisterType returnRegisterType = analyzedInstruction.postRegisterMap[returnRegister];
724fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com
725fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        if (returnRegisterType.category == RegisterType.Category.Unknown) {
726fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com            return false;
727fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        }
728fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com
729fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        checkRegister(returnRegisterType, ReferenceCategories);
730fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com
731fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com
732fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        TypeIdItem returnTypeIdItem = encodedMethod.method.getPrototype().getReturnType();
733fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        if (returnTypeIdItem.getTypeDescriptor().charAt(0) == 'V') {
734fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com            throw new ValidationException("Cannot use return with a void return type. Use return-void instead");
735fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        }
736fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com
737fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        RegisterType returnType = RegisterType.getRegisterTypeForTypeIdItem(returnTypeIdItem);
738fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com
739fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        if (!ReferenceCategories.contains(returnType.category)) {
740fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com            //TODO: could add which return-* variation should be used instead
741fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com            throw new ValidationException("Cannot use " + analyzedInstruction + " with return type " +
742fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com                    returnTypeIdItem.getTypeDescriptor());
743fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        }
744fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com
745fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        if (returnType.type.isInterface()) {
746fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com            if (!returnRegisterType.type.implementsInterface(returnType.type)) {
747fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com                //TODO: how to handle warnings?
748fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com            }
749fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        } else {
750fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com            if (!returnRegisterType.type.extendsClass(returnType.type)) {
751fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com                throw new ValidationException("The return value in register v" + Integer.toString(returnRegister) +
752fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com                        "(" + returnRegisterType.type.getClassType() + ") is not compatible with the method's return " +
753fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com                        "type (" + returnType.type.getClassType() + ")");
754fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com            }
755fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        }
756fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com
757fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        return true;
758fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com    }
759fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com
760fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com    private boolean handleConst(AnalyzedInstruction analyzedInstruction) {
761fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        LiteralInstruction instruction = (LiteralInstruction)analyzedInstruction.instruction;
762fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com
763fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        RegisterType newDestinationRegisterType = RegisterType.getRegisterTypeForLiteral(instruction.getLiteral());
764fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com
765fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        //we assume that the literal value is a valid value for the given instruction type, because it's impossible
766fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        //to store an invalid literal with the instruction. so we don't need to check the type of the literal
767fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        setDestinationRegisterTypeAndPropagateChanges(analyzedInstruction, newDestinationRegisterType);
768fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        return true;
769fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com    }
770fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com
771fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com    private boolean handleConstHigh16(AnalyzedInstruction analyzedInstruction) {
772fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        LiteralInstruction instruction = (LiteralInstruction)analyzedInstruction.instruction;
773fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com
774fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        //TODO: test this
775fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        long literalValue = instruction.getLiteral() << 16;
776fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        RegisterType newDestinationRegisterType = RegisterType.getRegisterTypeForLiteral(literalValue);
777fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com
778fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        //we assume that the literal value is a valid value for the given instruction type, because it's impossible
779fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        //to store an invalid literal with the instruction. so we don't need to check the type of the literal
780fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        setDestinationRegisterTypeAndPropagateChanges(analyzedInstruction, newDestinationRegisterType);
781fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        return true;
782fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com    }
783fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com
784fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com    private boolean handleWideConst(AnalyzedInstruction analyzedInstruction) {
785fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        setWideDestinationRegisterTypeAndPropagateChanges(analyzedInstruction,
786fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com                RegisterType.getRegisterType(RegisterType.Category.LongLo, null));
787fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        return true;
788fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com    }
789fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com
790fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com    private boolean handleConstString(AnalyzedInstruction analyzedInstruction) {
791fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        ClassPath.ClassDef stringClassDef = ClassPath.getClassDef("Ljava/lang/String;");
792fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        RegisterType stringType = RegisterType.getRegisterType(RegisterType.Category.Reference, stringClassDef);
793fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        setDestinationRegisterTypeAndPropagateChanges(analyzedInstruction, stringType);
794fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        return true;
795fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com    }
796fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com
797fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com    private boolean handleConstClass(AnalyzedInstruction analyzedInstruction) {
798fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        ClassPath.ClassDef classClassDef = ClassPath.getClassDef("Ljava/lang/Class;");
799fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        RegisterType classType = RegisterType.getRegisterType(RegisterType.Category.Reference, classClassDef);
800fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com
801fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        InstructionWithReference instruction = (InstructionWithReference)analyzedInstruction.instruction;
802fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        Item item = instruction.getReferencedItem();
803fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        assert item.getItemType() == ItemType.TYPE_TYPE_ID_ITEM;
804fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com
805fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        //make sure the referenced class is resolvable
806fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        //TODO: need to check class access
807fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        ClassPath.ClassDef classDef = ClassPath.getClassDef((TypeIdItem)item);
808fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        return false;
809fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com    }
810fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com
811fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com    private boolean handleMonitor(AnalyzedInstruction analyzedInstruction) {
812fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        SingleRegisterInstruction instruction = (SingleRegisterInstruction)analyzedInstruction;
813fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com
814fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        RegisterType registerType = analyzedInstruction.postRegisterMap[instruction.getRegisterA()];
815fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        assert registerType != null;
816fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        if (registerType.category == RegisterType.Category.Unknown) {
817fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com            return false;
818fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        }
819fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com
820fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        checkRegister(registerType, ReferenceCategories);
821fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        return true;
822fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com    }
823fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com
824fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com    private boolean handleCheckCast(AnalyzedInstruction analyzedInstruction) {
825fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        {
826fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com            //ensure the "source" register is a reference type
827fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com            SingleRegisterInstruction instruction = (SingleRegisterInstruction)analyzedInstruction.instruction;
828fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com
829fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com            RegisterType registerType = analyzedInstruction.getPreInstructionRegisterType(instruction.getRegisterA());
830fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com            assert registerType != null;
831fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com            if (registerType.category == RegisterType.Category.Unknown) {
832fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com                return false;
833fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com            }
834fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com
835fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com            checkRegister(registerType, ReferenceCategories);
836fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        }
837fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com
838fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        {
839fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com            //resolve and verify the class that we're casting to
840fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com            InstructionWithReference instruction = (InstructionWithReference)analyzedInstruction.instruction;
841fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com
842fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com            Item item = instruction.getReferencedItem();
843fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com            assert item.getItemType() == ItemType.TYPE_TYPE_ID_ITEM;
844fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com
845fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com            //TODO: need to check class access
846fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com            RegisterType newDestinationRegisterType = RegisterType.getRegisterTypeForTypeIdItem((TypeIdItem)item);
847fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com            try {
848fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com                checkRegister(newDestinationRegisterType, ReferenceCategories);
849fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com            } catch (ValidationException ex) {
850fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com                //TODO: verify that dalvik allows a non-reference type..
851fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com                //TODO: print a warning, but don't re-throw the exception. dalvik allows a non-reference type during validation (but throws an exception at runtime)
852fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com            }
853fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com
854fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com            setDestinationRegisterTypeAndPropagateChanges(analyzedInstruction, newDestinationRegisterType);
855fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com            return true;
856fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        }
857fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com    }
858fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com
859fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com    private boolean handleInstanceOf(AnalyzedInstruction analyzedInstruction) {
860fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        {
861fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com            //ensure the register that is being checks is a reference type
862fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com            TwoRegisterInstruction instruction = (TwoRegisterInstruction)analyzedInstruction;
863fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com
864fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com            RegisterType registerType = analyzedInstruction.getPreInstructionRegisterType(instruction.getRegisterB());
865fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com            assert registerType != null;
866fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com            if (registerType.category == RegisterType.Category.Unknown) {
867fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com                return false;
868fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com            }
869fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com
870fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com            checkRegister(registerType, ReferenceCategories);
871fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        }
872fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com
873fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        {
874fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com            //resolve and verify the class that we're checking against
875fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com            InstructionWithReference instruction = (InstructionWithReference)analyzedInstruction.instruction;
876fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com
877fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com            Item item = instruction.getReferencedItem();
878fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com            assert  item.getItemType() == ItemType.TYPE_TYPE_ID_ITEM;
879fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com            RegisterType registerType = RegisterType.getRegisterTypeForTypeIdItem((TypeIdItem)item);
880fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com            checkRegister(registerType, ReferenceCategories);
881fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com
882fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com            //TODO: is it valid to use an array type?
883fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com
884fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com            //TODO: could probably do an even more sophisticated check, where we check the possible register types against the specified type. In some cases, we could determine that it always fails, and print a warning to that effect.
885fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com            setDestinationRegisterTypeAndPropagateChanges(analyzedInstruction,
886fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com                    RegisterType.getRegisterType(RegisterType.Category.Boolean, null));
887fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com            return true;
888fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        }
889fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com    }
890fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com
891fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com    private boolean handleArrayLength(AnalyzedInstruction analyzedInstruction) {
892fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        TwoRegisterInstruction instruction = (TwoRegisterInstruction)analyzedInstruction;
893fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com
894fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        int arrayRegisterNumber = instruction.getRegisterB();
895fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        RegisterType arrayRegisterType = analyzedInstruction.getPreInstructionRegisterType(arrayRegisterNumber);
896fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        assert arrayRegisterType != null;
897fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        if (arrayRegisterType.category == RegisterType.Category.Unknown) {
898fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com            return false;
899fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        }
900fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com
901fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        assert arrayRegisterType.type instanceof ClassPath.ArrayClassDef;
902fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com
903fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        checkRegister(arrayRegisterType, ReferenceCategories);
904fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        if (arrayRegisterType.type != null) {
905fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com            if (arrayRegisterType.type.getClassType().charAt(0) != '[') {
906fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com                throw new ValidationException("Cannot use array-length with non-array type " +
907fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com                        arrayRegisterType.type.getClassType());
908d27ca7f7a61cfbe60e1c490bf645257d7d59fd39JesusFreke@JesusFreke.com            }
909d27ca7f7a61cfbe60e1c490bf645257d7d59fd39JesusFreke@JesusFreke.com        }
910d27ca7f7a61cfbe60e1c490bf645257d7d59fd39JesusFreke@JesusFreke.com
911fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        setDestinationRegisterTypeAndPropagateChanges(analyzedInstruction,
912fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com                RegisterType.getRegisterType(RegisterType.Category.Integer, null));
913fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        return true;
914fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com    }
915fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com
916fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com    private boolean handleNewInstance(AnalyzedInstruction analyzedInstruction) {
917fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        InstructionWithReference instruction = (InstructionWithReference)analyzedInstruction.instruction;
918fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com
919fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        Item item = instruction.getReferencedItem();
920fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        assert item.getItemType() == ItemType.TYPE_TYPE_ID_ITEM;
921fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com
922fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        //TODO: need to check class access
923fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        RegisterType classType = RegisterType.getRegisterTypeForTypeIdItem((TypeIdItem)item);
924fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        checkRegister(classType, ReferenceCategories);
925fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        if (((TypeIdItem)item).getTypeDescriptor().charAt(0) == '[') {
926fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com            throw new ValidationException("Cannot use array type \"" + ((TypeIdItem)item).getTypeDescriptor() +
927fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com                    "\" with new-instance. Use new-array instead.");
928d27ca7f7a61cfbe60e1c490bf645257d7d59fd39JesusFreke@JesusFreke.com        }
929d27ca7f7a61cfbe60e1c490bf645257d7d59fd39JesusFreke@JesusFreke.com
930fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        setDestinationRegisterTypeAndPropagateChanges(analyzedInstruction,
931fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com                RegisterType.getRegisterType(RegisterType.Category.UninitRef, classType.type));
932fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        return true;
933fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com    }
934fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com
935fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com    private boolean handleNewArray(AnalyzedInstruction analyzedInstruction) {
936fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        {
937fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com            TwoRegisterInstruction instruction = (TwoRegisterInstruction)analyzedInstruction.instruction;
938fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com
939fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com            int sizeRegister = instruction.getRegisterB();
940fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com            RegisterType registerType = analyzedInstruction.getPreInstructionRegisterType(sizeRegister);
941fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com            assert registerType != null;
942fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com
943fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com            if (registerType.category == RegisterType.Category.Unknown) {
944fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com                return false;
945fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com            }
946fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com
947fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com            checkRegister(registerType, Primitive32BitCategories);
948fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        }
949fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com
950fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        InstructionWithReference instruction = (InstructionWithReference)analyzedInstruction.instruction;
951fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com
952fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        Item item = instruction.getReferencedItem();
953fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        assert item.getItemType() == ItemType.TYPE_TYPE_ID_ITEM;
954fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com
955fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        RegisterType arrayType = RegisterType.getRegisterTypeForTypeIdItem((TypeIdItem)item);
956fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        assert arrayType.type instanceof ClassPath.ArrayClassDef;
957d27ca7f7a61cfbe60e1c490bf645257d7d59fd39JesusFreke@JesusFreke.com
958fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        checkRegister(arrayType, ReferenceCategories);
959fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        if (arrayType.type.getClassType().charAt(0) != '[') {
960fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com            throw new ValidationException("Cannot use non-array type \"" + arrayType.type.getClassType() +
961fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com                    "\" with new-array. Use new-instance instead.");
962fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        }
963fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com
964fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        setDestinationRegisterTypeAndPropagateChanges(analyzedInstruction, arrayType);
965fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        return true;
966fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com    }
967fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com
968ac8785e5d550c2ec7c7d02dd2990f859a78c111cJesusFreke@JesusFreke.com    private static interface RegisterIterator {
969ac8785e5d550c2ec7c7d02dd2990f859a78c111cJesusFreke@JesusFreke.com        int getRegister();
970ac8785e5d550c2ec7c7d02dd2990f859a78c111cJesusFreke@JesusFreke.com        boolean moveNext();
971ac8785e5d550c2ec7c7d02dd2990f859a78c111cJesusFreke@JesusFreke.com    }
972ac8785e5d550c2ec7c7d02dd2990f859a78c111cJesusFreke@JesusFreke.com
973ac8785e5d550c2ec7c7d02dd2990f859a78c111cJesusFreke@JesusFreke.com    private boolean handleFilledNewArrayCommon(AnalyzedInstruction analyzedInstruction,
974ac8785e5d550c2ec7c7d02dd2990f859a78c111cJesusFreke@JesusFreke.com                                               RegisterIterator registerIterator) {
975ac8785e5d550c2ec7c7d02dd2990f859a78c111cJesusFreke@JesusFreke.com        InstructionWithReference instruction = (InstructionWithReference)analyzedInstruction.instruction;
976ac8785e5d550c2ec7c7d02dd2990f859a78c111cJesusFreke@JesusFreke.com
9779e5dd85d837501e84e18617fc136c8203ab1f183JesusFreke@JesusFreke.com        RegisterType arrayType;
9789e5dd85d837501e84e18617fc136c8203ab1f183JesusFreke@JesusFreke.com        RegisterType arrayImmediateElementType;
9799e5dd85d837501e84e18617fc136c8203ab1f183JesusFreke@JesusFreke.com
980ac8785e5d550c2ec7c7d02dd2990f859a78c111cJesusFreke@JesusFreke.com        Item item = instruction.getReferencedItem();
981ac8785e5d550c2ec7c7d02dd2990f859a78c111cJesusFreke@JesusFreke.com        assert  item.getItemType() == ItemType.TYPE_TYPE_ID_ITEM;
9829e5dd85d837501e84e18617fc136c8203ab1f183JesusFreke@JesusFreke.com
983ac8785e5d550c2ec7c7d02dd2990f859a78c111cJesusFreke@JesusFreke.com        ClassPath.ClassDef classDef = ClassPath.getClassDef((TypeIdItem)item);
9849e5dd85d837501e84e18617fc136c8203ab1f183JesusFreke@JesusFreke.com
985ac8785e5d550c2ec7c7d02dd2990f859a78c111cJesusFreke@JesusFreke.com        if (classDef.getClassType().charAt(0) != '[') {
986ac8785e5d550c2ec7c7d02dd2990f859a78c111cJesusFreke@JesusFreke.com            throw new ValidationException("Cannot use non-array type \"" + classDef.getClassType() +
987ac8785e5d550c2ec7c7d02dd2990f859a78c111cJesusFreke@JesusFreke.com                "\" with new-array. Use new-instance instead.");
9889e5dd85d837501e84e18617fc136c8203ab1f183JesusFreke@JesusFreke.com        }
9899e5dd85d837501e84e18617fc136c8203ab1f183JesusFreke@JesusFreke.com
990ac8785e5d550c2ec7c7d02dd2990f859a78c111cJesusFreke@JesusFreke.com        ClassPath.ArrayClassDef arrayClassDef = (ClassPath.ArrayClassDef)classDef;
991ac8785e5d550c2ec7c7d02dd2990f859a78c111cJesusFreke@JesusFreke.com        arrayType = RegisterType.getRegisterType(RegisterType.Category.Reference, classDef);
992ac8785e5d550c2ec7c7d02dd2990f859a78c111cJesusFreke@JesusFreke.com        arrayImmediateElementType = RegisterType.getRegisterTypeForType(
993ac8785e5d550c2ec7c7d02dd2990f859a78c111cJesusFreke@JesusFreke.com                arrayClassDef.getImmediateElementClass().getClassType());
994ac8785e5d550c2ec7c7d02dd2990f859a78c111cJesusFreke@JesusFreke.com        String baseElementType = arrayClassDef.getBaseElementClass().getClassType();
995ac8785e5d550c2ec7c7d02dd2990f859a78c111cJesusFreke@JesusFreke.com        if (baseElementType.charAt(0) == 'J' || baseElementType.charAt(0) == 'D') {
996ac8785e5d550c2ec7c7d02dd2990f859a78c111cJesusFreke@JesusFreke.com            throw new ValidationException("Cannot use filled-new-array to create an array of wide values " +
997ac8785e5d550c2ec7c7d02dd2990f859a78c111cJesusFreke@JesusFreke.com                    "(long or double)");
998ac8785e5d550c2ec7c7d02dd2990f859a78c111cJesusFreke@JesusFreke.com        }
9999e5dd85d837501e84e18617fc136c8203ab1f183JesusFreke@JesusFreke.com
1000ac8785e5d550c2ec7c7d02dd2990f859a78c111cJesusFreke@JesusFreke.com        do {
1001ac8785e5d550c2ec7c7d02dd2990f859a78c111cJesusFreke@JesusFreke.com            int register = registerIterator.getRegister();
10029e5dd85d837501e84e18617fc136c8203ab1f183JesusFreke@JesusFreke.com            RegisterType elementType = analyzedInstruction.getPreInstructionRegisterType(register);
10039e5dd85d837501e84e18617fc136c8203ab1f183JesusFreke@JesusFreke.com            assert elementType != null;
10049e5dd85d837501e84e18617fc136c8203ab1f183JesusFreke@JesusFreke.com
10059e5dd85d837501e84e18617fc136c8203ab1f183JesusFreke@JesusFreke.com            if (elementType.category == RegisterType.Category.Unknown) {
10069e5dd85d837501e84e18617fc136c8203ab1f183JesusFreke@JesusFreke.com                return false;
10079e5dd85d837501e84e18617fc136c8203ab1f183JesusFreke@JesusFreke.com            }
10089e5dd85d837501e84e18617fc136c8203ab1f183JesusFreke@JesusFreke.com
10099e5dd85d837501e84e18617fc136c8203ab1f183JesusFreke@JesusFreke.com            if (!elementType.canBeAssignedTo(arrayImmediateElementType)) {
10109e5dd85d837501e84e18617fc136c8203ab1f183JesusFreke@JesusFreke.com                throw new ValidationException("Register v" + Integer.toString(register) + " is of type " +
10119e5dd85d837501e84e18617fc136c8203ab1f183JesusFreke@JesusFreke.com                        elementType.toString() + " and is incompatible with the array type " +
10129e5dd85d837501e84e18617fc136c8203ab1f183JesusFreke@JesusFreke.com                        arrayType.type.getClassType());
10139e5dd85d837501e84e18617fc136c8203ab1f183JesusFreke@JesusFreke.com            }
1014ac8785e5d550c2ec7c7d02dd2990f859a78c111cJesusFreke@JesusFreke.com        } while (registerIterator.moveNext());
10159e5dd85d837501e84e18617fc136c8203ab1f183JesusFreke@JesusFreke.com
10169e5dd85d837501e84e18617fc136c8203ab1f183JesusFreke@JesusFreke.com        setDestinationRegisterTypeAndPropagateChanges(analyzedInstruction, arrayType);
10179e5dd85d837501e84e18617fc136c8203ab1f183JesusFreke@JesusFreke.com        return true;
10189e5dd85d837501e84e18617fc136c8203ab1f183JesusFreke@JesusFreke.com    }
10199e5dd85d837501e84e18617fc136c8203ab1f183JesusFreke@JesusFreke.com
1020ac8785e5d550c2ec7c7d02dd2990f859a78c111cJesusFreke@JesusFreke.com    private boolean handleFilledNewArray(AnalyzedInstruction analyzedInstruction) {
1021ac8785e5d550c2ec7c7d02dd2990f859a78c111cJesusFreke@JesusFreke.com        FiveRegisterInstruction instruction = (FiveRegisterInstruction)analyzedInstruction.instruction;
1022ac8785e5d550c2ec7c7d02dd2990f859a78c111cJesusFreke@JesusFreke.com        final int registerCount = instruction.getRegCount();
1023ac8785e5d550c2ec7c7d02dd2990f859a78c111cJesusFreke@JesusFreke.com        final int[] registers = new int[]{instruction.getRegisterD(), instruction.getRegisterE(),
1024ac8785e5d550c2ec7c7d02dd2990f859a78c111cJesusFreke@JesusFreke.com                                          instruction.getRegisterF(), instruction.getRegisterG(),
1025ac8785e5d550c2ec7c7d02dd2990f859a78c111cJesusFreke@JesusFreke.com                                          instruction.getRegisterA()};
1026ac8785e5d550c2ec7c7d02dd2990f859a78c111cJesusFreke@JesusFreke.com
1027ac8785e5d550c2ec7c7d02dd2990f859a78c111cJesusFreke@JesusFreke.com        return handleFilledNewArrayCommon(analyzedInstruction,
1028ac8785e5d550c2ec7c7d02dd2990f859a78c111cJesusFreke@JesusFreke.com                new RegisterIterator() {
1029ac8785e5d550c2ec7c7d02dd2990f859a78c111cJesusFreke@JesusFreke.com                    private int currentRegister = 0;
1030ac8785e5d550c2ec7c7d02dd2990f859a78c111cJesusFreke@JesusFreke.com                    public int getRegister() {
1031ac8785e5d550c2ec7c7d02dd2990f859a78c111cJesusFreke@JesusFreke.com                        return registers[currentRegister];
1032ac8785e5d550c2ec7c7d02dd2990f859a78c111cJesusFreke@JesusFreke.com                    }
1033ac8785e5d550c2ec7c7d02dd2990f859a78c111cJesusFreke@JesusFreke.com
1034ac8785e5d550c2ec7c7d02dd2990f859a78c111cJesusFreke@JesusFreke.com                    public boolean moveNext() {
1035ac8785e5d550c2ec7c7d02dd2990f859a78c111cJesusFreke@JesusFreke.com                        currentRegister++;
1036ac8785e5d550c2ec7c7d02dd2990f859a78c111cJesusFreke@JesusFreke.com                        if (currentRegister >= registerCount) {
1037ac8785e5d550c2ec7c7d02dd2990f859a78c111cJesusFreke@JesusFreke.com                            return false;
1038ac8785e5d550c2ec7c7d02dd2990f859a78c111cJesusFreke@JesusFreke.com                        }
1039ac8785e5d550c2ec7c7d02dd2990f859a78c111cJesusFreke@JesusFreke.com                        return true;
1040ac8785e5d550c2ec7c7d02dd2990f859a78c111cJesusFreke@JesusFreke.com                    }
1041ac8785e5d550c2ec7c7d02dd2990f859a78c111cJesusFreke@JesusFreke.com                });
1042ac8785e5d550c2ec7c7d02dd2990f859a78c111cJesusFreke@JesusFreke.com    }
1043ac8785e5d550c2ec7c7d02dd2990f859a78c111cJesusFreke@JesusFreke.com
1044ac8785e5d550c2ec7c7d02dd2990f859a78c111cJesusFreke@JesusFreke.com    private boolean handleFilledNewArrayRange(AnalyzedInstruction analyzedInstruction) {
1045ac8785e5d550c2ec7c7d02dd2990f859a78c111cJesusFreke@JesusFreke.com        final RegisterRangeInstruction instruction = (RegisterRangeInstruction)analyzedInstruction.instruction;
1046ac8785e5d550c2ec7c7d02dd2990f859a78c111cJesusFreke@JesusFreke.com
1047ac8785e5d550c2ec7c7d02dd2990f859a78c111cJesusFreke@JesusFreke.com        //instruction.getStartRegister() and instruction.getRegCount() both return an int value, but are actually
1048ac8785e5d550c2ec7c7d02dd2990f859a78c111cJesusFreke@JesusFreke.com        //unsigned 16 bit values, so we don't have to worry about overflowing an int when adding them together
1049ac8785e5d550c2ec7c7d02dd2990f859a78c111cJesusFreke@JesusFreke.com        if (instruction.getStartRegister() + instruction.getRegCount() >= 1<<16) {
1050ac8785e5d550c2ec7c7d02dd2990f859a78c111cJesusFreke@JesusFreke.com            throw new ValidationException(String.format("Invalid register range {v%d .. v%d}. The ending register " +
1051472d3ea58455ebf43d21819b2701fad98b5a0f9cJesusFreke@JesusFreke.com                    "is larger than the largest allowed register of v65535.",
1052ac8785e5d550c2ec7c7d02dd2990f859a78c111cJesusFreke@JesusFreke.com                    instruction.getStartRegister(),
1053ac8785e5d550c2ec7c7d02dd2990f859a78c111cJesusFreke@JesusFreke.com                    instruction.getStartRegister() + instruction.getRegCount() - 1));
1054ac8785e5d550c2ec7c7d02dd2990f859a78c111cJesusFreke@JesusFreke.com        }
1055ac8785e5d550c2ec7c7d02dd2990f859a78c111cJesusFreke@JesusFreke.com
1056ac8785e5d550c2ec7c7d02dd2990f859a78c111cJesusFreke@JesusFreke.com        return handleFilledNewArrayCommon(analyzedInstruction,
1057ac8785e5d550c2ec7c7d02dd2990f859a78c111cJesusFreke@JesusFreke.com                new RegisterIterator() {
1058ac8785e5d550c2ec7c7d02dd2990f859a78c111cJesusFreke@JesusFreke.com                    private int currentRegister = 0;
1059ac8785e5d550c2ec7c7d02dd2990f859a78c111cJesusFreke@JesusFreke.com                    private final int startRegister = instruction.getStartRegister();
1060ac8785e5d550c2ec7c7d02dd2990f859a78c111cJesusFreke@JesusFreke.com                    private final int registerCount = instruction.getRegCount();
1061ac8785e5d550c2ec7c7d02dd2990f859a78c111cJesusFreke@JesusFreke.com
1062ac8785e5d550c2ec7c7d02dd2990f859a78c111cJesusFreke@JesusFreke.com                    public int getRegister() {
1063ac8785e5d550c2ec7c7d02dd2990f859a78c111cJesusFreke@JesusFreke.com                        return startRegister + currentRegister;
1064ac8785e5d550c2ec7c7d02dd2990f859a78c111cJesusFreke@JesusFreke.com                    }
1065ac8785e5d550c2ec7c7d02dd2990f859a78c111cJesusFreke@JesusFreke.com
1066ac8785e5d550c2ec7c7d02dd2990f859a78c111cJesusFreke@JesusFreke.com                    public boolean moveNext() {
1067ac8785e5d550c2ec7c7d02dd2990f859a78c111cJesusFreke@JesusFreke.com                        currentRegister++;
1068ac8785e5d550c2ec7c7d02dd2990f859a78c111cJesusFreke@JesusFreke.com                        if (currentRegister >= registerCount) {
1069ac8785e5d550c2ec7c7d02dd2990f859a78c111cJesusFreke@JesusFreke.com                            return false;
1070ac8785e5d550c2ec7c7d02dd2990f859a78c111cJesusFreke@JesusFreke.com                        }
1071ac8785e5d550c2ec7c7d02dd2990f859a78c111cJesusFreke@JesusFreke.com                        return true;
1072ac8785e5d550c2ec7c7d02dd2990f859a78c111cJesusFreke@JesusFreke.com                    }
1073ac8785e5d550c2ec7c7d02dd2990f859a78c111cJesusFreke@JesusFreke.com                });
1074ac8785e5d550c2ec7c7d02dd2990f859a78c111cJesusFreke@JesusFreke.com    }
1075ac8785e5d550c2ec7c7d02dd2990f859a78c111cJesusFreke@JesusFreke.com
1076472d3ea58455ebf43d21819b2701fad98b5a0f9cJesusFreke@JesusFreke.com    private boolean handleFillArrayData(AnalyzedInstruction analyzedInstruction) {
1077472d3ea58455ebf43d21819b2701fad98b5a0f9cJesusFreke@JesusFreke.com        SingleRegisterInstruction instruction = (SingleRegisterInstruction)analyzedInstruction.instruction;
1078472d3ea58455ebf43d21819b2701fad98b5a0f9cJesusFreke@JesusFreke.com
1079472d3ea58455ebf43d21819b2701fad98b5a0f9cJesusFreke@JesusFreke.com        int register = instruction.getRegisterA();
1080472d3ea58455ebf43d21819b2701fad98b5a0f9cJesusFreke@JesusFreke.com        RegisterType registerType = analyzedInstruction.getPreInstructionRegisterType(register);
1081472d3ea58455ebf43d21819b2701fad98b5a0f9cJesusFreke@JesusFreke.com        assert registerType != null;
1082472d3ea58455ebf43d21819b2701fad98b5a0f9cJesusFreke@JesusFreke.com
1083472d3ea58455ebf43d21819b2701fad98b5a0f9cJesusFreke@JesusFreke.com        if (registerType.category == RegisterType.Category.Unknown ||
1084472d3ea58455ebf43d21819b2701fad98b5a0f9cJesusFreke@JesusFreke.com            registerType.category == RegisterType.Category.Null) {
1085472d3ea58455ebf43d21819b2701fad98b5a0f9cJesusFreke@JesusFreke.com            return false;
1086472d3ea58455ebf43d21819b2701fad98b5a0f9cJesusFreke@JesusFreke.com        }
1087472d3ea58455ebf43d21819b2701fad98b5a0f9cJesusFreke@JesusFreke.com
1088472d3ea58455ebf43d21819b2701fad98b5a0f9cJesusFreke@JesusFreke.com        if (registerType.category != RegisterType.Category.Reference) {
1089472d3ea58455ebf43d21819b2701fad98b5a0f9cJesusFreke@JesusFreke.com            throw new ValidationException(String.format("Cannot use fill-array-data with non-array register v%d of " +
1090472d3ea58455ebf43d21819b2701fad98b5a0f9cJesusFreke@JesusFreke.com                    "type %s", register, registerType.toString()));
1091472d3ea58455ebf43d21819b2701fad98b5a0f9cJesusFreke@JesusFreke.com        }
1092472d3ea58455ebf43d21819b2701fad98b5a0f9cJesusFreke@JesusFreke.com
1093472d3ea58455ebf43d21819b2701fad98b5a0f9cJesusFreke@JesusFreke.com        assert registerType.type instanceof ClassPath.ArrayClassDef;
1094472d3ea58455ebf43d21819b2701fad98b5a0f9cJesusFreke@JesusFreke.com        ClassPath.ArrayClassDef arrayClassDef = (ClassPath.ArrayClassDef)registerType.type;
1095472d3ea58455ebf43d21819b2701fad98b5a0f9cJesusFreke@JesusFreke.com
1096472d3ea58455ebf43d21819b2701fad98b5a0f9cJesusFreke@JesusFreke.com        if (arrayClassDef.getArrayDimensions() != 1) {
1097472d3ea58455ebf43d21819b2701fad98b5a0f9cJesusFreke@JesusFreke.com            throw new ValidationException(String.format("Cannot use fill-array-data with array type %s. It can only " +
1098472d3ea58455ebf43d21819b2701fad98b5a0f9cJesusFreke@JesusFreke.com                    "be used with a one-dimensional array of primitives.", arrayClassDef.getClassType()));
1099472d3ea58455ebf43d21819b2701fad98b5a0f9cJesusFreke@JesusFreke.com        }
1100472d3ea58455ebf43d21819b2701fad98b5a0f9cJesusFreke@JesusFreke.com
1101472d3ea58455ebf43d21819b2701fad98b5a0f9cJesusFreke@JesusFreke.com        int elementWidth;
1102472d3ea58455ebf43d21819b2701fad98b5a0f9cJesusFreke@JesusFreke.com        switch (arrayClassDef.getBaseElementClass().getClassType().charAt(0)) {
1103472d3ea58455ebf43d21819b2701fad98b5a0f9cJesusFreke@JesusFreke.com            case 'Z':
1104472d3ea58455ebf43d21819b2701fad98b5a0f9cJesusFreke@JesusFreke.com            case 'B':
1105472d3ea58455ebf43d21819b2701fad98b5a0f9cJesusFreke@JesusFreke.com                elementWidth = 1;
1106472d3ea58455ebf43d21819b2701fad98b5a0f9cJesusFreke@JesusFreke.com                break;
1107472d3ea58455ebf43d21819b2701fad98b5a0f9cJesusFreke@JesusFreke.com            case 'C':
1108472d3ea58455ebf43d21819b2701fad98b5a0f9cJesusFreke@JesusFreke.com            case 'S':
1109472d3ea58455ebf43d21819b2701fad98b5a0f9cJesusFreke@JesusFreke.com                elementWidth = 2;
1110472d3ea58455ebf43d21819b2701fad98b5a0f9cJesusFreke@JesusFreke.com                break;
1111472d3ea58455ebf43d21819b2701fad98b5a0f9cJesusFreke@JesusFreke.com            case 'I':
1112472d3ea58455ebf43d21819b2701fad98b5a0f9cJesusFreke@JesusFreke.com            case 'F':
1113472d3ea58455ebf43d21819b2701fad98b5a0f9cJesusFreke@JesusFreke.com                elementWidth = 4;
1114472d3ea58455ebf43d21819b2701fad98b5a0f9cJesusFreke@JesusFreke.com                break;
1115472d3ea58455ebf43d21819b2701fad98b5a0f9cJesusFreke@JesusFreke.com            case 'J':
1116472d3ea58455ebf43d21819b2701fad98b5a0f9cJesusFreke@JesusFreke.com            case 'D':
1117472d3ea58455ebf43d21819b2701fad98b5a0f9cJesusFreke@JesusFreke.com                elementWidth = 8;
1118472d3ea58455ebf43d21819b2701fad98b5a0f9cJesusFreke@JesusFreke.com                break;
1119472d3ea58455ebf43d21819b2701fad98b5a0f9cJesusFreke@JesusFreke.com            default:
1120472d3ea58455ebf43d21819b2701fad98b5a0f9cJesusFreke@JesusFreke.com                throw new ValidationException(String.format("Cannot use fill-array-data with array type %s. It can " +
1121472d3ea58455ebf43d21819b2701fad98b5a0f9cJesusFreke@JesusFreke.com                        "only be used with a one-dimensional array of primitives.", arrayClassDef.getClassType()));
1122472d3ea58455ebf43d21819b2701fad98b5a0f9cJesusFreke@JesusFreke.com        }
1123472d3ea58455ebf43d21819b2701fad98b5a0f9cJesusFreke@JesusFreke.com
1124472d3ea58455ebf43d21819b2701fad98b5a0f9cJesusFreke@JesusFreke.com
1125472d3ea58455ebf43d21819b2701fad98b5a0f9cJesusFreke@JesusFreke.com        int arrayDataOffset = ((OffsetInstruction)analyzedInstruction.instruction).getTargetAddressOffset();
1126472d3ea58455ebf43d21819b2701fad98b5a0f9cJesusFreke@JesusFreke.com        AnalyzedInstruction arrayDataInstruction = this.instructions.get(arrayDataOffset);
1127472d3ea58455ebf43d21819b2701fad98b5a0f9cJesusFreke@JesusFreke.com        if (arrayDataInstruction == null || arrayDataInstruction.instruction.getFormat() != Format.ArrayData) {
1128472d3ea58455ebf43d21819b2701fad98b5a0f9cJesusFreke@JesusFreke.com            throw new ValidationException(String.format("Could not find an array data structure at code address 0x%x",
1129472d3ea58455ebf43d21819b2701fad98b5a0f9cJesusFreke@JesusFreke.com                    arrayDataOffset));
1130472d3ea58455ebf43d21819b2701fad98b5a0f9cJesusFreke@JesusFreke.com        }
1131472d3ea58455ebf43d21819b2701fad98b5a0f9cJesusFreke@JesusFreke.com
1132472d3ea58455ebf43d21819b2701fad98b5a0f9cJesusFreke@JesusFreke.com        ArrayDataPseudoInstruction arrayDataPseudoInstruction =
1133472d3ea58455ebf43d21819b2701fad98b5a0f9cJesusFreke@JesusFreke.com                (ArrayDataPseudoInstruction)arrayDataInstruction.instruction;
1134472d3ea58455ebf43d21819b2701fad98b5a0f9cJesusFreke@JesusFreke.com
1135472d3ea58455ebf43d21819b2701fad98b5a0f9cJesusFreke@JesusFreke.com        if (elementWidth != arrayDataPseudoInstruction.getElementWidth()) {
1136472d3ea58455ebf43d21819b2701fad98b5a0f9cJesusFreke@JesusFreke.com            throw new ValidationException(String.format("The array data at code address 0x%x does not have the " +
1137472d3ea58455ebf43d21819b2701fad98b5a0f9cJesusFreke@JesusFreke.com                    "correct element width for array type %s. Expecting element width %d, got element width %d.",
1138472d3ea58455ebf43d21819b2701fad98b5a0f9cJesusFreke@JesusFreke.com                    arrayDataOffset, arrayClassDef.getClassType(), elementWidth,
1139472d3ea58455ebf43d21819b2701fad98b5a0f9cJesusFreke@JesusFreke.com                    arrayDataPseudoInstruction.getElementWidth()));
1140472d3ea58455ebf43d21819b2701fad98b5a0f9cJesusFreke@JesusFreke.com        }
1141472d3ea58455ebf43d21819b2701fad98b5a0f9cJesusFreke@JesusFreke.com
1142472d3ea58455ebf43d21819b2701fad98b5a0f9cJesusFreke@JesusFreke.com        return true;
1143472d3ea58455ebf43d21819b2701fad98b5a0f9cJesusFreke@JesusFreke.com    }
1144472d3ea58455ebf43d21819b2701fad98b5a0f9cJesusFreke@JesusFreke.com
1145ed140ca3e4fa66a03970affb3415a9fe2a924312JesusFreke@JesusFreke.com    private boolean handleThrow(AnalyzedInstruction analyzedInstruction) {
1146ed140ca3e4fa66a03970affb3415a9fe2a924312JesusFreke@JesusFreke.com        int register = ((SingleRegisterInstruction)analyzedInstruction.instruction).getRegisterA();
1147ed140ca3e4fa66a03970affb3415a9fe2a924312JesusFreke@JesusFreke.com
1148ed140ca3e4fa66a03970affb3415a9fe2a924312JesusFreke@JesusFreke.com        RegisterType registerType = analyzedInstruction.getPreInstructionRegisterType(register);
1149ed140ca3e4fa66a03970affb3415a9fe2a924312JesusFreke@JesusFreke.com        assert registerType != null;
1150ed140ca3e4fa66a03970affb3415a9fe2a924312JesusFreke@JesusFreke.com
1151ed140ca3e4fa66a03970affb3415a9fe2a924312JesusFreke@JesusFreke.com        if (registerType.category == RegisterType.Category.Unknown) {
1152ed140ca3e4fa66a03970affb3415a9fe2a924312JesusFreke@JesusFreke.com            return false;
1153ed140ca3e4fa66a03970affb3415a9fe2a924312JesusFreke@JesusFreke.com        }
1154ed140ca3e4fa66a03970affb3415a9fe2a924312JesusFreke@JesusFreke.com
1155ed140ca3e4fa66a03970affb3415a9fe2a924312JesusFreke@JesusFreke.com        if (registerType.category == RegisterType.Category.Null) {
1156ed140ca3e4fa66a03970affb3415a9fe2a924312JesusFreke@JesusFreke.com            return true;
1157ed140ca3e4fa66a03970affb3415a9fe2a924312JesusFreke@JesusFreke.com        }
1158ed140ca3e4fa66a03970affb3415a9fe2a924312JesusFreke@JesusFreke.com
1159ed140ca3e4fa66a03970affb3415a9fe2a924312JesusFreke@JesusFreke.com        if (registerType.category != RegisterType.Category.Reference) {
1160ed140ca3e4fa66a03970affb3415a9fe2a924312JesusFreke@JesusFreke.com            throw new ValidationException(String.format("Cannot use throw with non-reference type %s in register v%d",
1161ed140ca3e4fa66a03970affb3415a9fe2a924312JesusFreke@JesusFreke.com                    registerType.toString(), register));
1162ed140ca3e4fa66a03970affb3415a9fe2a924312JesusFreke@JesusFreke.com        }
1163ed140ca3e4fa66a03970affb3415a9fe2a924312JesusFreke@JesusFreke.com
1164ed140ca3e4fa66a03970affb3415a9fe2a924312JesusFreke@JesusFreke.com        assert registerType.type != null;
1165ed140ca3e4fa66a03970affb3415a9fe2a924312JesusFreke@JesusFreke.com
1166ed140ca3e4fa66a03970affb3415a9fe2a924312JesusFreke@JesusFreke.com        if (!registerType.type.extendsClass(ClassPath.getClassDef("Ljava/lang/Throwable;"))) {
1167ed140ca3e4fa66a03970affb3415a9fe2a924312JesusFreke@JesusFreke.com            throw new ValidationException(String.format("Cannot use throw with non-throwable type %s in register v%d",
1168ed140ca3e4fa66a03970affb3415a9fe2a924312JesusFreke@JesusFreke.com                    registerType.type.getClassType(), register));
1169ed140ca3e4fa66a03970affb3415a9fe2a924312JesusFreke@JesusFreke.com        }
1170ed140ca3e4fa66a03970affb3415a9fe2a924312JesusFreke@JesusFreke.com
1171ed140ca3e4fa66a03970affb3415a9fe2a924312JesusFreke@JesusFreke.com        return true;
1172ed140ca3e4fa66a03970affb3415a9fe2a924312JesusFreke@JesusFreke.com    }
1173ed140ca3e4fa66a03970affb3415a9fe2a924312JesusFreke@JesusFreke.com
1174cda44f70cfebfae4875cd77455a171075aebac4dJesusFreke@JesusFreke.com    private boolean handleSwitch(AnalyzedInstruction analyzedInstruction, Format expectedSwitchDataFormat) {
1175cda44f70cfebfae4875cd77455a171075aebac4dJesusFreke@JesusFreke.com        int register = ((SingleRegisterInstruction)analyzedInstruction.instruction).getRegisterA();
1176cda44f70cfebfae4875cd77455a171075aebac4dJesusFreke@JesusFreke.com        int switchCodeAddressOffset = ((OffsetInstruction)analyzedInstruction.instruction).getTargetAddressOffset();
1177cda44f70cfebfae4875cd77455a171075aebac4dJesusFreke@JesusFreke.com
1178cda44f70cfebfae4875cd77455a171075aebac4dJesusFreke@JesusFreke.com        RegisterType registerType = analyzedInstruction.getPreInstructionRegisterType(register);
1179cda44f70cfebfae4875cd77455a171075aebac4dJesusFreke@JesusFreke.com        assert registerType != null;
1180cda44f70cfebfae4875cd77455a171075aebac4dJesusFreke@JesusFreke.com
1181cda44f70cfebfae4875cd77455a171075aebac4dJesusFreke@JesusFreke.com        if (registerType.category == RegisterType.Category.Unknown) {
1182cda44f70cfebfae4875cd77455a171075aebac4dJesusFreke@JesusFreke.com            return false;
1183cda44f70cfebfae4875cd77455a171075aebac4dJesusFreke@JesusFreke.com        }
1184cda44f70cfebfae4875cd77455a171075aebac4dJesusFreke@JesusFreke.com
1185cda44f70cfebfae4875cd77455a171075aebac4dJesusFreke@JesusFreke.com        checkRegister(registerType, Primitive32BitCategories);
1186cda44f70cfebfae4875cd77455a171075aebac4dJesusFreke@JesusFreke.com
1187cda44f70cfebfae4875cd77455a171075aebac4dJesusFreke@JesusFreke.com        int switchDataCodeAddress = this.getInstructionAddress(analyzedInstruction) + switchCodeAddressOffset;
1188cda44f70cfebfae4875cd77455a171075aebac4dJesusFreke@JesusFreke.com        AnalyzedInstruction switchDataAnalyzedInstruction = instructions.get(switchDataCodeAddress);
1189cda44f70cfebfae4875cd77455a171075aebac4dJesusFreke@JesusFreke.com
1190cda44f70cfebfae4875cd77455a171075aebac4dJesusFreke@JesusFreke.com        if (switchDataAnalyzedInstruction == null ||
1191cda44f70cfebfae4875cd77455a171075aebac4dJesusFreke@JesusFreke.com            switchDataAnalyzedInstruction.instruction.getFormat() != expectedSwitchDataFormat) {
1192cda44f70cfebfae4875cd77455a171075aebac4dJesusFreke@JesusFreke.com            throw new ValidationException(String.format("There is no %s structure at code address 0x%x",
1193cda44f70cfebfae4875cd77455a171075aebac4dJesusFreke@JesusFreke.com                    expectedSwitchDataFormat.name(), switchDataCodeAddress));
1194cda44f70cfebfae4875cd77455a171075aebac4dJesusFreke@JesusFreke.com        }
1195cda44f70cfebfae4875cd77455a171075aebac4dJesusFreke@JesusFreke.com
1196cda44f70cfebfae4875cd77455a171075aebac4dJesusFreke@JesusFreke.com        return true;
1197cda44f70cfebfae4875cd77455a171075aebac4dJesusFreke@JesusFreke.com    }
1198cda44f70cfebfae4875cd77455a171075aebac4dJesusFreke@JesusFreke.com
1199fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com    private static void checkRegister(RegisterType registerType, EnumSet validCategories) {
1200fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        if (!validCategories.contains(registerType.category)) {
1201fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com            //TODO: add expected categories to error message
1202fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com            throw new ValidationException("Invalid register type. Expecting one of: " + " but got \"" +
1203fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com                    registerType.category + "\"");
1204fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        }
1205fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com    }
1206fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com
1207fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com    private static void checkWideDestinationPair(AnalyzedInstruction analyzedInstruction) {
1208fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        int register = analyzedInstruction.getDestinationRegister();
1209fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com
1210fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        if (register == (analyzedInstruction.postRegisterMap.length - 1)) {
1211fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com            throw new ValidationException("v" + register + " is the last register and not a valid wide register " +
1212fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com                    "pair.");
1213fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        }
1214fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com    }
1215fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com
1216fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com    private static RegisterType getAndCheckWideSourcePair(AnalyzedInstruction analyzedInstruction, int firstRegister) {
1217fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        assert firstRegister >= 0 && firstRegister < analyzedInstruction.postRegisterMap.length;
1218fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com
1219fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        if (firstRegister == analyzedInstruction.postRegisterMap.length - 1) {
1220fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com            throw new ValidationException("v" + firstRegister + " is the last register and not a valid wide register " +
1221fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com                    "pair.");
1222fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        }
1223fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com
1224fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        RegisterType registerType = analyzedInstruction.getPreInstructionRegisterType(firstRegister);
1225fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        assert registerType != null;
1226fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        if (registerType.category == RegisterType.Category.Unknown) {
1227fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com            return registerType;
1228fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        }
1229fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        checkRegister(registerType, WideLowCategories);
1230fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com
1231fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        RegisterType secondRegisterType = analyzedInstruction.getPreInstructionRegisterType(firstRegister + 1);
1232fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        assert secondRegisterType != null;
1233fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        checkRegister(secondRegisterType, WideHighCategories);
1234fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com
1235fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        if ((       registerType.category == RegisterType.Category.LongLo &&
1236fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com                    secondRegisterType.category == RegisterType.Category.DoubleHi)
1237fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com            ||  (   registerType.category == RegisterType.Category.DoubleLo &&
1238fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com                    secondRegisterType.category == RegisterType.Category.LongHi)) {
1239fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com            assert false;
1240fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com            throw new ValidationException("The first register in the wide register pair isn't the same type (long " +
1241fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com                    "vs. double) as the second register in the pair");
1242fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        }
1243d27ca7f7a61cfbe60e1c490bf645257d7d59fd39JesusFreke@JesusFreke.com
1244fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        return registerType;
1245d27ca7f7a61cfbe60e1c490bf645257d7d59fd39JesusFreke@JesusFreke.com    }
1246d27ca7f7a61cfbe60e1c490bf645257d7d59fd39JesusFreke@JesusFreke.com}
1247