MethodAnalyzer.java revision 300ad56aa3c343a84017ae7a2267dc516b5b6202
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
18300ad56aa3c343a84017ae7a2267dc516b5b6202JesusFreke@JesusFreke.com    private BitSet instructionsToVerify;
19300ad56aa3c343a84017ae7a2267dc516b5b6202JesusFreke@JesusFreke.com
20d27ca7f7a61cfbe60e1c490bf645257d7d59fd39JesusFreke@JesusFreke.com    //This is a dummy instruction that occurs immediately before the first real instruction. We can initialize the
21d27ca7f7a61cfbe60e1c490bf645257d7d59fd39JesusFreke@JesusFreke.com    //register types for this instruction to the parameter types, in order to have them propagate to all of its
22d27ca7f7a61cfbe60e1c490bf645257d7d59fd39JesusFreke@JesusFreke.com    //successors, e.g. the first real instruction, the first instructions in any exception handlers covering the first
23d27ca7f7a61cfbe60e1c490bf645257d7d59fd39JesusFreke@JesusFreke.com    //instruction, etc.
24d27ca7f7a61cfbe60e1c490bf645257d7d59fd39JesusFreke@JesusFreke.com    private AnalyzedInstruction startOfMethod;
25d27ca7f7a61cfbe60e1c490bf645257d7d59fd39JesusFreke@JesusFreke.com
26d27ca7f7a61cfbe60e1c490bf645257d7d59fd39JesusFreke@JesusFreke.com    public MethodAnalyzer(ClassDataItem.EncodedMethod encodedMethod) {
27d27ca7f7a61cfbe60e1c490bf645257d7d59fd39JesusFreke@JesusFreke.com        if (encodedMethod == null) {
28d27ca7f7a61cfbe60e1c490bf645257d7d59fd39JesusFreke@JesusFreke.com            throw new IllegalArgumentException("encodedMethod cannot be null");
29d27ca7f7a61cfbe60e1c490bf645257d7d59fd39JesusFreke@JesusFreke.com        }
30fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        if (encodedMethod.codeItem == null || encodedMethod.codeItem.getInstructions().length == 0) {
31d27ca7f7a61cfbe60e1c490bf645257d7d59fd39JesusFreke@JesusFreke.com            throw new IllegalArgumentException("The method has no code");
32d27ca7f7a61cfbe60e1c490bf645257d7d59fd39JesusFreke@JesusFreke.com        }
33d27ca7f7a61cfbe60e1c490bf645257d7d59fd39JesusFreke@JesusFreke.com        this.encodedMethod = encodedMethod;
34d27ca7f7a61cfbe60e1c490bf645257d7d59fd39JesusFreke@JesusFreke.com        buildInstructionList();
35fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com
36fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        //override AnalyzedInstruction and provide custom implementations of some of the methods, so that we don't
37fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        //have to handle the case this special case of instruction being null, in the main class
38fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        startOfMethod = new AnalyzedInstruction(null, -1, encodedMethod.codeItem.getRegisterCount()) {
39fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com            public boolean setsRegister() {
40fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com                return false;
41fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com            }
42fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com
43fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com            @Override
44fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com            public boolean setsWideRegister() {
45fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com                return false;
46fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com            }
47fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com
48fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com            @Override
49fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com            public boolean setsRegister(int registerNumber) {
50fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com                return false;
51fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com            }
52fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com
53fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com            @Override
54fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com            public int getDestinationRegister() {
55fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com                assert false;
56fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com                return -1;
57fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com            };
58fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        };
59300ad56aa3c343a84017ae7a2267dc516b5b6202JesusFreke@JesusFreke.com
60300ad56aa3c343a84017ae7a2267dc516b5b6202JesusFreke@JesusFreke.com        instructionsToVerify = new BitSet(instructions.size());
61d27ca7f7a61cfbe60e1c490bf645257d7d59fd39JesusFreke@JesusFreke.com    }
62d27ca7f7a61cfbe60e1c490bf645257d7d59fd39JesusFreke@JesusFreke.com
63d27ca7f7a61cfbe60e1c490bf645257d7d59fd39JesusFreke@JesusFreke.com    public AnalyzedInstruction[] analyze() {
64fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        assert encodedMethod != null;
65fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        assert encodedMethod.codeItem != null;
66fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com
67fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        if (analyzed) {
68fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com            return makeInstructionArray();
69fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        }
70fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com
71fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        CodeItem codeItem = encodedMethod.codeItem;
72fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        MethodIdItem methodIdItem = encodedMethod.method;
73fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com
74fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        int totalRegisters = codeItem.getRegisterCount();
75fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        int parameterRegisters = methodIdItem.getPrototype().getParameterRegisterCount();
76fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com
77fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        //if this isn't a static method, determine which register is the "this" register and set the type to the
78fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        //current class
79fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        if ((encodedMethod.accessFlags & AccessFlags.STATIC.getValue()) == 0) {
80fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com            int thisRegister = totalRegisters - parameterRegisters - 1;
81fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com
82fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com            //if this is a constructor, then set the "this" register to an uninitialized reference of the current class
83fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com            if ((encodedMethod.accessFlags & AccessFlags.CONSTRUCTOR.getValue()) != 0) {
84fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@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
85fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com                if (!encodedMethod.method.getMethodName().equals("<init>")) {
86fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com                    throw new ValidationException("The constructor flag can only be used with an <init> method.");
87fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com                }
88fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com
89fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com                setRegisterTypeAndPropagateChanges(startOfMethod, thisRegister,
90fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com                        RegisterType.getRegisterType(RegisterType.Category.UninitRef,
91fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com                            ClassPath.getClassDef(methodIdItem.getContainingClass())));
92fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com            } else {
93fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com                if (encodedMethod.method.getMethodName().equals("<init>")) {
94fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com                    throw new ValidationException("An <init> method must have the \"constructor\" access flag");
95fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com                }
96fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com
97fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com                setRegisterTypeAndPropagateChanges(startOfMethod, thisRegister,
98fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com                        RegisterType.getRegisterType(RegisterType.Category.Reference,
99fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com                            ClassPath.getClassDef(methodIdItem.getContainingClass())));
100fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com            }
101fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        }
102fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com
103fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        TypeListItem parameters = methodIdItem.getPrototype().getParameters();
104fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        if (parameters != null) {
105fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com            RegisterType[] parameterTypes = getParameterTypes(parameters, parameterRegisters);
106fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com            for (int i=0; i<parameterTypes.length; i++) {
107fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com                RegisterType registerType = parameterTypes[i];
108fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com                int registerNum = (totalRegisters - parameterRegisters) + i;
109fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com                setRegisterTypeAndPropagateChanges(startOfMethod, registerNum, registerType);
110fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com            }
111fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        }
112fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com
113300ad56aa3c343a84017ae7a2267dc516b5b6202JesusFreke@JesusFreke.com        BitSet analyzedInstructions = new BitSet(instructionsToVerify.size());
114300ad56aa3c343a84017ae7a2267dc516b5b6202JesusFreke@JesusFreke.com
115300ad56aa3c343a84017ae7a2267dc516b5b6202JesusFreke@JesusFreke.com        //make sure all of the "first instructions" are marked for processing
116300ad56aa3c343a84017ae7a2267dc516b5b6202JesusFreke@JesusFreke.com        for (AnalyzedInstruction successor: startOfMethod.successors) {
117300ad56aa3c343a84017ae7a2267dc516b5b6202JesusFreke@JesusFreke.com            instructionsToVerify.set(successor.instructionIndex);
118300ad56aa3c343a84017ae7a2267dc516b5b6202JesusFreke@JesusFreke.com        }
119300ad56aa3c343a84017ae7a2267dc516b5b6202JesusFreke@JesusFreke.com
120300ad56aa3c343a84017ae7a2267dc516b5b6202JesusFreke@JesusFreke.com        while (!instructionsToVerify.isEmpty()) {
121300ad56aa3c343a84017ae7a2267dc516b5b6202JesusFreke@JesusFreke.com            for(int i=instructionsToVerify.nextSetBit(0); i>=0; i=instructionsToVerify.nextSetBit(i+1)) {
122300ad56aa3c343a84017ae7a2267dc516b5b6202JesusFreke@JesusFreke.com                analyzeInstruction(instructions.get(i));
123300ad56aa3c343a84017ae7a2267dc516b5b6202JesusFreke@JesusFreke.com            }
124300ad56aa3c343a84017ae7a2267dc516b5b6202JesusFreke@JesusFreke.com        }
125300ad56aa3c343a84017ae7a2267dc516b5b6202JesusFreke@JesusFreke.com
126fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        analyzed = true;
127fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        return makeInstructionArray();
128fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com    }
129fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com
130fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com    private int getThisRegister() {
131fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        assert (encodedMethod.accessFlags & AccessFlags.STATIC.getValue()) == 0;
132fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com
133fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        CodeItem codeItem = encodedMethod.codeItem;
134fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        assert codeItem != null;
135fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com
136fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        MethodIdItem methodIdItem = encodedMethod.method;
137fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        assert methodIdItem != null;
138fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com
139fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        int totalRegisters = codeItem.getRegisterCount();
140fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        if (totalRegisters == 0) {
141fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com            throw new ValidationException("A non-static method must have at least 1 register");
142fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        }
143fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com
144fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        int parameterRegisters = methodIdItem.getPrototype().getParameterRegisterCount();
145fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com
146fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        return totalRegisters - parameterRegisters - 1;
147fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com    }
148fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com
149fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com    private boolean isInstanceConstructor() {
150fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        return (encodedMethod.accessFlags & AccessFlags.STATIC.getValue()) == 0 &&
151fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com               (encodedMethod.accessFlags & AccessFlags.CONSTRUCTOR.getValue()) != 0;
152fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com    }
153fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com
154fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com    private boolean isStaticConstructor() {
155fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        return (encodedMethod.accessFlags & AccessFlags.STATIC.getValue()) != 0 &&
156fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com               (encodedMethod.accessFlags & AccessFlags.CONSTRUCTOR.getValue()) != 0;
157fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com    }
158fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com
159fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com    public AnalyzedInstruction[] makeInstructionArray() {
160fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        AnalyzedInstruction[] instructionArray = new AnalyzedInstruction[instructions.size()];
161fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        for (int i=0; i<instructions.size(); i++) {
162fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com            instructionArray[i] = instructions.valueAt(i);
163fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        }
164fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        return instructionArray;
165fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com    }
166fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com
167fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com    private static RegisterType[] getParameterTypes(TypeListItem typeListItem, int parameterRegisterCount) {
168fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        assert typeListItem != null;
169fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        assert parameterRegisterCount == typeListItem.getRegisterCount();
170fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com
171fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        RegisterType[] registerTypes = new RegisterType[parameterRegisterCount];
172fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com
173fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        int registerNum = 0;
174fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        for (TypeIdItem type: typeListItem.getTypes()) {
175fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com            if (type.getRegisterCount() == 2) {
176fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com                registerTypes[registerNum++] = RegisterType.getWideRegisterTypeForTypeIdItem(type, true);
177fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com                registerTypes[registerNum++] = RegisterType.getWideRegisterTypeForTypeIdItem(type, false);
178fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com            } else {
179fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com                registerTypes[registerNum] = RegisterType.getRegisterTypeForTypeIdItem(type);
180fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com            }
181fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        }
182fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com
183fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        return registerTypes;
184fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com    }
185fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com
186fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com    private int getInstructionAddress(AnalyzedInstruction instruction) {
187fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        return instructions.keyAt(instruction.instructionIndex);
188fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com    }
189fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com
190fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com    private void setWideDestinationRegisterTypeAndPropagateChanges(AnalyzedInstruction analyzedInstruction,
191fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com                                                                   RegisterType registerType) {
192fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        assert registerType.category == RegisterType.Category.LongLo ||
193fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com               registerType.category == RegisterType.Category.DoubleLo;
194fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com
195fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        checkWideDestinationPair(analyzedInstruction);
196fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com
197fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        setRegisterTypeAndPropagateChanges(analyzedInstruction, analyzedInstruction.getDestinationRegister(),
198fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com                registerType);
199fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        if (registerType.category == RegisterType.Category.LongLo) {
200fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com            setRegisterTypeAndPropagateChanges(analyzedInstruction, analyzedInstruction.getDestinationRegister() + 1,
201fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com                RegisterType.getRegisterType(RegisterType.Category.LongHi, null));
202fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        } else {
203fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com            setRegisterTypeAndPropagateChanges(analyzedInstruction, analyzedInstruction.getDestinationRegister() + 1,
204fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com                RegisterType.getRegisterType(RegisterType.Category.DoubleHi, null));
205fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        }
206fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com    }
207fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com
208fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com    private void setDestinationRegisterTypeAndPropagateChanges(AnalyzedInstruction analyzedInstruction,
209fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com                                                               RegisterType registerType) {
210fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        setRegisterTypeAndPropagateChanges(analyzedInstruction, analyzedInstruction.getDestinationRegister(),
211fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com                registerType);
212fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com    }
213fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com
214fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com    private void setRegisterTypeAndPropagateChanges(AnalyzedInstruction instruction, int registerNumber,
215fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com                                                RegisterType registerType) {
216fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com
217fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        BitSet changedInstructions = new BitSet(instructions.size());
218fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com
219fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        boolean changed = instruction.setPostRegisterType(registerNumber, registerType);
220fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com
221fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        if (!changed || instruction.setsRegister(registerNumber)) {
222fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com            return;
223fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        }
224fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com
225fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        propagateRegisterToSuccessors(instruction, registerNumber, changedInstructions);
226fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com
227fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        //using a for loop inside the while loop optimizes for the common case of the successors of an instruction
228fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        //occurring after the instruction. Any successors that occur prior to the instruction will be picked up on
229fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        //the next iteration of the while loop.
230fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        //this could also be done recursively, but in large methods it would likely cause very deep recursion,
231fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        //which would requires the user to specify a larger stack size. This isn't really a problem, but it is
232fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        //slightly annoying.
233fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        while (!changedInstructions.isEmpty()) {
234fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com            for (int instructionIndex=changedInstructions.nextSetBit(0);
235fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com                     instructionIndex>=0;
236fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com                     instructionIndex=changedInstructions.nextSetBit(instructionIndex)) {
237fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com
238fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com                changedInstructions.clear(instructionIndex);
239fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com
240fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com                propagateRegisterToSuccessors(instructions.valueAt(instructionIndex), registerNumber,
241fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com                        changedInstructions);
242fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com            }
243fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        }
244d27ca7f7a61cfbe60e1c490bf645257d7d59fd39JesusFreke@JesusFreke.com    }
245d27ca7f7a61cfbe60e1c490bf645257d7d59fd39JesusFreke@JesusFreke.com
246fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com    private void propagateRegisterToSuccessors(AnalyzedInstruction instruction, int registerNumber,
247fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com                                               BitSet changedInstructions) {
248fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        for (AnalyzedInstruction successor: instruction.successors) {
249fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com            if (!successor.setsRegister(registerNumber)) {
250fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com                RegisterType registerType = successor.getMergedRegisterTypeFromPredecessors(registerNumber);
251fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com
252fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com                if (successor.setPostRegisterType(registerNumber, registerType)) {
253fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com                    changedInstructions.set(successor.instructionIndex);
254300ad56aa3c343a84017ae7a2267dc516b5b6202JesusFreke@JesusFreke.com                    instructionsToVerify.set(successor.instructionIndex);
255fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com                }
256fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com            }
257fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        }
258fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com    }
259fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com
260fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com
261fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com
262d27ca7f7a61cfbe60e1c490bf645257d7d59fd39JesusFreke@JesusFreke.com    private void buildInstructionList() {
263d27ca7f7a61cfbe60e1c490bf645257d7d59fd39JesusFreke@JesusFreke.com        assert encodedMethod != null;
264d27ca7f7a61cfbe60e1c490bf645257d7d59fd39JesusFreke@JesusFreke.com        assert encodedMethod.codeItem != null;
265fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        int registerCount = encodedMethod.codeItem.getRegisterCount();
266d27ca7f7a61cfbe60e1c490bf645257d7d59fd39JesusFreke@JesusFreke.com
267fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        startOfMethod = new AnalyzedInstruction(null, -1, registerCount);
268d27ca7f7a61cfbe60e1c490bf645257d7d59fd39JesusFreke@JesusFreke.com
269d27ca7f7a61cfbe60e1c490bf645257d7d59fd39JesusFreke@JesusFreke.com        Instruction[] insns = encodedMethod.codeItem.getInstructions();
270d27ca7f7a61cfbe60e1c490bf645257d7d59fd39JesusFreke@JesusFreke.com
271fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        instructions = new SparseArray<AnalyzedInstruction>(insns.length);
272d27ca7f7a61cfbe60e1c490bf645257d7d59fd39JesusFreke@JesusFreke.com
273d27ca7f7a61cfbe60e1c490bf645257d7d59fd39JesusFreke@JesusFreke.com        //first, create all the instructions and populate the instructionAddresses array
274d27ca7f7a61cfbe60e1c490bf645257d7d59fd39JesusFreke@JesusFreke.com        int currentCodeAddress = 0;
275d27ca7f7a61cfbe60e1c490bf645257d7d59fd39JesusFreke@JesusFreke.com        for (int i=0; i<insns.length; i++) {
276fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com            instructions.append(currentCodeAddress, new AnalyzedInstruction(insns[i], i, registerCount));
277fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com            assert instructions.indexOfKey(currentCodeAddress) == i;
278d27ca7f7a61cfbe60e1c490bf645257d7d59fd39JesusFreke@JesusFreke.com            currentCodeAddress += insns[i].getSize(currentCodeAddress);
279d27ca7f7a61cfbe60e1c490bf645257d7d59fd39JesusFreke@JesusFreke.com        }
280d27ca7f7a61cfbe60e1c490bf645257d7d59fd39JesusFreke@JesusFreke.com
281d27ca7f7a61cfbe60e1c490bf645257d7d59fd39JesusFreke@JesusFreke.com        //next, populate the exceptionHandlers array. The array item for each instruction that can throw an exception
282d27ca7f7a61cfbe60e1c490bf645257d7d59fd39JesusFreke@JesusFreke.com        //and is covered by a try block should be set to a list of the first instructions of each exception handler
283d27ca7f7a61cfbe60e1c490bf645257d7d59fd39JesusFreke@JesusFreke.com        //for the try block covering the instruction
284d27ca7f7a61cfbe60e1c490bf645257d7d59fd39JesusFreke@JesusFreke.com        CodeItem.TryItem[] tries = encodedMethod.codeItem.getTries();
285d27ca7f7a61cfbe60e1c490bf645257d7d59fd39JesusFreke@JesusFreke.com        int triesIndex = 0;
286d27ca7f7a61cfbe60e1c490bf645257d7d59fd39JesusFreke@JesusFreke.com        CodeItem.TryItem currentTry = null;
287fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        AnalyzedInstruction[] currentExceptionHandlers = null;
288fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        AnalyzedInstruction[][] exceptionHandlers = new AnalyzedInstruction[insns.length][];
289d27ca7f7a61cfbe60e1c490bf645257d7d59fd39JesusFreke@JesusFreke.com
290fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        for (int i=0; i<instructions.size(); i++) {
291fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com            AnalyzedInstruction instruction = instructions.valueAt(i);
292d27ca7f7a61cfbe60e1c490bf645257d7d59fd39JesusFreke@JesusFreke.com            Opcode instructionOpcode = instruction.instruction.opcode;
293d27ca7f7a61cfbe60e1c490bf645257d7d59fd39JesusFreke@JesusFreke.com
294d27ca7f7a61cfbe60e1c490bf645257d7d59fd39JesusFreke@JesusFreke.com            //check if we have gone past the end of the current try
295d27ca7f7a61cfbe60e1c490bf645257d7d59fd39JesusFreke@JesusFreke.com            if (currentTry != null) {
296d27ca7f7a61cfbe60e1c490bf645257d7d59fd39JesusFreke@JesusFreke.com                if (currentTry.getStartCodeAddress() + currentTry.getTryLength() <= currentCodeAddress) {
297d27ca7f7a61cfbe60e1c490bf645257d7d59fd39JesusFreke@JesusFreke.com                    currentTry = null;
298d27ca7f7a61cfbe60e1c490bf645257d7d59fd39JesusFreke@JesusFreke.com                    triesIndex++;
299d27ca7f7a61cfbe60e1c490bf645257d7d59fd39JesusFreke@JesusFreke.com                }
300d27ca7f7a61cfbe60e1c490bf645257d7d59fd39JesusFreke@JesusFreke.com            }
301d27ca7f7a61cfbe60e1c490bf645257d7d59fd39JesusFreke@JesusFreke.com
302d27ca7f7a61cfbe60e1c490bf645257d7d59fd39JesusFreke@JesusFreke.com            //check if the next try is applicable yet
303d27ca7f7a61cfbe60e1c490bf645257d7d59fd39JesusFreke@JesusFreke.com            if (currentTry == null && triesIndex < tries.length) {
304d27ca7f7a61cfbe60e1c490bf645257d7d59fd39JesusFreke@JesusFreke.com                CodeItem.TryItem tryItem = tries[triesIndex];
305d27ca7f7a61cfbe60e1c490bf645257d7d59fd39JesusFreke@JesusFreke.com                if (tryItem.getStartCodeAddress() <= currentCodeAddress) {
306d27ca7f7a61cfbe60e1c490bf645257d7d59fd39JesusFreke@JesusFreke.com                    assert(tryItem.getStartCodeAddress() + tryItem.getTryLength() > currentCodeAddress);
307d27ca7f7a61cfbe60e1c490bf645257d7d59fd39JesusFreke@JesusFreke.com
308d27ca7f7a61cfbe60e1c490bf645257d7d59fd39JesusFreke@JesusFreke.com                    currentTry = tryItem;
309d27ca7f7a61cfbe60e1c490bf645257d7d59fd39JesusFreke@JesusFreke.com
310d27ca7f7a61cfbe60e1c490bf645257d7d59fd39JesusFreke@JesusFreke.com                    currentExceptionHandlers = buildExceptionHandlerArray(tryItem);
311d27ca7f7a61cfbe60e1c490bf645257d7d59fd39JesusFreke@JesusFreke.com                }
312d27ca7f7a61cfbe60e1c490bf645257d7d59fd39JesusFreke@JesusFreke.com            }
313d27ca7f7a61cfbe60e1c490bf645257d7d59fd39JesusFreke@JesusFreke.com
314d27ca7f7a61cfbe60e1c490bf645257d7d59fd39JesusFreke@JesusFreke.com            //if we're inside a try block, and the instruction can throw an exception, then add the exception handlers
315d27ca7f7a61cfbe60e1c490bf645257d7d59fd39JesusFreke@JesusFreke.com            //for the current instruction
316d27ca7f7a61cfbe60e1c490bf645257d7d59fd39JesusFreke@JesusFreke.com            if (currentTry != null && instructionOpcode.canThrow()) {
317d27ca7f7a61cfbe60e1c490bf645257d7d59fd39JesusFreke@JesusFreke.com                exceptionHandlers[i] = currentExceptionHandlers;
318d27ca7f7a61cfbe60e1c490bf645257d7d59fd39JesusFreke@JesusFreke.com            }
319d27ca7f7a61cfbe60e1c490bf645257d7d59fd39JesusFreke@JesusFreke.com        }
320d27ca7f7a61cfbe60e1c490bf645257d7d59fd39JesusFreke@JesusFreke.com
321d27ca7f7a61cfbe60e1c490bf645257d7d59fd39JesusFreke@JesusFreke.com        //finally, populate the successors and predecessors for each instruction
322fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        assert instructions.size() > 0;
323fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        addPredecessorSuccessor(startOfMethod, instructions.valueAt(0), exceptionHandlers);
324fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        startOfMethod.addSuccessor(instructions.valueAt(0));
325fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com
326fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        for (int i=0; i<instructions.size(); i++) {
327fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com            AnalyzedInstruction instruction = instructions.valueAt(i);
328d27ca7f7a61cfbe60e1c490bf645257d7d59fd39JesusFreke@JesusFreke.com            Opcode instructionOpcode = instruction.instruction.opcode;
329fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com            int instructionCodeAddress = getInstructionAddress(instruction);
330d27ca7f7a61cfbe60e1c490bf645257d7d59fd39JesusFreke@JesusFreke.com
331d27ca7f7a61cfbe60e1c490bf645257d7d59fd39JesusFreke@JesusFreke.com            if (instruction.instruction.opcode.canContinue()) {
332fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com                if (i == instructions.size() - 1) {
333d27ca7f7a61cfbe60e1c490bf645257d7d59fd39JesusFreke@JesusFreke.com                    throw new ValidationException("Execution can continue past the last instruction");
334d27ca7f7a61cfbe60e1c490bf645257d7d59fd39JesusFreke@JesusFreke.com                }
335fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com                AnalyzedInstruction nextInstruction = instructions.valueAt(i+1);
336fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com                addPredecessorSuccessor(instruction, nextInstruction, exceptionHandlers);
337d27ca7f7a61cfbe60e1c490bf645257d7d59fd39JesusFreke@JesusFreke.com            }
338d27ca7f7a61cfbe60e1c490bf645257d7d59fd39JesusFreke@JesusFreke.com
339d27ca7f7a61cfbe60e1c490bf645257d7d59fd39JesusFreke@JesusFreke.com            if (instruction instanceof OffsetInstruction) {
340d27ca7f7a61cfbe60e1c490bf645257d7d59fd39JesusFreke@JesusFreke.com                OffsetInstruction offsetInstruction = (OffsetInstruction)instruction;
341d27ca7f7a61cfbe60e1c490bf645257d7d59fd39JesusFreke@JesusFreke.com
342d27ca7f7a61cfbe60e1c490bf645257d7d59fd39JesusFreke@JesusFreke.com                if (instructionOpcode == Opcode.PACKED_SWITCH || instructionOpcode == Opcode.SPARSE_SWITCH) {
343d27ca7f7a61cfbe60e1c490bf645257d7d59fd39JesusFreke@JesusFreke.com                    MultiOffsetInstruction switchDataInstruction =
344fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com                            (MultiOffsetInstruction)instructions.get(instructionCodeAddress +
345d27ca7f7a61cfbe60e1c490bf645257d7d59fd39JesusFreke@JesusFreke.com                                    offsetInstruction.getTargetAddressOffset()).instruction;
346d27ca7f7a61cfbe60e1c490bf645257d7d59fd39JesusFreke@JesusFreke.com                    for (int targetAddressOffset: switchDataInstruction.getTargets()) {
347fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com                        AnalyzedInstruction targetInstruction = instructions.get(instructionCodeAddress +
348d27ca7f7a61cfbe60e1c490bf645257d7d59fd39JesusFreke@JesusFreke.com                                targetAddressOffset);
349d27ca7f7a61cfbe60e1c490bf645257d7d59fd39JesusFreke@JesusFreke.com
350fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com                        addPredecessorSuccessor(instruction, targetInstruction, exceptionHandlers);
351d27ca7f7a61cfbe60e1c490bf645257d7d59fd39JesusFreke@JesusFreke.com                    }
352d27ca7f7a61cfbe60e1c490bf645257d7d59fd39JesusFreke@JesusFreke.com                } else {
353d27ca7f7a61cfbe60e1c490bf645257d7d59fd39JesusFreke@JesusFreke.com                    int targetAddressOffset = offsetInstruction.getTargetAddressOffset();
354fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com                    AnalyzedInstruction targetInstruction = instructions.get(instructionCodeAddress +
355fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com                            targetAddressOffset);
356fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com                    addPredecessorSuccessor(instruction, targetInstruction, exceptionHandlers);
357d27ca7f7a61cfbe60e1c490bf645257d7d59fd39JesusFreke@JesusFreke.com                }
358d27ca7f7a61cfbe60e1c490bf645257d7d59fd39JesusFreke@JesusFreke.com            }
359d27ca7f7a61cfbe60e1c490bf645257d7d59fd39JesusFreke@JesusFreke.com        }
360d27ca7f7a61cfbe60e1c490bf645257d7d59fd39JesusFreke@JesusFreke.com    }
361d27ca7f7a61cfbe60e1c490bf645257d7d59fd39JesusFreke@JesusFreke.com
362d27ca7f7a61cfbe60e1c490bf645257d7d59fd39JesusFreke@JesusFreke.com    private void addPredecessorSuccessor(AnalyzedInstruction predecessor, AnalyzedInstruction successor,
363fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com                                                AnalyzedInstruction[][] exceptionHandlers) {
364fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        addPredecessorSuccessor(predecessor, successor, exceptionHandlers, false);
365fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com    }
366fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com
367fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com    private void addPredecessorSuccessor(AnalyzedInstruction predecessor, AnalyzedInstruction successor,
368fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com                                                AnalyzedInstruction[][] exceptionHandlers, boolean allowMoveException) {
369fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com
370fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        if (!allowMoveException && successor.instruction.opcode == Opcode.MOVE_EXCEPTION) {
371fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com            throw new ValidationException("Execution can pass from the " + predecessor.instruction.opcode.name +
372fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com                    " instruction at code address 0x" + Integer.toHexString(getInstructionAddress(predecessor)) +
373fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com                    " to the move-exception instruction at address 0x" +
374fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com                    Integer.toHexString(getInstructionAddress(successor)));
375fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        }
376d27ca7f7a61cfbe60e1c490bf645257d7d59fd39JesusFreke@JesusFreke.com
377d27ca7f7a61cfbe60e1c490bf645257d7d59fd39JesusFreke@JesusFreke.com        if (!predecessor.addSuccessor(successor)) {
378d27ca7f7a61cfbe60e1c490bf645257d7d59fd39JesusFreke@JesusFreke.com            //if predecessor already had successor as a successor, then there's nothing else to do
379d27ca7f7a61cfbe60e1c490bf645257d7d59fd39JesusFreke@JesusFreke.com            return;
380d27ca7f7a61cfbe60e1c490bf645257d7d59fd39JesusFreke@JesusFreke.com        }
381d27ca7f7a61cfbe60e1c490bf645257d7d59fd39JesusFreke@JesusFreke.com
382d27ca7f7a61cfbe60e1c490bf645257d7d59fd39JesusFreke@JesusFreke.com        successor.addPredecessor(predecessor);
383d27ca7f7a61cfbe60e1c490bf645257d7d59fd39JesusFreke@JesusFreke.com
384fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        //TODO: need to handle the case of monitor-exit as a special case - the exception is thrown *after* the instruction executes
385d27ca7f7a61cfbe60e1c490bf645257d7d59fd39JesusFreke@JesusFreke.com        //if the successor can throw an instruction, then we need to add the exception handlers as additional
386d27ca7f7a61cfbe60e1c490bf645257d7d59fd39JesusFreke@JesusFreke.com        //successors to the predecessor (and then apply this same logic recursively if needed)
387fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        AnalyzedInstruction[] exceptionHandlersForSuccessor = exceptionHandlers[successor.instructionIndex];
388d27ca7f7a61cfbe60e1c490bf645257d7d59fd39JesusFreke@JesusFreke.com        if (exceptionHandlersForSuccessor != null) {
389d27ca7f7a61cfbe60e1c490bf645257d7d59fd39JesusFreke@JesusFreke.com            //the item for this instruction in exceptionHandlersForSuccessor should only be set if this instruction
390d27ca7f7a61cfbe60e1c490bf645257d7d59fd39JesusFreke@JesusFreke.com            //can throw an exception
391d27ca7f7a61cfbe60e1c490bf645257d7d59fd39JesusFreke@JesusFreke.com            assert predecessor.instruction.opcode.canThrow();
392d27ca7f7a61cfbe60e1c490bf645257d7d59fd39JesusFreke@JesusFreke.com
393fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com            for (AnalyzedInstruction exceptionHandler: exceptionHandlersForSuccessor) {
394fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com                addPredecessorSuccessor(predecessor, exceptionHandler, exceptionHandlers, true);
395d27ca7f7a61cfbe60e1c490bf645257d7d59fd39JesusFreke@JesusFreke.com            }
396d27ca7f7a61cfbe60e1c490bf645257d7d59fd39JesusFreke@JesusFreke.com        }
397d27ca7f7a61cfbe60e1c490bf645257d7d59fd39JesusFreke@JesusFreke.com    }
398d27ca7f7a61cfbe60e1c490bf645257d7d59fd39JesusFreke@JesusFreke.com
399fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com    private AnalyzedInstruction[] buildExceptionHandlerArray(CodeItem.TryItem tryItem) {
400d27ca7f7a61cfbe60e1c490bf645257d7d59fd39JesusFreke@JesusFreke.com        int exceptionHandlerCount = tryItem.encodedCatchHandler.handlers.length;
401d27ca7f7a61cfbe60e1c490bf645257d7d59fd39JesusFreke@JesusFreke.com        int catchAllHandler = tryItem.encodedCatchHandler.getCatchAllHandlerAddress();
402d27ca7f7a61cfbe60e1c490bf645257d7d59fd39JesusFreke@JesusFreke.com        if (catchAllHandler != -1) {
403d27ca7f7a61cfbe60e1c490bf645257d7d59fd39JesusFreke@JesusFreke.com            exceptionHandlerCount++;
404d27ca7f7a61cfbe60e1c490bf645257d7d59fd39JesusFreke@JesusFreke.com        }
405d27ca7f7a61cfbe60e1c490bf645257d7d59fd39JesusFreke@JesusFreke.com
406fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        AnalyzedInstruction[] exceptionHandlers = new AnalyzedInstruction[exceptionHandlerCount];
407d27ca7f7a61cfbe60e1c490bf645257d7d59fd39JesusFreke@JesusFreke.com        for (int i=0; i<tryItem.encodedCatchHandler.handlers.length; i++) {
408fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com            exceptionHandlers[i] = instructions.get(tryItem.encodedCatchHandler.handlers[i].getHandlerAddress());
409d27ca7f7a61cfbe60e1c490bf645257d7d59fd39JesusFreke@JesusFreke.com        }
410d27ca7f7a61cfbe60e1c490bf645257d7d59fd39JesusFreke@JesusFreke.com
411d27ca7f7a61cfbe60e1c490bf645257d7d59fd39JesusFreke@JesusFreke.com        if (catchAllHandler != -1) {
412fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com            exceptionHandlers[exceptionHandlers.length - 1] = instructions.get(catchAllHandler);
413d27ca7f7a61cfbe60e1c490bf645257d7d59fd39JesusFreke@JesusFreke.com        }
414d27ca7f7a61cfbe60e1c490bf645257d7d59fd39JesusFreke@JesusFreke.com
415d27ca7f7a61cfbe60e1c490bf645257d7d59fd39JesusFreke@JesusFreke.com        return exceptionHandlers;
416d27ca7f7a61cfbe60e1c490bf645257d7d59fd39JesusFreke@JesusFreke.com    }
417d27ca7f7a61cfbe60e1c490bf645257d7d59fd39JesusFreke@JesusFreke.com
418300ad56aa3c343a84017ae7a2267dc516b5b6202JesusFreke@JesusFreke.com    private boolean analyzeInstruction(AnalyzedInstruction analyzedInstruction) {
419fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        Instruction instruction = analyzedInstruction.instruction;
420fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com
421fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        switch (instruction.opcode) {
422fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com            case NOP:
423fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com                return true;
424fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com            case MOVE:
425fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com            case MOVE_FROM16:
426fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com            case MOVE_16:
427fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com                return handleMove(analyzedInstruction, Primitive32BitCategories);
428fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com            case MOVE_WIDE:
429fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com            case MOVE_WIDE_FROM16:
430fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com            case MOVE_WIDE_16:
431fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com                return handleMoveWide(analyzedInstruction);
432fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com            case MOVE_OBJECT:
433fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com            case MOVE_OBJECT_FROM16:
434fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com            case MOVE_OBJECT_16:
435fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com                return handleMove(analyzedInstruction, ReferenceCategories);
436fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com            case MOVE_RESULT:
437fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com                return handleMoveResult(analyzedInstruction, Primitive32BitCategories);
438fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com            case MOVE_RESULT_WIDE:
439fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com                return handleMoveResult(analyzedInstruction, WideLowCategories);
440fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com            case MOVE_RESULT_OBJECT:
441fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com                return handleMoveResult(analyzedInstruction, ReferenceCategories);
442fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com            case MOVE_EXCEPTION:
443fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com                return handleMoveException(analyzedInstruction);
444fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com            case RETURN_VOID:
445fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com                return handleReturnVoid(analyzedInstruction);
446fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com            case RETURN:
447fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com                return handleReturn(analyzedInstruction);
448fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com            case RETURN_WIDE:
449fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com                return handleReturnWide(analyzedInstruction);
450fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com            case RETURN_OBJECT:
451fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com                return handleReturnObject(analyzedInstruction);
452fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com            case CONST_4:
453fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com            case CONST_16:
454fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com            case CONST:
455fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com                return handleConst(analyzedInstruction);
456fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com            case CONST_HIGH16:
457fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com                return handleConstHigh16(analyzedInstruction);
458fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com            case CONST_WIDE_16:
459fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com            case CONST_WIDE_32:
460fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com            case CONST_WIDE:
461fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com            case CONST_WIDE_HIGH16:
462fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com                return handleWideConst(analyzedInstruction);
463fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com            case CONST_STRING:
464fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com            case CONST_STRING_JUMBO:
465fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com                return handleConstString(analyzedInstruction);
466fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com            case CONST_CLASS:
467fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com                return handleConstClass(analyzedInstruction);
468fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com            case MONITOR_ENTER:
469fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com            case MONITOR_EXIT:
470fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com                return handleMonitor(analyzedInstruction);
471fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com            case CHECK_CAST:
472fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com                return handleCheckCast(analyzedInstruction);
473fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com            case INSTANCE_OF:
474fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com                return handleInstanceOf(analyzedInstruction);
475fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com            case ARRAY_LENGTH:
476fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com                return handleArrayLength(analyzedInstruction);
477fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com            case NEW_INSTANCE:
478fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com                return handleNewInstance(analyzedInstruction);
479fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com            case NEW_ARRAY:
480fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com                return handleNewArray(analyzedInstruction);
4819e5dd85d837501e84e18617fc136c8203ab1f183JesusFreke@JesusFreke.com            case FILLED_NEW_ARRAY:
4829e5dd85d837501e84e18617fc136c8203ab1f183JesusFreke@JesusFreke.com                return handleFilledNewArray(analyzedInstruction);
483ac8785e5d550c2ec7c7d02dd2990f859a78c111cJesusFreke@JesusFreke.com            case FILLED_NEW_ARRAY_RANGE:
484ac8785e5d550c2ec7c7d02dd2990f859a78c111cJesusFreke@JesusFreke.com                return handleFilledNewArrayRange(analyzedInstruction);
485472d3ea58455ebf43d21819b2701fad98b5a0f9cJesusFreke@JesusFreke.com            case FILL_ARRAY_DATA:
486472d3ea58455ebf43d21819b2701fad98b5a0f9cJesusFreke@JesusFreke.com                return handleFillArrayData(analyzedInstruction);
487ed140ca3e4fa66a03970affb3415a9fe2a924312JesusFreke@JesusFreke.com            case THROW:
488ed140ca3e4fa66a03970affb3415a9fe2a924312JesusFreke@JesusFreke.com                return handleThrow(analyzedInstruction);
489898edda7cea48c02687bb71804a98cfd6e260b89JesusFreke@JesusFreke.com            case GOTO:
490898edda7cea48c02687bb71804a98cfd6e260b89JesusFreke@JesusFreke.com            case GOTO_16:
491898edda7cea48c02687bb71804a98cfd6e260b89JesusFreke@JesusFreke.com            case GOTO_32:
492898edda7cea48c02687bb71804a98cfd6e260b89JesusFreke@JesusFreke.com                //nothing to do
493898edda7cea48c02687bb71804a98cfd6e260b89JesusFreke@JesusFreke.com                return true;
494cda44f70cfebfae4875cd77455a171075aebac4dJesusFreke@JesusFreke.com            case PACKED_SWITCH:
495cda44f70cfebfae4875cd77455a171075aebac4dJesusFreke@JesusFreke.com                return handleSwitch(analyzedInstruction, Format.PackedSwitchData);
496cda44f70cfebfae4875cd77455a171075aebac4dJesusFreke@JesusFreke.com            case SPARSE_SWITCH:
497cda44f70cfebfae4875cd77455a171075aebac4dJesusFreke@JesusFreke.com                return handleSwitch(analyzedInstruction, Format.SparseSwitchData);
498f1a74cea19f10e9059e05f1cee6ae45baf118108JesusFreke@JesusFreke.com            case CMPL_FLOAT:
499f1a74cea19f10e9059e05f1cee6ae45baf118108JesusFreke@JesusFreke.com            case CMPG_FLOAT:
500f1a74cea19f10e9059e05f1cee6ae45baf118108JesusFreke@JesusFreke.com                return handleFloatCmp(analyzedInstruction);
501f1a74cea19f10e9059e05f1cee6ae45baf118108JesusFreke@JesusFreke.com            case CMPL_DOUBLE:
502f1a74cea19f10e9059e05f1cee6ae45baf118108JesusFreke@JesusFreke.com            case CMPG_DOUBLE:
503f1a74cea19f10e9059e05f1cee6ae45baf118108JesusFreke@JesusFreke.com            case CMP_LONG:
504f1a74cea19f10e9059e05f1cee6ae45baf118108JesusFreke@JesusFreke.com                return handleWideCmp(analyzedInstruction);
505aba6bb0bbd1537a6df9614ee579773e4a8af70ffJesusFreke@JesusFreke.com            case IF_EQ:
506aba6bb0bbd1537a6df9614ee579773e4a8af70ffJesusFreke@JesusFreke.com            case IF_NE:
507aba6bb0bbd1537a6df9614ee579773e4a8af70ffJesusFreke@JesusFreke.com                return handleIfEqNe(analyzedInstruction);
508150acd9db94f9886f6fc32e89acc15a1a5c1466fJesusFreke@JesusFreke.com            case IF_LT:
509150acd9db94f9886f6fc32e89acc15a1a5c1466fJesusFreke@JesusFreke.com            case IF_GE:
510150acd9db94f9886f6fc32e89acc15a1a5c1466fJesusFreke@JesusFreke.com            case IF_GT:
511150acd9db94f9886f6fc32e89acc15a1a5c1466fJesusFreke@JesusFreke.com            case IF_LE:
512150acd9db94f9886f6fc32e89acc15a1a5c1466fJesusFreke@JesusFreke.com                return handleIf(analyzedInstruction);
513cb00252b6aed86cd3e7c426015cea83fcdbaa806JesusFreke@JesusFreke.com            case IF_EQZ:
514cb00252b6aed86cd3e7c426015cea83fcdbaa806JesusFreke@JesusFreke.com            case IF_NEZ:
515cb00252b6aed86cd3e7c426015cea83fcdbaa806JesusFreke@JesusFreke.com                return handleIfEqzNez(analyzedInstruction);
51616a709ba046343bfefc15a6cdb0be38282126223JesusFreke@JesusFreke.com            case IF_LTZ:
51716a709ba046343bfefc15a6cdb0be38282126223JesusFreke@JesusFreke.com            case IF_GEZ:
51816a709ba046343bfefc15a6cdb0be38282126223JesusFreke@JesusFreke.com            case IF_GTZ:
51916a709ba046343bfefc15a6cdb0be38282126223JesusFreke@JesusFreke.com            case IF_LEZ:
52016a709ba046343bfefc15a6cdb0be38282126223JesusFreke@JesusFreke.com                return handleIfz(analyzedInstruction);
521b2397452907c28b0743bbbcdf9fa6b2a8208aeabJesusFreke@JesusFreke.com            case AGET:
522b2397452907c28b0743bbbcdf9fa6b2a8208aeabJesusFreke@JesusFreke.com                return handle32BitPrimitiveAget(analyzedInstruction, RegisterType.Category.Integer);
523b2397452907c28b0743bbbcdf9fa6b2a8208aeabJesusFreke@JesusFreke.com            case AGET_BOOLEAN:
524b2397452907c28b0743bbbcdf9fa6b2a8208aeabJesusFreke@JesusFreke.com                return handle32BitPrimitiveAget(analyzedInstruction, RegisterType.Category.Boolean);
525b2397452907c28b0743bbbcdf9fa6b2a8208aeabJesusFreke@JesusFreke.com            case AGET_BYTE:
526b2397452907c28b0743bbbcdf9fa6b2a8208aeabJesusFreke@JesusFreke.com                return handle32BitPrimitiveAget(analyzedInstruction, RegisterType.Category.Byte);
527b2397452907c28b0743bbbcdf9fa6b2a8208aeabJesusFreke@JesusFreke.com            case AGET_CHAR:
528b2397452907c28b0743bbbcdf9fa6b2a8208aeabJesusFreke@JesusFreke.com                return handle32BitPrimitiveAget(analyzedInstruction, RegisterType.Category.Char);
529b2397452907c28b0743bbbcdf9fa6b2a8208aeabJesusFreke@JesusFreke.com            case AGET_SHORT:
530b2397452907c28b0743bbbcdf9fa6b2a8208aeabJesusFreke@JesusFreke.com                return handle32BitPrimitiveAget(analyzedInstruction, RegisterType.Category.Short);
531c308b24b6261ea81497a69e6d4d7ef6319943b10JesusFreke@JesusFreke.com            case AGET_WIDE:
532c308b24b6261ea81497a69e6d4d7ef6319943b10JesusFreke@JesusFreke.com                return handleAgetWide(analyzedInstruction);
533461a797324f0377db6cf06f680dec894b6f91204JesusFreke@JesusFreke.com            case AGET_OBJECT:
534461a797324f0377db6cf06f680dec894b6f91204JesusFreke@JesusFreke.com                return handleAgetObject(analyzedInstruction);
535c849236be2031b02d66eac4149617fd8a83572b4JesusFreke@JesusFreke.com            case APUT:
536c849236be2031b02d66eac4149617fd8a83572b4JesusFreke@JesusFreke.com                return handle32BitPrimitiveAput(analyzedInstruction, RegisterType.Category.Integer);
537c849236be2031b02d66eac4149617fd8a83572b4JesusFreke@JesusFreke.com            case APUT_BOOLEAN:
538c849236be2031b02d66eac4149617fd8a83572b4JesusFreke@JesusFreke.com                return handle32BitPrimitiveAput(analyzedInstruction, RegisterType.Category.Boolean);
539c849236be2031b02d66eac4149617fd8a83572b4JesusFreke@JesusFreke.com            case APUT_BYTE:
540c849236be2031b02d66eac4149617fd8a83572b4JesusFreke@JesusFreke.com                return handle32BitPrimitiveAput(analyzedInstruction, RegisterType.Category.Byte);
541c849236be2031b02d66eac4149617fd8a83572b4JesusFreke@JesusFreke.com            case APUT_CHAR:
542c849236be2031b02d66eac4149617fd8a83572b4JesusFreke@JesusFreke.com                return handle32BitPrimitiveAput(analyzedInstruction, RegisterType.Category.Char);
543c849236be2031b02d66eac4149617fd8a83572b4JesusFreke@JesusFreke.com            case APUT_SHORT:
544c849236be2031b02d66eac4149617fd8a83572b4JesusFreke@JesusFreke.com                return handle32BitPrimitiveAput(analyzedInstruction, RegisterType.Category.Short);
54555d43e36eb862bf86ceaf9c664789ce2c4d92af8JesusFreke@JesusFreke.com            case APUT_WIDE:
54655d43e36eb862bf86ceaf9c664789ce2c4d92af8JesusFreke@JesusFreke.com                return handleAputWide(analyzedInstruction);
547898e750048326802a488623d1ebf475df9bca209JesusFreke@JesusFreke.com            case APUT_OBJECT:
548898e750048326802a488623d1ebf475df9bca209JesusFreke@JesusFreke.com                return handleAputObject(analyzedInstruction);
5494f84e8f9e9bf4c74cbb2fc083d16ecb4fe0ec501JesusFreke@JesusFreke.com            case IGET:
5504f84e8f9e9bf4c74cbb2fc083d16ecb4fe0ec501JesusFreke@JesusFreke.com                return handle32BitPrimitiveIget(analyzedInstruction, RegisterType.Category.Integer);
5514f84e8f9e9bf4c74cbb2fc083d16ecb4fe0ec501JesusFreke@JesusFreke.com            case IGET_BOOLEAN:
5524f84e8f9e9bf4c74cbb2fc083d16ecb4fe0ec501JesusFreke@JesusFreke.com                return handle32BitPrimitiveIget(analyzedInstruction, RegisterType.Category.Boolean);
5534f84e8f9e9bf4c74cbb2fc083d16ecb4fe0ec501JesusFreke@JesusFreke.com            case IGET_BYTE:
5544f84e8f9e9bf4c74cbb2fc083d16ecb4fe0ec501JesusFreke@JesusFreke.com                return handle32BitPrimitiveIget(analyzedInstruction, RegisterType.Category.Byte);
5554f84e8f9e9bf4c74cbb2fc083d16ecb4fe0ec501JesusFreke@JesusFreke.com            case IGET_CHAR:
5564f84e8f9e9bf4c74cbb2fc083d16ecb4fe0ec501JesusFreke@JesusFreke.com                return handle32BitPrimitiveIget(analyzedInstruction, RegisterType.Category.Char);
5574f84e8f9e9bf4c74cbb2fc083d16ecb4fe0ec501JesusFreke@JesusFreke.com            case IGET_SHORT:
5584f84e8f9e9bf4c74cbb2fc083d16ecb4fe0ec501JesusFreke@JesusFreke.com                return handle32BitPrimitiveIget(analyzedInstruction, RegisterType.Category.Short);
5599d92fd3748eab8f23502dc11aff06e6e7d29d1f3JesusFreke@JesusFreke.com            case IGET_WIDE:
5609d92fd3748eab8f23502dc11aff06e6e7d29d1f3JesusFreke@JesusFreke.com                return handleIgetWide(analyzedInstruction);
5617a58f2434a2d906735ce585064d0fa46003c460dJesusFreke@JesusFreke.com            case IGET_OBJECT:
5627a58f2434a2d906735ce585064d0fa46003c460dJesusFreke@JesusFreke.com                return handleIgetObject(analyzedInstruction);
5639971346f4ce431e103c900cfdc14299ea25c685dJesusFreke@JesusFreke.com            case IPUT:
5649971346f4ce431e103c900cfdc14299ea25c685dJesusFreke@JesusFreke.com                return handle32BitPrimitiveIput(analyzedInstruction, RegisterType.Category.Integer);
5659971346f4ce431e103c900cfdc14299ea25c685dJesusFreke@JesusFreke.com            case IPUT_BOOLEAN:
5669971346f4ce431e103c900cfdc14299ea25c685dJesusFreke@JesusFreke.com                return handle32BitPrimitiveIput(analyzedInstruction, RegisterType.Category.Boolean);
5679971346f4ce431e103c900cfdc14299ea25c685dJesusFreke@JesusFreke.com            case IPUT_BYTE:
5689971346f4ce431e103c900cfdc14299ea25c685dJesusFreke@JesusFreke.com                return handle32BitPrimitiveIput(analyzedInstruction, RegisterType.Category.Byte);
5699971346f4ce431e103c900cfdc14299ea25c685dJesusFreke@JesusFreke.com            case IPUT_CHAR:
5709971346f4ce431e103c900cfdc14299ea25c685dJesusFreke@JesusFreke.com                return handle32BitPrimitiveIput(analyzedInstruction, RegisterType.Category.Char);
5719971346f4ce431e103c900cfdc14299ea25c685dJesusFreke@JesusFreke.com            case IPUT_SHORT:
5729971346f4ce431e103c900cfdc14299ea25c685dJesusFreke@JesusFreke.com                return handle32BitPrimitiveIput(analyzedInstruction, RegisterType.Category.Short);
57392616c9f60a30b5d5ac423675db732cb2428ce79JesusFreke@JesusFreke.com            case IPUT_WIDE:
57492616c9f60a30b5d5ac423675db732cb2428ce79JesusFreke@JesusFreke.com                return handleIputWide(analyzedInstruction);
57550ff6247416eff1a90edd1ebc222ac2cdc5c15cfJesusFreke@JesusFreke.com            case IPUT_OBJECT:
57650ff6247416eff1a90edd1ebc222ac2cdc5c15cfJesusFreke@JesusFreke.com                return handleIputObject(analyzedInstruction);
577052f4890ab954dc8510230b2992904a1a66c5dccJesusFreke@JesusFreke.com            case SGET:
578052f4890ab954dc8510230b2992904a1a66c5dccJesusFreke@JesusFreke.com                return handle32BitPrimitiveSget(analyzedInstruction, RegisterType.Category.Integer);
579052f4890ab954dc8510230b2992904a1a66c5dccJesusFreke@JesusFreke.com            case SGET_BOOLEAN:
580052f4890ab954dc8510230b2992904a1a66c5dccJesusFreke@JesusFreke.com                return handle32BitPrimitiveSget(analyzedInstruction, RegisterType.Category.Boolean);
581052f4890ab954dc8510230b2992904a1a66c5dccJesusFreke@JesusFreke.com            case SGET_BYTE:
582052f4890ab954dc8510230b2992904a1a66c5dccJesusFreke@JesusFreke.com                return handle32BitPrimitiveSget(analyzedInstruction, RegisterType.Category.Byte);
583052f4890ab954dc8510230b2992904a1a66c5dccJesusFreke@JesusFreke.com            case SGET_CHAR:
584052f4890ab954dc8510230b2992904a1a66c5dccJesusFreke@JesusFreke.com                return handle32BitPrimitiveSget(analyzedInstruction, RegisterType.Category.Char);
585052f4890ab954dc8510230b2992904a1a66c5dccJesusFreke@JesusFreke.com            case SGET_SHORT:
586052f4890ab954dc8510230b2992904a1a66c5dccJesusFreke@JesusFreke.com                return handle32BitPrimitiveSget(analyzedInstruction, RegisterType.Category.Short);
5872f233fefd9d73af8fab4037a6f874b161b98b259JesusFreke@JesusFreke.com            case SGET_WIDE:
5882f233fefd9d73af8fab4037a6f874b161b98b259JesusFreke@JesusFreke.com                return handleSgetWide(analyzedInstruction);
5892d6d6eb22c86c79344b85ffe46fdd4268566bd0fJesusFreke@JesusFreke.com            case SGET_OBJECT:
5902d6d6eb22c86c79344b85ffe46fdd4268566bd0fJesusFreke@JesusFreke.com                return handleSgetObject(analyzedInstruction);
5919d45d563fedaddab6bbdd421b139fe91d2f15fc8JesusFreke@JesusFreke.com            case SPUT:
5929d45d563fedaddab6bbdd421b139fe91d2f15fc8JesusFreke@JesusFreke.com                return handle32BitPrimitiveSput(analyzedInstruction, RegisterType.Category.Integer);
5939d45d563fedaddab6bbdd421b139fe91d2f15fc8JesusFreke@JesusFreke.com            case SPUT_BOOLEAN:
5949d45d563fedaddab6bbdd421b139fe91d2f15fc8JesusFreke@JesusFreke.com                return handle32BitPrimitiveSput(analyzedInstruction, RegisterType.Category.Boolean);
5959d45d563fedaddab6bbdd421b139fe91d2f15fc8JesusFreke@JesusFreke.com            case SPUT_BYTE:
5969d45d563fedaddab6bbdd421b139fe91d2f15fc8JesusFreke@JesusFreke.com                return handle32BitPrimitiveSput(analyzedInstruction, RegisterType.Category.Byte);
5979d45d563fedaddab6bbdd421b139fe91d2f15fc8JesusFreke@JesusFreke.com            case SPUT_CHAR:
5989d45d563fedaddab6bbdd421b139fe91d2f15fc8JesusFreke@JesusFreke.com                return handle32BitPrimitiveSput(analyzedInstruction, RegisterType.Category.Char);
5999d45d563fedaddab6bbdd421b139fe91d2f15fc8JesusFreke@JesusFreke.com            case SPUT_SHORT:
6009d45d563fedaddab6bbdd421b139fe91d2f15fc8JesusFreke@JesusFreke.com                return handle32BitPrimitiveSput(analyzedInstruction, RegisterType.Category.Short);
601f08a9e1c2c130a5ed5923999fec0283f91b48a09JesusFreke@JesusFreke.com            case SPUT_WIDE:
602f08a9e1c2c130a5ed5923999fec0283f91b48a09JesusFreke@JesusFreke.com                return handleSputWide(analyzedInstruction);
60351cec00885cdc063ee27ee6b67680189be34f8f9JesusFreke@JesusFreke.com            case SPUT_OBJECT:
60451cec00885cdc063ee27ee6b67680189be34f8f9JesusFreke@JesusFreke.com                return handleSputObject(analyzedInstruction);
605fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        }
606b2397452907c28b0743bbbcdf9fa6b2a8208aeabJesusFreke@JesusFreke.com
607fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        assert false;
608fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        return false;
609fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com    }
610fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com
611fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com    private static final EnumSet<RegisterType.Category> Primitive32BitCategories = EnumSet.of(
612fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com            RegisterType.Category.Null,
613fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com            RegisterType.Category.Boolean,
614fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com            RegisterType.Category.Byte,
615fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com            RegisterType.Category.Short,
616fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com            RegisterType.Category.Char,
617fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com            RegisterType.Category.Integer,
618fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com            RegisterType.Category.Float);
619fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com
620fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com    private static final EnumSet<RegisterType.Category> WideLowCategories = EnumSet.of(
621fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com            RegisterType.Category.LongLo,
622fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com            RegisterType.Category.DoubleLo);
623fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com
624fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com    private static final EnumSet<RegisterType.Category> WideHighCategories = EnumSet.of(
625fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com            RegisterType.Category.LongHi,
626fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com            RegisterType.Category.DoubleHi);
627fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com
628fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com    private static final EnumSet<RegisterType.Category> ReferenceCategories = EnumSet.of(
629fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com            RegisterType.Category.Null,
630fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com            RegisterType.Category.Reference);
631fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com
632fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com    private boolean handleMove(AnalyzedInstruction analyzedInstruction,
633fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com                               EnumSet<RegisterType.Category> allowedCategories) {
634fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        TwoRegisterInstruction instruction = (TwoRegisterInstruction)analyzedInstruction.instruction;
635fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com
636fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        //get the "pre-instruction" register type for the source register
637fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        RegisterType sourceRegisterType = analyzedInstruction.getPreInstructionRegisterType(instruction.getRegisterB());
638fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        assert sourceRegisterType != null;
639fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com
640fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        if (sourceRegisterType.category == RegisterType.Category.Unknown) {
641fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@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
642fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com            return false;
643fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        }
644d27ca7f7a61cfbe60e1c490bf645257d7d59fd39JesusFreke@JesusFreke.com
645fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        checkRegister(sourceRegisterType, allowedCategories);
646d27ca7f7a61cfbe60e1c490bf645257d7d59fd39JesusFreke@JesusFreke.com
647fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        setDestinationRegisterTypeAndPropagateChanges(analyzedInstruction, sourceRegisterType);
648fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        return true;
649fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com    }
650fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com
651fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com    private boolean handleMoveWide(AnalyzedInstruction analyzedInstruction) {
652fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        TwoRegisterInstruction instruction = (TwoRegisterInstruction)analyzedInstruction.instruction;
653fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com
654fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        RegisterType sourceRegisterType = getAndCheckWideSourcePair(analyzedInstruction,
655fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com                instruction.getRegisterB());
656fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        assert sourceRegisterType != null;
657fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com
658fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        if (sourceRegisterType.category == RegisterType.Category.Unknown) {
659fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@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
660fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com            return false;
661fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        }
662fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com
663fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        checkWideDestinationPair(analyzedInstruction);
664fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com
665fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        setDestinationRegisterTypeAndPropagateChanges(analyzedInstruction, sourceRegisterType);
666fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        return true;
667fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com    }
668fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com
669fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com    private boolean handleMoveResult(AnalyzedInstruction analyzedInstruction,
670fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com                                     EnumSet<RegisterType.Category> allowedCategories) {
671fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com
672fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        //TODO: handle the case when the previous instruction is an odexed instruction
673fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com
674fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        if (analyzedInstruction.instructionIndex == 0) {
675fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com            throw new ValidationException(analyzedInstruction.instruction.opcode.name + " cannot be the first " +
676fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com                    "instruction in a method. It must occur after an invoke-*/fill-new-array instruction");
677fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        }
678fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com
679fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        AnalyzedInstruction previousInstruction = instructions.valueAt(analyzedInstruction.instructionIndex-1);
680fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com
681fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        if (!previousInstruction.instruction.opcode.setsResult()) {
682fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com            throw new ValidationException(analyzedInstruction.instruction.opcode.name + " must occur after an " +
683fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com                    "invoke-*/fill-new-array instruction");
684fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        }
685fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com
686fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        if (analyzedInstruction.instruction.opcode.setsWideRegister()) {
687fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com            checkWideDestinationPair(analyzedInstruction);
688fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        }
689fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com
690fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        //TODO: does dalvik allow a move-result after an invoke with a void return type?
691fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        RegisterType destinationRegisterType;
692fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com
693fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        InstructionWithReference invokeInstruction = (InstructionWithReference)previousInstruction.instruction;
694fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        Item item = invokeInstruction.getReferencedItem();
695fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com
696fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        if (item instanceof MethodIdItem) {
697fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com            destinationRegisterType = RegisterType.getRegisterTypeForTypeIdItem(
698fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com                    ((MethodIdItem)item).getPrototype().getReturnType());
699fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        } else {
700fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com            assert item instanceof TypeIdItem;
701fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com            destinationRegisterType = RegisterType.getRegisterTypeForTypeIdItem((TypeIdItem)item);
702fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        }
703fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com
704fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        checkRegister(destinationRegisterType, allowedCategories);
705fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        setDestinationRegisterTypeAndPropagateChanges(analyzedInstruction, destinationRegisterType);
706fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        return true;
707fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com    }
708fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com
709fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com    private boolean handleMoveException(AnalyzedInstruction analyzedInstruction) {
710fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        CodeItem.TryItem[] tries = encodedMethod.codeItem.getTries();
711fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        int instructionAddress = getInstructionAddress(analyzedInstruction);
712fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com
713fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        if (tries == null) {
714fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com            throw new ValidationException("move-exception must be the first instruction in an exception handler block");
715fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        }
716fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com
717fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        RegisterType exceptionType = null;
718fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com
719fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        for (CodeItem.TryItem tryItem: encodedMethod.codeItem.getTries()) {
720fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com            if (tryItem.encodedCatchHandler.getCatchAllHandlerAddress() == instructionAddress) {
721fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com                exceptionType = RegisterType.getRegisterType(RegisterType.Category.Reference,
722fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com                        ClassPath.getClassDef("Ljava/lang/Throwable;"));
723fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com                break;
724fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com            }
725fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com            for (CodeItem.EncodedTypeAddrPair handler: tryItem.encodedCatchHandler.handlers) {
726fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com                if (handler.getHandlerAddress() == instructionAddress) {
727fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com                    exceptionType = RegisterType.getRegisterTypeForTypeIdItem(handler.exceptionType)
728fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com                            .merge(exceptionType);
729fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com                }
730fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com            }
731fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        }
732fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com
733fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@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)
734fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        checkRegister(exceptionType, ReferenceCategories);
735fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        setDestinationRegisterTypeAndPropagateChanges(analyzedInstruction, exceptionType);
736fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        return true;
737fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com    }
738fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com
739fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com    private boolean checkConstructorReturn(AnalyzedInstruction analyzedInstruction) {
740fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        assert this.isInstanceConstructor();
741fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com
742fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        //if we're in an instance constructor (an <init> method), then the superclass <init> must have been called.
743fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        //When execution enters the method, the "this" register is set as an uninitialized reference to the containing
744fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        //class. Once the superclass' <init> is called, the "this" register is upgraded to a full-blown reference type,
745fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        //so we need to ensure that the "this" register isn't an uninitialized reference
746fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com
747fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        int thisRegister = getThisRegister();
748fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        RegisterType thisRegisterType = analyzedInstruction.postRegisterMap[thisRegister];
749fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com
750fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        if (thisRegisterType.category == RegisterType.Category.Unknown) {
751fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com            //we don't have enough information yet, so return false. We'll come back later
752fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com            return false;
753fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        }
754fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        if (thisRegisterType.category == RegisterType.Category.UninitRef) {
755fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com            throw new ValidationException("Returning from constructor without calling the superclass' <init>");
756fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        }
757fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        assert thisRegisterType.category == RegisterType.Category.Reference;
758fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        assert thisRegisterType.type == ClassPath.getClassDef(encodedMethod.method.getContainingClass());
759fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        return true;
760fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com    }
761fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com
762fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com    private boolean handleReturnVoid(AnalyzedInstruction analyzedInstruction) {
763fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        if (this.isInstanceConstructor()) {
764fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com            if (!checkConstructorReturn(analyzedInstruction)) {
765fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com                return false;
766fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com            }
767fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        }
768fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com
769fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        TypeIdItem returnType = encodedMethod.method.getPrototype().getReturnType();
770fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        if (returnType.getTypeDescriptor().charAt(0) != 'V') {
771fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com            //TODO: could add which return-* variation should be used instead
772fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com            throw new ValidationException("Cannot use return-void with a non-void return type (" +
773fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com                returnType.getTypeDescriptor() + ")");
774fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        }
775fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        return true;
776fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com    }
777fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com
778fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com    private boolean handleReturn(AnalyzedInstruction analyzedInstruction) {
779fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        if (this.isInstanceConstructor()) {
780fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com            if (!checkConstructorReturn(analyzedInstruction)) {
781fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com                return false;
782fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com            }
783fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        }
784fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com
785fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        SingleRegisterInstruction instruction = (SingleRegisterInstruction)analyzedInstruction.instruction;
786fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        RegisterType returnRegisterType = analyzedInstruction.postRegisterMap[instruction.getRegisterA()];
787fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com
788fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        if (returnRegisterType.category == RegisterType.Category.Unknown) {
789fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com            return false;
790fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        }
791fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com
792fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        checkRegister(returnRegisterType, Primitive32BitCategories);
793fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com
794fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        TypeIdItem returnType = encodedMethod.method.getPrototype().getReturnType();
795fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        if (returnType.getTypeDescriptor().charAt(0) == 'V') {
796fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com            throw new ValidationException("Cannot use return with a void return type. Use return-void instead");
797fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        }
798fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com
799fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        RegisterType registerType = RegisterType.getRegisterTypeForTypeIdItem(returnType);
800fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com
801fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        if (!Primitive32BitCategories.contains(registerType.category)) {
802fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com            //TODO: could add which return-* variation should be used instead
803fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com            throw new ValidationException("Cannot use return with return type " + returnType.getTypeDescriptor());
804fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        }
805fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com
806fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com
807fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        return true;
808fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com    }
809fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com
810fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com    private boolean handleReturnWide(AnalyzedInstruction analyzedInstruction) {
811fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        if (this.isInstanceConstructor()) {
812fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com            if (!checkConstructorReturn(analyzedInstruction)) {
813fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com                return false;
814fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com            }
815fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        }
816fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com
817fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        SingleRegisterInstruction instruction = (SingleRegisterInstruction)analyzedInstruction.instruction;
818fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        RegisterType returnType = getAndCheckWideSourcePair(analyzedInstruction, instruction.getRegisterA());
819fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com
820fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        if (returnType.category == RegisterType.Category.Unknown) {
821fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com            return false;
822fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        }
823fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com
824fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com
825fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        TypeIdItem returnTypeIdItem = encodedMethod.method.getPrototype().getReturnType();
826fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        if (returnTypeIdItem.getTypeDescriptor().charAt(0) == 'V') {
827fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com            throw new ValidationException("Cannot use return-wide with a void return type. Use return-void instead");
828fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        }
829fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com
830fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        returnType = RegisterType.getRegisterTypeForTypeIdItem(returnTypeIdItem);
831fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        if (!WideLowCategories.contains(returnType.category)) {
832fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com            //TODO: could add which return-* variation should be used instead
833fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com            throw new ValidationException("Cannot use return-wide with return type " +
834fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com                    returnTypeIdItem.getTypeDescriptor());
835fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        }
836fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com
837fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        return true;
838fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com    }
839fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com
840fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com    private boolean handleReturnObject(AnalyzedInstruction analyzedInstruction) {
841fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        if (this.isInstanceConstructor()) {
842fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com            if (!checkConstructorReturn(analyzedInstruction)) {
843fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com                return false;
844fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com            }
845fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        }
846fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com
847fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        SingleRegisterInstruction instruction = (SingleRegisterInstruction)analyzedInstruction.instruction;
848fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        int returnRegister = instruction.getRegisterA();
849fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        RegisterType returnRegisterType = analyzedInstruction.postRegisterMap[returnRegister];
850fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com
851fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        if (returnRegisterType.category == RegisterType.Category.Unknown) {
852fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com            return false;
853fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        }
854fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com
855fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        checkRegister(returnRegisterType, ReferenceCategories);
856fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com
857fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com
858fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        TypeIdItem returnTypeIdItem = encodedMethod.method.getPrototype().getReturnType();
859fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        if (returnTypeIdItem.getTypeDescriptor().charAt(0) == 'V') {
860fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com            throw new ValidationException("Cannot use return with a void return type. Use return-void instead");
861fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        }
862fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com
863fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        RegisterType returnType = RegisterType.getRegisterTypeForTypeIdItem(returnTypeIdItem);
864fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com
865fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        if (!ReferenceCategories.contains(returnType.category)) {
866fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com            //TODO: could add which return-* variation should be used instead
867fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com            throw new ValidationException("Cannot use " + analyzedInstruction + " with return type " +
868fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com                    returnTypeIdItem.getTypeDescriptor());
869fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        }
870fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com
871fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        if (returnType.type.isInterface()) {
872fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com            if (!returnRegisterType.type.implementsInterface(returnType.type)) {
873fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com                //TODO: how to handle warnings?
874fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com            }
875fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        } else {
876fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com            if (!returnRegisterType.type.extendsClass(returnType.type)) {
877fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com                throw new ValidationException("The return value in register v" + Integer.toString(returnRegister) +
878fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com                        "(" + returnRegisterType.type.getClassType() + ") is not compatible with the method's return " +
879fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com                        "type (" + returnType.type.getClassType() + ")");
880fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com            }
881fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        }
882fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com
883fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        return true;
884fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com    }
885fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com
886fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com    private boolean handleConst(AnalyzedInstruction analyzedInstruction) {
887fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        LiteralInstruction instruction = (LiteralInstruction)analyzedInstruction.instruction;
888fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com
889fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        RegisterType newDestinationRegisterType = RegisterType.getRegisterTypeForLiteral(instruction.getLiteral());
890fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com
891fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        //we assume that the literal value is a valid value for the given instruction type, because it's impossible
892fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        //to store an invalid literal with the instruction. so we don't need to check the type of the literal
893fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        setDestinationRegisterTypeAndPropagateChanges(analyzedInstruction, newDestinationRegisterType);
894fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        return true;
895fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com    }
896fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com
897fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com    private boolean handleConstHigh16(AnalyzedInstruction analyzedInstruction) {
898fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        LiteralInstruction instruction = (LiteralInstruction)analyzedInstruction.instruction;
899fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com
900fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        //TODO: test this
901fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        long literalValue = instruction.getLiteral() << 16;
902fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        RegisterType newDestinationRegisterType = RegisterType.getRegisterTypeForLiteral(literalValue);
903fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com
904fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        //we assume that the literal value is a valid value for the given instruction type, because it's impossible
905fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        //to store an invalid literal with the instruction. so we don't need to check the type of the literal
906fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        setDestinationRegisterTypeAndPropagateChanges(analyzedInstruction, newDestinationRegisterType);
907fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        return true;
908fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com    }
909fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com
910fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com    private boolean handleWideConst(AnalyzedInstruction analyzedInstruction) {
911fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        setWideDestinationRegisterTypeAndPropagateChanges(analyzedInstruction,
912fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com                RegisterType.getRegisterType(RegisterType.Category.LongLo, null));
913fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        return true;
914fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com    }
915fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com
916fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com    private boolean handleConstString(AnalyzedInstruction analyzedInstruction) {
917fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        ClassPath.ClassDef stringClassDef = ClassPath.getClassDef("Ljava/lang/String;");
918fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        RegisterType stringType = RegisterType.getRegisterType(RegisterType.Category.Reference, stringClassDef);
919fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        setDestinationRegisterTypeAndPropagateChanges(analyzedInstruction, stringType);
920fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        return true;
921fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com    }
922fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com
923fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com    private boolean handleConstClass(AnalyzedInstruction analyzedInstruction) {
924fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        ClassPath.ClassDef classClassDef = ClassPath.getClassDef("Ljava/lang/Class;");
925fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        RegisterType classType = RegisterType.getRegisterType(RegisterType.Category.Reference, classClassDef);
926fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com
927fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        InstructionWithReference instruction = (InstructionWithReference)analyzedInstruction.instruction;
928fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        Item item = instruction.getReferencedItem();
929fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        assert item.getItemType() == ItemType.TYPE_TYPE_ID_ITEM;
930fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com
931fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        //make sure the referenced class is resolvable
932fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        //TODO: need to check class access
933fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        ClassPath.ClassDef classDef = ClassPath.getClassDef((TypeIdItem)item);
934fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        return false;
935fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com    }
936fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com
937fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com    private boolean handleMonitor(AnalyzedInstruction analyzedInstruction) {
938fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        SingleRegisterInstruction instruction = (SingleRegisterInstruction)analyzedInstruction;
939fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com
940fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        RegisterType registerType = analyzedInstruction.postRegisterMap[instruction.getRegisterA()];
941fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        assert registerType != null;
942fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        if (registerType.category == RegisterType.Category.Unknown) {
943fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com            return false;
944fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        }
945fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com
946fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        checkRegister(registerType, ReferenceCategories);
947fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        return true;
948fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com    }
949fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com
950fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com    private boolean handleCheckCast(AnalyzedInstruction analyzedInstruction) {
951fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        {
952fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com            //ensure the "source" register is a reference type
953fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com            SingleRegisterInstruction instruction = (SingleRegisterInstruction)analyzedInstruction.instruction;
954fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com
955fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com            RegisterType registerType = analyzedInstruction.getPreInstructionRegisterType(instruction.getRegisterA());
956fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com            assert registerType != null;
957fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com            if (registerType.category == RegisterType.Category.Unknown) {
958fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com                return false;
959fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com            }
960fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com
961fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com            checkRegister(registerType, ReferenceCategories);
962fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        }
963fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com
964fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        {
965fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com            //resolve and verify the class that we're casting to
966fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com            InstructionWithReference instruction = (InstructionWithReference)analyzedInstruction.instruction;
967fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com
968fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com            Item item = instruction.getReferencedItem();
969fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com            assert item.getItemType() == ItemType.TYPE_TYPE_ID_ITEM;
970fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com
971fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com            //TODO: need to check class access
972fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com            RegisterType newDestinationRegisterType = RegisterType.getRegisterTypeForTypeIdItem((TypeIdItem)item);
973fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com            try {
974fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com                checkRegister(newDestinationRegisterType, ReferenceCategories);
975fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com            } catch (ValidationException ex) {
976fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com                //TODO: verify that dalvik allows a non-reference type..
977fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@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)
978fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com            }
979fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com
980fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com            setDestinationRegisterTypeAndPropagateChanges(analyzedInstruction, newDestinationRegisterType);
981fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com            return true;
982fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        }
983fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com    }
984fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com
985fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com    private boolean handleInstanceOf(AnalyzedInstruction analyzedInstruction) {
986fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        {
987fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com            //ensure the register that is being checks is a reference type
988fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com            TwoRegisterInstruction instruction = (TwoRegisterInstruction)analyzedInstruction;
989fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com
990fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com            RegisterType registerType = analyzedInstruction.getPreInstructionRegisterType(instruction.getRegisterB());
991fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com            assert registerType != null;
992fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com            if (registerType.category == RegisterType.Category.Unknown) {
993fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com                return false;
994fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com            }
995fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com
996fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com            checkRegister(registerType, ReferenceCategories);
997fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        }
998fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com
999fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        {
1000fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com            //resolve and verify the class that we're checking against
1001fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com            InstructionWithReference instruction = (InstructionWithReference)analyzedInstruction.instruction;
1002fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com
1003fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com            Item item = instruction.getReferencedItem();
1004fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com            assert  item.getItemType() == ItemType.TYPE_TYPE_ID_ITEM;
1005fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com            RegisterType registerType = RegisterType.getRegisterTypeForTypeIdItem((TypeIdItem)item);
1006fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com            checkRegister(registerType, ReferenceCategories);
1007fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com
1008fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com            //TODO: is it valid to use an array type?
1009fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com
1010fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@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.
1011fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com            setDestinationRegisterTypeAndPropagateChanges(analyzedInstruction,
1012fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com                    RegisterType.getRegisterType(RegisterType.Category.Boolean, null));
1013fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com            return true;
1014fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        }
1015fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com    }
1016fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com
1017fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com    private boolean handleArrayLength(AnalyzedInstruction analyzedInstruction) {
1018fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        TwoRegisterInstruction instruction = (TwoRegisterInstruction)analyzedInstruction;
1019fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com
1020fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        int arrayRegisterNumber = instruction.getRegisterB();
1021fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        RegisterType arrayRegisterType = analyzedInstruction.getPreInstructionRegisterType(arrayRegisterNumber);
1022fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        assert arrayRegisterType != null;
1023fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        if (arrayRegisterType.category == RegisterType.Category.Unknown) {
1024fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com            return false;
1025fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        }
1026fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com
1027fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        assert arrayRegisterType.type instanceof ClassPath.ArrayClassDef;
1028fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com
1029fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        checkRegister(arrayRegisterType, ReferenceCategories);
1030fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        if (arrayRegisterType.type != null) {
1031fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com            if (arrayRegisterType.type.getClassType().charAt(0) != '[') {
1032fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com                throw new ValidationException("Cannot use array-length with non-array type " +
1033fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com                        arrayRegisterType.type.getClassType());
1034d27ca7f7a61cfbe60e1c490bf645257d7d59fd39JesusFreke@JesusFreke.com            }
1035d27ca7f7a61cfbe60e1c490bf645257d7d59fd39JesusFreke@JesusFreke.com        }
1036d27ca7f7a61cfbe60e1c490bf645257d7d59fd39JesusFreke@JesusFreke.com
1037fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        setDestinationRegisterTypeAndPropagateChanges(analyzedInstruction,
1038fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com                RegisterType.getRegisterType(RegisterType.Category.Integer, null));
1039fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        return true;
1040fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com    }
1041fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com
1042fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com    private boolean handleNewInstance(AnalyzedInstruction analyzedInstruction) {
1043fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        InstructionWithReference instruction = (InstructionWithReference)analyzedInstruction.instruction;
1044fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com
1045a0314c265e76426e3e05e615cc713cf36c78cb85JesusFreke@JesusFreke.com        int register = ((SingleRegisterInstruction)analyzedInstruction.instruction).getRegisterA();
1046a0314c265e76426e3e05e615cc713cf36c78cb85JesusFreke@JesusFreke.com        RegisterType destRegisterType = analyzedInstruction.postRegisterMap[register];
1047a0314c265e76426e3e05e615cc713cf36c78cb85JesusFreke@JesusFreke.com        if (destRegisterType.category != RegisterType.Category.Unknown) {
1048a0314c265e76426e3e05e615cc713cf36c78cb85JesusFreke@JesusFreke.com            assert destRegisterType.category == RegisterType.Category.UninitRef;
1049a0314c265e76426e3e05e615cc713cf36c78cb85JesusFreke@JesusFreke.com
1050a0314c265e76426e3e05e615cc713cf36c78cb85JesusFreke@JesusFreke.com            //the "post-instruction" destination register will only be set if we've gone over
1051a0314c265e76426e3e05e615cc713cf36c78cb85JesusFreke@JesusFreke.com            //this instruction at least once before. If this is the case, then we need to check
1052a0314c265e76426e3e05e615cc713cf36c78cb85JesusFreke@JesusFreke.com            //all the other registers, and make sure that none of them contain the same
1053a0314c265e76426e3e05e615cc713cf36c78cb85JesusFreke@JesusFreke.com            //uninitialized reference that is in the destination register.
1054a0314c265e76426e3e05e615cc713cf36c78cb85JesusFreke@JesusFreke.com
1055a0314c265e76426e3e05e615cc713cf36c78cb85JesusFreke@JesusFreke.com            for (int i=0; i<analyzedInstruction.postRegisterMap.length; i++) {
1056a0314c265e76426e3e05e615cc713cf36c78cb85JesusFreke@JesusFreke.com                if (i==register) {
1057a0314c265e76426e3e05e615cc713cf36c78cb85JesusFreke@JesusFreke.com                    continue;
1058a0314c265e76426e3e05e615cc713cf36c78cb85JesusFreke@JesusFreke.com                }
1059a0314c265e76426e3e05e615cc713cf36c78cb85JesusFreke@JesusFreke.com
1060a0314c265e76426e3e05e615cc713cf36c78cb85JesusFreke@JesusFreke.com                if (analyzedInstruction.getPreInstructionRegisterType(i) == destRegisterType) {
1061a0314c265e76426e3e05e615cc713cf36c78cb85JesusFreke@JesusFreke.com                    throw new ValidationException(String.format("Register v%d contains an uninitialized reference " +
1062a0314c265e76426e3e05e615cc713cf36c78cb85JesusFreke@JesusFreke.com                            "that was created by this new-instance instruction.", i));
1063a0314c265e76426e3e05e615cc713cf36c78cb85JesusFreke@JesusFreke.com                }
1064a0314c265e76426e3e05e615cc713cf36c78cb85JesusFreke@JesusFreke.com            }
1065a0314c265e76426e3e05e615cc713cf36c78cb85JesusFreke@JesusFreke.com        }
1066a0314c265e76426e3e05e615cc713cf36c78cb85JesusFreke@JesusFreke.com
1067fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        Item item = instruction.getReferencedItem();
1068fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        assert item.getItemType() == ItemType.TYPE_TYPE_ID_ITEM;
1069fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com
1070fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        //TODO: need to check class access
1071fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        RegisterType classType = RegisterType.getRegisterTypeForTypeIdItem((TypeIdItem)item);
1072fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        checkRegister(classType, ReferenceCategories);
1073fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        if (((TypeIdItem)item).getTypeDescriptor().charAt(0) == '[') {
1074fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com            throw new ValidationException("Cannot use array type \"" + ((TypeIdItem)item).getTypeDescriptor() +
1075fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com                    "\" with new-instance. Use new-array instead.");
1076d27ca7f7a61cfbe60e1c490bf645257d7d59fd39JesusFreke@JesusFreke.com        }
1077d27ca7f7a61cfbe60e1c490bf645257d7d59fd39JesusFreke@JesusFreke.com
1078fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        setDestinationRegisterTypeAndPropagateChanges(analyzedInstruction,
1079a0314c265e76426e3e05e615cc713cf36c78cb85JesusFreke@JesusFreke.com                RegisterType.getUnitializedReference(classType.type));
1080fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        return true;
1081fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com    }
1082fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com
1083fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com    private boolean handleNewArray(AnalyzedInstruction analyzedInstruction) {
1084fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        {
1085fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com            TwoRegisterInstruction instruction = (TwoRegisterInstruction)analyzedInstruction.instruction;
1086fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com
1087fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com            int sizeRegister = instruction.getRegisterB();
1088fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com            RegisterType registerType = analyzedInstruction.getPreInstructionRegisterType(sizeRegister);
1089fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com            assert registerType != null;
1090fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com
1091fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com            if (registerType.category == RegisterType.Category.Unknown) {
1092fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com                return false;
1093fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com            }
1094fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com
1095fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com            checkRegister(registerType, Primitive32BitCategories);
1096fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        }
1097fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com
1098fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        InstructionWithReference instruction = (InstructionWithReference)analyzedInstruction.instruction;
1099fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com
1100fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        Item item = instruction.getReferencedItem();
1101fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        assert item.getItemType() == ItemType.TYPE_TYPE_ID_ITEM;
1102fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com
1103fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        RegisterType arrayType = RegisterType.getRegisterTypeForTypeIdItem((TypeIdItem)item);
1104fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        assert arrayType.type instanceof ClassPath.ArrayClassDef;
1105d27ca7f7a61cfbe60e1c490bf645257d7d59fd39JesusFreke@JesusFreke.com
1106fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        checkRegister(arrayType, ReferenceCategories);
1107fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        if (arrayType.type.getClassType().charAt(0) != '[') {
1108fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com            throw new ValidationException("Cannot use non-array type \"" + arrayType.type.getClassType() +
1109fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com                    "\" with new-array. Use new-instance instead.");
1110fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        }
1111fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com
1112fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        setDestinationRegisterTypeAndPropagateChanges(analyzedInstruction, arrayType);
1113fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        return true;
1114fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com    }
1115fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com
1116ac8785e5d550c2ec7c7d02dd2990f859a78c111cJesusFreke@JesusFreke.com    private static interface RegisterIterator {
1117ac8785e5d550c2ec7c7d02dd2990f859a78c111cJesusFreke@JesusFreke.com        int getRegister();
1118ac8785e5d550c2ec7c7d02dd2990f859a78c111cJesusFreke@JesusFreke.com        boolean moveNext();
111906d1aacf61792afcdb273cf458e1e3daead0cf85JesusFreke@JesusFreke.com        int getCount();
11206192896f88638177ab6a5e64535f834f4a08b726JesusFreke@JesusFreke.com        boolean pastEnd();
1121ac8785e5d550c2ec7c7d02dd2990f859a78c111cJesusFreke@JesusFreke.com    }
1122ac8785e5d550c2ec7c7d02dd2990f859a78c111cJesusFreke@JesusFreke.com
1123b615ba6f51a42428937236a640480d6f7f9dc511JesusFreke@JesusFreke.com    private static class Format35cRegisterIterator implements RegisterIterator {
1124b615ba6f51a42428937236a640480d6f7f9dc511JesusFreke@JesusFreke.com        private final int registerCount;
1125b615ba6f51a42428937236a640480d6f7f9dc511JesusFreke@JesusFreke.com        private final int[] registers;
1126b615ba6f51a42428937236a640480d6f7f9dc511JesusFreke@JesusFreke.com        private int currentRegister = 0;
1127b615ba6f51a42428937236a640480d6f7f9dc511JesusFreke@JesusFreke.com
1128b615ba6f51a42428937236a640480d6f7f9dc511JesusFreke@JesusFreke.com        public Format35cRegisterIterator(FiveRegisterInstruction instruction) {
1129b615ba6f51a42428937236a640480d6f7f9dc511JesusFreke@JesusFreke.com            registerCount = instruction.getRegCount();
1130b615ba6f51a42428937236a640480d6f7f9dc511JesusFreke@JesusFreke.com            registers = new int[]{instruction.getRegisterD(), instruction.getRegisterE(),
1131b615ba6f51a42428937236a640480d6f7f9dc511JesusFreke@JesusFreke.com                                  instruction.getRegisterF(), instruction.getRegisterG(),
1132b615ba6f51a42428937236a640480d6f7f9dc511JesusFreke@JesusFreke.com                                  instruction.getRegisterA()};
1133b615ba6f51a42428937236a640480d6f7f9dc511JesusFreke@JesusFreke.com        }
1134b615ba6f51a42428937236a640480d6f7f9dc511JesusFreke@JesusFreke.com
1135b615ba6f51a42428937236a640480d6f7f9dc511JesusFreke@JesusFreke.com        public int getRegister() {
1136b615ba6f51a42428937236a640480d6f7f9dc511JesusFreke@JesusFreke.com            return registers[currentRegister];
1137b615ba6f51a42428937236a640480d6f7f9dc511JesusFreke@JesusFreke.com        }
1138b615ba6f51a42428937236a640480d6f7f9dc511JesusFreke@JesusFreke.com
1139b615ba6f51a42428937236a640480d6f7f9dc511JesusFreke@JesusFreke.com        public boolean moveNext() {
1140b615ba6f51a42428937236a640480d6f7f9dc511JesusFreke@JesusFreke.com            currentRegister++;
1141b615ba6f51a42428937236a640480d6f7f9dc511JesusFreke@JesusFreke.com            return pastEnd();
1142b615ba6f51a42428937236a640480d6f7f9dc511JesusFreke@JesusFreke.com        }
1143b615ba6f51a42428937236a640480d6f7f9dc511JesusFreke@JesusFreke.com
1144b615ba6f51a42428937236a640480d6f7f9dc511JesusFreke@JesusFreke.com        public int getCount() {
1145b615ba6f51a42428937236a640480d6f7f9dc511JesusFreke@JesusFreke.com            return registerCount;
1146b615ba6f51a42428937236a640480d6f7f9dc511JesusFreke@JesusFreke.com        }
1147b615ba6f51a42428937236a640480d6f7f9dc511JesusFreke@JesusFreke.com
1148b615ba6f51a42428937236a640480d6f7f9dc511JesusFreke@JesusFreke.com        public boolean pastEnd() {
1149b615ba6f51a42428937236a640480d6f7f9dc511JesusFreke@JesusFreke.com            return currentRegister >= registerCount;
1150b615ba6f51a42428937236a640480d6f7f9dc511JesusFreke@JesusFreke.com        }
1151b615ba6f51a42428937236a640480d6f7f9dc511JesusFreke@JesusFreke.com    }
1152b615ba6f51a42428937236a640480d6f7f9dc511JesusFreke@JesusFreke.com
1153b615ba6f51a42428937236a640480d6f7f9dc511JesusFreke@JesusFreke.com    private static class Format3rcRegisterIterator implements RegisterIterator {
1154b615ba6f51a42428937236a640480d6f7f9dc511JesusFreke@JesusFreke.com        private final int startRegister;
1155b615ba6f51a42428937236a640480d6f7f9dc511JesusFreke@JesusFreke.com        private final int registerCount;
1156b615ba6f51a42428937236a640480d6f7f9dc511JesusFreke@JesusFreke.com        private int currentRegister = 0;
1157b615ba6f51a42428937236a640480d6f7f9dc511JesusFreke@JesusFreke.com
1158b615ba6f51a42428937236a640480d6f7f9dc511JesusFreke@JesusFreke.com        public Format3rcRegisterIterator(RegisterRangeInstruction instruction) {
1159b615ba6f51a42428937236a640480d6f7f9dc511JesusFreke@JesusFreke.com            startRegister = instruction.getStartRegister();
1160b615ba6f51a42428937236a640480d6f7f9dc511JesusFreke@JesusFreke.com            registerCount = instruction.getRegCount();
1161b615ba6f51a42428937236a640480d6f7f9dc511JesusFreke@JesusFreke.com        }
1162b615ba6f51a42428937236a640480d6f7f9dc511JesusFreke@JesusFreke.com
1163b615ba6f51a42428937236a640480d6f7f9dc511JesusFreke@JesusFreke.com        public int getRegister() {
1164b615ba6f51a42428937236a640480d6f7f9dc511JesusFreke@JesusFreke.com            return startRegister + currentRegister;
1165b615ba6f51a42428937236a640480d6f7f9dc511JesusFreke@JesusFreke.com        }
1166b615ba6f51a42428937236a640480d6f7f9dc511JesusFreke@JesusFreke.com
1167b615ba6f51a42428937236a640480d6f7f9dc511JesusFreke@JesusFreke.com        public boolean moveNext() {
1168b615ba6f51a42428937236a640480d6f7f9dc511JesusFreke@JesusFreke.com            currentRegister++;
1169b615ba6f51a42428937236a640480d6f7f9dc511JesusFreke@JesusFreke.com            return pastEnd();
1170b615ba6f51a42428937236a640480d6f7f9dc511JesusFreke@JesusFreke.com        }
1171b615ba6f51a42428937236a640480d6f7f9dc511JesusFreke@JesusFreke.com
1172b615ba6f51a42428937236a640480d6f7f9dc511JesusFreke@JesusFreke.com        public int getCount() {
1173b615ba6f51a42428937236a640480d6f7f9dc511JesusFreke@JesusFreke.com            return registerCount;
1174b615ba6f51a42428937236a640480d6f7f9dc511JesusFreke@JesusFreke.com        }
1175b615ba6f51a42428937236a640480d6f7f9dc511JesusFreke@JesusFreke.com
1176b615ba6f51a42428937236a640480d6f7f9dc511JesusFreke@JesusFreke.com        public boolean pastEnd() {
1177b615ba6f51a42428937236a640480d6f7f9dc511JesusFreke@JesusFreke.com            return currentRegister >= registerCount;
1178b615ba6f51a42428937236a640480d6f7f9dc511JesusFreke@JesusFreke.com        }
1179b615ba6f51a42428937236a640480d6f7f9dc511JesusFreke@JesusFreke.com    }
1180b615ba6f51a42428937236a640480d6f7f9dc511JesusFreke@JesusFreke.com
1181ac8785e5d550c2ec7c7d02dd2990f859a78c111cJesusFreke@JesusFreke.com    private boolean handleFilledNewArrayCommon(AnalyzedInstruction analyzedInstruction,
1182ac8785e5d550c2ec7c7d02dd2990f859a78c111cJesusFreke@JesusFreke.com                                               RegisterIterator registerIterator) {
1183ac8785e5d550c2ec7c7d02dd2990f859a78c111cJesusFreke@JesusFreke.com        InstructionWithReference instruction = (InstructionWithReference)analyzedInstruction.instruction;
1184ac8785e5d550c2ec7c7d02dd2990f859a78c111cJesusFreke@JesusFreke.com
11859e5dd85d837501e84e18617fc136c8203ab1f183JesusFreke@JesusFreke.com        RegisterType arrayType;
11869e5dd85d837501e84e18617fc136c8203ab1f183JesusFreke@JesusFreke.com        RegisterType arrayImmediateElementType;
11879e5dd85d837501e84e18617fc136c8203ab1f183JesusFreke@JesusFreke.com
1188ac8785e5d550c2ec7c7d02dd2990f859a78c111cJesusFreke@JesusFreke.com        Item item = instruction.getReferencedItem();
1189ac8785e5d550c2ec7c7d02dd2990f859a78c111cJesusFreke@JesusFreke.com        assert  item.getItemType() == ItemType.TYPE_TYPE_ID_ITEM;
11909e5dd85d837501e84e18617fc136c8203ab1f183JesusFreke@JesusFreke.com
1191ac8785e5d550c2ec7c7d02dd2990f859a78c111cJesusFreke@JesusFreke.com        ClassPath.ClassDef classDef = ClassPath.getClassDef((TypeIdItem)item);
11929e5dd85d837501e84e18617fc136c8203ab1f183JesusFreke@JesusFreke.com
1193ac8785e5d550c2ec7c7d02dd2990f859a78c111cJesusFreke@JesusFreke.com        if (classDef.getClassType().charAt(0) != '[') {
1194ac8785e5d550c2ec7c7d02dd2990f859a78c111cJesusFreke@JesusFreke.com            throw new ValidationException("Cannot use non-array type \"" + classDef.getClassType() +
1195ac8785e5d550c2ec7c7d02dd2990f859a78c111cJesusFreke@JesusFreke.com                "\" with new-array. Use new-instance instead.");
11969e5dd85d837501e84e18617fc136c8203ab1f183JesusFreke@JesusFreke.com        }
11979e5dd85d837501e84e18617fc136c8203ab1f183JesusFreke@JesusFreke.com
1198ac8785e5d550c2ec7c7d02dd2990f859a78c111cJesusFreke@JesusFreke.com        ClassPath.ArrayClassDef arrayClassDef = (ClassPath.ArrayClassDef)classDef;
1199ac8785e5d550c2ec7c7d02dd2990f859a78c111cJesusFreke@JesusFreke.com        arrayType = RegisterType.getRegisterType(RegisterType.Category.Reference, classDef);
1200ac8785e5d550c2ec7c7d02dd2990f859a78c111cJesusFreke@JesusFreke.com        arrayImmediateElementType = RegisterType.getRegisterTypeForType(
1201ac8785e5d550c2ec7c7d02dd2990f859a78c111cJesusFreke@JesusFreke.com                arrayClassDef.getImmediateElementClass().getClassType());
1202ac8785e5d550c2ec7c7d02dd2990f859a78c111cJesusFreke@JesusFreke.com        String baseElementType = arrayClassDef.getBaseElementClass().getClassType();
1203ac8785e5d550c2ec7c7d02dd2990f859a78c111cJesusFreke@JesusFreke.com        if (baseElementType.charAt(0) == 'J' || baseElementType.charAt(0) == 'D') {
1204ac8785e5d550c2ec7c7d02dd2990f859a78c111cJesusFreke@JesusFreke.com            throw new ValidationException("Cannot use filled-new-array to create an array of wide values " +
1205ac8785e5d550c2ec7c7d02dd2990f859a78c111cJesusFreke@JesusFreke.com                    "(long or double)");
1206ac8785e5d550c2ec7c7d02dd2990f859a78c111cJesusFreke@JesusFreke.com        }
12079e5dd85d837501e84e18617fc136c8203ab1f183JesusFreke@JesusFreke.com
1208ac8785e5d550c2ec7c7d02dd2990f859a78c111cJesusFreke@JesusFreke.com        do {
1209ac8785e5d550c2ec7c7d02dd2990f859a78c111cJesusFreke@JesusFreke.com            int register = registerIterator.getRegister();
12109e5dd85d837501e84e18617fc136c8203ab1f183JesusFreke@JesusFreke.com            RegisterType elementType = analyzedInstruction.getPreInstructionRegisterType(register);
12119e5dd85d837501e84e18617fc136c8203ab1f183JesusFreke@JesusFreke.com            assert elementType != null;
12129e5dd85d837501e84e18617fc136c8203ab1f183JesusFreke@JesusFreke.com
12139e5dd85d837501e84e18617fc136c8203ab1f183JesusFreke@JesusFreke.com            if (elementType.category == RegisterType.Category.Unknown) {
12149e5dd85d837501e84e18617fc136c8203ab1f183JesusFreke@JesusFreke.com                return false;
12159e5dd85d837501e84e18617fc136c8203ab1f183JesusFreke@JesusFreke.com            }
12169e5dd85d837501e84e18617fc136c8203ab1f183JesusFreke@JesusFreke.com
12179e5dd85d837501e84e18617fc136c8203ab1f183JesusFreke@JesusFreke.com            if (!elementType.canBeAssignedTo(arrayImmediateElementType)) {
12189e5dd85d837501e84e18617fc136c8203ab1f183JesusFreke@JesusFreke.com                throw new ValidationException("Register v" + Integer.toString(register) + " is of type " +
12199e5dd85d837501e84e18617fc136c8203ab1f183JesusFreke@JesusFreke.com                        elementType.toString() + " and is incompatible with the array type " +
12209e5dd85d837501e84e18617fc136c8203ab1f183JesusFreke@JesusFreke.com                        arrayType.type.getClassType());
12219e5dd85d837501e84e18617fc136c8203ab1f183JesusFreke@JesusFreke.com            }
1222ac8785e5d550c2ec7c7d02dd2990f859a78c111cJesusFreke@JesusFreke.com        } while (registerIterator.moveNext());
12239e5dd85d837501e84e18617fc136c8203ab1f183JesusFreke@JesusFreke.com
12249e5dd85d837501e84e18617fc136c8203ab1f183JesusFreke@JesusFreke.com        setDestinationRegisterTypeAndPropagateChanges(analyzedInstruction, arrayType);
12259e5dd85d837501e84e18617fc136c8203ab1f183JesusFreke@JesusFreke.com        return true;
12269e5dd85d837501e84e18617fc136c8203ab1f183JesusFreke@JesusFreke.com    }
12279e5dd85d837501e84e18617fc136c8203ab1f183JesusFreke@JesusFreke.com
1228ac8785e5d550c2ec7c7d02dd2990f859a78c111cJesusFreke@JesusFreke.com    private boolean handleFilledNewArray(AnalyzedInstruction analyzedInstruction) {
1229ac8785e5d550c2ec7c7d02dd2990f859a78c111cJesusFreke@JesusFreke.com        FiveRegisterInstruction instruction = (FiveRegisterInstruction)analyzedInstruction.instruction;
1230b615ba6f51a42428937236a640480d6f7f9dc511JesusFreke@JesusFreke.com        return handleFilledNewArrayCommon(analyzedInstruction, new Format35cRegisterIterator(instruction));
1231ac8785e5d550c2ec7c7d02dd2990f859a78c111cJesusFreke@JesusFreke.com    }
1232ac8785e5d550c2ec7c7d02dd2990f859a78c111cJesusFreke@JesusFreke.com
1233ac8785e5d550c2ec7c7d02dd2990f859a78c111cJesusFreke@JesusFreke.com    private boolean handleFilledNewArrayRange(AnalyzedInstruction analyzedInstruction) {
1234b615ba6f51a42428937236a640480d6f7f9dc511JesusFreke@JesusFreke.com        RegisterRangeInstruction instruction = (RegisterRangeInstruction)analyzedInstruction.instruction;
1235ac8785e5d550c2ec7c7d02dd2990f859a78c111cJesusFreke@JesusFreke.com
1236ac8785e5d550c2ec7c7d02dd2990f859a78c111cJesusFreke@JesusFreke.com        //instruction.getStartRegister() and instruction.getRegCount() both return an int value, but are actually
1237ac8785e5d550c2ec7c7d02dd2990f859a78c111cJesusFreke@JesusFreke.com        //unsigned 16 bit values, so we don't have to worry about overflowing an int when adding them together
1238ac8785e5d550c2ec7c7d02dd2990f859a78c111cJesusFreke@JesusFreke.com        if (instruction.getStartRegister() + instruction.getRegCount() >= 1<<16) {
1239ac8785e5d550c2ec7c7d02dd2990f859a78c111cJesusFreke@JesusFreke.com            throw new ValidationException(String.format("Invalid register range {v%d .. v%d}. The ending register " +
1240472d3ea58455ebf43d21819b2701fad98b5a0f9cJesusFreke@JesusFreke.com                    "is larger than the largest allowed register of v65535.",
1241ac8785e5d550c2ec7c7d02dd2990f859a78c111cJesusFreke@JesusFreke.com                    instruction.getStartRegister(),
1242ac8785e5d550c2ec7c7d02dd2990f859a78c111cJesusFreke@JesusFreke.com                    instruction.getStartRegister() + instruction.getRegCount() - 1));
1243ac8785e5d550c2ec7c7d02dd2990f859a78c111cJesusFreke@JesusFreke.com        }
1244ac8785e5d550c2ec7c7d02dd2990f859a78c111cJesusFreke@JesusFreke.com
1245b615ba6f51a42428937236a640480d6f7f9dc511JesusFreke@JesusFreke.com        return handleFilledNewArrayCommon(analyzedInstruction, new Format3rcRegisterIterator(instruction));
1246ac8785e5d550c2ec7c7d02dd2990f859a78c111cJesusFreke@JesusFreke.com    }
1247ac8785e5d550c2ec7c7d02dd2990f859a78c111cJesusFreke@JesusFreke.com
1248472d3ea58455ebf43d21819b2701fad98b5a0f9cJesusFreke@JesusFreke.com    private boolean handleFillArrayData(AnalyzedInstruction analyzedInstruction) {
1249472d3ea58455ebf43d21819b2701fad98b5a0f9cJesusFreke@JesusFreke.com        SingleRegisterInstruction instruction = (SingleRegisterInstruction)analyzedInstruction.instruction;
1250472d3ea58455ebf43d21819b2701fad98b5a0f9cJesusFreke@JesusFreke.com
1251472d3ea58455ebf43d21819b2701fad98b5a0f9cJesusFreke@JesusFreke.com        int register = instruction.getRegisterA();
1252472d3ea58455ebf43d21819b2701fad98b5a0f9cJesusFreke@JesusFreke.com        RegisterType registerType = analyzedInstruction.getPreInstructionRegisterType(register);
1253472d3ea58455ebf43d21819b2701fad98b5a0f9cJesusFreke@JesusFreke.com        assert registerType != null;
1254472d3ea58455ebf43d21819b2701fad98b5a0f9cJesusFreke@JesusFreke.com
1255472d3ea58455ebf43d21819b2701fad98b5a0f9cJesusFreke@JesusFreke.com        if (registerType.category == RegisterType.Category.Unknown ||
1256472d3ea58455ebf43d21819b2701fad98b5a0f9cJesusFreke@JesusFreke.com            registerType.category == RegisterType.Category.Null) {
1257472d3ea58455ebf43d21819b2701fad98b5a0f9cJesusFreke@JesusFreke.com            return false;
1258472d3ea58455ebf43d21819b2701fad98b5a0f9cJesusFreke@JesusFreke.com        }
1259472d3ea58455ebf43d21819b2701fad98b5a0f9cJesusFreke@JesusFreke.com
1260472d3ea58455ebf43d21819b2701fad98b5a0f9cJesusFreke@JesusFreke.com        if (registerType.category != RegisterType.Category.Reference) {
1261472d3ea58455ebf43d21819b2701fad98b5a0f9cJesusFreke@JesusFreke.com            throw new ValidationException(String.format("Cannot use fill-array-data with non-array register v%d of " +
1262472d3ea58455ebf43d21819b2701fad98b5a0f9cJesusFreke@JesusFreke.com                    "type %s", register, registerType.toString()));
1263472d3ea58455ebf43d21819b2701fad98b5a0f9cJesusFreke@JesusFreke.com        }
1264472d3ea58455ebf43d21819b2701fad98b5a0f9cJesusFreke@JesusFreke.com
1265472d3ea58455ebf43d21819b2701fad98b5a0f9cJesusFreke@JesusFreke.com        assert registerType.type instanceof ClassPath.ArrayClassDef;
1266472d3ea58455ebf43d21819b2701fad98b5a0f9cJesusFreke@JesusFreke.com        ClassPath.ArrayClassDef arrayClassDef = (ClassPath.ArrayClassDef)registerType.type;
1267472d3ea58455ebf43d21819b2701fad98b5a0f9cJesusFreke@JesusFreke.com
1268472d3ea58455ebf43d21819b2701fad98b5a0f9cJesusFreke@JesusFreke.com        if (arrayClassDef.getArrayDimensions() != 1) {
1269472d3ea58455ebf43d21819b2701fad98b5a0f9cJesusFreke@JesusFreke.com            throw new ValidationException(String.format("Cannot use fill-array-data with array type %s. It can only " +
1270472d3ea58455ebf43d21819b2701fad98b5a0f9cJesusFreke@JesusFreke.com                    "be used with a one-dimensional array of primitives.", arrayClassDef.getClassType()));
1271472d3ea58455ebf43d21819b2701fad98b5a0f9cJesusFreke@JesusFreke.com        }
1272472d3ea58455ebf43d21819b2701fad98b5a0f9cJesusFreke@JesusFreke.com
1273472d3ea58455ebf43d21819b2701fad98b5a0f9cJesusFreke@JesusFreke.com        int elementWidth;
1274472d3ea58455ebf43d21819b2701fad98b5a0f9cJesusFreke@JesusFreke.com        switch (arrayClassDef.getBaseElementClass().getClassType().charAt(0)) {
1275472d3ea58455ebf43d21819b2701fad98b5a0f9cJesusFreke@JesusFreke.com            case 'Z':
1276472d3ea58455ebf43d21819b2701fad98b5a0f9cJesusFreke@JesusFreke.com            case 'B':
1277472d3ea58455ebf43d21819b2701fad98b5a0f9cJesusFreke@JesusFreke.com                elementWidth = 1;
1278472d3ea58455ebf43d21819b2701fad98b5a0f9cJesusFreke@JesusFreke.com                break;
1279472d3ea58455ebf43d21819b2701fad98b5a0f9cJesusFreke@JesusFreke.com            case 'C':
1280472d3ea58455ebf43d21819b2701fad98b5a0f9cJesusFreke@JesusFreke.com            case 'S':
1281472d3ea58455ebf43d21819b2701fad98b5a0f9cJesusFreke@JesusFreke.com                elementWidth = 2;
1282472d3ea58455ebf43d21819b2701fad98b5a0f9cJesusFreke@JesusFreke.com                break;
1283472d3ea58455ebf43d21819b2701fad98b5a0f9cJesusFreke@JesusFreke.com            case 'I':
1284472d3ea58455ebf43d21819b2701fad98b5a0f9cJesusFreke@JesusFreke.com            case 'F':
1285472d3ea58455ebf43d21819b2701fad98b5a0f9cJesusFreke@JesusFreke.com                elementWidth = 4;
1286472d3ea58455ebf43d21819b2701fad98b5a0f9cJesusFreke@JesusFreke.com                break;
1287472d3ea58455ebf43d21819b2701fad98b5a0f9cJesusFreke@JesusFreke.com            case 'J':
1288472d3ea58455ebf43d21819b2701fad98b5a0f9cJesusFreke@JesusFreke.com            case 'D':
1289472d3ea58455ebf43d21819b2701fad98b5a0f9cJesusFreke@JesusFreke.com                elementWidth = 8;
1290472d3ea58455ebf43d21819b2701fad98b5a0f9cJesusFreke@JesusFreke.com                break;
1291472d3ea58455ebf43d21819b2701fad98b5a0f9cJesusFreke@JesusFreke.com            default:
1292472d3ea58455ebf43d21819b2701fad98b5a0f9cJesusFreke@JesusFreke.com                throw new ValidationException(String.format("Cannot use fill-array-data with array type %s. It can " +
1293472d3ea58455ebf43d21819b2701fad98b5a0f9cJesusFreke@JesusFreke.com                        "only be used with a one-dimensional array of primitives.", arrayClassDef.getClassType()));
1294472d3ea58455ebf43d21819b2701fad98b5a0f9cJesusFreke@JesusFreke.com        }
1295472d3ea58455ebf43d21819b2701fad98b5a0f9cJesusFreke@JesusFreke.com
1296472d3ea58455ebf43d21819b2701fad98b5a0f9cJesusFreke@JesusFreke.com
1297b7e78115277e30c71e6e991da3f31c5a1403c634JesusFreke@JesusFreke.com        int arrayDataAddressOffset = ((OffsetInstruction)analyzedInstruction.instruction).getTargetAddressOffset();
1298b7e78115277e30c71e6e991da3f31c5a1403c634JesusFreke@JesusFreke.com        int arrayDataCodeAddress = getInstructionAddress(analyzedInstruction) + arrayDataAddressOffset;
1299b7e78115277e30c71e6e991da3f31c5a1403c634JesusFreke@JesusFreke.com        AnalyzedInstruction arrayDataInstruction = this.instructions.get(arrayDataCodeAddress);
1300472d3ea58455ebf43d21819b2701fad98b5a0f9cJesusFreke@JesusFreke.com        if (arrayDataInstruction == null || arrayDataInstruction.instruction.getFormat() != Format.ArrayData) {
1301472d3ea58455ebf43d21819b2701fad98b5a0f9cJesusFreke@JesusFreke.com            throw new ValidationException(String.format("Could not find an array data structure at code address 0x%x",
1302b7e78115277e30c71e6e991da3f31c5a1403c634JesusFreke@JesusFreke.com                    arrayDataCodeAddress));
1303472d3ea58455ebf43d21819b2701fad98b5a0f9cJesusFreke@JesusFreke.com        }
1304472d3ea58455ebf43d21819b2701fad98b5a0f9cJesusFreke@JesusFreke.com
1305472d3ea58455ebf43d21819b2701fad98b5a0f9cJesusFreke@JesusFreke.com        ArrayDataPseudoInstruction arrayDataPseudoInstruction =
1306472d3ea58455ebf43d21819b2701fad98b5a0f9cJesusFreke@JesusFreke.com                (ArrayDataPseudoInstruction)arrayDataInstruction.instruction;
1307472d3ea58455ebf43d21819b2701fad98b5a0f9cJesusFreke@JesusFreke.com
1308472d3ea58455ebf43d21819b2701fad98b5a0f9cJesusFreke@JesusFreke.com        if (elementWidth != arrayDataPseudoInstruction.getElementWidth()) {
1309472d3ea58455ebf43d21819b2701fad98b5a0f9cJesusFreke@JesusFreke.com            throw new ValidationException(String.format("The array data at code address 0x%x does not have the " +
1310472d3ea58455ebf43d21819b2701fad98b5a0f9cJesusFreke@JesusFreke.com                    "correct element width for array type %s. Expecting element width %d, got element width %d.",
1311b7e78115277e30c71e6e991da3f31c5a1403c634JesusFreke@JesusFreke.com                    arrayDataCodeAddress, arrayClassDef.getClassType(), elementWidth,
1312472d3ea58455ebf43d21819b2701fad98b5a0f9cJesusFreke@JesusFreke.com                    arrayDataPseudoInstruction.getElementWidth()));
1313472d3ea58455ebf43d21819b2701fad98b5a0f9cJesusFreke@JesusFreke.com        }
1314472d3ea58455ebf43d21819b2701fad98b5a0f9cJesusFreke@JesusFreke.com
1315472d3ea58455ebf43d21819b2701fad98b5a0f9cJesusFreke@JesusFreke.com        return true;
1316472d3ea58455ebf43d21819b2701fad98b5a0f9cJesusFreke@JesusFreke.com    }
1317472d3ea58455ebf43d21819b2701fad98b5a0f9cJesusFreke@JesusFreke.com
1318ed140ca3e4fa66a03970affb3415a9fe2a924312JesusFreke@JesusFreke.com    private boolean handleThrow(AnalyzedInstruction analyzedInstruction) {
1319ed140ca3e4fa66a03970affb3415a9fe2a924312JesusFreke@JesusFreke.com        int register = ((SingleRegisterInstruction)analyzedInstruction.instruction).getRegisterA();
1320ed140ca3e4fa66a03970affb3415a9fe2a924312JesusFreke@JesusFreke.com
1321ed140ca3e4fa66a03970affb3415a9fe2a924312JesusFreke@JesusFreke.com        RegisterType registerType = analyzedInstruction.getPreInstructionRegisterType(register);
1322ed140ca3e4fa66a03970affb3415a9fe2a924312JesusFreke@JesusFreke.com        assert registerType != null;
1323ed140ca3e4fa66a03970affb3415a9fe2a924312JesusFreke@JesusFreke.com
1324ed140ca3e4fa66a03970affb3415a9fe2a924312JesusFreke@JesusFreke.com        if (registerType.category == RegisterType.Category.Unknown) {
1325ed140ca3e4fa66a03970affb3415a9fe2a924312JesusFreke@JesusFreke.com            return false;
1326ed140ca3e4fa66a03970affb3415a9fe2a924312JesusFreke@JesusFreke.com        }
1327ed140ca3e4fa66a03970affb3415a9fe2a924312JesusFreke@JesusFreke.com
1328ed140ca3e4fa66a03970affb3415a9fe2a924312JesusFreke@JesusFreke.com        if (registerType.category == RegisterType.Category.Null) {
1329ed140ca3e4fa66a03970affb3415a9fe2a924312JesusFreke@JesusFreke.com            return true;
1330ed140ca3e4fa66a03970affb3415a9fe2a924312JesusFreke@JesusFreke.com        }
1331ed140ca3e4fa66a03970affb3415a9fe2a924312JesusFreke@JesusFreke.com
1332ed140ca3e4fa66a03970affb3415a9fe2a924312JesusFreke@JesusFreke.com        if (registerType.category != RegisterType.Category.Reference) {
1333ed140ca3e4fa66a03970affb3415a9fe2a924312JesusFreke@JesusFreke.com            throw new ValidationException(String.format("Cannot use throw with non-reference type %s in register v%d",
1334ed140ca3e4fa66a03970affb3415a9fe2a924312JesusFreke@JesusFreke.com                    registerType.toString(), register));
1335ed140ca3e4fa66a03970affb3415a9fe2a924312JesusFreke@JesusFreke.com        }
1336ed140ca3e4fa66a03970affb3415a9fe2a924312JesusFreke@JesusFreke.com
1337ed140ca3e4fa66a03970affb3415a9fe2a924312JesusFreke@JesusFreke.com        assert registerType.type != null;
1338ed140ca3e4fa66a03970affb3415a9fe2a924312JesusFreke@JesusFreke.com
1339ed140ca3e4fa66a03970affb3415a9fe2a924312JesusFreke@JesusFreke.com        if (!registerType.type.extendsClass(ClassPath.getClassDef("Ljava/lang/Throwable;"))) {
1340ed140ca3e4fa66a03970affb3415a9fe2a924312JesusFreke@JesusFreke.com            throw new ValidationException(String.format("Cannot use throw with non-throwable type %s in register v%d",
1341ed140ca3e4fa66a03970affb3415a9fe2a924312JesusFreke@JesusFreke.com                    registerType.type.getClassType(), register));
1342ed140ca3e4fa66a03970affb3415a9fe2a924312JesusFreke@JesusFreke.com        }
1343ed140ca3e4fa66a03970affb3415a9fe2a924312JesusFreke@JesusFreke.com
1344ed140ca3e4fa66a03970affb3415a9fe2a924312JesusFreke@JesusFreke.com        return true;
1345ed140ca3e4fa66a03970affb3415a9fe2a924312JesusFreke@JesusFreke.com    }
1346ed140ca3e4fa66a03970affb3415a9fe2a924312JesusFreke@JesusFreke.com
1347cda44f70cfebfae4875cd77455a171075aebac4dJesusFreke@JesusFreke.com    private boolean handleSwitch(AnalyzedInstruction analyzedInstruction, Format expectedSwitchDataFormat) {
1348cda44f70cfebfae4875cd77455a171075aebac4dJesusFreke@JesusFreke.com        int register = ((SingleRegisterInstruction)analyzedInstruction.instruction).getRegisterA();
1349cda44f70cfebfae4875cd77455a171075aebac4dJesusFreke@JesusFreke.com        int switchCodeAddressOffset = ((OffsetInstruction)analyzedInstruction.instruction).getTargetAddressOffset();
1350cda44f70cfebfae4875cd77455a171075aebac4dJesusFreke@JesusFreke.com
1351cda44f70cfebfae4875cd77455a171075aebac4dJesusFreke@JesusFreke.com        RegisterType registerType = analyzedInstruction.getPreInstructionRegisterType(register);
1352cda44f70cfebfae4875cd77455a171075aebac4dJesusFreke@JesusFreke.com        assert registerType != null;
1353cda44f70cfebfae4875cd77455a171075aebac4dJesusFreke@JesusFreke.com
1354cda44f70cfebfae4875cd77455a171075aebac4dJesusFreke@JesusFreke.com        if (registerType.category == RegisterType.Category.Unknown) {
1355cda44f70cfebfae4875cd77455a171075aebac4dJesusFreke@JesusFreke.com            return false;
1356cda44f70cfebfae4875cd77455a171075aebac4dJesusFreke@JesusFreke.com        }
1357cda44f70cfebfae4875cd77455a171075aebac4dJesusFreke@JesusFreke.com
1358cda44f70cfebfae4875cd77455a171075aebac4dJesusFreke@JesusFreke.com        checkRegister(registerType, Primitive32BitCategories);
1359cda44f70cfebfae4875cd77455a171075aebac4dJesusFreke@JesusFreke.com
1360cda44f70cfebfae4875cd77455a171075aebac4dJesusFreke@JesusFreke.com        int switchDataCodeAddress = this.getInstructionAddress(analyzedInstruction) + switchCodeAddressOffset;
1361cda44f70cfebfae4875cd77455a171075aebac4dJesusFreke@JesusFreke.com        AnalyzedInstruction switchDataAnalyzedInstruction = instructions.get(switchDataCodeAddress);
1362cda44f70cfebfae4875cd77455a171075aebac4dJesusFreke@JesusFreke.com
1363cda44f70cfebfae4875cd77455a171075aebac4dJesusFreke@JesusFreke.com        if (switchDataAnalyzedInstruction == null ||
1364cda44f70cfebfae4875cd77455a171075aebac4dJesusFreke@JesusFreke.com            switchDataAnalyzedInstruction.instruction.getFormat() != expectedSwitchDataFormat) {
1365cda44f70cfebfae4875cd77455a171075aebac4dJesusFreke@JesusFreke.com            throw new ValidationException(String.format("There is no %s structure at code address 0x%x",
1366cda44f70cfebfae4875cd77455a171075aebac4dJesusFreke@JesusFreke.com                    expectedSwitchDataFormat.name(), switchDataCodeAddress));
1367cda44f70cfebfae4875cd77455a171075aebac4dJesusFreke@JesusFreke.com        }
1368cda44f70cfebfae4875cd77455a171075aebac4dJesusFreke@JesusFreke.com
1369cda44f70cfebfae4875cd77455a171075aebac4dJesusFreke@JesusFreke.com        return true;
1370cda44f70cfebfae4875cd77455a171075aebac4dJesusFreke@JesusFreke.com    }
1371cda44f70cfebfae4875cd77455a171075aebac4dJesusFreke@JesusFreke.com
1372f1a74cea19f10e9059e05f1cee6ae45baf118108JesusFreke@JesusFreke.com    private boolean handleFloatCmp(AnalyzedInstruction analyzedInstruction) {
1373f1a74cea19f10e9059e05f1cee6ae45baf118108JesusFreke@JesusFreke.com        ThreeRegisterInstruction instruction = (ThreeRegisterInstruction)analyzedInstruction.instruction;
1374f1a74cea19f10e9059e05f1cee6ae45baf118108JesusFreke@JesusFreke.com
1375f1a74cea19f10e9059e05f1cee6ae45baf118108JesusFreke@JesusFreke.com        RegisterType registerType = analyzedInstruction.getPreInstructionRegisterType(instruction.getRegisterB());
1376f1a74cea19f10e9059e05f1cee6ae45baf118108JesusFreke@JesusFreke.com        assert registerType != null;
1377f1a74cea19f10e9059e05f1cee6ae45baf118108JesusFreke@JesusFreke.com
1378f1a74cea19f10e9059e05f1cee6ae45baf118108JesusFreke@JesusFreke.com        if (registerType.category == RegisterType.Category.Unknown) {
1379f1a74cea19f10e9059e05f1cee6ae45baf118108JesusFreke@JesusFreke.com            return false;
1380f1a74cea19f10e9059e05f1cee6ae45baf118108JesusFreke@JesusFreke.com        }
1381f1a74cea19f10e9059e05f1cee6ae45baf118108JesusFreke@JesusFreke.com        checkRegister(registerType, Primitive32BitCategories);
1382f1a74cea19f10e9059e05f1cee6ae45baf118108JesusFreke@JesusFreke.com
1383f1a74cea19f10e9059e05f1cee6ae45baf118108JesusFreke@JesusFreke.com        registerType = analyzedInstruction.getPreInstructionRegisterType(instruction.getRegisterC());
1384f1a74cea19f10e9059e05f1cee6ae45baf118108JesusFreke@JesusFreke.com        assert registerType != null;
1385f1a74cea19f10e9059e05f1cee6ae45baf118108JesusFreke@JesusFreke.com
1386f1a74cea19f10e9059e05f1cee6ae45baf118108JesusFreke@JesusFreke.com        if (registerType.category == RegisterType.Category.Unknown) {
1387f1a74cea19f10e9059e05f1cee6ae45baf118108JesusFreke@JesusFreke.com            return false;
1388f1a74cea19f10e9059e05f1cee6ae45baf118108JesusFreke@JesusFreke.com        }
1389f1a74cea19f10e9059e05f1cee6ae45baf118108JesusFreke@JesusFreke.com        checkRegister(registerType, Primitive32BitCategories);
1390f1a74cea19f10e9059e05f1cee6ae45baf118108JesusFreke@JesusFreke.com
1391f1a74cea19f10e9059e05f1cee6ae45baf118108JesusFreke@JesusFreke.com        setDestinationRegisterTypeAndPropagateChanges(analyzedInstruction,
1392f1a74cea19f10e9059e05f1cee6ae45baf118108JesusFreke@JesusFreke.com                RegisterType.getRegisterType(RegisterType.Category.Byte, null));
1393f1a74cea19f10e9059e05f1cee6ae45baf118108JesusFreke@JesusFreke.com        return true;
1394f1a74cea19f10e9059e05f1cee6ae45baf118108JesusFreke@JesusFreke.com    }
1395f1a74cea19f10e9059e05f1cee6ae45baf118108JesusFreke@JesusFreke.com
1396f1a74cea19f10e9059e05f1cee6ae45baf118108JesusFreke@JesusFreke.com    private boolean handleWideCmp(AnalyzedInstruction analyzedInstruction) {
1397f1a74cea19f10e9059e05f1cee6ae45baf118108JesusFreke@JesusFreke.com        ThreeRegisterInstruction instruction = (ThreeRegisterInstruction)analyzedInstruction.instruction;
1398f1a74cea19f10e9059e05f1cee6ae45baf118108JesusFreke@JesusFreke.com
1399f1a74cea19f10e9059e05f1cee6ae45baf118108JesusFreke@JesusFreke.com        RegisterType registerType = getAndCheckWideSourcePair(analyzedInstruction, instruction.getRegisterB());
1400f1a74cea19f10e9059e05f1cee6ae45baf118108JesusFreke@JesusFreke.com        assert registerType != null;
1401f1a74cea19f10e9059e05f1cee6ae45baf118108JesusFreke@JesusFreke.com        if (registerType.category == RegisterType.Category.Unknown) {
1402f1a74cea19f10e9059e05f1cee6ae45baf118108JesusFreke@JesusFreke.com            return false;
1403f1a74cea19f10e9059e05f1cee6ae45baf118108JesusFreke@JesusFreke.com        }
1404f1a74cea19f10e9059e05f1cee6ae45baf118108JesusFreke@JesusFreke.com
1405f1a74cea19f10e9059e05f1cee6ae45baf118108JesusFreke@JesusFreke.com        registerType = getAndCheckWideSourcePair(analyzedInstruction, instruction.getRegisterC());
1406f1a74cea19f10e9059e05f1cee6ae45baf118108JesusFreke@JesusFreke.com        assert registerType != null;
1407f1a74cea19f10e9059e05f1cee6ae45baf118108JesusFreke@JesusFreke.com        if (registerType.category == RegisterType.Category.Unknown) {
1408f1a74cea19f10e9059e05f1cee6ae45baf118108JesusFreke@JesusFreke.com            return false;
1409f1a74cea19f10e9059e05f1cee6ae45baf118108JesusFreke@JesusFreke.com        }
1410f1a74cea19f10e9059e05f1cee6ae45baf118108JesusFreke@JesusFreke.com
1411f1a74cea19f10e9059e05f1cee6ae45baf118108JesusFreke@JesusFreke.com        setDestinationRegisterTypeAndPropagateChanges(analyzedInstruction,
1412f1a74cea19f10e9059e05f1cee6ae45baf118108JesusFreke@JesusFreke.com                RegisterType.getRegisterType(RegisterType.Category.Byte, null));
1413f1a74cea19f10e9059e05f1cee6ae45baf118108JesusFreke@JesusFreke.com        return true;
1414f1a74cea19f10e9059e05f1cee6ae45baf118108JesusFreke@JesusFreke.com    }
1415f1a74cea19f10e9059e05f1cee6ae45baf118108JesusFreke@JesusFreke.com
1416aba6bb0bbd1537a6df9614ee579773e4a8af70ffJesusFreke@JesusFreke.com    private boolean handleIfEqNe(AnalyzedInstruction analyzedInstruction) {
1417aba6bb0bbd1537a6df9614ee579773e4a8af70ffJesusFreke@JesusFreke.com        TwoRegisterInstruction instruction = (TwoRegisterInstruction)analyzedInstruction.instruction;
1418aba6bb0bbd1537a6df9614ee579773e4a8af70ffJesusFreke@JesusFreke.com
1419aba6bb0bbd1537a6df9614ee579773e4a8af70ffJesusFreke@JesusFreke.com        RegisterType registerType1 = analyzedInstruction.getPreInstructionRegisterType(instruction.getRegisterA());
1420aba6bb0bbd1537a6df9614ee579773e4a8af70ffJesusFreke@JesusFreke.com        assert registerType1 != null;
1421aba6bb0bbd1537a6df9614ee579773e4a8af70ffJesusFreke@JesusFreke.com        if (registerType1.category == RegisterType.Category.Unknown) {
1422aba6bb0bbd1537a6df9614ee579773e4a8af70ffJesusFreke@JesusFreke.com            return false;
1423aba6bb0bbd1537a6df9614ee579773e4a8af70ffJesusFreke@JesusFreke.com        }
1424aba6bb0bbd1537a6df9614ee579773e4a8af70ffJesusFreke@JesusFreke.com
1425aba6bb0bbd1537a6df9614ee579773e4a8af70ffJesusFreke@JesusFreke.com        RegisterType registerType2 = analyzedInstruction.getPreInstructionRegisterType(instruction.getRegisterB());
1426aba6bb0bbd1537a6df9614ee579773e4a8af70ffJesusFreke@JesusFreke.com        assert registerType2 != null;
1427aba6bb0bbd1537a6df9614ee579773e4a8af70ffJesusFreke@JesusFreke.com        if (registerType2.category == RegisterType.Category.Unknown) {
1428aba6bb0bbd1537a6df9614ee579773e4a8af70ffJesusFreke@JesusFreke.com            return false;
1429aba6bb0bbd1537a6df9614ee579773e4a8af70ffJesusFreke@JesusFreke.com        }
1430aba6bb0bbd1537a6df9614ee579773e4a8af70ffJesusFreke@JesusFreke.com
1431aba6bb0bbd1537a6df9614ee579773e4a8af70ffJesusFreke@JesusFreke.com        if (!(
1432aba6bb0bbd1537a6df9614ee579773e4a8af70ffJesusFreke@JesusFreke.com                (ReferenceCategories.contains(registerType1.category) &&
1433aba6bb0bbd1537a6df9614ee579773e4a8af70ffJesusFreke@JesusFreke.com                ReferenceCategories.contains(registerType2.category))
1434aba6bb0bbd1537a6df9614ee579773e4a8af70ffJesusFreke@JesusFreke.com                    ||
1435aba6bb0bbd1537a6df9614ee579773e4a8af70ffJesusFreke@JesusFreke.com                (Primitive32BitCategories.contains(registerType1.category) &&
1436aba6bb0bbd1537a6df9614ee579773e4a8af70ffJesusFreke@JesusFreke.com                Primitive32BitCategories.contains(registerType2.category))
1437aba6bb0bbd1537a6df9614ee579773e4a8af70ffJesusFreke@JesusFreke.com              )) {
1438aba6bb0bbd1537a6df9614ee579773e4a8af70ffJesusFreke@JesusFreke.com
1439aba6bb0bbd1537a6df9614ee579773e4a8af70ffJesusFreke@JesusFreke.com            throw new ValidationException(String.format("%s cannot be used on registers of dissimilar types %s and " +
1440aba6bb0bbd1537a6df9614ee579773e4a8af70ffJesusFreke@JesusFreke.com                    "%s. They must both be a reference type or a primitive 32 bit type.",
1441aba6bb0bbd1537a6df9614ee579773e4a8af70ffJesusFreke@JesusFreke.com                    analyzedInstruction.instruction.opcode.name, registerType1.toString(), registerType2.toString()));
1442aba6bb0bbd1537a6df9614ee579773e4a8af70ffJesusFreke@JesusFreke.com        }
1443aba6bb0bbd1537a6df9614ee579773e4a8af70ffJesusFreke@JesusFreke.com
1444aba6bb0bbd1537a6df9614ee579773e4a8af70ffJesusFreke@JesusFreke.com        return true;
1445aba6bb0bbd1537a6df9614ee579773e4a8af70ffJesusFreke@JesusFreke.com    }
1446aba6bb0bbd1537a6df9614ee579773e4a8af70ffJesusFreke@JesusFreke.com
1447150acd9db94f9886f6fc32e89acc15a1a5c1466fJesusFreke@JesusFreke.com    private boolean handleIf(AnalyzedInstruction analyzedInstruction) {
1448150acd9db94f9886f6fc32e89acc15a1a5c1466fJesusFreke@JesusFreke.com        TwoRegisterInstruction instruction = (TwoRegisterInstruction)analyzedInstruction.instruction;
1449150acd9db94f9886f6fc32e89acc15a1a5c1466fJesusFreke@JesusFreke.com
1450150acd9db94f9886f6fc32e89acc15a1a5c1466fJesusFreke@JesusFreke.com        RegisterType registerType = analyzedInstruction.getPreInstructionRegisterType(instruction.getRegisterA());
1451150acd9db94f9886f6fc32e89acc15a1a5c1466fJesusFreke@JesusFreke.com        assert registerType != null;
1452150acd9db94f9886f6fc32e89acc15a1a5c1466fJesusFreke@JesusFreke.com
1453150acd9db94f9886f6fc32e89acc15a1a5c1466fJesusFreke@JesusFreke.com        if (registerType.category == RegisterType.Category.Unknown) {
1454150acd9db94f9886f6fc32e89acc15a1a5c1466fJesusFreke@JesusFreke.com            return false;
1455150acd9db94f9886f6fc32e89acc15a1a5c1466fJesusFreke@JesusFreke.com        }
1456150acd9db94f9886f6fc32e89acc15a1a5c1466fJesusFreke@JesusFreke.com        checkRegister(registerType, Primitive32BitCategories);
1457150acd9db94f9886f6fc32e89acc15a1a5c1466fJesusFreke@JesusFreke.com
1458150acd9db94f9886f6fc32e89acc15a1a5c1466fJesusFreke@JesusFreke.com        registerType = analyzedInstruction.getPreInstructionRegisterType(instruction.getRegisterB());
1459150acd9db94f9886f6fc32e89acc15a1a5c1466fJesusFreke@JesusFreke.com        assert registerType != null;
1460150acd9db94f9886f6fc32e89acc15a1a5c1466fJesusFreke@JesusFreke.com
1461150acd9db94f9886f6fc32e89acc15a1a5c1466fJesusFreke@JesusFreke.com        if (registerType.category == RegisterType.Category.Unknown) {
1462150acd9db94f9886f6fc32e89acc15a1a5c1466fJesusFreke@JesusFreke.com            return false;
1463150acd9db94f9886f6fc32e89acc15a1a5c1466fJesusFreke@JesusFreke.com        }
1464150acd9db94f9886f6fc32e89acc15a1a5c1466fJesusFreke@JesusFreke.com        checkRegister(registerType, Primitive32BitCategories);
1465150acd9db94f9886f6fc32e89acc15a1a5c1466fJesusFreke@JesusFreke.com
1466150acd9db94f9886f6fc32e89acc15a1a5c1466fJesusFreke@JesusFreke.com        return true;
1467150acd9db94f9886f6fc32e89acc15a1a5c1466fJesusFreke@JesusFreke.com    }
1468150acd9db94f9886f6fc32e89acc15a1a5c1466fJesusFreke@JesusFreke.com
1469cb00252b6aed86cd3e7c426015cea83fcdbaa806JesusFreke@JesusFreke.com    private boolean handleIfEqzNez(AnalyzedInstruction analyzedInstruction) {
1470cb00252b6aed86cd3e7c426015cea83fcdbaa806JesusFreke@JesusFreke.com        SingleRegisterInstruction instruction = (SingleRegisterInstruction)analyzedInstruction.instruction;
1471cb00252b6aed86cd3e7c426015cea83fcdbaa806JesusFreke@JesusFreke.com
1472cb00252b6aed86cd3e7c426015cea83fcdbaa806JesusFreke@JesusFreke.com        RegisterType registerType = analyzedInstruction.getPreInstructionRegisterType(instruction.getRegisterA());
1473cb00252b6aed86cd3e7c426015cea83fcdbaa806JesusFreke@JesusFreke.com        assert registerType != null;
1474cb00252b6aed86cd3e7c426015cea83fcdbaa806JesusFreke@JesusFreke.com        if (registerType.category == RegisterType.Category.Unknown) {
1475cb00252b6aed86cd3e7c426015cea83fcdbaa806JesusFreke@JesusFreke.com            return false;
1476cb00252b6aed86cd3e7c426015cea83fcdbaa806JesusFreke@JesusFreke.com        }
1477cb00252b6aed86cd3e7c426015cea83fcdbaa806JesusFreke@JesusFreke.com
1478cb00252b6aed86cd3e7c426015cea83fcdbaa806JesusFreke@JesusFreke.com        if (!ReferenceCategories.contains(registerType.category) &&
1479cb00252b6aed86cd3e7c426015cea83fcdbaa806JesusFreke@JesusFreke.com            !Primitive32BitCategories.contains(registerType.category)) {
1480cb00252b6aed86cd3e7c426015cea83fcdbaa806JesusFreke@JesusFreke.com            throw new ValidationException(String.format("%s cannot be used with register type %s. Expecting 32-bit " +
1481cb00252b6aed86cd3e7c426015cea83fcdbaa806JesusFreke@JesusFreke.com                    "primitive type or reference type.", analyzedInstruction.instruction.opcode));
1482cb00252b6aed86cd3e7c426015cea83fcdbaa806JesusFreke@JesusFreke.com        }
1483cb00252b6aed86cd3e7c426015cea83fcdbaa806JesusFreke@JesusFreke.com
1484cb00252b6aed86cd3e7c426015cea83fcdbaa806JesusFreke@JesusFreke.com        return true;
1485cb00252b6aed86cd3e7c426015cea83fcdbaa806JesusFreke@JesusFreke.com    }
1486cb00252b6aed86cd3e7c426015cea83fcdbaa806JesusFreke@JesusFreke.com
148716a709ba046343bfefc15a6cdb0be38282126223JesusFreke@JesusFreke.com    private boolean handleIfz(AnalyzedInstruction analyzedInstruction) {
148816a709ba046343bfefc15a6cdb0be38282126223JesusFreke@JesusFreke.com        SingleRegisterInstruction instruction = (SingleRegisterInstruction)analyzedInstruction.instruction;
148916a709ba046343bfefc15a6cdb0be38282126223JesusFreke@JesusFreke.com
149016a709ba046343bfefc15a6cdb0be38282126223JesusFreke@JesusFreke.com        RegisterType registerType = analyzedInstruction.getPreInstructionRegisterType(instruction.getRegisterA());
149116a709ba046343bfefc15a6cdb0be38282126223JesusFreke@JesusFreke.com        assert registerType != null;
149216a709ba046343bfefc15a6cdb0be38282126223JesusFreke@JesusFreke.com
149316a709ba046343bfefc15a6cdb0be38282126223JesusFreke@JesusFreke.com        if (registerType.category == RegisterType.Category.Unknown) {
149416a709ba046343bfefc15a6cdb0be38282126223JesusFreke@JesusFreke.com            return false;
149516a709ba046343bfefc15a6cdb0be38282126223JesusFreke@JesusFreke.com        }
149616a709ba046343bfefc15a6cdb0be38282126223JesusFreke@JesusFreke.com        checkRegister(registerType, Primitive32BitCategories);
149716a709ba046343bfefc15a6cdb0be38282126223JesusFreke@JesusFreke.com
149816a709ba046343bfefc15a6cdb0be38282126223JesusFreke@JesusFreke.com        return true;
149916a709ba046343bfefc15a6cdb0be38282126223JesusFreke@JesusFreke.com    }
150016a709ba046343bfefc15a6cdb0be38282126223JesusFreke@JesusFreke.com
1501b2397452907c28b0743bbbcdf9fa6b2a8208aeabJesusFreke@JesusFreke.com    private boolean handle32BitPrimitiveAget(AnalyzedInstruction analyzedInstruction,
1502b2397452907c28b0743bbbcdf9fa6b2a8208aeabJesusFreke@JesusFreke.com                                             RegisterType.Category instructionCategory) {
1503b2397452907c28b0743bbbcdf9fa6b2a8208aeabJesusFreke@JesusFreke.com        ThreeRegisterInstruction instruction = (ThreeRegisterInstruction)analyzedInstruction.instruction;
1504b2397452907c28b0743bbbcdf9fa6b2a8208aeabJesusFreke@JesusFreke.com
1505b2397452907c28b0743bbbcdf9fa6b2a8208aeabJesusFreke@JesusFreke.com        RegisterType indexRegisterType = analyzedInstruction.getPreInstructionRegisterType(instruction.getRegisterC());
1506b2397452907c28b0743bbbcdf9fa6b2a8208aeabJesusFreke@JesusFreke.com        assert indexRegisterType != null;
1507b2397452907c28b0743bbbcdf9fa6b2a8208aeabJesusFreke@JesusFreke.com        if (indexRegisterType.category == RegisterType.Category.Unknown) {
1508b2397452907c28b0743bbbcdf9fa6b2a8208aeabJesusFreke@JesusFreke.com            return false;
1509b2397452907c28b0743bbbcdf9fa6b2a8208aeabJesusFreke@JesusFreke.com        }
1510b2397452907c28b0743bbbcdf9fa6b2a8208aeabJesusFreke@JesusFreke.com        checkRegister(indexRegisterType, Primitive32BitCategories);
1511b2397452907c28b0743bbbcdf9fa6b2a8208aeabJesusFreke@JesusFreke.com
1512b2397452907c28b0743bbbcdf9fa6b2a8208aeabJesusFreke@JesusFreke.com        RegisterType arrayRegisterType = analyzedInstruction.getPreInstructionRegisterType(instruction.getRegisterB());
1513b2397452907c28b0743bbbcdf9fa6b2a8208aeabJesusFreke@JesusFreke.com        assert arrayRegisterType != null;
1514b2397452907c28b0743bbbcdf9fa6b2a8208aeabJesusFreke@JesusFreke.com        if (indexRegisterType.category == RegisterType.Category.Unknown) {
1515b2397452907c28b0743bbbcdf9fa6b2a8208aeabJesusFreke@JesusFreke.com            return false;
1516b2397452907c28b0743bbbcdf9fa6b2a8208aeabJesusFreke@JesusFreke.com        }
1517b2397452907c28b0743bbbcdf9fa6b2a8208aeabJesusFreke@JesusFreke.com
1518b2397452907c28b0743bbbcdf9fa6b2a8208aeabJesusFreke@JesusFreke.com        if (arrayRegisterType.category != RegisterType.Category.Null) {
1519b2397452907c28b0743bbbcdf9fa6b2a8208aeabJesusFreke@JesusFreke.com            if (arrayRegisterType.category != RegisterType.Category.Reference) {
1520b2397452907c28b0743bbbcdf9fa6b2a8208aeabJesusFreke@JesusFreke.com                throw new ValidationException(String.format("Cannot use %s with non-array type %s",
1521b2397452907c28b0743bbbcdf9fa6b2a8208aeabJesusFreke@JesusFreke.com                        analyzedInstruction.instruction.opcode.name, arrayRegisterType.category.toString()));
1522b2397452907c28b0743bbbcdf9fa6b2a8208aeabJesusFreke@JesusFreke.com            }
1523b2397452907c28b0743bbbcdf9fa6b2a8208aeabJesusFreke@JesusFreke.com
1524b2397452907c28b0743bbbcdf9fa6b2a8208aeabJesusFreke@JesusFreke.com            assert arrayRegisterType.type != null;
1525b2397452907c28b0743bbbcdf9fa6b2a8208aeabJesusFreke@JesusFreke.com            if (arrayRegisterType.type.getClassType().charAt(0) != '[') {
1526b2397452907c28b0743bbbcdf9fa6b2a8208aeabJesusFreke@JesusFreke.com                throw new ValidationException(String.format("Cannot use %s with non-array type %s",
1527b2397452907c28b0743bbbcdf9fa6b2a8208aeabJesusFreke@JesusFreke.com                        analyzedInstruction.instruction.opcode.name, arrayRegisterType.type.getClassType()));
1528b2397452907c28b0743bbbcdf9fa6b2a8208aeabJesusFreke@JesusFreke.com            }
1529b2397452907c28b0743bbbcdf9fa6b2a8208aeabJesusFreke@JesusFreke.com
1530b2397452907c28b0743bbbcdf9fa6b2a8208aeabJesusFreke@JesusFreke.com            assert arrayRegisterType.type instanceof ClassPath.ArrayClassDef;
1531b2397452907c28b0743bbbcdf9fa6b2a8208aeabJesusFreke@JesusFreke.com            ClassPath.ArrayClassDef arrayClassDef = (ClassPath.ArrayClassDef)arrayRegisterType.type;
1532b2397452907c28b0743bbbcdf9fa6b2a8208aeabJesusFreke@JesusFreke.com
1533b2397452907c28b0743bbbcdf9fa6b2a8208aeabJesusFreke@JesusFreke.com            if (arrayClassDef.getArrayDimensions() != 1) {
1534b2397452907c28b0743bbbcdf9fa6b2a8208aeabJesusFreke@JesusFreke.com                throw new ValidationException(String.format("Cannot use %s with multi-dimensional array type %s",
1535b2397452907c28b0743bbbcdf9fa6b2a8208aeabJesusFreke@JesusFreke.com                        analyzedInstruction.instruction.opcode.name, arrayRegisterType.type.getClassType()));
1536b2397452907c28b0743bbbcdf9fa6b2a8208aeabJesusFreke@JesusFreke.com            }
1537b2397452907c28b0743bbbcdf9fa6b2a8208aeabJesusFreke@JesusFreke.com
1538b2397452907c28b0743bbbcdf9fa6b2a8208aeabJesusFreke@JesusFreke.com            RegisterType arrayBaseType =
1539b2397452907c28b0743bbbcdf9fa6b2a8208aeabJesusFreke@JesusFreke.com                    RegisterType.getRegisterTypeForType(arrayClassDef.getBaseElementClass().getClassType());
1540b2397452907c28b0743bbbcdf9fa6b2a8208aeabJesusFreke@JesusFreke.com            if (checkArrayFieldAssignment(arrayBaseType.category, instructionCategory)) {
1541b2397452907c28b0743bbbcdf9fa6b2a8208aeabJesusFreke@JesusFreke.com                throw new ValidationException(String.format("Cannot use %s with array type %s. Incorrect array type " +
1542b2397452907c28b0743bbbcdf9fa6b2a8208aeabJesusFreke@JesusFreke.com                        "for the instruction.", analyzedInstruction.instruction.opcode.name,
1543b2397452907c28b0743bbbcdf9fa6b2a8208aeabJesusFreke@JesusFreke.com                        arrayRegisterType.type.getClassType()));
1544b2397452907c28b0743bbbcdf9fa6b2a8208aeabJesusFreke@JesusFreke.com            }
1545b2397452907c28b0743bbbcdf9fa6b2a8208aeabJesusFreke@JesusFreke.com        }
1546b2397452907c28b0743bbbcdf9fa6b2a8208aeabJesusFreke@JesusFreke.com
1547b2397452907c28b0743bbbcdf9fa6b2a8208aeabJesusFreke@JesusFreke.com        setDestinationRegisterTypeAndPropagateChanges(analyzedInstruction,
1548b2397452907c28b0743bbbcdf9fa6b2a8208aeabJesusFreke@JesusFreke.com                RegisterType.getRegisterType(instructionCategory, null));
1549b2397452907c28b0743bbbcdf9fa6b2a8208aeabJesusFreke@JesusFreke.com
1550b2397452907c28b0743bbbcdf9fa6b2a8208aeabJesusFreke@JesusFreke.com        return true;
1551b2397452907c28b0743bbbcdf9fa6b2a8208aeabJesusFreke@JesusFreke.com    }
1552b2397452907c28b0743bbbcdf9fa6b2a8208aeabJesusFreke@JesusFreke.com
1553c308b24b6261ea81497a69e6d4d7ef6319943b10JesusFreke@JesusFreke.com    private boolean handleAgetWide(AnalyzedInstruction analyzedInstruction) {
1554c308b24b6261ea81497a69e6d4d7ef6319943b10JesusFreke@JesusFreke.com        ThreeRegisterInstruction instruction = (ThreeRegisterInstruction)analyzedInstruction.instruction;
1555c308b24b6261ea81497a69e6d4d7ef6319943b10JesusFreke@JesusFreke.com
1556c308b24b6261ea81497a69e6d4d7ef6319943b10JesusFreke@JesusFreke.com        RegisterType indexRegisterType = analyzedInstruction.getPreInstructionRegisterType(instruction.getRegisterC());
1557c308b24b6261ea81497a69e6d4d7ef6319943b10JesusFreke@JesusFreke.com        assert indexRegisterType != null;
1558c308b24b6261ea81497a69e6d4d7ef6319943b10JesusFreke@JesusFreke.com        if (indexRegisterType.category == RegisterType.Category.Unknown) {
1559c308b24b6261ea81497a69e6d4d7ef6319943b10JesusFreke@JesusFreke.com            return false;
1560c308b24b6261ea81497a69e6d4d7ef6319943b10JesusFreke@JesusFreke.com        }
1561c308b24b6261ea81497a69e6d4d7ef6319943b10JesusFreke@JesusFreke.com        checkRegister(indexRegisterType, Primitive32BitCategories);
1562c308b24b6261ea81497a69e6d4d7ef6319943b10JesusFreke@JesusFreke.com
1563c308b24b6261ea81497a69e6d4d7ef6319943b10JesusFreke@JesusFreke.com        RegisterType arrayRegisterType = analyzedInstruction.getPreInstructionRegisterType(instruction.getRegisterB());
1564c308b24b6261ea81497a69e6d4d7ef6319943b10JesusFreke@JesusFreke.com        assert arrayRegisterType != null;
1565c308b24b6261ea81497a69e6d4d7ef6319943b10JesusFreke@JesusFreke.com        if (indexRegisterType.category == RegisterType.Category.Unknown) {
1566c308b24b6261ea81497a69e6d4d7ef6319943b10JesusFreke@JesusFreke.com            return false;
1567c308b24b6261ea81497a69e6d4d7ef6319943b10JesusFreke@JesusFreke.com        }
1568c308b24b6261ea81497a69e6d4d7ef6319943b10JesusFreke@JesusFreke.com
1569c308b24b6261ea81497a69e6d4d7ef6319943b10JesusFreke@JesusFreke.com        if (arrayRegisterType.category != RegisterType.Category.Null) {
1570c308b24b6261ea81497a69e6d4d7ef6319943b10JesusFreke@JesusFreke.com            if (arrayRegisterType.category != RegisterType.Category.Reference) {
1571c308b24b6261ea81497a69e6d4d7ef6319943b10JesusFreke@JesusFreke.com                throw new ValidationException(String.format("Cannot use aget-wide with non-array type %s",
1572c308b24b6261ea81497a69e6d4d7ef6319943b10JesusFreke@JesusFreke.com                        arrayRegisterType.category.toString()));
1573c308b24b6261ea81497a69e6d4d7ef6319943b10JesusFreke@JesusFreke.com            }
1574c308b24b6261ea81497a69e6d4d7ef6319943b10JesusFreke@JesusFreke.com
1575c308b24b6261ea81497a69e6d4d7ef6319943b10JesusFreke@JesusFreke.com            assert arrayRegisterType.type != null;
1576c308b24b6261ea81497a69e6d4d7ef6319943b10JesusFreke@JesusFreke.com            if (arrayRegisterType.type.getClassType().charAt(0) != '[') {
1577c308b24b6261ea81497a69e6d4d7ef6319943b10JesusFreke@JesusFreke.com                throw new ValidationException(String.format("Cannot use aget-wide with non-array type %s",
1578c308b24b6261ea81497a69e6d4d7ef6319943b10JesusFreke@JesusFreke.com                        arrayRegisterType.type.getClassType()));
1579c308b24b6261ea81497a69e6d4d7ef6319943b10JesusFreke@JesusFreke.com            }
1580c308b24b6261ea81497a69e6d4d7ef6319943b10JesusFreke@JesusFreke.com
1581c308b24b6261ea81497a69e6d4d7ef6319943b10JesusFreke@JesusFreke.com            assert arrayRegisterType.type instanceof ClassPath.ArrayClassDef;
1582c308b24b6261ea81497a69e6d4d7ef6319943b10JesusFreke@JesusFreke.com            ClassPath.ArrayClassDef arrayClassDef = (ClassPath.ArrayClassDef)arrayRegisterType.type;
1583c308b24b6261ea81497a69e6d4d7ef6319943b10JesusFreke@JesusFreke.com
1584c308b24b6261ea81497a69e6d4d7ef6319943b10JesusFreke@JesusFreke.com            if (arrayClassDef.getArrayDimensions() != 1) {
1585c308b24b6261ea81497a69e6d4d7ef6319943b10JesusFreke@JesusFreke.com                throw new ValidationException(String.format("Cannot use aget-wide with multi-dimensional array type %s",
1586c308b24b6261ea81497a69e6d4d7ef6319943b10JesusFreke@JesusFreke.com                        arrayRegisterType.type.getClassType()));
1587c308b24b6261ea81497a69e6d4d7ef6319943b10JesusFreke@JesusFreke.com            }
1588c308b24b6261ea81497a69e6d4d7ef6319943b10JesusFreke@JesusFreke.com
1589c308b24b6261ea81497a69e6d4d7ef6319943b10JesusFreke@JesusFreke.com            char arrayBaseType = arrayClassDef.getBaseElementClass().getClassType().charAt(0);
1590c308b24b6261ea81497a69e6d4d7ef6319943b10JesusFreke@JesusFreke.com            if (arrayBaseType == 'J') {
1591c308b24b6261ea81497a69e6d4d7ef6319943b10JesusFreke@JesusFreke.com                setWideDestinationRegisterTypeAndPropagateChanges(analyzedInstruction,
1592c308b24b6261ea81497a69e6d4d7ef6319943b10JesusFreke@JesusFreke.com                        RegisterType.getRegisterType(RegisterType.Category.LongLo, null));
1593c308b24b6261ea81497a69e6d4d7ef6319943b10JesusFreke@JesusFreke.com            } else if (arrayBaseType == 'D') {
1594c308b24b6261ea81497a69e6d4d7ef6319943b10JesusFreke@JesusFreke.com                setWideDestinationRegisterTypeAndPropagateChanges(analyzedInstruction,
1595c308b24b6261ea81497a69e6d4d7ef6319943b10JesusFreke@JesusFreke.com                        RegisterType.getRegisterType(RegisterType.Category.DoubleLo, null));
1596c308b24b6261ea81497a69e6d4d7ef6319943b10JesusFreke@JesusFreke.com            } else {
1597c308b24b6261ea81497a69e6d4d7ef6319943b10JesusFreke@JesusFreke.com                throw new ValidationException(String.format("Cannot use aget-wide with array type %s. Incorrect " +
1598c308b24b6261ea81497a69e6d4d7ef6319943b10JesusFreke@JesusFreke.com                        "array type for the instruction.", arrayRegisterType.type.getClassType()));
1599c308b24b6261ea81497a69e6d4d7ef6319943b10JesusFreke@JesusFreke.com            }
1600c308b24b6261ea81497a69e6d4d7ef6319943b10JesusFreke@JesusFreke.com        } else {
1601c308b24b6261ea81497a69e6d4d7ef6319943b10JesusFreke@JesusFreke.com            setWideDestinationRegisterTypeAndPropagateChanges(analyzedInstruction,
1602c308b24b6261ea81497a69e6d4d7ef6319943b10JesusFreke@JesusFreke.com                        RegisterType.getRegisterType(RegisterType.Category.LongLo, null));
1603c308b24b6261ea81497a69e6d4d7ef6319943b10JesusFreke@JesusFreke.com        }
1604c308b24b6261ea81497a69e6d4d7ef6319943b10JesusFreke@JesusFreke.com
1605c308b24b6261ea81497a69e6d4d7ef6319943b10JesusFreke@JesusFreke.com        return true;
1606c308b24b6261ea81497a69e6d4d7ef6319943b10JesusFreke@JesusFreke.com    }
1607c308b24b6261ea81497a69e6d4d7ef6319943b10JesusFreke@JesusFreke.com
1608461a797324f0377db6cf06f680dec894b6f91204JesusFreke@JesusFreke.com    private boolean handleAgetObject(AnalyzedInstruction analyzedInstruction) {
1609461a797324f0377db6cf06f680dec894b6f91204JesusFreke@JesusFreke.com        ThreeRegisterInstruction instruction = (ThreeRegisterInstruction)analyzedInstruction.instruction;
1610461a797324f0377db6cf06f680dec894b6f91204JesusFreke@JesusFreke.com
1611461a797324f0377db6cf06f680dec894b6f91204JesusFreke@JesusFreke.com        RegisterType indexRegisterType = analyzedInstruction.getPreInstructionRegisterType(instruction.getRegisterC());
1612461a797324f0377db6cf06f680dec894b6f91204JesusFreke@JesusFreke.com        assert indexRegisterType != null;
1613461a797324f0377db6cf06f680dec894b6f91204JesusFreke@JesusFreke.com        if (indexRegisterType.category == RegisterType.Category.Unknown) {
1614461a797324f0377db6cf06f680dec894b6f91204JesusFreke@JesusFreke.com            return false;
1615461a797324f0377db6cf06f680dec894b6f91204JesusFreke@JesusFreke.com        }
1616461a797324f0377db6cf06f680dec894b6f91204JesusFreke@JesusFreke.com        checkRegister(indexRegisterType, Primitive32BitCategories);
1617461a797324f0377db6cf06f680dec894b6f91204JesusFreke@JesusFreke.com
1618461a797324f0377db6cf06f680dec894b6f91204JesusFreke@JesusFreke.com        RegisterType arrayRegisterType = analyzedInstruction.getPreInstructionRegisterType(instruction.getRegisterB());
1619461a797324f0377db6cf06f680dec894b6f91204JesusFreke@JesusFreke.com        assert arrayRegisterType != null;
1620461a797324f0377db6cf06f680dec894b6f91204JesusFreke@JesusFreke.com        if (indexRegisterType.category == RegisterType.Category.Unknown) {
1621461a797324f0377db6cf06f680dec894b6f91204JesusFreke@JesusFreke.com            return false;
1622461a797324f0377db6cf06f680dec894b6f91204JesusFreke@JesusFreke.com        }
1623461a797324f0377db6cf06f680dec894b6f91204JesusFreke@JesusFreke.com
1624461a797324f0377db6cf06f680dec894b6f91204JesusFreke@JesusFreke.com        if (arrayRegisterType.category != RegisterType.Category.Null) {
1625461a797324f0377db6cf06f680dec894b6f91204JesusFreke@JesusFreke.com            if (arrayRegisterType.category != RegisterType.Category.Reference) {
1626461a797324f0377db6cf06f680dec894b6f91204JesusFreke@JesusFreke.com                throw new ValidationException(String.format("Cannot use aget-object with non-array type %s",
1627461a797324f0377db6cf06f680dec894b6f91204JesusFreke@JesusFreke.com                        arrayRegisterType.category.toString()));
1628461a797324f0377db6cf06f680dec894b6f91204JesusFreke@JesusFreke.com            }
1629461a797324f0377db6cf06f680dec894b6f91204JesusFreke@JesusFreke.com
1630461a797324f0377db6cf06f680dec894b6f91204JesusFreke@JesusFreke.com            assert arrayRegisterType.type != null;
1631461a797324f0377db6cf06f680dec894b6f91204JesusFreke@JesusFreke.com            if (arrayRegisterType.type.getClassType().charAt(0) != '[') {
1632461a797324f0377db6cf06f680dec894b6f91204JesusFreke@JesusFreke.com                throw new ValidationException(String.format("Cannot use aget-object with non-array type %s",
1633461a797324f0377db6cf06f680dec894b6f91204JesusFreke@JesusFreke.com                        arrayRegisterType.type.getClassType()));
1634461a797324f0377db6cf06f680dec894b6f91204JesusFreke@JesusFreke.com            }
1635461a797324f0377db6cf06f680dec894b6f91204JesusFreke@JesusFreke.com
1636461a797324f0377db6cf06f680dec894b6f91204JesusFreke@JesusFreke.com            assert arrayRegisterType.type instanceof ClassPath.ArrayClassDef;
1637461a797324f0377db6cf06f680dec894b6f91204JesusFreke@JesusFreke.com            ClassPath.ArrayClassDef arrayClassDef = (ClassPath.ArrayClassDef)arrayRegisterType.type;
1638461a797324f0377db6cf06f680dec894b6f91204JesusFreke@JesusFreke.com
1639461a797324f0377db6cf06f680dec894b6f91204JesusFreke@JesusFreke.com            ClassPath.ClassDef elementClassDef = arrayClassDef.getImmediateElementClass();
1640461a797324f0377db6cf06f680dec894b6f91204JesusFreke@JesusFreke.com            char elementTypePrefix = elementClassDef.getClassType().charAt(0);
1641461a797324f0377db6cf06f680dec894b6f91204JesusFreke@JesusFreke.com            if (elementTypePrefix != 'L' && elementTypePrefix != '[') {
1642461a797324f0377db6cf06f680dec894b6f91204JesusFreke@JesusFreke.com                throw new ValidationException(String.format("Cannot use aget-object with array type %s. Incorrect " +
1643461a797324f0377db6cf06f680dec894b6f91204JesusFreke@JesusFreke.com                        "array type for the instruction.", arrayRegisterType.type.getClassType()));
1644461a797324f0377db6cf06f680dec894b6f91204JesusFreke@JesusFreke.com            }
1645461a797324f0377db6cf06f680dec894b6f91204JesusFreke@JesusFreke.com
1646461a797324f0377db6cf06f680dec894b6f91204JesusFreke@JesusFreke.com            setDestinationRegisterTypeAndPropagateChanges(analyzedInstruction,
1647461a797324f0377db6cf06f680dec894b6f91204JesusFreke@JesusFreke.com                    RegisterType.getRegisterType(RegisterType.Category.Reference, elementClassDef));
1648461a797324f0377db6cf06f680dec894b6f91204JesusFreke@JesusFreke.com        } else {
1649461a797324f0377db6cf06f680dec894b6f91204JesusFreke@JesusFreke.com            setDestinationRegisterTypeAndPropagateChanges(analyzedInstruction,
1650461a797324f0377db6cf06f680dec894b6f91204JesusFreke@JesusFreke.com                    RegisterType.getRegisterType(RegisterType.Category.Null, null));
1651461a797324f0377db6cf06f680dec894b6f91204JesusFreke@JesusFreke.com        }
1652461a797324f0377db6cf06f680dec894b6f91204JesusFreke@JesusFreke.com
1653461a797324f0377db6cf06f680dec894b6f91204JesusFreke@JesusFreke.com        return true;
1654461a797324f0377db6cf06f680dec894b6f91204JesusFreke@JesusFreke.com    }
1655461a797324f0377db6cf06f680dec894b6f91204JesusFreke@JesusFreke.com
1656c849236be2031b02d66eac4149617fd8a83572b4JesusFreke@JesusFreke.com    private boolean handle32BitPrimitiveAput(AnalyzedInstruction analyzedInstruction,
1657c849236be2031b02d66eac4149617fd8a83572b4JesusFreke@JesusFreke.com                                             RegisterType.Category instructionCategory) {
1658c849236be2031b02d66eac4149617fd8a83572b4JesusFreke@JesusFreke.com        ThreeRegisterInstruction instruction = (ThreeRegisterInstruction)analyzedInstruction.instruction;
1659c849236be2031b02d66eac4149617fd8a83572b4JesusFreke@JesusFreke.com
1660c849236be2031b02d66eac4149617fd8a83572b4JesusFreke@JesusFreke.com        RegisterType indexRegisterType = analyzedInstruction.getPreInstructionRegisterType(instruction.getRegisterC());
1661c849236be2031b02d66eac4149617fd8a83572b4JesusFreke@JesusFreke.com        assert indexRegisterType != null;
1662c849236be2031b02d66eac4149617fd8a83572b4JesusFreke@JesusFreke.com        if (indexRegisterType.category == RegisterType.Category.Unknown) {
1663c849236be2031b02d66eac4149617fd8a83572b4JesusFreke@JesusFreke.com            return false;
1664c849236be2031b02d66eac4149617fd8a83572b4JesusFreke@JesusFreke.com        }
1665c849236be2031b02d66eac4149617fd8a83572b4JesusFreke@JesusFreke.com        checkRegister(indexRegisterType, Primitive32BitCategories);
1666c849236be2031b02d66eac4149617fd8a83572b4JesusFreke@JesusFreke.com
1667c849236be2031b02d66eac4149617fd8a83572b4JesusFreke@JesusFreke.com
1668c849236be2031b02d66eac4149617fd8a83572b4JesusFreke@JesusFreke.com        RegisterType sourceRegisterType = analyzedInstruction.getPreInstructionRegisterType(instruction.getRegisterA());
1669c849236be2031b02d66eac4149617fd8a83572b4JesusFreke@JesusFreke.com        assert sourceRegisterType != null;
1670c849236be2031b02d66eac4149617fd8a83572b4JesusFreke@JesusFreke.com        if (sourceRegisterType.category == RegisterType.Category.Unknown) {
1671c849236be2031b02d66eac4149617fd8a83572b4JesusFreke@JesusFreke.com            return false;
1672c849236be2031b02d66eac4149617fd8a83572b4JesusFreke@JesusFreke.com        }
1673c849236be2031b02d66eac4149617fd8a83572b4JesusFreke@JesusFreke.com        RegisterType instructionRegisterType = RegisterType.getRegisterType(instructionCategory, null);
1674c849236be2031b02d66eac4149617fd8a83572b4JesusFreke@JesusFreke.com        if (!sourceRegisterType.canBeAssignedTo(instructionRegisterType)) {
1675c849236be2031b02d66eac4149617fd8a83572b4JesusFreke@JesusFreke.com            throw new ValidationException(String.format("Cannot use %s with source register type %s.",
1676c849236be2031b02d66eac4149617fd8a83572b4JesusFreke@JesusFreke.com                    analyzedInstruction.instruction.opcode.name, sourceRegisterType.toString()));
1677c849236be2031b02d66eac4149617fd8a83572b4JesusFreke@JesusFreke.com        }
1678c849236be2031b02d66eac4149617fd8a83572b4JesusFreke@JesusFreke.com
1679c849236be2031b02d66eac4149617fd8a83572b4JesusFreke@JesusFreke.com
1680c849236be2031b02d66eac4149617fd8a83572b4JesusFreke@JesusFreke.com        RegisterType arrayRegisterType = analyzedInstruction.getPreInstructionRegisterType(instruction.getRegisterB());
1681c849236be2031b02d66eac4149617fd8a83572b4JesusFreke@JesusFreke.com        assert arrayRegisterType != null;
1682c849236be2031b02d66eac4149617fd8a83572b4JesusFreke@JesusFreke.com        if (indexRegisterType.category == RegisterType.Category.Unknown) {
1683c849236be2031b02d66eac4149617fd8a83572b4JesusFreke@JesusFreke.com            return false;
1684c849236be2031b02d66eac4149617fd8a83572b4JesusFreke@JesusFreke.com        }
1685c849236be2031b02d66eac4149617fd8a83572b4JesusFreke@JesusFreke.com
1686c849236be2031b02d66eac4149617fd8a83572b4JesusFreke@JesusFreke.com        if (arrayRegisterType.category != RegisterType.Category.Null) {
1687c849236be2031b02d66eac4149617fd8a83572b4JesusFreke@JesusFreke.com            if (arrayRegisterType.category != RegisterType.Category.Reference) {
1688c849236be2031b02d66eac4149617fd8a83572b4JesusFreke@JesusFreke.com                throw new ValidationException(String.format("Cannot use %s with non-array type %s",
1689c849236be2031b02d66eac4149617fd8a83572b4JesusFreke@JesusFreke.com                        analyzedInstruction.instruction.opcode.name, arrayRegisterType.category.toString()));
1690c849236be2031b02d66eac4149617fd8a83572b4JesusFreke@JesusFreke.com            }
1691c849236be2031b02d66eac4149617fd8a83572b4JesusFreke@JesusFreke.com
1692c849236be2031b02d66eac4149617fd8a83572b4JesusFreke@JesusFreke.com            assert arrayRegisterType.type != null;
1693c849236be2031b02d66eac4149617fd8a83572b4JesusFreke@JesusFreke.com            if (arrayRegisterType.type.getClassType().charAt(0) != '[') {
1694c849236be2031b02d66eac4149617fd8a83572b4JesusFreke@JesusFreke.com                throw new ValidationException(String.format("Cannot use %s with non-array type %s",
1695c849236be2031b02d66eac4149617fd8a83572b4JesusFreke@JesusFreke.com                        analyzedInstruction.instruction.opcode.name, arrayRegisterType.type.getClassType()));
1696c849236be2031b02d66eac4149617fd8a83572b4JesusFreke@JesusFreke.com            }
1697c849236be2031b02d66eac4149617fd8a83572b4JesusFreke@JesusFreke.com
1698c849236be2031b02d66eac4149617fd8a83572b4JesusFreke@JesusFreke.com            assert arrayRegisterType.type instanceof ClassPath.ArrayClassDef;
1699c849236be2031b02d66eac4149617fd8a83572b4JesusFreke@JesusFreke.com            ClassPath.ArrayClassDef arrayClassDef = (ClassPath.ArrayClassDef)arrayRegisterType.type;
1700c849236be2031b02d66eac4149617fd8a83572b4JesusFreke@JesusFreke.com
1701c849236be2031b02d66eac4149617fd8a83572b4JesusFreke@JesusFreke.com            if (arrayClassDef.getArrayDimensions() != 1) {
1702c849236be2031b02d66eac4149617fd8a83572b4JesusFreke@JesusFreke.com                throw new ValidationException(String.format("Cannot use %s with multi-dimensional array type %s",
1703c849236be2031b02d66eac4149617fd8a83572b4JesusFreke@JesusFreke.com                        analyzedInstruction.instruction.opcode.name, arrayRegisterType.type.getClassType()));
1704c849236be2031b02d66eac4149617fd8a83572b4JesusFreke@JesusFreke.com            }
1705c849236be2031b02d66eac4149617fd8a83572b4JesusFreke@JesusFreke.com
1706c849236be2031b02d66eac4149617fd8a83572b4JesusFreke@JesusFreke.com            RegisterType arrayBaseType =
1707c849236be2031b02d66eac4149617fd8a83572b4JesusFreke@JesusFreke.com                    RegisterType.getRegisterTypeForType(arrayClassDef.getBaseElementClass().getClassType());
1708c849236be2031b02d66eac4149617fd8a83572b4JesusFreke@JesusFreke.com            if (checkArrayFieldAssignment(arrayBaseType.category, instructionCategory)) {
1709c849236be2031b02d66eac4149617fd8a83572b4JesusFreke@JesusFreke.com                throw new ValidationException(String.format("Cannot use %s with array type %s. Incorrect array type " +
1710c849236be2031b02d66eac4149617fd8a83572b4JesusFreke@JesusFreke.com                        "for the instruction.", analyzedInstruction.instruction.opcode.name,
1711c849236be2031b02d66eac4149617fd8a83572b4JesusFreke@JesusFreke.com                        arrayRegisterType.type.getClassType()));
171255d43e36eb862bf86ceaf9c664789ce2c4d92af8JesusFreke@JesusFreke.com            }
171355d43e36eb862bf86ceaf9c664789ce2c4d92af8JesusFreke@JesusFreke.com        }
171455d43e36eb862bf86ceaf9c664789ce2c4d92af8JesusFreke@JesusFreke.com
171555d43e36eb862bf86ceaf9c664789ce2c4d92af8JesusFreke@JesusFreke.com        return true;
171655d43e36eb862bf86ceaf9c664789ce2c4d92af8JesusFreke@JesusFreke.com    }
171755d43e36eb862bf86ceaf9c664789ce2c4d92af8JesusFreke@JesusFreke.com
171855d43e36eb862bf86ceaf9c664789ce2c4d92af8JesusFreke@JesusFreke.com    private boolean handleAputWide(AnalyzedInstruction analyzedInstruction) {
171955d43e36eb862bf86ceaf9c664789ce2c4d92af8JesusFreke@JesusFreke.com        ThreeRegisterInstruction instruction = (ThreeRegisterInstruction)analyzedInstruction.instruction;
172055d43e36eb862bf86ceaf9c664789ce2c4d92af8JesusFreke@JesusFreke.com
172155d43e36eb862bf86ceaf9c664789ce2c4d92af8JesusFreke@JesusFreke.com        RegisterType indexRegisterType = analyzedInstruction.getPreInstructionRegisterType(instruction.getRegisterC());
172255d43e36eb862bf86ceaf9c664789ce2c4d92af8JesusFreke@JesusFreke.com        assert indexRegisterType != null;
172355d43e36eb862bf86ceaf9c664789ce2c4d92af8JesusFreke@JesusFreke.com        if (indexRegisterType.category == RegisterType.Category.Unknown) {
172455d43e36eb862bf86ceaf9c664789ce2c4d92af8JesusFreke@JesusFreke.com            return false;
172555d43e36eb862bf86ceaf9c664789ce2c4d92af8JesusFreke@JesusFreke.com        }
172655d43e36eb862bf86ceaf9c664789ce2c4d92af8JesusFreke@JesusFreke.com        checkRegister(indexRegisterType, Primitive32BitCategories);
172755d43e36eb862bf86ceaf9c664789ce2c4d92af8JesusFreke@JesusFreke.com
172855d43e36eb862bf86ceaf9c664789ce2c4d92af8JesusFreke@JesusFreke.com        RegisterType sourceRegisterType = getAndCheckWideSourcePair(analyzedInstruction, instruction.getRegisterA());
172955d43e36eb862bf86ceaf9c664789ce2c4d92af8JesusFreke@JesusFreke.com        if (sourceRegisterType.category == RegisterType.Category.Unknown) {
173055d43e36eb862bf86ceaf9c664789ce2c4d92af8JesusFreke@JesusFreke.com            return false;
173155d43e36eb862bf86ceaf9c664789ce2c4d92af8JesusFreke@JesusFreke.com        }
173255d43e36eb862bf86ceaf9c664789ce2c4d92af8JesusFreke@JesusFreke.com
173355d43e36eb862bf86ceaf9c664789ce2c4d92af8JesusFreke@JesusFreke.com        RegisterType arrayRegisterType = analyzedInstruction.getPreInstructionRegisterType(instruction.getRegisterB());
173455d43e36eb862bf86ceaf9c664789ce2c4d92af8JesusFreke@JesusFreke.com        assert arrayRegisterType != null;
173555d43e36eb862bf86ceaf9c664789ce2c4d92af8JesusFreke@JesusFreke.com        if (indexRegisterType.category == RegisterType.Category.Unknown) {
173655d43e36eb862bf86ceaf9c664789ce2c4d92af8JesusFreke@JesusFreke.com            return false;
173755d43e36eb862bf86ceaf9c664789ce2c4d92af8JesusFreke@JesusFreke.com        }
173855d43e36eb862bf86ceaf9c664789ce2c4d92af8JesusFreke@JesusFreke.com
173955d43e36eb862bf86ceaf9c664789ce2c4d92af8JesusFreke@JesusFreke.com        if (arrayRegisterType.category != RegisterType.Category.Null) {
174055d43e36eb862bf86ceaf9c664789ce2c4d92af8JesusFreke@JesusFreke.com            if (arrayRegisterType.category != RegisterType.Category.Reference) {
174155d43e36eb862bf86ceaf9c664789ce2c4d92af8JesusFreke@JesusFreke.com                throw new ValidationException(String.format("Cannot use aput-wide with non-array type %s",
174255d43e36eb862bf86ceaf9c664789ce2c4d92af8JesusFreke@JesusFreke.com                        arrayRegisterType.category.toString()));
174355d43e36eb862bf86ceaf9c664789ce2c4d92af8JesusFreke@JesusFreke.com            }
174455d43e36eb862bf86ceaf9c664789ce2c4d92af8JesusFreke@JesusFreke.com
174555d43e36eb862bf86ceaf9c664789ce2c4d92af8JesusFreke@JesusFreke.com            assert arrayRegisterType.type != null;
174655d43e36eb862bf86ceaf9c664789ce2c4d92af8JesusFreke@JesusFreke.com            if (arrayRegisterType.type.getClassType().charAt(0) != '[') {
174755d43e36eb862bf86ceaf9c664789ce2c4d92af8JesusFreke@JesusFreke.com                throw new ValidationException(String.format("Cannot use aput-wide with non-array type %s",
174855d43e36eb862bf86ceaf9c664789ce2c4d92af8JesusFreke@JesusFreke.com                        arrayRegisterType.type.getClassType()));
174955d43e36eb862bf86ceaf9c664789ce2c4d92af8JesusFreke@JesusFreke.com            }
175055d43e36eb862bf86ceaf9c664789ce2c4d92af8JesusFreke@JesusFreke.com
175155d43e36eb862bf86ceaf9c664789ce2c4d92af8JesusFreke@JesusFreke.com            assert arrayRegisterType.type instanceof ClassPath.ArrayClassDef;
175255d43e36eb862bf86ceaf9c664789ce2c4d92af8JesusFreke@JesusFreke.com            ClassPath.ArrayClassDef arrayClassDef = (ClassPath.ArrayClassDef)arrayRegisterType.type;
175355d43e36eb862bf86ceaf9c664789ce2c4d92af8JesusFreke@JesusFreke.com
175455d43e36eb862bf86ceaf9c664789ce2c4d92af8JesusFreke@JesusFreke.com            if (arrayClassDef.getArrayDimensions() != 1) {
175555d43e36eb862bf86ceaf9c664789ce2c4d92af8JesusFreke@JesusFreke.com                throw new ValidationException(String.format("Cannot use aput-wide with multi-dimensional array type %s",
175655d43e36eb862bf86ceaf9c664789ce2c4d92af8JesusFreke@JesusFreke.com                        arrayRegisterType.type.getClassType()));
175755d43e36eb862bf86ceaf9c664789ce2c4d92af8JesusFreke@JesusFreke.com            }
175855d43e36eb862bf86ceaf9c664789ce2c4d92af8JesusFreke@JesusFreke.com
175955d43e36eb862bf86ceaf9c664789ce2c4d92af8JesusFreke@JesusFreke.com            char arrayBaseType = arrayClassDef.getBaseElementClass().getClassType().charAt(0);
176055d43e36eb862bf86ceaf9c664789ce2c4d92af8JesusFreke@JesusFreke.com            if (arrayBaseType != 'J' && arrayBaseType != 'D') {
176155d43e36eb862bf86ceaf9c664789ce2c4d92af8JesusFreke@JesusFreke.com                throw new ValidationException(String.format("Cannot use aput-wide with array type %s. Incorrect " +
176255d43e36eb862bf86ceaf9c664789ce2c4d92af8JesusFreke@JesusFreke.com                        "array type for the instruction.", arrayRegisterType.type.getClassType()));
1763898e750048326802a488623d1ebf475df9bca209JesusFreke@JesusFreke.com            }
1764898e750048326802a488623d1ebf475df9bca209JesusFreke@JesusFreke.com        }
1765898e750048326802a488623d1ebf475df9bca209JesusFreke@JesusFreke.com
1766898e750048326802a488623d1ebf475df9bca209JesusFreke@JesusFreke.com        return true;
1767898e750048326802a488623d1ebf475df9bca209JesusFreke@JesusFreke.com    }
1768898e750048326802a488623d1ebf475df9bca209JesusFreke@JesusFreke.com
1769898e750048326802a488623d1ebf475df9bca209JesusFreke@JesusFreke.com    private boolean handleAputObject(AnalyzedInstruction analyzedInstruction) {
1770898e750048326802a488623d1ebf475df9bca209JesusFreke@JesusFreke.com        ThreeRegisterInstruction instruction = (ThreeRegisterInstruction)analyzedInstruction.instruction;
1771898e750048326802a488623d1ebf475df9bca209JesusFreke@JesusFreke.com
1772898e750048326802a488623d1ebf475df9bca209JesusFreke@JesusFreke.com        RegisterType indexRegisterType = analyzedInstruction.getPreInstructionRegisterType(instruction.getRegisterC());
1773898e750048326802a488623d1ebf475df9bca209JesusFreke@JesusFreke.com        assert indexRegisterType != null;
1774898e750048326802a488623d1ebf475df9bca209JesusFreke@JesusFreke.com        if (indexRegisterType.category == RegisterType.Category.Unknown) {
1775898e750048326802a488623d1ebf475df9bca209JesusFreke@JesusFreke.com            return false;
1776898e750048326802a488623d1ebf475df9bca209JesusFreke@JesusFreke.com        }
1777898e750048326802a488623d1ebf475df9bca209JesusFreke@JesusFreke.com        checkRegister(indexRegisterType, Primitive32BitCategories);
1778898e750048326802a488623d1ebf475df9bca209JesusFreke@JesusFreke.com
1779898e750048326802a488623d1ebf475df9bca209JesusFreke@JesusFreke.com        RegisterType sourceRegisterType = analyzedInstruction.getPreInstructionRegisterType(instruction.getRegisterA());
1780898e750048326802a488623d1ebf475df9bca209JesusFreke@JesusFreke.com        assert sourceRegisterType != null;
1781898e750048326802a488623d1ebf475df9bca209JesusFreke@JesusFreke.com        if (sourceRegisterType.category == RegisterType.Category.Unknown) {
1782898e750048326802a488623d1ebf475df9bca209JesusFreke@JesusFreke.com            return false;
1783898e750048326802a488623d1ebf475df9bca209JesusFreke@JesusFreke.com        }
17846d11e9062dfaa27c7fa8719d9d9b4f58b0d5cfa0JesusFreke@JesusFreke.com        //TODO: ensure sourceRegisterType is a Reference type?
1785898e750048326802a488623d1ebf475df9bca209JesusFreke@JesusFreke.com
1786898e750048326802a488623d1ebf475df9bca209JesusFreke@JesusFreke.com        RegisterType arrayRegisterType = analyzedInstruction.getPreInstructionRegisterType(instruction.getRegisterB());
1787898e750048326802a488623d1ebf475df9bca209JesusFreke@JesusFreke.com        assert arrayRegisterType != null;
1788898e750048326802a488623d1ebf475df9bca209JesusFreke@JesusFreke.com        if (indexRegisterType.category == RegisterType.Category.Unknown) {
1789898e750048326802a488623d1ebf475df9bca209JesusFreke@JesusFreke.com            return false;
1790898e750048326802a488623d1ebf475df9bca209JesusFreke@JesusFreke.com        }
1791898e750048326802a488623d1ebf475df9bca209JesusFreke@JesusFreke.com
1792898e750048326802a488623d1ebf475df9bca209JesusFreke@JesusFreke.com        if (arrayRegisterType.category != RegisterType.Category.Null) {
1793898e750048326802a488623d1ebf475df9bca209JesusFreke@JesusFreke.com            //don't check the source type against the array type, just make sure it is an array of reference types
1794898e750048326802a488623d1ebf475df9bca209JesusFreke@JesusFreke.com
1795898e750048326802a488623d1ebf475df9bca209JesusFreke@JesusFreke.com            if (arrayRegisterType.category != RegisterType.Category.Reference) {
1796898e750048326802a488623d1ebf475df9bca209JesusFreke@JesusFreke.com                throw new ValidationException(String.format("Cannot use aget-object with non-array type %s",
1797898e750048326802a488623d1ebf475df9bca209JesusFreke@JesusFreke.com                        arrayRegisterType.category.toString()));
1798898e750048326802a488623d1ebf475df9bca209JesusFreke@JesusFreke.com            }
1799898e750048326802a488623d1ebf475df9bca209JesusFreke@JesusFreke.com
1800898e750048326802a488623d1ebf475df9bca209JesusFreke@JesusFreke.com            assert arrayRegisterType.type != null;
1801898e750048326802a488623d1ebf475df9bca209JesusFreke@JesusFreke.com            if (arrayRegisterType.type.getClassType().charAt(0) != '[') {
1802898e750048326802a488623d1ebf475df9bca209JesusFreke@JesusFreke.com                throw new ValidationException(String.format("Cannot use aget-object with non-array type %s",
1803898e750048326802a488623d1ebf475df9bca209JesusFreke@JesusFreke.com                        arrayRegisterType.type.getClassType()));
1804898e750048326802a488623d1ebf475df9bca209JesusFreke@JesusFreke.com            }
1805898e750048326802a488623d1ebf475df9bca209JesusFreke@JesusFreke.com
1806898e750048326802a488623d1ebf475df9bca209JesusFreke@JesusFreke.com            assert arrayRegisterType.type instanceof ClassPath.ArrayClassDef;
1807898e750048326802a488623d1ebf475df9bca209JesusFreke@JesusFreke.com            ClassPath.ArrayClassDef arrayClassDef = (ClassPath.ArrayClassDef)arrayRegisterType.type;
1808898e750048326802a488623d1ebf475df9bca209JesusFreke@JesusFreke.com
1809898e750048326802a488623d1ebf475df9bca209JesusFreke@JesusFreke.com            ClassPath.ClassDef elementClassDef = arrayClassDef.getImmediateElementClass();
1810898e750048326802a488623d1ebf475df9bca209JesusFreke@JesusFreke.com            char elementTypePrefix = elementClassDef.getClassType().charAt(0);
1811898e750048326802a488623d1ebf475df9bca209JesusFreke@JesusFreke.com            if (elementTypePrefix != 'L' && elementTypePrefix != '[') {
1812898e750048326802a488623d1ebf475df9bca209JesusFreke@JesusFreke.com                throw new ValidationException(String.format("Cannot use aget-object with array type %s. Incorrect " +
1813898e750048326802a488623d1ebf475df9bca209JesusFreke@JesusFreke.com                        "array type for the instruction.", arrayRegisterType.type.getClassType()));
1814c849236be2031b02d66eac4149617fd8a83572b4JesusFreke@JesusFreke.com            }
1815c849236be2031b02d66eac4149617fd8a83572b4JesusFreke@JesusFreke.com        }
1816c849236be2031b02d66eac4149617fd8a83572b4JesusFreke@JesusFreke.com
1817c849236be2031b02d66eac4149617fd8a83572b4JesusFreke@JesusFreke.com        return true;
1818c849236be2031b02d66eac4149617fd8a83572b4JesusFreke@JesusFreke.com    }
1819c849236be2031b02d66eac4149617fd8a83572b4JesusFreke@JesusFreke.com
18204f84e8f9e9bf4c74cbb2fc083d16ecb4fe0ec501JesusFreke@JesusFreke.com    private boolean handle32BitPrimitiveIget(AnalyzedInstruction analyzedInstruction,
18214f84e8f9e9bf4c74cbb2fc083d16ecb4fe0ec501JesusFreke@JesusFreke.com                                             RegisterType.Category instructionCategory) {
18224f84e8f9e9bf4c74cbb2fc083d16ecb4fe0ec501JesusFreke@JesusFreke.com        TwoRegisterInstruction instruction = (TwoRegisterInstruction)analyzedInstruction.instruction;
18234f84e8f9e9bf4c74cbb2fc083d16ecb4fe0ec501JesusFreke@JesusFreke.com
18244f84e8f9e9bf4c74cbb2fc083d16ecb4fe0ec501JesusFreke@JesusFreke.com        RegisterType objectRegisterType = analyzedInstruction.getPreInstructionRegisterType(instruction.getRegisterB());
18254f84e8f9e9bf4c74cbb2fc083d16ecb4fe0ec501JesusFreke@JesusFreke.com        assert objectRegisterType != null;
18264f84e8f9e9bf4c74cbb2fc083d16ecb4fe0ec501JesusFreke@JesusFreke.com        if (objectRegisterType.category == RegisterType.Category.Unknown) {
18274f84e8f9e9bf4c74cbb2fc083d16ecb4fe0ec501JesusFreke@JesusFreke.com            return false;
18284f84e8f9e9bf4c74cbb2fc083d16ecb4fe0ec501JesusFreke@JesusFreke.com        }
18294f84e8f9e9bf4c74cbb2fc083d16ecb4fe0ec501JesusFreke@JesusFreke.com        checkRegister(objectRegisterType, ReferenceCategories);
18304f84e8f9e9bf4c74cbb2fc083d16ecb4fe0ec501JesusFreke@JesusFreke.com
18314f84e8f9e9bf4c74cbb2fc083d16ecb4fe0ec501JesusFreke@JesusFreke.com        //TODO: check access
18324f84e8f9e9bf4c74cbb2fc083d16ecb4fe0ec501JesusFreke@JesusFreke.com        //TODO: allow an uninitialized "this" reference, if the current method is an <init> method
18334f84e8f9e9bf4c74cbb2fc083d16ecb4fe0ec501JesusFreke@JesusFreke.com        Item referencedItem = ((InstructionWithReference)analyzedInstruction.instruction).getReferencedItem();
18344f84e8f9e9bf4c74cbb2fc083d16ecb4fe0ec501JesusFreke@JesusFreke.com        assert referencedItem instanceof FieldIdItem;
18354f84e8f9e9bf4c74cbb2fc083d16ecb4fe0ec501JesusFreke@JesusFreke.com        FieldIdItem field = (FieldIdItem)referencedItem;
18364f84e8f9e9bf4c74cbb2fc083d16ecb4fe0ec501JesusFreke@JesusFreke.com
18374f84e8f9e9bf4c74cbb2fc083d16ecb4fe0ec501JesusFreke@JesusFreke.com        if (objectRegisterType.category != RegisterType.Category.Null &&
18384f84e8f9e9bf4c74cbb2fc083d16ecb4fe0ec501JesusFreke@JesusFreke.com            !objectRegisterType.type.extendsClass(ClassPath.getClassDef(field.getContainingClass()))) {
18394f84e8f9e9bf4c74cbb2fc083d16ecb4fe0ec501JesusFreke@JesusFreke.com            throw new ValidationException(String.format("Cannot access field %s through type %s",
18404f84e8f9e9bf4c74cbb2fc083d16ecb4fe0ec501JesusFreke@JesusFreke.com                    field.getFieldString(), objectRegisterType.type.getClassType()));
18414f84e8f9e9bf4c74cbb2fc083d16ecb4fe0ec501JesusFreke@JesusFreke.com        }
18424f84e8f9e9bf4c74cbb2fc083d16ecb4fe0ec501JesusFreke@JesusFreke.com
18434f84e8f9e9bf4c74cbb2fc083d16ecb4fe0ec501JesusFreke@JesusFreke.com        RegisterType fieldType = RegisterType.getRegisterTypeForTypeIdItem(field.getFieldType());
18444f84e8f9e9bf4c74cbb2fc083d16ecb4fe0ec501JesusFreke@JesusFreke.com
18454f84e8f9e9bf4c74cbb2fc083d16ecb4fe0ec501JesusFreke@JesusFreke.com        if (!checkArrayFieldAssignment(fieldType.category, instructionCategory)) {
18464f84e8f9e9bf4c74cbb2fc083d16ecb4fe0ec501JesusFreke@JesusFreke.com                throw new ValidationException(String.format("Cannot use %s with field %s. Incorrect field type " +
18474f84e8f9e9bf4c74cbb2fc083d16ecb4fe0ec501JesusFreke@JesusFreke.com                        "for the instruction.", analyzedInstruction.instruction.opcode.name,
18484f84e8f9e9bf4c74cbb2fc083d16ecb4fe0ec501JesusFreke@JesusFreke.com                        field.getFieldString()));
18494f84e8f9e9bf4c74cbb2fc083d16ecb4fe0ec501JesusFreke@JesusFreke.com        }
18504f84e8f9e9bf4c74cbb2fc083d16ecb4fe0ec501JesusFreke@JesusFreke.com
18514f84e8f9e9bf4c74cbb2fc083d16ecb4fe0ec501JesusFreke@JesusFreke.com        setDestinationRegisterTypeAndPropagateChanges(analyzedInstruction,
18524f84e8f9e9bf4c74cbb2fc083d16ecb4fe0ec501JesusFreke@JesusFreke.com                RegisterType.getRegisterType(instructionCategory, null));
18534f84e8f9e9bf4c74cbb2fc083d16ecb4fe0ec501JesusFreke@JesusFreke.com
18544f84e8f9e9bf4c74cbb2fc083d16ecb4fe0ec501JesusFreke@JesusFreke.com        return true;
18554f84e8f9e9bf4c74cbb2fc083d16ecb4fe0ec501JesusFreke@JesusFreke.com    }
18564f84e8f9e9bf4c74cbb2fc083d16ecb4fe0ec501JesusFreke@JesusFreke.com
18579d92fd3748eab8f23502dc11aff06e6e7d29d1f3JesusFreke@JesusFreke.com    private boolean handleIgetWide(AnalyzedInstruction analyzedInstruction) {
18589d92fd3748eab8f23502dc11aff06e6e7d29d1f3JesusFreke@JesusFreke.com        TwoRegisterInstruction instruction = (TwoRegisterInstruction)analyzedInstruction.instruction;
18599d92fd3748eab8f23502dc11aff06e6e7d29d1f3JesusFreke@JesusFreke.com
18609d92fd3748eab8f23502dc11aff06e6e7d29d1f3JesusFreke@JesusFreke.com        RegisterType objectRegisterType = analyzedInstruction.getPreInstructionRegisterType(instruction.getRegisterB());
18619d92fd3748eab8f23502dc11aff06e6e7d29d1f3JesusFreke@JesusFreke.com        assert objectRegisterType != null;
18629d92fd3748eab8f23502dc11aff06e6e7d29d1f3JesusFreke@JesusFreke.com        if (objectRegisterType.category == RegisterType.Category.Unknown) {
18639d92fd3748eab8f23502dc11aff06e6e7d29d1f3JesusFreke@JesusFreke.com            return false;
18649d92fd3748eab8f23502dc11aff06e6e7d29d1f3JesusFreke@JesusFreke.com        }
18659d92fd3748eab8f23502dc11aff06e6e7d29d1f3JesusFreke@JesusFreke.com        checkRegister(objectRegisterType, ReferenceCategories);
18669d92fd3748eab8f23502dc11aff06e6e7d29d1f3JesusFreke@JesusFreke.com
18679d92fd3748eab8f23502dc11aff06e6e7d29d1f3JesusFreke@JesusFreke.com        getAndCheckWideSourcePair(analyzedInstruction, instruction.getRegisterB());
18689d92fd3748eab8f23502dc11aff06e6e7d29d1f3JesusFreke@JesusFreke.com
18699d92fd3748eab8f23502dc11aff06e6e7d29d1f3JesusFreke@JesusFreke.com        //TODO: check access
18709d92fd3748eab8f23502dc11aff06e6e7d29d1f3JesusFreke@JesusFreke.com        //TODO: allow an uninitialized "this" reference, if the current method is an <init> method
18719d92fd3748eab8f23502dc11aff06e6e7d29d1f3JesusFreke@JesusFreke.com        Item referencedItem = ((InstructionWithReference)analyzedInstruction.instruction).getReferencedItem();
18729d92fd3748eab8f23502dc11aff06e6e7d29d1f3JesusFreke@JesusFreke.com        assert referencedItem instanceof FieldIdItem;
18739d92fd3748eab8f23502dc11aff06e6e7d29d1f3JesusFreke@JesusFreke.com        FieldIdItem field = (FieldIdItem)referencedItem;
18749d92fd3748eab8f23502dc11aff06e6e7d29d1f3JesusFreke@JesusFreke.com
18759d92fd3748eab8f23502dc11aff06e6e7d29d1f3JesusFreke@JesusFreke.com        if (objectRegisterType.category != RegisterType.Category.Null &&
18769d92fd3748eab8f23502dc11aff06e6e7d29d1f3JesusFreke@JesusFreke.com            !objectRegisterType.type.extendsClass(ClassPath.getClassDef(field.getContainingClass()))) {
18779d92fd3748eab8f23502dc11aff06e6e7d29d1f3JesusFreke@JesusFreke.com            throw new ValidationException(String.format("Cannot access field %s through type %s",
18789d92fd3748eab8f23502dc11aff06e6e7d29d1f3JesusFreke@JesusFreke.com                    field.getFieldString(), objectRegisterType.type.getClassType()));
18799d92fd3748eab8f23502dc11aff06e6e7d29d1f3JesusFreke@JesusFreke.com        }
18809d92fd3748eab8f23502dc11aff06e6e7d29d1f3JesusFreke@JesusFreke.com
18819d92fd3748eab8f23502dc11aff06e6e7d29d1f3JesusFreke@JesusFreke.com        RegisterType fieldType = RegisterType.getRegisterTypeForTypeIdItem(field.getFieldType());
18829d92fd3748eab8f23502dc11aff06e6e7d29d1f3JesusFreke@JesusFreke.com
18839d92fd3748eab8f23502dc11aff06e6e7d29d1f3JesusFreke@JesusFreke.com        try {
18849d92fd3748eab8f23502dc11aff06e6e7d29d1f3JesusFreke@JesusFreke.com            checkRegister(fieldType, WideLowCategories);
18859d92fd3748eab8f23502dc11aff06e6e7d29d1f3JesusFreke@JesusFreke.com        } catch (ValidationException ex) {
18869d92fd3748eab8f23502dc11aff06e6e7d29d1f3JesusFreke@JesusFreke.com            throw new ValidationException(String.format("Cannot use %s with field %s. Incorrect field type " +
18879d92fd3748eab8f23502dc11aff06e6e7d29d1f3JesusFreke@JesusFreke.com                        "for the instruction.", analyzedInstruction.instruction.opcode.name,
18889d92fd3748eab8f23502dc11aff06e6e7d29d1f3JesusFreke@JesusFreke.com                        field.getFieldString()));
18899d92fd3748eab8f23502dc11aff06e6e7d29d1f3JesusFreke@JesusFreke.com        }
18909d92fd3748eab8f23502dc11aff06e6e7d29d1f3JesusFreke@JesusFreke.com
18919d92fd3748eab8f23502dc11aff06e6e7d29d1f3JesusFreke@JesusFreke.com        setWideDestinationRegisterTypeAndPropagateChanges(analyzedInstruction, fieldType);
18927a58f2434a2d906735ce585064d0fa46003c460dJesusFreke@JesusFreke.com
18937a58f2434a2d906735ce585064d0fa46003c460dJesusFreke@JesusFreke.com        return true;
18947a58f2434a2d906735ce585064d0fa46003c460dJesusFreke@JesusFreke.com    }
18957a58f2434a2d906735ce585064d0fa46003c460dJesusFreke@JesusFreke.com
18967a58f2434a2d906735ce585064d0fa46003c460dJesusFreke@JesusFreke.com    private boolean handleIgetObject(AnalyzedInstruction analyzedInstruction) {
18977a58f2434a2d906735ce585064d0fa46003c460dJesusFreke@JesusFreke.com        TwoRegisterInstruction instruction = (TwoRegisterInstruction)analyzedInstruction.instruction;
18987a58f2434a2d906735ce585064d0fa46003c460dJesusFreke@JesusFreke.com
18997a58f2434a2d906735ce585064d0fa46003c460dJesusFreke@JesusFreke.com        RegisterType objectRegisterType = analyzedInstruction.getPreInstructionRegisterType(instruction.getRegisterB());
19007a58f2434a2d906735ce585064d0fa46003c460dJesusFreke@JesusFreke.com        assert objectRegisterType != null;
19017a58f2434a2d906735ce585064d0fa46003c460dJesusFreke@JesusFreke.com        if (objectRegisterType.category == RegisterType.Category.Unknown) {
19027a58f2434a2d906735ce585064d0fa46003c460dJesusFreke@JesusFreke.com            return false;
19037a58f2434a2d906735ce585064d0fa46003c460dJesusFreke@JesusFreke.com        }
19047a58f2434a2d906735ce585064d0fa46003c460dJesusFreke@JesusFreke.com        checkRegister(objectRegisterType, ReferenceCategories);
19057a58f2434a2d906735ce585064d0fa46003c460dJesusFreke@JesusFreke.com
19067a58f2434a2d906735ce585064d0fa46003c460dJesusFreke@JesusFreke.com        //TODO: check access
19077a58f2434a2d906735ce585064d0fa46003c460dJesusFreke@JesusFreke.com        //TODO: allow an uninitialized "this" reference, if the current method is an <init> method
19087a58f2434a2d906735ce585064d0fa46003c460dJesusFreke@JesusFreke.com        Item referencedItem = ((InstructionWithReference)analyzedInstruction.instruction).getReferencedItem();
19097a58f2434a2d906735ce585064d0fa46003c460dJesusFreke@JesusFreke.com        assert referencedItem instanceof FieldIdItem;
19107a58f2434a2d906735ce585064d0fa46003c460dJesusFreke@JesusFreke.com        FieldIdItem field = (FieldIdItem)referencedItem;
19117a58f2434a2d906735ce585064d0fa46003c460dJesusFreke@JesusFreke.com
19127a58f2434a2d906735ce585064d0fa46003c460dJesusFreke@JesusFreke.com        if (objectRegisterType.category != RegisterType.Category.Null &&
19137a58f2434a2d906735ce585064d0fa46003c460dJesusFreke@JesusFreke.com            !objectRegisterType.type.extendsClass(ClassPath.getClassDef(field.getContainingClass()))) {
19147a58f2434a2d906735ce585064d0fa46003c460dJesusFreke@JesusFreke.com            throw new ValidationException(String.format("Cannot access field %s through type %s",
19157a58f2434a2d906735ce585064d0fa46003c460dJesusFreke@JesusFreke.com                    field.getFieldString(), objectRegisterType.type.getClassType()));
19167a58f2434a2d906735ce585064d0fa46003c460dJesusFreke@JesusFreke.com        }
19177a58f2434a2d906735ce585064d0fa46003c460dJesusFreke@JesusFreke.com
19187a58f2434a2d906735ce585064d0fa46003c460dJesusFreke@JesusFreke.com        RegisterType fieldType = RegisterType.getRegisterTypeForTypeIdItem(field.getFieldType());
19197a58f2434a2d906735ce585064d0fa46003c460dJesusFreke@JesusFreke.com
19207a58f2434a2d906735ce585064d0fa46003c460dJesusFreke@JesusFreke.com        if (fieldType.category != RegisterType.Category.Reference) {
19217a58f2434a2d906735ce585064d0fa46003c460dJesusFreke@JesusFreke.com            throw new ValidationException(String.format("Cannot use %s with field %s. Incorrect field type " +
19227a58f2434a2d906735ce585064d0fa46003c460dJesusFreke@JesusFreke.com                        "for the instruction.", analyzedInstruction.instruction.opcode.name,
19237a58f2434a2d906735ce585064d0fa46003c460dJesusFreke@JesusFreke.com                        field.getFieldString()));
19247a58f2434a2d906735ce585064d0fa46003c460dJesusFreke@JesusFreke.com        }
19257a58f2434a2d906735ce585064d0fa46003c460dJesusFreke@JesusFreke.com
19267a58f2434a2d906735ce585064d0fa46003c460dJesusFreke@JesusFreke.com        setDestinationRegisterTypeAndPropagateChanges(analyzedInstruction, fieldType);
19279d92fd3748eab8f23502dc11aff06e6e7d29d1f3JesusFreke@JesusFreke.com
19289d92fd3748eab8f23502dc11aff06e6e7d29d1f3JesusFreke@JesusFreke.com        return true;
19299d92fd3748eab8f23502dc11aff06e6e7d29d1f3JesusFreke@JesusFreke.com    }
19309d92fd3748eab8f23502dc11aff06e6e7d29d1f3JesusFreke@JesusFreke.com
19319971346f4ce431e103c900cfdc14299ea25c685dJesusFreke@JesusFreke.com    private boolean handle32BitPrimitiveIput(AnalyzedInstruction analyzedInstruction,
19329971346f4ce431e103c900cfdc14299ea25c685dJesusFreke@JesusFreke.com                                             RegisterType.Category instructionCategory) {
19339971346f4ce431e103c900cfdc14299ea25c685dJesusFreke@JesusFreke.com        TwoRegisterInstruction instruction = (TwoRegisterInstruction)analyzedInstruction.instruction;
19349971346f4ce431e103c900cfdc14299ea25c685dJesusFreke@JesusFreke.com
19359971346f4ce431e103c900cfdc14299ea25c685dJesusFreke@JesusFreke.com        RegisterType objectRegisterType = analyzedInstruction.getPreInstructionRegisterType(instruction.getRegisterB());
19369971346f4ce431e103c900cfdc14299ea25c685dJesusFreke@JesusFreke.com        assert objectRegisterType != null;
19379971346f4ce431e103c900cfdc14299ea25c685dJesusFreke@JesusFreke.com        if (objectRegisterType.category == RegisterType.Category.Unknown) {
19389971346f4ce431e103c900cfdc14299ea25c685dJesusFreke@JesusFreke.com            return false;
19399971346f4ce431e103c900cfdc14299ea25c685dJesusFreke@JesusFreke.com        }
19409971346f4ce431e103c900cfdc14299ea25c685dJesusFreke@JesusFreke.com        checkRegister(objectRegisterType, ReferenceCategories);
19419971346f4ce431e103c900cfdc14299ea25c685dJesusFreke@JesusFreke.com
19429971346f4ce431e103c900cfdc14299ea25c685dJesusFreke@JesusFreke.com        RegisterType sourceRegisterType = analyzedInstruction.getPreInstructionRegisterType(instruction.getRegisterA());
19439971346f4ce431e103c900cfdc14299ea25c685dJesusFreke@JesusFreke.com        assert sourceRegisterType != null;
19449971346f4ce431e103c900cfdc14299ea25c685dJesusFreke@JesusFreke.com        if (sourceRegisterType.category == RegisterType.Category.Unknown) {
19459971346f4ce431e103c900cfdc14299ea25c685dJesusFreke@JesusFreke.com            return false;
19469971346f4ce431e103c900cfdc14299ea25c685dJesusFreke@JesusFreke.com        }
19479971346f4ce431e103c900cfdc14299ea25c685dJesusFreke@JesusFreke.com
19489971346f4ce431e103c900cfdc14299ea25c685dJesusFreke@JesusFreke.com        //per CodeVerify.c in dalvik:
19499971346f4ce431e103c900cfdc14299ea25c685dJesusFreke@JesusFreke.com        //java generates synthetic functions that write byte values into boolean fields
19509971346f4ce431e103c900cfdc14299ea25c685dJesusFreke@JesusFreke.com        if (sourceRegisterType.category == RegisterType.Category.Byte &&
19519971346f4ce431e103c900cfdc14299ea25c685dJesusFreke@JesusFreke.com            instructionCategory == RegisterType.Category.Boolean) {
19529971346f4ce431e103c900cfdc14299ea25c685dJesusFreke@JesusFreke.com
19539971346f4ce431e103c900cfdc14299ea25c685dJesusFreke@JesusFreke.com            sourceRegisterType = RegisterType.getRegisterType(RegisterType.Category.Boolean, null);
19549971346f4ce431e103c900cfdc14299ea25c685dJesusFreke@JesusFreke.com        }
19559971346f4ce431e103c900cfdc14299ea25c685dJesusFreke@JesusFreke.com
19569971346f4ce431e103c900cfdc14299ea25c685dJesusFreke@JesusFreke.com        RegisterType instructionRegisterType = RegisterType.getRegisterType(instructionCategory, null);
19579971346f4ce431e103c900cfdc14299ea25c685dJesusFreke@JesusFreke.com        if (!sourceRegisterType.canBeAssignedTo(instructionRegisterType)) {
19589971346f4ce431e103c900cfdc14299ea25c685dJesusFreke@JesusFreke.com            throw new ValidationException(String.format("Cannot use %s with source register type %s.",
19599971346f4ce431e103c900cfdc14299ea25c685dJesusFreke@JesusFreke.com                    analyzedInstruction.instruction.opcode.name, sourceRegisterType.toString()));
19609971346f4ce431e103c900cfdc14299ea25c685dJesusFreke@JesusFreke.com        }
19619971346f4ce431e103c900cfdc14299ea25c685dJesusFreke@JesusFreke.com
19629971346f4ce431e103c900cfdc14299ea25c685dJesusFreke@JesusFreke.com
19639971346f4ce431e103c900cfdc14299ea25c685dJesusFreke@JesusFreke.com        //TODO: check access
19649971346f4ce431e103c900cfdc14299ea25c685dJesusFreke@JesusFreke.com        //TODO: allow an uninitialized "this" reference, if the current method is an <init> method
19659971346f4ce431e103c900cfdc14299ea25c685dJesusFreke@JesusFreke.com        Item referencedItem = ((InstructionWithReference)analyzedInstruction.instruction).getReferencedItem();
19669971346f4ce431e103c900cfdc14299ea25c685dJesusFreke@JesusFreke.com        assert referencedItem instanceof FieldIdItem;
19679971346f4ce431e103c900cfdc14299ea25c685dJesusFreke@JesusFreke.com        FieldIdItem field = (FieldIdItem)referencedItem;
19689971346f4ce431e103c900cfdc14299ea25c685dJesusFreke@JesusFreke.com
19699971346f4ce431e103c900cfdc14299ea25c685dJesusFreke@JesusFreke.com        if (objectRegisterType.category != RegisterType.Category.Null &&
19709971346f4ce431e103c900cfdc14299ea25c685dJesusFreke@JesusFreke.com            !objectRegisterType.type.extendsClass(ClassPath.getClassDef(field.getContainingClass()))) {
19719971346f4ce431e103c900cfdc14299ea25c685dJesusFreke@JesusFreke.com            throw new ValidationException(String.format("Cannot access field %s through type %s",
19729971346f4ce431e103c900cfdc14299ea25c685dJesusFreke@JesusFreke.com                    field.getFieldString(), objectRegisterType.type.getClassType()));
19739971346f4ce431e103c900cfdc14299ea25c685dJesusFreke@JesusFreke.com        }
19749971346f4ce431e103c900cfdc14299ea25c685dJesusFreke@JesusFreke.com
19759971346f4ce431e103c900cfdc14299ea25c685dJesusFreke@JesusFreke.com        RegisterType fieldType = RegisterType.getRegisterTypeForTypeIdItem(field.getFieldType());
19769971346f4ce431e103c900cfdc14299ea25c685dJesusFreke@JesusFreke.com
19779971346f4ce431e103c900cfdc14299ea25c685dJesusFreke@JesusFreke.com        if (!checkArrayFieldAssignment(fieldType.category, instructionCategory)) {
19789971346f4ce431e103c900cfdc14299ea25c685dJesusFreke@JesusFreke.com                throw new ValidationException(String.format("Cannot use %s with field %s. Incorrect field type " +
19799971346f4ce431e103c900cfdc14299ea25c685dJesusFreke@JesusFreke.com                        "for the instruction.", analyzedInstruction.instruction.opcode.name,
19809971346f4ce431e103c900cfdc14299ea25c685dJesusFreke@JesusFreke.com                        field.getFieldString()));
19819971346f4ce431e103c900cfdc14299ea25c685dJesusFreke@JesusFreke.com        }
19829971346f4ce431e103c900cfdc14299ea25c685dJesusFreke@JesusFreke.com
19839971346f4ce431e103c900cfdc14299ea25c685dJesusFreke@JesusFreke.com        return true;
19849971346f4ce431e103c900cfdc14299ea25c685dJesusFreke@JesusFreke.com    }
19859971346f4ce431e103c900cfdc14299ea25c685dJesusFreke@JesusFreke.com
198692616c9f60a30b5d5ac423675db732cb2428ce79JesusFreke@JesusFreke.com    private boolean handleIputWide(AnalyzedInstruction analyzedInstruction) {
198792616c9f60a30b5d5ac423675db732cb2428ce79JesusFreke@JesusFreke.com        TwoRegisterInstruction instruction = (TwoRegisterInstruction)analyzedInstruction.instruction;
198892616c9f60a30b5d5ac423675db732cb2428ce79JesusFreke@JesusFreke.com
198992616c9f60a30b5d5ac423675db732cb2428ce79JesusFreke@JesusFreke.com        RegisterType objectRegisterType = analyzedInstruction.getPreInstructionRegisterType(instruction.getRegisterB());
199092616c9f60a30b5d5ac423675db732cb2428ce79JesusFreke@JesusFreke.com        assert objectRegisterType != null;
199192616c9f60a30b5d5ac423675db732cb2428ce79JesusFreke@JesusFreke.com        if (objectRegisterType.category == RegisterType.Category.Unknown) {
199292616c9f60a30b5d5ac423675db732cb2428ce79JesusFreke@JesusFreke.com            return false;
199392616c9f60a30b5d5ac423675db732cb2428ce79JesusFreke@JesusFreke.com        }
199492616c9f60a30b5d5ac423675db732cb2428ce79JesusFreke@JesusFreke.com        checkRegister(objectRegisterType, ReferenceCategories);
199592616c9f60a30b5d5ac423675db732cb2428ce79JesusFreke@JesusFreke.com
199692616c9f60a30b5d5ac423675db732cb2428ce79JesusFreke@JesusFreke.com        RegisterType sourceRegisterType = getAndCheckWideSourcePair(analyzedInstruction, instruction.getRegisterA());
199792616c9f60a30b5d5ac423675db732cb2428ce79JesusFreke@JesusFreke.com        assert sourceRegisterType != null;
199892616c9f60a30b5d5ac423675db732cb2428ce79JesusFreke@JesusFreke.com        if (sourceRegisterType.category == RegisterType.Category.Unknown) {
199992616c9f60a30b5d5ac423675db732cb2428ce79JesusFreke@JesusFreke.com            return false;
200092616c9f60a30b5d5ac423675db732cb2428ce79JesusFreke@JesusFreke.com        }
200192616c9f60a30b5d5ac423675db732cb2428ce79JesusFreke@JesusFreke.com
200292616c9f60a30b5d5ac423675db732cb2428ce79JesusFreke@JesusFreke.com        //TODO: check access
200392616c9f60a30b5d5ac423675db732cb2428ce79JesusFreke@JesusFreke.com        //TODO: allow an uninitialized "this" reference, if the current method is an <init> method
200492616c9f60a30b5d5ac423675db732cb2428ce79JesusFreke@JesusFreke.com        Item referencedItem = ((InstructionWithReference)analyzedInstruction.instruction).getReferencedItem();
200592616c9f60a30b5d5ac423675db732cb2428ce79JesusFreke@JesusFreke.com        assert referencedItem instanceof FieldIdItem;
200692616c9f60a30b5d5ac423675db732cb2428ce79JesusFreke@JesusFreke.com        FieldIdItem field = (FieldIdItem)referencedItem;
200792616c9f60a30b5d5ac423675db732cb2428ce79JesusFreke@JesusFreke.com
200892616c9f60a30b5d5ac423675db732cb2428ce79JesusFreke@JesusFreke.com        if (objectRegisterType.category != RegisterType.Category.Null &&
200992616c9f60a30b5d5ac423675db732cb2428ce79JesusFreke@JesusFreke.com                !objectRegisterType.type.extendsClass(ClassPath.getClassDef(field.getContainingClass()))) {
201092616c9f60a30b5d5ac423675db732cb2428ce79JesusFreke@JesusFreke.com            throw new ValidationException(String.format("Cannot access field %s through type %s",
201192616c9f60a30b5d5ac423675db732cb2428ce79JesusFreke@JesusFreke.com                    field.getFieldString(), objectRegisterType.type.getClassType()));
201292616c9f60a30b5d5ac423675db732cb2428ce79JesusFreke@JesusFreke.com        }
201392616c9f60a30b5d5ac423675db732cb2428ce79JesusFreke@JesusFreke.com
201492616c9f60a30b5d5ac423675db732cb2428ce79JesusFreke@JesusFreke.com        RegisterType fieldType = RegisterType.getRegisterTypeForTypeIdItem(field.getFieldType());
201592616c9f60a30b5d5ac423675db732cb2428ce79JesusFreke@JesusFreke.com
201692616c9f60a30b5d5ac423675db732cb2428ce79JesusFreke@JesusFreke.com        if (!WideLowCategories.contains(fieldType.category)) {
201792616c9f60a30b5d5ac423675db732cb2428ce79JesusFreke@JesusFreke.com            throw new ValidationException(String.format("Cannot use %s with field %s. Incorrect field type " +
201892616c9f60a30b5d5ac423675db732cb2428ce79JesusFreke@JesusFreke.com                    "for the instruction.", analyzedInstruction.instruction.opcode.name,
201992616c9f60a30b5d5ac423675db732cb2428ce79JesusFreke@JesusFreke.com                    field.getFieldString()));
202092616c9f60a30b5d5ac423675db732cb2428ce79JesusFreke@JesusFreke.com        }
202192616c9f60a30b5d5ac423675db732cb2428ce79JesusFreke@JesusFreke.com
202292616c9f60a30b5d5ac423675db732cb2428ce79JesusFreke@JesusFreke.com        return true;
202392616c9f60a30b5d5ac423675db732cb2428ce79JesusFreke@JesusFreke.com    }
202492616c9f60a30b5d5ac423675db732cb2428ce79JesusFreke@JesusFreke.com
202550ff6247416eff1a90edd1ebc222ac2cdc5c15cfJesusFreke@JesusFreke.com    private boolean handleIputObject(AnalyzedInstruction analyzedInstruction) {
202650ff6247416eff1a90edd1ebc222ac2cdc5c15cfJesusFreke@JesusFreke.com        TwoRegisterInstruction instruction = (TwoRegisterInstruction)analyzedInstruction.instruction;
202750ff6247416eff1a90edd1ebc222ac2cdc5c15cfJesusFreke@JesusFreke.com
202850ff6247416eff1a90edd1ebc222ac2cdc5c15cfJesusFreke@JesusFreke.com        RegisterType objectRegisterType = analyzedInstruction.getPreInstructionRegisterType(instruction.getRegisterB());
202950ff6247416eff1a90edd1ebc222ac2cdc5c15cfJesusFreke@JesusFreke.com        assert objectRegisterType != null;
203050ff6247416eff1a90edd1ebc222ac2cdc5c15cfJesusFreke@JesusFreke.com        if (objectRegisterType.category == RegisterType.Category.Unknown) {
203150ff6247416eff1a90edd1ebc222ac2cdc5c15cfJesusFreke@JesusFreke.com            return false;
203250ff6247416eff1a90edd1ebc222ac2cdc5c15cfJesusFreke@JesusFreke.com        }
203350ff6247416eff1a90edd1ebc222ac2cdc5c15cfJesusFreke@JesusFreke.com        checkRegister(objectRegisterType, ReferenceCategories);
203450ff6247416eff1a90edd1ebc222ac2cdc5c15cfJesusFreke@JesusFreke.com
203550ff6247416eff1a90edd1ebc222ac2cdc5c15cfJesusFreke@JesusFreke.com        RegisterType sourceRegisterType = analyzedInstruction.getPreInstructionRegisterType(instruction.getRegisterA());
203650ff6247416eff1a90edd1ebc222ac2cdc5c15cfJesusFreke@JesusFreke.com        assert sourceRegisterType != null;
203750ff6247416eff1a90edd1ebc222ac2cdc5c15cfJesusFreke@JesusFreke.com        if (sourceRegisterType.category == RegisterType.Category.Unknown) {
203850ff6247416eff1a90edd1ebc222ac2cdc5c15cfJesusFreke@JesusFreke.com            return false;
203950ff6247416eff1a90edd1ebc222ac2cdc5c15cfJesusFreke@JesusFreke.com        }
20406d11e9062dfaa27c7fa8719d9d9b4f58b0d5cfa0JesusFreke@JesusFreke.com        checkRegister(sourceRegisterType, ReferenceCategories);
204150ff6247416eff1a90edd1ebc222ac2cdc5c15cfJesusFreke@JesusFreke.com
204250ff6247416eff1a90edd1ebc222ac2cdc5c15cfJesusFreke@JesusFreke.com        //TODO: check access
204350ff6247416eff1a90edd1ebc222ac2cdc5c15cfJesusFreke@JesusFreke.com        //TODO: allow an uninitialized "this" reference, if the current method is an <init> method
204450ff6247416eff1a90edd1ebc222ac2cdc5c15cfJesusFreke@JesusFreke.com        Item referencedItem = ((InstructionWithReference)analyzedInstruction.instruction).getReferencedItem();
204550ff6247416eff1a90edd1ebc222ac2cdc5c15cfJesusFreke@JesusFreke.com        assert referencedItem instanceof FieldIdItem;
204650ff6247416eff1a90edd1ebc222ac2cdc5c15cfJesusFreke@JesusFreke.com        FieldIdItem field = (FieldIdItem)referencedItem;
204750ff6247416eff1a90edd1ebc222ac2cdc5c15cfJesusFreke@JesusFreke.com
204850ff6247416eff1a90edd1ebc222ac2cdc5c15cfJesusFreke@JesusFreke.com        if (objectRegisterType.category != RegisterType.Category.Null &&
204950ff6247416eff1a90edd1ebc222ac2cdc5c15cfJesusFreke@JesusFreke.com            !objectRegisterType.type.extendsClass(ClassPath.getClassDef(field.getContainingClass()))) {
205050ff6247416eff1a90edd1ebc222ac2cdc5c15cfJesusFreke@JesusFreke.com            throw new ValidationException(String.format("Cannot access field %s through type %s",
205150ff6247416eff1a90edd1ebc222ac2cdc5c15cfJesusFreke@JesusFreke.com                    field.getFieldString(), objectRegisterType.type.getClassType()));
205250ff6247416eff1a90edd1ebc222ac2cdc5c15cfJesusFreke@JesusFreke.com        }
205350ff6247416eff1a90edd1ebc222ac2cdc5c15cfJesusFreke@JesusFreke.com
205450ff6247416eff1a90edd1ebc222ac2cdc5c15cfJesusFreke@JesusFreke.com        RegisterType fieldType = RegisterType.getRegisterTypeForTypeIdItem(field.getFieldType());
205550ff6247416eff1a90edd1ebc222ac2cdc5c15cfJesusFreke@JesusFreke.com
205650ff6247416eff1a90edd1ebc222ac2cdc5c15cfJesusFreke@JesusFreke.com        if (fieldType.category != RegisterType.Category.Reference) {
205750ff6247416eff1a90edd1ebc222ac2cdc5c15cfJesusFreke@JesusFreke.com            throw new ValidationException(String.format("Cannot use %s with field %s. Incorrect field type " +
205850ff6247416eff1a90edd1ebc222ac2cdc5c15cfJesusFreke@JesusFreke.com                        "for the instruction.", analyzedInstruction.instruction.opcode.name,
205950ff6247416eff1a90edd1ebc222ac2cdc5c15cfJesusFreke@JesusFreke.com                        field.getFieldString()));
206050ff6247416eff1a90edd1ebc222ac2cdc5c15cfJesusFreke@JesusFreke.com        }
206150ff6247416eff1a90edd1ebc222ac2cdc5c15cfJesusFreke@JesusFreke.com
206250ff6247416eff1a90edd1ebc222ac2cdc5c15cfJesusFreke@JesusFreke.com        if (sourceRegisterType.category != RegisterType.Category.Null &&
206350ff6247416eff1a90edd1ebc222ac2cdc5c15cfJesusFreke@JesusFreke.com            !fieldType.type.isInterface() &&
206450ff6247416eff1a90edd1ebc222ac2cdc5c15cfJesusFreke@JesusFreke.com            !sourceRegisterType.type.extendsClass(fieldType.type)) {
206550ff6247416eff1a90edd1ebc222ac2cdc5c15cfJesusFreke@JesusFreke.com
206650ff6247416eff1a90edd1ebc222ac2cdc5c15cfJesusFreke@JesusFreke.com            throw new ValidationException(String.format("Cannot store a value of type %s into a field of type %s",
206750ff6247416eff1a90edd1ebc222ac2cdc5c15cfJesusFreke@JesusFreke.com                    sourceRegisterType.type.getClassType(), fieldType.type.getClassType()));
206850ff6247416eff1a90edd1ebc222ac2cdc5c15cfJesusFreke@JesusFreke.com        }
206950ff6247416eff1a90edd1ebc222ac2cdc5c15cfJesusFreke@JesusFreke.com
207050ff6247416eff1a90edd1ebc222ac2cdc5c15cfJesusFreke@JesusFreke.com        return true;
207150ff6247416eff1a90edd1ebc222ac2cdc5c15cfJesusFreke@JesusFreke.com    }
207250ff6247416eff1a90edd1ebc222ac2cdc5c15cfJesusFreke@JesusFreke.com
2073052f4890ab954dc8510230b2992904a1a66c5dccJesusFreke@JesusFreke.com    private boolean handle32BitPrimitiveSget(AnalyzedInstruction analyzedInstruction,
2074052f4890ab954dc8510230b2992904a1a66c5dccJesusFreke@JesusFreke.com                                             RegisterType.Category instructionCategory) {
2075052f4890ab954dc8510230b2992904a1a66c5dccJesusFreke@JesusFreke.com        //TODO: check access
2076052f4890ab954dc8510230b2992904a1a66c5dccJesusFreke@JesusFreke.com        Item referencedItem = ((InstructionWithReference)analyzedInstruction.instruction).getReferencedItem();
2077052f4890ab954dc8510230b2992904a1a66c5dccJesusFreke@JesusFreke.com        assert referencedItem instanceof FieldIdItem;
2078052f4890ab954dc8510230b2992904a1a66c5dccJesusFreke@JesusFreke.com        FieldIdItem field = (FieldIdItem)referencedItem;
2079052f4890ab954dc8510230b2992904a1a66c5dccJesusFreke@JesusFreke.com
2080052f4890ab954dc8510230b2992904a1a66c5dccJesusFreke@JesusFreke.com        RegisterType fieldType = RegisterType.getRegisterTypeForTypeIdItem(field.getFieldType());
2081052f4890ab954dc8510230b2992904a1a66c5dccJesusFreke@JesusFreke.com
2082052f4890ab954dc8510230b2992904a1a66c5dccJesusFreke@JesusFreke.com        if (!checkArrayFieldAssignment(fieldType.category, instructionCategory)) {
2083052f4890ab954dc8510230b2992904a1a66c5dccJesusFreke@JesusFreke.com                throw new ValidationException(String.format("Cannot use %s with field %s. Incorrect field type " +
2084052f4890ab954dc8510230b2992904a1a66c5dccJesusFreke@JesusFreke.com                        "for the instruction.", analyzedInstruction.instruction.opcode.name,
2085052f4890ab954dc8510230b2992904a1a66c5dccJesusFreke@JesusFreke.com                        field.getFieldString()));
2086052f4890ab954dc8510230b2992904a1a66c5dccJesusFreke@JesusFreke.com        }
2087052f4890ab954dc8510230b2992904a1a66c5dccJesusFreke@JesusFreke.com
2088052f4890ab954dc8510230b2992904a1a66c5dccJesusFreke@JesusFreke.com        setDestinationRegisterTypeAndPropagateChanges(analyzedInstruction,
2089052f4890ab954dc8510230b2992904a1a66c5dccJesusFreke@JesusFreke.com                RegisterType.getRegisterType(instructionCategory, null));
2090052f4890ab954dc8510230b2992904a1a66c5dccJesusFreke@JesusFreke.com
2091052f4890ab954dc8510230b2992904a1a66c5dccJesusFreke@JesusFreke.com        return true;
2092052f4890ab954dc8510230b2992904a1a66c5dccJesusFreke@JesusFreke.com    }
2093052f4890ab954dc8510230b2992904a1a66c5dccJesusFreke@JesusFreke.com
20942f233fefd9d73af8fab4037a6f874b161b98b259JesusFreke@JesusFreke.com    private boolean handleSgetWide(AnalyzedInstruction analyzedInstruction) {
20952f233fefd9d73af8fab4037a6f874b161b98b259JesusFreke@JesusFreke.com        //TODO: check access
20962f233fefd9d73af8fab4037a6f874b161b98b259JesusFreke@JesusFreke.com        Item referencedItem = ((InstructionWithReference)analyzedInstruction.instruction).getReferencedItem();
20972f233fefd9d73af8fab4037a6f874b161b98b259JesusFreke@JesusFreke.com        assert referencedItem instanceof FieldIdItem;
20982f233fefd9d73af8fab4037a6f874b161b98b259JesusFreke@JesusFreke.com        FieldIdItem field = (FieldIdItem)referencedItem;
20992f233fefd9d73af8fab4037a6f874b161b98b259JesusFreke@JesusFreke.com
21002f233fefd9d73af8fab4037a6f874b161b98b259JesusFreke@JesusFreke.com        RegisterType fieldType = RegisterType.getRegisterTypeForTypeIdItem(field.getFieldType());
21012f233fefd9d73af8fab4037a6f874b161b98b259JesusFreke@JesusFreke.com
21022f233fefd9d73af8fab4037a6f874b161b98b259JesusFreke@JesusFreke.com
21032f233fefd9d73af8fab4037a6f874b161b98b259JesusFreke@JesusFreke.com        if (fieldType.category != RegisterType.Category.LongLo &&
21042f233fefd9d73af8fab4037a6f874b161b98b259JesusFreke@JesusFreke.com            fieldType.category != RegisterType.Category.DoubleLo) {
21052f233fefd9d73af8fab4037a6f874b161b98b259JesusFreke@JesusFreke.com
21062f233fefd9d73af8fab4037a6f874b161b98b259JesusFreke@JesusFreke.com            throw new ValidationException(String.format("Cannot use %s with field %s. Incorrect field type " +
21072f233fefd9d73af8fab4037a6f874b161b98b259JesusFreke@JesusFreke.com                    "for the instruction.", analyzedInstruction.instruction.opcode.name,
21082f233fefd9d73af8fab4037a6f874b161b98b259JesusFreke@JesusFreke.com                    field.getFieldString()));
21092f233fefd9d73af8fab4037a6f874b161b98b259JesusFreke@JesusFreke.com        }
21102f233fefd9d73af8fab4037a6f874b161b98b259JesusFreke@JesusFreke.com
21112f233fefd9d73af8fab4037a6f874b161b98b259JesusFreke@JesusFreke.com        setWideDestinationRegisterTypeAndPropagateChanges(analyzedInstruction, fieldType);
21122d6d6eb22c86c79344b85ffe46fdd4268566bd0fJesusFreke@JesusFreke.com
21132d6d6eb22c86c79344b85ffe46fdd4268566bd0fJesusFreke@JesusFreke.com        return true;
21142d6d6eb22c86c79344b85ffe46fdd4268566bd0fJesusFreke@JesusFreke.com    }
21152d6d6eb22c86c79344b85ffe46fdd4268566bd0fJesusFreke@JesusFreke.com
21162d6d6eb22c86c79344b85ffe46fdd4268566bd0fJesusFreke@JesusFreke.com    private boolean handleSgetObject(AnalyzedInstruction analyzedInstruction) {
21172d6d6eb22c86c79344b85ffe46fdd4268566bd0fJesusFreke@JesusFreke.com        //TODO: check access
21182d6d6eb22c86c79344b85ffe46fdd4268566bd0fJesusFreke@JesusFreke.com        Item referencedItem = ((InstructionWithReference)analyzedInstruction.instruction).getReferencedItem();
21192d6d6eb22c86c79344b85ffe46fdd4268566bd0fJesusFreke@JesusFreke.com        assert referencedItem instanceof FieldIdItem;
21202d6d6eb22c86c79344b85ffe46fdd4268566bd0fJesusFreke@JesusFreke.com        FieldIdItem field = (FieldIdItem)referencedItem;
21212d6d6eb22c86c79344b85ffe46fdd4268566bd0fJesusFreke@JesusFreke.com
21222d6d6eb22c86c79344b85ffe46fdd4268566bd0fJesusFreke@JesusFreke.com        RegisterType fieldType = RegisterType.getRegisterTypeForTypeIdItem(field.getFieldType());
21232d6d6eb22c86c79344b85ffe46fdd4268566bd0fJesusFreke@JesusFreke.com
21242d6d6eb22c86c79344b85ffe46fdd4268566bd0fJesusFreke@JesusFreke.com        if (fieldType.category != RegisterType.Category.Reference) {
21252d6d6eb22c86c79344b85ffe46fdd4268566bd0fJesusFreke@JesusFreke.com                throw new ValidationException(String.format("Cannot use %s with field %s. Incorrect field type " +
21262d6d6eb22c86c79344b85ffe46fdd4268566bd0fJesusFreke@JesusFreke.com                        "for the instruction.", analyzedInstruction.instruction.opcode.name,
21272d6d6eb22c86c79344b85ffe46fdd4268566bd0fJesusFreke@JesusFreke.com                        field.getFieldString()));
21282d6d6eb22c86c79344b85ffe46fdd4268566bd0fJesusFreke@JesusFreke.com        }
21292d6d6eb22c86c79344b85ffe46fdd4268566bd0fJesusFreke@JesusFreke.com
21302d6d6eb22c86c79344b85ffe46fdd4268566bd0fJesusFreke@JesusFreke.com        setDestinationRegisterTypeAndPropagateChanges(analyzedInstruction, fieldType);
21312f233fefd9d73af8fab4037a6f874b161b98b259JesusFreke@JesusFreke.com
21322f233fefd9d73af8fab4037a6f874b161b98b259JesusFreke@JesusFreke.com        return true;
21332f233fefd9d73af8fab4037a6f874b161b98b259JesusFreke@JesusFreke.com    }
21342f233fefd9d73af8fab4037a6f874b161b98b259JesusFreke@JesusFreke.com
21359d45d563fedaddab6bbdd421b139fe91d2f15fc8JesusFreke@JesusFreke.com    private boolean handle32BitPrimitiveSput(AnalyzedInstruction analyzedInstruction,
21369d45d563fedaddab6bbdd421b139fe91d2f15fc8JesusFreke@JesusFreke.com                                             RegisterType.Category instructionCategory) {
21379d45d563fedaddab6bbdd421b139fe91d2f15fc8JesusFreke@JesusFreke.com        SingleRegisterInstruction instruction = (SingleRegisterInstruction)analyzedInstruction.instruction;
21389d45d563fedaddab6bbdd421b139fe91d2f15fc8JesusFreke@JesusFreke.com
21399d45d563fedaddab6bbdd421b139fe91d2f15fc8JesusFreke@JesusFreke.com        RegisterType sourceRegisterType = analyzedInstruction.getPreInstructionRegisterType(instruction.getRegisterA());
21409d45d563fedaddab6bbdd421b139fe91d2f15fc8JesusFreke@JesusFreke.com        assert sourceRegisterType != null;
21419d45d563fedaddab6bbdd421b139fe91d2f15fc8JesusFreke@JesusFreke.com        if (sourceRegisterType.category == RegisterType.Category.Unknown) {
21429d45d563fedaddab6bbdd421b139fe91d2f15fc8JesusFreke@JesusFreke.com            return false;
21439d45d563fedaddab6bbdd421b139fe91d2f15fc8JesusFreke@JesusFreke.com        }
21449d45d563fedaddab6bbdd421b139fe91d2f15fc8JesusFreke@JesusFreke.com
21459d45d563fedaddab6bbdd421b139fe91d2f15fc8JesusFreke@JesusFreke.com        //per CodeVerify.c in dalvik:
21469d45d563fedaddab6bbdd421b139fe91d2f15fc8JesusFreke@JesusFreke.com        //java generates synthetic functions that write byte values into boolean fields
21479d45d563fedaddab6bbdd421b139fe91d2f15fc8JesusFreke@JesusFreke.com        if (sourceRegisterType.category == RegisterType.Category.Byte &&
21489d45d563fedaddab6bbdd421b139fe91d2f15fc8JesusFreke@JesusFreke.com            instructionCategory == RegisterType.Category.Boolean) {
21499d45d563fedaddab6bbdd421b139fe91d2f15fc8JesusFreke@JesusFreke.com
21509d45d563fedaddab6bbdd421b139fe91d2f15fc8JesusFreke@JesusFreke.com            sourceRegisterType = RegisterType.getRegisterType(RegisterType.Category.Boolean, null);
21519d45d563fedaddab6bbdd421b139fe91d2f15fc8JesusFreke@JesusFreke.com        }
21529d45d563fedaddab6bbdd421b139fe91d2f15fc8JesusFreke@JesusFreke.com
21539d45d563fedaddab6bbdd421b139fe91d2f15fc8JesusFreke@JesusFreke.com        RegisterType instructionRegisterType = RegisterType.getRegisterType(instructionCategory, null);
21549d45d563fedaddab6bbdd421b139fe91d2f15fc8JesusFreke@JesusFreke.com        if (!sourceRegisterType.canBeAssignedTo(instructionRegisterType)) {
21559d45d563fedaddab6bbdd421b139fe91d2f15fc8JesusFreke@JesusFreke.com            throw new ValidationException(String.format("Cannot use %s with source register type %s.",
21569d45d563fedaddab6bbdd421b139fe91d2f15fc8JesusFreke@JesusFreke.com                    analyzedInstruction.instruction.opcode.name, sourceRegisterType.toString()));
21579d45d563fedaddab6bbdd421b139fe91d2f15fc8JesusFreke@JesusFreke.com        }
21589d45d563fedaddab6bbdd421b139fe91d2f15fc8JesusFreke@JesusFreke.com
21599d45d563fedaddab6bbdd421b139fe91d2f15fc8JesusFreke@JesusFreke.com        //TODO: check access
21609d45d563fedaddab6bbdd421b139fe91d2f15fc8JesusFreke@JesusFreke.com        Item referencedItem = ((InstructionWithReference)analyzedInstruction.instruction).getReferencedItem();
21619d45d563fedaddab6bbdd421b139fe91d2f15fc8JesusFreke@JesusFreke.com        assert referencedItem instanceof FieldIdItem;
21629d45d563fedaddab6bbdd421b139fe91d2f15fc8JesusFreke@JesusFreke.com        FieldIdItem field = (FieldIdItem)referencedItem;
21639d45d563fedaddab6bbdd421b139fe91d2f15fc8JesusFreke@JesusFreke.com
21649d45d563fedaddab6bbdd421b139fe91d2f15fc8JesusFreke@JesusFreke.com        RegisterType fieldType = RegisterType.getRegisterTypeForTypeIdItem(field.getFieldType());
21659d45d563fedaddab6bbdd421b139fe91d2f15fc8JesusFreke@JesusFreke.com
21669d45d563fedaddab6bbdd421b139fe91d2f15fc8JesusFreke@JesusFreke.com        if (!checkArrayFieldAssignment(fieldType.category, instructionCategory)) {
21679d45d563fedaddab6bbdd421b139fe91d2f15fc8JesusFreke@JesusFreke.com                throw new ValidationException(String.format("Cannot use %s with field %s. Incorrect field type " +
21689d45d563fedaddab6bbdd421b139fe91d2f15fc8JesusFreke@JesusFreke.com                        "for the instruction.", analyzedInstruction.instruction.opcode.name,
21699d45d563fedaddab6bbdd421b139fe91d2f15fc8JesusFreke@JesusFreke.com                        field.getFieldString()));
21709d45d563fedaddab6bbdd421b139fe91d2f15fc8JesusFreke@JesusFreke.com        }
21719d45d563fedaddab6bbdd421b139fe91d2f15fc8JesusFreke@JesusFreke.com
21729d45d563fedaddab6bbdd421b139fe91d2f15fc8JesusFreke@JesusFreke.com        return true;
21739d45d563fedaddab6bbdd421b139fe91d2f15fc8JesusFreke@JesusFreke.com    }
21749d45d563fedaddab6bbdd421b139fe91d2f15fc8JesusFreke@JesusFreke.com
2175f08a9e1c2c130a5ed5923999fec0283f91b48a09JesusFreke@JesusFreke.com    private boolean handleSputWide(AnalyzedInstruction analyzedInstruction) {
2176f08a9e1c2c130a5ed5923999fec0283f91b48a09JesusFreke@JesusFreke.com        SingleRegisterInstruction instruction = (SingleRegisterInstruction)analyzedInstruction.instruction;
2177f08a9e1c2c130a5ed5923999fec0283f91b48a09JesusFreke@JesusFreke.com
2178f08a9e1c2c130a5ed5923999fec0283f91b48a09JesusFreke@JesusFreke.com
2179f08a9e1c2c130a5ed5923999fec0283f91b48a09JesusFreke@JesusFreke.com        RegisterType sourceRegisterType = getAndCheckWideSourcePair(analyzedInstruction, instruction.getRegisterA());
2180f08a9e1c2c130a5ed5923999fec0283f91b48a09JesusFreke@JesusFreke.com        assert sourceRegisterType != null;
2181f08a9e1c2c130a5ed5923999fec0283f91b48a09JesusFreke@JesusFreke.com        if (sourceRegisterType.category == RegisterType.Category.Unknown) {
2182f08a9e1c2c130a5ed5923999fec0283f91b48a09JesusFreke@JesusFreke.com            return false;
2183f08a9e1c2c130a5ed5923999fec0283f91b48a09JesusFreke@JesusFreke.com        }
2184f08a9e1c2c130a5ed5923999fec0283f91b48a09JesusFreke@JesusFreke.com
2185f08a9e1c2c130a5ed5923999fec0283f91b48a09JesusFreke@JesusFreke.com        //TODO: check access
2186f08a9e1c2c130a5ed5923999fec0283f91b48a09JesusFreke@JesusFreke.com        Item referencedItem = ((InstructionWithReference)analyzedInstruction.instruction).getReferencedItem();
2187f08a9e1c2c130a5ed5923999fec0283f91b48a09JesusFreke@JesusFreke.com        assert referencedItem instanceof FieldIdItem;
2188f08a9e1c2c130a5ed5923999fec0283f91b48a09JesusFreke@JesusFreke.com        FieldIdItem field = (FieldIdItem)referencedItem;
2189f08a9e1c2c130a5ed5923999fec0283f91b48a09JesusFreke@JesusFreke.com
2190f08a9e1c2c130a5ed5923999fec0283f91b48a09JesusFreke@JesusFreke.com        RegisterType fieldType = RegisterType.getRegisterTypeForTypeIdItem(field.getFieldType());
2191f08a9e1c2c130a5ed5923999fec0283f91b48a09JesusFreke@JesusFreke.com
2192f08a9e1c2c130a5ed5923999fec0283f91b48a09JesusFreke@JesusFreke.com        if (!WideLowCategories.contains(fieldType.category)) {
2193f08a9e1c2c130a5ed5923999fec0283f91b48a09JesusFreke@JesusFreke.com                throw new ValidationException(String.format("Cannot use %s with field %s. Incorrect field type " +
2194f08a9e1c2c130a5ed5923999fec0283f91b48a09JesusFreke@JesusFreke.com                        "for the instruction.", analyzedInstruction.instruction.opcode.name,
2195f08a9e1c2c130a5ed5923999fec0283f91b48a09JesusFreke@JesusFreke.com                        field.getFieldString()));
2196f08a9e1c2c130a5ed5923999fec0283f91b48a09JesusFreke@JesusFreke.com        }
2197f08a9e1c2c130a5ed5923999fec0283f91b48a09JesusFreke@JesusFreke.com
2198f08a9e1c2c130a5ed5923999fec0283f91b48a09JesusFreke@JesusFreke.com        setWideDestinationRegisterTypeAndPropagateChanges(analyzedInstruction, fieldType);
2199f08a9e1c2c130a5ed5923999fec0283f91b48a09JesusFreke@JesusFreke.com
2200f08a9e1c2c130a5ed5923999fec0283f91b48a09JesusFreke@JesusFreke.com        return true;
2201f08a9e1c2c130a5ed5923999fec0283f91b48a09JesusFreke@JesusFreke.com    }
2202f08a9e1c2c130a5ed5923999fec0283f91b48a09JesusFreke@JesusFreke.com
220351cec00885cdc063ee27ee6b67680189be34f8f9JesusFreke@JesusFreke.com    private boolean handleSputObject(AnalyzedInstruction analyzedInstruction) {
220451cec00885cdc063ee27ee6b67680189be34f8f9JesusFreke@JesusFreke.com        SingleRegisterInstruction instruction = (SingleRegisterInstruction)analyzedInstruction.instruction;
220551cec00885cdc063ee27ee6b67680189be34f8f9JesusFreke@JesusFreke.com
220651cec00885cdc063ee27ee6b67680189be34f8f9JesusFreke@JesusFreke.com        RegisterType sourceRegisterType = analyzedInstruction.getPreInstructionRegisterType(instruction.getRegisterA());
220751cec00885cdc063ee27ee6b67680189be34f8f9JesusFreke@JesusFreke.com        assert sourceRegisterType != null;
220851cec00885cdc063ee27ee6b67680189be34f8f9JesusFreke@JesusFreke.com        if (sourceRegisterType.category == RegisterType.Category.Unknown) {
220951cec00885cdc063ee27ee6b67680189be34f8f9JesusFreke@JesusFreke.com            return false;
221051cec00885cdc063ee27ee6b67680189be34f8f9JesusFreke@JesusFreke.com        }
221151cec00885cdc063ee27ee6b67680189be34f8f9JesusFreke@JesusFreke.com        checkRegister(sourceRegisterType, ReferenceCategories);
221251cec00885cdc063ee27ee6b67680189be34f8f9JesusFreke@JesusFreke.com
221351cec00885cdc063ee27ee6b67680189be34f8f9JesusFreke@JesusFreke.com        //TODO: check access
221451cec00885cdc063ee27ee6b67680189be34f8f9JesusFreke@JesusFreke.com        Item referencedItem = ((InstructionWithReference)analyzedInstruction.instruction).getReferencedItem();
221551cec00885cdc063ee27ee6b67680189be34f8f9JesusFreke@JesusFreke.com        assert referencedItem instanceof FieldIdItem;
221651cec00885cdc063ee27ee6b67680189be34f8f9JesusFreke@JesusFreke.com        FieldIdItem field = (FieldIdItem)referencedItem;
221751cec00885cdc063ee27ee6b67680189be34f8f9JesusFreke@JesusFreke.com
221851cec00885cdc063ee27ee6b67680189be34f8f9JesusFreke@JesusFreke.com        RegisterType fieldType = RegisterType.getRegisterTypeForTypeIdItem(field.getFieldType());
221951cec00885cdc063ee27ee6b67680189be34f8f9JesusFreke@JesusFreke.com
222051cec00885cdc063ee27ee6b67680189be34f8f9JesusFreke@JesusFreke.com        if (fieldType.category != RegisterType.Category.Reference) {
222151cec00885cdc063ee27ee6b67680189be34f8f9JesusFreke@JesusFreke.com            throw new ValidationException(String.format("Cannot use %s with field %s. Incorrect field type " +
222251cec00885cdc063ee27ee6b67680189be34f8f9JesusFreke@JesusFreke.com                        "for the instruction.", analyzedInstruction.instruction.opcode.name,
222351cec00885cdc063ee27ee6b67680189be34f8f9JesusFreke@JesusFreke.com                        field.getFieldString()));
222451cec00885cdc063ee27ee6b67680189be34f8f9JesusFreke@JesusFreke.com        }
222551cec00885cdc063ee27ee6b67680189be34f8f9JesusFreke@JesusFreke.com
222651cec00885cdc063ee27ee6b67680189be34f8f9JesusFreke@JesusFreke.com        if (sourceRegisterType.category != RegisterType.Category.Null &&
222751cec00885cdc063ee27ee6b67680189be34f8f9JesusFreke@JesusFreke.com            !fieldType.type.isInterface() &&
222851cec00885cdc063ee27ee6b67680189be34f8f9JesusFreke@JesusFreke.com            !sourceRegisterType.type.extendsClass(fieldType.type)) {
222951cec00885cdc063ee27ee6b67680189be34f8f9JesusFreke@JesusFreke.com
223051cec00885cdc063ee27ee6b67680189be34f8f9JesusFreke@JesusFreke.com            throw new ValidationException(String.format("Cannot store a value of type %s into a field of type %s",
223151cec00885cdc063ee27ee6b67680189be34f8f9JesusFreke@JesusFreke.com                    sourceRegisterType.type.getClassType(), fieldType.type.getClassType()));
223251cec00885cdc063ee27ee6b67680189be34f8f9JesusFreke@JesusFreke.com        }
223351cec00885cdc063ee27ee6b67680189be34f8f9JesusFreke@JesusFreke.com
223451cec00885cdc063ee27ee6b67680189be34f8f9JesusFreke@JesusFreke.com        return true;
223551cec00885cdc063ee27ee6b67680189be34f8f9JesusFreke@JesusFreke.com    }
223651cec00885cdc063ee27ee6b67680189be34f8f9JesusFreke@JesusFreke.com
2237b2397452907c28b0743bbbcdf9fa6b2a8208aeabJesusFreke@JesusFreke.com    private static boolean checkArrayFieldAssignment(RegisterType.Category arrayFieldCategory,
2238b2397452907c28b0743bbbcdf9fa6b2a8208aeabJesusFreke@JesusFreke.com                                                  RegisterType.Category instructionCategory) {
2239b2397452907c28b0743bbbcdf9fa6b2a8208aeabJesusFreke@JesusFreke.com        if (arrayFieldCategory == instructionCategory) {
2240b2397452907c28b0743bbbcdf9fa6b2a8208aeabJesusFreke@JesusFreke.com            return true;
2241b2397452907c28b0743bbbcdf9fa6b2a8208aeabJesusFreke@JesusFreke.com        }
2242b2397452907c28b0743bbbcdf9fa6b2a8208aeabJesusFreke@JesusFreke.com
2243b2397452907c28b0743bbbcdf9fa6b2a8208aeabJesusFreke@JesusFreke.com        if ((arrayFieldCategory == RegisterType.Category.Integer &&
2244b2397452907c28b0743bbbcdf9fa6b2a8208aeabJesusFreke@JesusFreke.com             instructionCategory == RegisterType.Category.Float) ||
2245b2397452907c28b0743bbbcdf9fa6b2a8208aeabJesusFreke@JesusFreke.com            (arrayFieldCategory == RegisterType.Category.Float &&
2246b2397452907c28b0743bbbcdf9fa6b2a8208aeabJesusFreke@JesusFreke.com             instructionCategory == RegisterType.Category.Integer)) {
2247b2397452907c28b0743bbbcdf9fa6b2a8208aeabJesusFreke@JesusFreke.com            return true;
2248b2397452907c28b0743bbbcdf9fa6b2a8208aeabJesusFreke@JesusFreke.com        }
2249b2397452907c28b0743bbbcdf9fa6b2a8208aeabJesusFreke@JesusFreke.com        return false;
2250b2397452907c28b0743bbbcdf9fa6b2a8208aeabJesusFreke@JesusFreke.com    }
2251b2397452907c28b0743bbbcdf9fa6b2a8208aeabJesusFreke@JesusFreke.com
2252fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com    private static void checkRegister(RegisterType registerType, EnumSet validCategories) {
2253fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        if (!validCategories.contains(registerType.category)) {
2254fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com            //TODO: add expected categories to error message
2255fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com            throw new ValidationException("Invalid register type. Expecting one of: " + " but got \"" +
2256fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com                    registerType.category + "\"");
2257fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        }
2258fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com    }
2259fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com
2260fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com    private static void checkWideDestinationPair(AnalyzedInstruction analyzedInstruction) {
2261fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        int register = analyzedInstruction.getDestinationRegister();
2262fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com
2263fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        if (register == (analyzedInstruction.postRegisterMap.length - 1)) {
2264fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com            throw new ValidationException("v" + register + " is the last register and not a valid wide register " +
2265fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com                    "pair.");
2266fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        }
2267fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com    }
2268fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com
2269fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com    private static RegisterType getAndCheckWideSourcePair(AnalyzedInstruction analyzedInstruction, int firstRegister) {
2270fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        assert firstRegister >= 0 && firstRegister < analyzedInstruction.postRegisterMap.length;
2271fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com
2272fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        if (firstRegister == analyzedInstruction.postRegisterMap.length - 1) {
2273fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com            throw new ValidationException("v" + firstRegister + " is the last register and not a valid wide register " +
2274fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com                    "pair.");
2275fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        }
2276fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com
2277fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        RegisterType registerType = analyzedInstruction.getPreInstructionRegisterType(firstRegister);
2278fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        assert registerType != null;
2279fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        if (registerType.category == RegisterType.Category.Unknown) {
2280fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com            return registerType;
2281fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        }
2282fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        checkRegister(registerType, WideLowCategories);
2283fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com
2284fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        RegisterType secondRegisterType = analyzedInstruction.getPreInstructionRegisterType(firstRegister + 1);
2285fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        assert secondRegisterType != null;
2286fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        checkRegister(secondRegisterType, WideHighCategories);
2287fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com
2288fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        if ((       registerType.category == RegisterType.Category.LongLo &&
2289fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com                    secondRegisterType.category == RegisterType.Category.DoubleHi)
2290fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com            ||  (   registerType.category == RegisterType.Category.DoubleLo &&
2291fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com                    secondRegisterType.category == RegisterType.Category.LongHi)) {
2292fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com            assert false;
2293fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com            throw new ValidationException("The first register in the wide register pair isn't the same type (long " +
2294fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com                    "vs. double) as the second register in the pair");
2295fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        }
2296d27ca7f7a61cfbe60e1c490bf645257d7d59fd39JesusFreke@JesusFreke.com
2297fffb29fd9d67ba1396bd2999de4f0d9a44b79837JesusFreke@JesusFreke.com        return registerType;
2298d27ca7f7a61cfbe60e1c490bf645257d7d59fd39JesusFreke@JesusFreke.com    }
2299d27ca7f7a61cfbe60e1c490bf645257d7d59fd39JesusFreke@JesusFreke.com}
2300