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