refactor the validation for source register types

git-svn-id: https://smali.googlecode.com/svn/trunk@615 55b6fa8a-2a1e-11de-a435-ffa8d773f76a
This commit is contained in:
JesusFreke@JesusFreke.com
2010-02-08 02:28:01 +00:00
parent ee7ca05c81
commit 85e17ca30a

View File

@ -188,42 +188,24 @@ public class MethodAnalyzer {
return instructions.keyAt(instruction.instructionIndex);
}
private void setWideDestinationRegisterTypeAndPropagateChanges(AnalyzedInstruction analyzedInstruction,
RegisterType registerType) {
assert registerType.category == RegisterType.Category.LongLo ||
registerType.category == RegisterType.Category.DoubleLo;
checkWideDestinationPair(analyzedInstruction);
setRegisterTypeAndPropagateChanges(analyzedInstruction, analyzedInstruction.getDestinationRegister(),
registerType);
if (registerType.category == RegisterType.Category.LongLo) {
setRegisterTypeAndPropagateChanges(analyzedInstruction, analyzedInstruction.getDestinationRegister() + 1,
RegisterType.getRegisterType(RegisterType.Category.LongHi, null));
} else {
setRegisterTypeAndPropagateChanges(analyzedInstruction, analyzedInstruction.getDestinationRegister() + 1,
RegisterType.getRegisterType(RegisterType.Category.DoubleHi, null));
}
}
private void setDestinationRegisterTypeAndPropagateChanges(AnalyzedInstruction analyzedInstruction,
RegisterType registerType) {
setRegisterTypeAndPropagateChanges(analyzedInstruction, analyzedInstruction.getDestinationRegister(),
registerType);
}
private void setRegisterTypeAndPropagateChanges(AnalyzedInstruction instruction, int registerNumber,
private void setRegisterTypeAndPropagateChanges(AnalyzedInstruction analyzedInstruction, int registerNumber,
RegisterType registerType) {
BitSet changedInstructions = new BitSet(instructions.size());
boolean changed = instruction.setPostRegisterType(registerNumber, registerType);
boolean changed = analyzedInstruction.setPostRegisterType(registerNumber, registerType);
if (!changed || instruction.setsRegister(registerNumber)) {
if (!changed || analyzedInstruction.setsRegister(registerNumber)) {
return;
}
propagateRegisterToSuccessors(instruction, registerNumber, changedInstructions);
propagateRegisterToSuccessors(analyzedInstruction, registerNumber, changedInstructions);
//using a for loop inside the while loop optimizes for the common case of the successors of an instruction
//occurring after the instruction. Any successors that occur prior to the instruction will be picked up on
@ -242,6 +224,16 @@ public class MethodAnalyzer {
changedInstructions);
}
}
if (registerType.category == RegisterType.Category.LongLo) {
checkWidePair(registerNumber, analyzedInstruction);
setRegisterTypeAndPropagateChanges(analyzedInstruction, registerNumber+1,
RegisterType.getRegisterType(RegisterType.Category.LongHi, null));
} else if (registerType.category == RegisterType.Category.DoubleLo) {
checkWidePair(registerNumber, analyzedInstruction);
setRegisterTypeAndPropagateChanges(analyzedInstruction, registerNumber+1,
RegisterType.getRegisterType(RegisterType.Category.DoubleHi, null));
}
}
private void propagateRegisterToSuccessors(AnalyzedInstruction instruction, int registerNumber,
@ -434,7 +426,7 @@ public class MethodAnalyzer {
case MOVE_WIDE:
case MOVE_WIDE_FROM16:
case MOVE_WIDE_16:
handleMoveWide(analyzedInstruction);
handleMove(analyzedInstruction, WideLowCategories);
return;
case MOVE_OBJECT:
case MOVE_OBJECT_FROM16:
@ -457,13 +449,13 @@ public class MethodAnalyzer {
handleReturnVoid(analyzedInstruction);
return;
case RETURN:
handleReturn(analyzedInstruction);
handleReturn(analyzedInstruction, Primitive32BitCategories);
return;
case RETURN_WIDE:
handleReturnWide(analyzedInstruction);
handleReturn(analyzedInstruction, WideLowCategories);
return;
case RETURN_OBJECT:
handleReturnObject(analyzedInstruction);
handleReturn(analyzedInstruction, ReferenceCategories);
return;
case CONST_4:
case CONST_16:
@ -530,12 +522,12 @@ public class MethodAnalyzer {
return;
case CMPL_FLOAT:
case CMPG_FLOAT:
handleFloatCmp(analyzedInstruction);
handleFloatWideCmp(analyzedInstruction, Primitive32BitCategories);
return;
case CMPL_DOUBLE:
case CMPG_DOUBLE:
case CMP_LONG:
handleWideCmp(analyzedInstruction);
handleFloatWideCmp(analyzedInstruction, WideLowCategories);
return;
case IF_EQ:
case IF_NE:
@ -737,27 +729,23 @@ public class MethodAnalyzer {
RegisterType.Category.Null,
RegisterType.Category.Reference);
private void handleMove(AnalyzedInstruction analyzedInstruction,
EnumSet<RegisterType.Category> allowedCategories) {
private static final EnumSet<RegisterType.Category> ReferenceAndPrimitive32BitCategories = EnumSet.of(
RegisterType.Category.Null,
RegisterType.Category.Boolean,
RegisterType.Category.Byte,
RegisterType.Category.Short,
RegisterType.Category.Char,
RegisterType.Category.Integer,
RegisterType.Category.Float,
RegisterType.Category.Reference);
private void handleMove(AnalyzedInstruction analyzedInstruction, EnumSet validCategories) {
TwoRegisterInstruction instruction = (TwoRegisterInstruction)analyzedInstruction.instruction;
//get the "pre-instruction" register type for the source register
RegisterType sourceRegisterType = analyzedInstruction.getPreInstructionRegisterType(instruction.getRegisterB());
assert sourceRegisterType != null;
checkRegister(sourceRegisterType, allowedCategories);
setDestinationRegisterTypeAndPropagateChanges(analyzedInstruction, sourceRegisterType);
}
private void handleMoveWide(AnalyzedInstruction analyzedInstruction) {
TwoRegisterInstruction instruction = (TwoRegisterInstruction)analyzedInstruction.instruction;
RegisterType sourceRegisterType = getAndCheckWideSourcePair(analyzedInstruction,
instruction.getRegisterB());
assert sourceRegisterType != null;
checkWideDestinationPair(analyzedInstruction);
RegisterType sourceRegisterType = getAndCheckSourceRegister(analyzedInstruction, instruction.getRegisterB(),
validCategories);
setDestinationRegisterTypeAndPropagateChanges(analyzedInstruction, sourceRegisterType);
}
@ -779,26 +767,26 @@ public class MethodAnalyzer {
"invoke-*/fill-new-array instruction");
}
if (analyzedInstruction.instruction.opcode.setsWideRegister()) {
checkWideDestinationPair(analyzedInstruction);
}
//TODO: does dalvik allow a move-result after an invoke with a void return type?
RegisterType destinationRegisterType;
RegisterType resultRegisterType;
InstructionWithReference invokeInstruction = (InstructionWithReference)previousInstruction.instruction;
Item item = invokeInstruction.getReferencedItem();
if (item instanceof MethodIdItem) {
destinationRegisterType = RegisterType.getRegisterTypeForTypeIdItem(
resultRegisterType = RegisterType.getRegisterTypeForTypeIdItem(
((MethodIdItem)item).getPrototype().getReturnType());
} else {
assert item instanceof TypeIdItem;
destinationRegisterType = RegisterType.getRegisterTypeForTypeIdItem((TypeIdItem)item);
resultRegisterType = RegisterType.getRegisterTypeForTypeIdItem((TypeIdItem)item);
}
checkRegister(destinationRegisterType, allowedCategories);
setDestinationRegisterTypeAndPropagateChanges(analyzedInstruction, destinationRegisterType);
if (!allowedCategories.contains(resultRegisterType.category)) {
throw new ValidationException(String.format("Wrong move-result* instruction for return value %s",
resultRegisterType.toString()));
}
setDestinationRegisterTypeAndPropagateChanges(analyzedInstruction, resultRegisterType);
}
private void handleMoveException(AnalyzedInstruction analyzedInstruction) {
@ -825,8 +813,16 @@ public class MethodAnalyzer {
}
}
if (exceptionType == null) {
throw new ValidationException("move-exception must be the first instruction in an exception handler block");
}
//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)
checkRegister(exceptionType, ReferenceCategories);
if (exceptionType.category != RegisterType.Category.Reference) {
throw new ValidationException(String.format("Exception type %s is not a reference type",
exceptionType.toString()));
}
setDestinationRegisterTypeAndPropagateChanges(analyzedInstruction, exceptionType);
}
@ -861,83 +857,40 @@ public class MethodAnalyzer {
}
}
private void handleReturn(AnalyzedInstruction analyzedInstruction) {
if (this.isInstanceConstructor()) {
checkConstructorReturn(analyzedInstruction);
}
SingleRegisterInstruction instruction = (SingleRegisterInstruction)analyzedInstruction.instruction;
RegisterType returnRegisterType = analyzedInstruction.postRegisterMap[instruction.getRegisterA()];
checkRegister(returnRegisterType, Primitive32BitCategories);
TypeIdItem returnType = encodedMethod.method.getPrototype().getReturnType();
if (returnType.getTypeDescriptor().charAt(0) == 'V') {
throw new ValidationException("Cannot use return with a void return type. Use return-void instead");
}
RegisterType registerType = RegisterType.getRegisterTypeForTypeIdItem(returnType);
if (!Primitive32BitCategories.contains(registerType.category)) {
//TODO: could add which return-* variation should be used instead
throw new ValidationException("Cannot use return with return type " + returnType.getTypeDescriptor());
}
}
private void handleReturnWide(AnalyzedInstruction analyzedInstruction) {
if (this.isInstanceConstructor()) {
checkConstructorReturn(analyzedInstruction);
}
SingleRegisterInstruction instruction = (SingleRegisterInstruction)analyzedInstruction.instruction;
RegisterType returnType = getAndCheckWideSourcePair(analyzedInstruction, instruction.getRegisterA());
TypeIdItem returnTypeIdItem = encodedMethod.method.getPrototype().getReturnType();
if (returnTypeIdItem.getTypeDescriptor().charAt(0) == 'V') {
throw new ValidationException("Cannot use return-wide with a void return type. Use return-void instead");
}
returnType = RegisterType.getRegisterTypeForTypeIdItem(returnTypeIdItem);
if (!WideLowCategories.contains(returnType.category)) {
//TODO: could add which return-* variation should be used instead
throw new ValidationException("Cannot use return-wide with return type " +
returnTypeIdItem.getTypeDescriptor());
}
}
private void handleReturnObject(AnalyzedInstruction analyzedInstruction) {
private void handleReturn(AnalyzedInstruction analyzedInstruction, EnumSet validCategories) {
if (this.isInstanceConstructor()) {
checkConstructorReturn(analyzedInstruction);
}
SingleRegisterInstruction instruction = (SingleRegisterInstruction)analyzedInstruction.instruction;
int returnRegister = instruction.getRegisterA();
RegisterType returnRegisterType = analyzedInstruction.postRegisterMap[returnRegister];
RegisterType returnRegisterType = getAndCheckSourceRegister(analyzedInstruction, returnRegister,
validCategories);
checkRegister(returnRegisterType, ReferenceCategories);
TypeIdItem returnTypeIdItem = encodedMethod.method.getPrototype().getReturnType();
if (returnTypeIdItem.getTypeDescriptor().charAt(0) == 'V') {
TypeIdItem returnType = encodedMethod.method.getPrototype().getReturnType();
if (returnType.getTypeDescriptor().charAt(0) == 'V') {
throw new ValidationException("Cannot use return with a void return type. Use return-void instead");
}
RegisterType returnType = RegisterType.getRegisterTypeForTypeIdItem(returnTypeIdItem);
RegisterType methodReturnRegisterType = RegisterType.getRegisterTypeForTypeIdItem(returnType);
if (!ReferenceCategories.contains(returnType.category)) {
if (!validCategories.contains(methodReturnRegisterType.category)) {
//TODO: could add which return-* variation should be used instead
throw new ValidationException("Cannot use " + analyzedInstruction + " with return type " +
returnTypeIdItem.getTypeDescriptor());
throw new ValidationException(String.format("Cannot use %s with return type %s",
analyzedInstruction.instruction.opcode.name, returnType.getTypeDescriptor()));
}
if (returnType.type.isInterface()) {
if (!returnRegisterType.type.implementsInterface(returnType.type)) {
//TODO: how to handle warnings?
}
} else {
if (!returnRegisterType.type.extendsClass(returnType.type)) {
throw new ValidationException("The return value in register v" + Integer.toString(returnRegister) +
"(" + returnRegisterType.type.getClassType() + ") is not compatible with the method's return " +
"type (" + returnType.type.getClassType() + ")");
if (validCategories == ReferenceCategories) {
if (methodReturnRegisterType.type.isInterface()) {
if (!returnRegisterType.type.implementsInterface(methodReturnRegisterType.type)) {
//TODO: how to handle warnings?
}
} else {
if (!returnRegisterType.type.extendsClass(methodReturnRegisterType.type)) {
throw new ValidationException(String.format("The return value in register v%d (%s) is not " +
"compatible with the method's return type %s", returnRegister,
returnRegisterType.type.getClassType(), methodReturnRegisterType.type.getClassType()));
}
}
}
}
@ -965,7 +918,7 @@ public class MethodAnalyzer {
}
private void handleWideConst(AnalyzedInstruction analyzedInstruction) {
setWideDestinationRegisterTypeAndPropagateChanges(analyzedInstruction,
setDestinationRegisterTypeAndPropagateChanges(analyzedInstruction,
RegisterType.getRegisterType(RegisterType.Category.LongLo, null));
}
@ -989,12 +942,8 @@ public class MethodAnalyzer {
}
private void handleMonitor(AnalyzedInstruction analyzedInstruction) {
SingleRegisterInstruction instruction = (SingleRegisterInstruction)analyzedInstruction;
RegisterType registerType = analyzedInstruction.postRegisterMap[instruction.getRegisterA()];
assert registerType != null;
checkRegister(registerType, ReferenceCategories);
SingleRegisterInstruction instruction = (SingleRegisterInstruction)analyzedInstruction.instruction;
getAndCheckSourceRegister(analyzedInstruction, instruction.getRegisterA(), ReferenceCategories);
}
private void handleCheckCast(AnalyzedInstruction analyzedInstruction) {
@ -1002,10 +951,8 @@ public class MethodAnalyzer {
//ensure the "source" register is a reference type
SingleRegisterInstruction instruction = (SingleRegisterInstruction)analyzedInstruction.instruction;
RegisterType registerType = analyzedInstruction.getPreInstructionRegisterType(instruction.getRegisterA());
assert registerType != null;
checkRegister(registerType, ReferenceCategories);
RegisterType registerType = getAndCheckSourceRegister(analyzedInstruction, instruction.getRegisterA(),
ReferenceCategories);
}
{
@ -1016,27 +963,22 @@ public class MethodAnalyzer {
assert item.getItemType() == ItemType.TYPE_TYPE_ID_ITEM;
//TODO: need to check class access
RegisterType newDestinationRegisterType = RegisterType.getRegisterTypeForTypeIdItem((TypeIdItem)item);
try {
checkRegister(newDestinationRegisterType, ReferenceCategories);
} catch (ValidationException ex) {
RegisterType castRegisterType = RegisterType.getRegisterTypeForTypeIdItem((TypeIdItem)item);
if (castRegisterType.category != RegisterType.Category.Reference) {
//TODO: verify that dalvik allows a non-reference type..
//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)
}
setDestinationRegisterTypeAndPropagateChanges(analyzedInstruction, newDestinationRegisterType);
setDestinationRegisterTypeAndPropagateChanges(analyzedInstruction, castRegisterType);
}
}
private void handleInstanceOf(AnalyzedInstruction analyzedInstruction) {
{
//ensure the register that is being checks is a reference type
TwoRegisterInstruction instruction = (TwoRegisterInstruction)analyzedInstruction;
TwoRegisterInstruction instruction = (TwoRegisterInstruction)analyzedInstruction.instruction;
RegisterType registerType = analyzedInstruction.getPreInstructionRegisterType(instruction.getRegisterB());
assert registerType != null;
checkRegister(registerType, ReferenceCategories);
getAndCheckSourceRegister(analyzedInstruction, instruction.getRegisterB(), ReferenceCategories);
}
{
@ -1046,7 +988,10 @@ public class MethodAnalyzer {
Item item = instruction.getReferencedItem();
assert item.getItemType() == ItemType.TYPE_TYPE_ID_ITEM;
RegisterType registerType = RegisterType.getRegisterTypeForTypeIdItem((TypeIdItem)item);
checkRegister(registerType, ReferenceCategories);
if (registerType.category != RegisterType.Category.Reference) {
throw new ValidationException(String.format("Cannot use instance-of with a non-reference type %s",
registerType.toString()));
}
//TODO: is it valid to use an array type?
@ -1057,22 +1002,21 @@ public class MethodAnalyzer {
}
private void handleArrayLength(AnalyzedInstruction analyzedInstruction) {
TwoRegisterInstruction instruction = (TwoRegisterInstruction)analyzedInstruction;
TwoRegisterInstruction instruction = (TwoRegisterInstruction)analyzedInstruction.instruction;
int arrayRegisterNumber = instruction.getRegisterB();
RegisterType arrayRegisterType = analyzedInstruction.getPreInstructionRegisterType(arrayRegisterNumber);
assert arrayRegisterType != null;
RegisterType arrayRegisterType = getAndCheckSourceRegister(analyzedInstruction, arrayRegisterNumber,
ReferenceCategories);
assert arrayRegisterType.type instanceof ClassPath.ArrayClassDef;
checkRegister(arrayRegisterType, ReferenceCategories);
if (arrayRegisterType.type != null) {
if (arrayRegisterType.type.getClassType().charAt(0) != '[') {
throw new ValidationException("Cannot use array-length with non-array type " +
arrayRegisterType.type.getClassType());
throw new ValidationException(String.format("Cannot use array-length with non-array type %s",
arrayRegisterType.type.getClassType()));
}
}
assert arrayRegisterType.type instanceof ClassPath.ArrayClassDef;
setDestinationRegisterTypeAndPropagateChanges(analyzedInstruction,
RegisterType.getRegisterType(RegisterType.Category.Integer, null));
}
@ -1107,7 +1051,11 @@ public class MethodAnalyzer {
//TODO: need to check class access
RegisterType classType = RegisterType.getRegisterTypeForTypeIdItem((TypeIdItem)item);
checkRegister(classType, ReferenceCategories);
if (classType.category != RegisterType.Category.Reference) {
throw new ValidationException(String.format("Cannot use new-instance with a non-reference type %s",
classType.toString()));
}
if (((TypeIdItem)item).getTypeDescriptor().charAt(0) == '[') {
throw new ValidationException("Cannot use array type \"" + ((TypeIdItem)item).getTypeDescriptor() +
"\" with new-instance. Use new-array instead.");
@ -1120,12 +1068,7 @@ public class MethodAnalyzer {
private void handleNewArray(AnalyzedInstruction analyzedInstruction) {
{
TwoRegisterInstruction instruction = (TwoRegisterInstruction)analyzedInstruction.instruction;
int sizeRegister = instruction.getRegisterB();
RegisterType registerType = analyzedInstruction.getPreInstructionRegisterType(sizeRegister);
assert registerType != null;
checkRegister(registerType, Primitive32BitCategories);
getAndCheckSourceRegister(analyzedInstruction, instruction.getRegisterB(), Primitive32BitCategories);
}
InstructionWithReference instruction = (InstructionWithReference)analyzedInstruction.instruction;
@ -1136,7 +1079,10 @@ public class MethodAnalyzer {
RegisterType arrayType = RegisterType.getRegisterTypeForTypeIdItem((TypeIdItem)item);
assert arrayType.type instanceof ClassPath.ArrayClassDef;
checkRegister(arrayType, ReferenceCategories);
if (arrayType.category != RegisterType.Category.Reference) {
throw new ValidationException(String.format("Cannot use new-array with a non-reference type %s",
arrayType.toString()));
}
if (arrayType.type.getClassType().charAt(0) != '[') {
throw new ValidationException("Cannot use non-array type \"" + arrayType.type.getClassType() +
"\" with new-array. Use new-instance instead.");
@ -1366,10 +1312,7 @@ public class MethodAnalyzer {
int register = ((SingleRegisterInstruction)analyzedInstruction.instruction).getRegisterA();
int switchCodeAddressOffset = ((OffsetInstruction)analyzedInstruction.instruction).getTargetAddressOffset();
RegisterType registerType = analyzedInstruction.getPreInstructionRegisterType(register);
assert registerType != null;
checkRegister(registerType, Primitive32BitCategories);
getAndCheckSourceRegister(analyzedInstruction, register, Primitive32BitCategories);
int switchDataCodeAddress = this.getInstructionAddress(analyzedInstruction) + switchCodeAddressOffset;
AnalyzedInstruction switchDataAnalyzedInstruction = instructions.get(switchDataCodeAddress);
@ -1381,31 +1324,11 @@ public class MethodAnalyzer {
}
}
private void handleFloatCmp(AnalyzedInstruction analyzedInstruction) {
private void handleFloatWideCmp(AnalyzedInstruction analyzedInstruction, EnumSet validCategories) {
ThreeRegisterInstruction instruction = (ThreeRegisterInstruction)analyzedInstruction.instruction;
RegisterType registerType = analyzedInstruction.getPreInstructionRegisterType(instruction.getRegisterB());
assert registerType != null;
checkRegister(registerType, Primitive32BitCategories);
registerType = analyzedInstruction.getPreInstructionRegisterType(instruction.getRegisterC());
assert registerType != null;
checkRegister(registerType, Primitive32BitCategories);
setDestinationRegisterTypeAndPropagateChanges(analyzedInstruction,
RegisterType.getRegisterType(RegisterType.Category.Byte, null));
}
private void handleWideCmp(AnalyzedInstruction analyzedInstruction) {
ThreeRegisterInstruction instruction = (ThreeRegisterInstruction)analyzedInstruction.instruction;
RegisterType registerType = getAndCheckWideSourcePair(analyzedInstruction, instruction.getRegisterB());
assert registerType != null;
registerType = getAndCheckWideSourcePair(analyzedInstruction, instruction.getRegisterC());
assert registerType != null;
getAndCheckSourceRegister(analyzedInstruction, instruction.getRegisterB(), validCategories);
getAndCheckSourceRegister(analyzedInstruction, instruction.getRegisterC(), validCategories);
setDestinationRegisterTypeAndPropagateChanges(analyzedInstruction,
RegisterType.getRegisterType(RegisterType.Category.Byte, null));
@ -1437,46 +1360,28 @@ public class MethodAnalyzer {
private void handleIf(AnalyzedInstruction analyzedInstruction) {
TwoRegisterInstruction instruction = (TwoRegisterInstruction)analyzedInstruction.instruction;
RegisterType registerType = analyzedInstruction.getPreInstructionRegisterType(instruction.getRegisterA());
assert registerType != null;
checkRegister(registerType, Primitive32BitCategories);
registerType = analyzedInstruction.getPreInstructionRegisterType(instruction.getRegisterB());
assert registerType != null;
checkRegister(registerType, Primitive32BitCategories);
getAndCheckSourceRegister(analyzedInstruction, instruction.getRegisterA(), Primitive32BitCategories);
getAndCheckSourceRegister(analyzedInstruction, instruction.getRegisterB(), Primitive32BitCategories);
}
private void handleIfEqzNez(AnalyzedInstruction analyzedInstruction) {
SingleRegisterInstruction instruction = (SingleRegisterInstruction)analyzedInstruction.instruction;
RegisterType registerType = analyzedInstruction.getPreInstructionRegisterType(instruction.getRegisterA());
assert registerType != null;
if (!ReferenceCategories.contains(registerType.category) &&
!Primitive32BitCategories.contains(registerType.category)) {
throw new ValidationException(String.format("%s cannot be used with register type %s. Expecting 32-bit " +
"primitive type or reference type.", analyzedInstruction.instruction.opcode));
}
getAndCheckSourceRegister(analyzedInstruction, instruction.getRegisterA(),
ReferenceAndPrimitive32BitCategories);
}
private void handleIfz(AnalyzedInstruction analyzedInstruction) {
SingleRegisterInstruction instruction = (SingleRegisterInstruction)analyzedInstruction.instruction;
RegisterType registerType = analyzedInstruction.getPreInstructionRegisterType(instruction.getRegisterA());
assert registerType != null;
checkRegister(registerType, Primitive32BitCategories);
getAndCheckSourceRegister(analyzedInstruction, instruction.getRegisterA(), Primitive32BitCategories);
}
private void handle32BitPrimitiveAget(AnalyzedInstruction analyzedInstruction,
RegisterType.Category instructionCategory) {
ThreeRegisterInstruction instruction = (ThreeRegisterInstruction)analyzedInstruction.instruction;
RegisterType indexRegisterType = analyzedInstruction.getPreInstructionRegisterType(instruction.getRegisterC());
assert indexRegisterType != null;
checkRegister(indexRegisterType, Primitive32BitCategories);
getAndCheckSourceRegister(analyzedInstruction, instruction.getRegisterC(), Primitive32BitCategories);
RegisterType arrayRegisterType = analyzedInstruction.getPreInstructionRegisterType(instruction.getRegisterB());
assert arrayRegisterType != null;
@ -1517,9 +1422,7 @@ public class MethodAnalyzer {
private void handleAgetWide(AnalyzedInstruction analyzedInstruction) {
ThreeRegisterInstruction instruction = (ThreeRegisterInstruction)analyzedInstruction.instruction;
RegisterType indexRegisterType = analyzedInstruction.getPreInstructionRegisterType(instruction.getRegisterC());
assert indexRegisterType != null;
checkRegister(indexRegisterType, Primitive32BitCategories);
getAndCheckSourceRegister(analyzedInstruction, instruction.getRegisterC(), Primitive32BitCategories);
RegisterType arrayRegisterType = analyzedInstruction.getPreInstructionRegisterType(instruction.getRegisterB());
assert arrayRegisterType != null;
@ -1546,17 +1449,17 @@ public class MethodAnalyzer {
char arrayBaseType = arrayClassDef.getBaseElementClass().getClassType().charAt(0);
if (arrayBaseType == 'J') {
setWideDestinationRegisterTypeAndPropagateChanges(analyzedInstruction,
setDestinationRegisterTypeAndPropagateChanges(analyzedInstruction,
RegisterType.getRegisterType(RegisterType.Category.LongLo, null));
} else if (arrayBaseType == 'D') {
setWideDestinationRegisterTypeAndPropagateChanges(analyzedInstruction,
setDestinationRegisterTypeAndPropagateChanges(analyzedInstruction,
RegisterType.getRegisterType(RegisterType.Category.DoubleLo, null));
} else {
throw new ValidationException(String.format("Cannot use aget-wide with array type %s. Incorrect " +
"array type for the instruction.", arrayRegisterType.type.getClassType()));
}
} else {
setWideDestinationRegisterTypeAndPropagateChanges(analyzedInstruction,
setDestinationRegisterTypeAndPropagateChanges(analyzedInstruction,
RegisterType.getRegisterType(RegisterType.Category.LongLo, null));
}
}
@ -1564,9 +1467,7 @@ public class MethodAnalyzer {
private void handleAgetObject(AnalyzedInstruction analyzedInstruction) {
ThreeRegisterInstruction instruction = (ThreeRegisterInstruction)analyzedInstruction.instruction;
RegisterType indexRegisterType = analyzedInstruction.getPreInstructionRegisterType(instruction.getRegisterC());
assert indexRegisterType != null;
checkRegister(indexRegisterType, Primitive32BitCategories);
getAndCheckSourceRegister(analyzedInstruction, instruction.getRegisterC(), Primitive32BitCategories);
RegisterType arrayRegisterType = analyzedInstruction.getPreInstructionRegisterType(instruction.getRegisterB());
assert arrayRegisterType != null;
@ -1605,10 +1506,7 @@ public class MethodAnalyzer {
RegisterType.Category instructionCategory) {
ThreeRegisterInstruction instruction = (ThreeRegisterInstruction)analyzedInstruction.instruction;
RegisterType indexRegisterType = analyzedInstruction.getPreInstructionRegisterType(instruction.getRegisterC());
assert indexRegisterType != null;
checkRegister(indexRegisterType, Primitive32BitCategories);
getAndCheckSourceRegister(analyzedInstruction, instruction.getRegisterC(), Primitive32BitCategories);
RegisterType sourceRegisterType = analyzedInstruction.getPreInstructionRegisterType(instruction.getRegisterA());
assert sourceRegisterType != null;
@ -1655,11 +1553,8 @@ public class MethodAnalyzer {
private void handleAputWide(AnalyzedInstruction analyzedInstruction) {
ThreeRegisterInstruction instruction = (ThreeRegisterInstruction)analyzedInstruction.instruction;
RegisterType indexRegisterType = analyzedInstruction.getPreInstructionRegisterType(instruction.getRegisterC());
assert indexRegisterType != null;
checkRegister(indexRegisterType, Primitive32BitCategories);
RegisterType sourceRegisterType = getAndCheckWideSourcePair(analyzedInstruction, instruction.getRegisterA());
getAndCheckSourceRegister(analyzedInstruction, instruction.getRegisterC(), Primitive32BitCategories);
getAndCheckSourceRegister(analyzedInstruction, instruction.getRegisterA(), WideLowCategories);
RegisterType arrayRegisterType = analyzedInstruction.getPreInstructionRegisterType(instruction.getRegisterB());
assert arrayRegisterType != null;
@ -1695,9 +1590,7 @@ public class MethodAnalyzer {
private void handleAputObject(AnalyzedInstruction analyzedInstruction) {
ThreeRegisterInstruction instruction = (ThreeRegisterInstruction)analyzedInstruction.instruction;
RegisterType indexRegisterType = analyzedInstruction.getPreInstructionRegisterType(instruction.getRegisterC());
assert indexRegisterType != null;
checkRegister(indexRegisterType, Primitive32BitCategories);
getAndCheckSourceRegister(analyzedInstruction, instruction.getRegisterC(), Primitive32BitCategories);
RegisterType sourceRegisterType = analyzedInstruction.getPreInstructionRegisterType(instruction.getRegisterA());
assert sourceRegisterType != null;
@ -1737,9 +1630,8 @@ public class MethodAnalyzer {
RegisterType.Category instructionCategory) {
TwoRegisterInstruction instruction = (TwoRegisterInstruction)analyzedInstruction.instruction;
RegisterType objectRegisterType = analyzedInstruction.getPreInstructionRegisterType(instruction.getRegisterB());
assert objectRegisterType != null;
checkRegister(objectRegisterType, ReferenceCategories);
RegisterType objectRegisterType = getAndCheckSourceRegister(analyzedInstruction, instruction.getRegisterB(),
ReferenceCategories);
//TODO: check access
//TODO: allow an uninitialized "this" reference, if the current method is an <init> method
@ -1768,11 +1660,8 @@ public class MethodAnalyzer {
private void handleIgetWide(AnalyzedInstruction analyzedInstruction) {
TwoRegisterInstruction instruction = (TwoRegisterInstruction)analyzedInstruction.instruction;
RegisterType objectRegisterType = analyzedInstruction.getPreInstructionRegisterType(instruction.getRegisterB());
assert objectRegisterType != null;
checkRegister(objectRegisterType, ReferenceCategories);
getAndCheckWideSourcePair(analyzedInstruction, instruction.getRegisterB());
RegisterType objectRegisterType = getAndCheckSourceRegister(analyzedInstruction, instruction.getRegisterB(),
ReferenceCategories);
//TODO: check access
//TODO: allow an uninitialized "this" reference, if the current method is an <init> method
@ -1788,23 +1677,20 @@ public class MethodAnalyzer {
RegisterType fieldType = RegisterType.getRegisterTypeForTypeIdItem(field.getFieldType());
try {
checkRegister(fieldType, WideLowCategories);
} catch (ValidationException ex) {
if (!WideLowCategories.contains(fieldType.category)) {
throw new ValidationException(String.format("Cannot use %s with field %s. Incorrect field type " +
"for the instruction.", analyzedInstruction.instruction.opcode.name,
field.getFieldString()));
"for the instruction.", analyzedInstruction.instruction.opcode.name,
field.getFieldString()));
}
setWideDestinationRegisterTypeAndPropagateChanges(analyzedInstruction, fieldType);
setDestinationRegisterTypeAndPropagateChanges(analyzedInstruction, fieldType);
}
private void handleIgetObject(AnalyzedInstruction analyzedInstruction) {
TwoRegisterInstruction instruction = (TwoRegisterInstruction)analyzedInstruction.instruction;
RegisterType objectRegisterType = analyzedInstruction.getPreInstructionRegisterType(instruction.getRegisterB());
assert objectRegisterType != null;
checkRegister(objectRegisterType, ReferenceCategories);
RegisterType objectRegisterType = getAndCheckSourceRegister(analyzedInstruction, instruction.getRegisterB(),
ReferenceCategories);
//TODO: check access
//TODO: allow an uninitialized "this" reference, if the current method is an <init> method
@ -1833,9 +1719,8 @@ public class MethodAnalyzer {
RegisterType.Category instructionCategory) {
TwoRegisterInstruction instruction = (TwoRegisterInstruction)analyzedInstruction.instruction;
RegisterType objectRegisterType = analyzedInstruction.getPreInstructionRegisterType(instruction.getRegisterB());
assert objectRegisterType != null;
checkRegister(objectRegisterType, ReferenceCategories);
RegisterType objectRegisterType = getAndCheckSourceRegister(analyzedInstruction, instruction.getRegisterB(),
ReferenceCategories);
RegisterType sourceRegisterType = analyzedInstruction.getPreInstructionRegisterType(instruction.getRegisterA());
assert sourceRegisterType != null;
@ -1879,12 +1764,10 @@ public class MethodAnalyzer {
private void handleIputWide(AnalyzedInstruction analyzedInstruction) {
TwoRegisterInstruction instruction = (TwoRegisterInstruction)analyzedInstruction.instruction;
RegisterType objectRegisterType = analyzedInstruction.getPreInstructionRegisterType(instruction.getRegisterB());
assert objectRegisterType != null;
checkRegister(objectRegisterType, ReferenceCategories);
RegisterType objectRegisterType = getAndCheckSourceRegister(analyzedInstruction, instruction.getRegisterB(),
ReferenceCategories);
RegisterType sourceRegisterType = getAndCheckWideSourcePair(analyzedInstruction, instruction.getRegisterA());
assert sourceRegisterType != null;
getAndCheckSourceRegister(analyzedInstruction, instruction.getRegisterA(), WideLowCategories);
//TODO: check access
//TODO: allow an uninitialized "this" reference, if the current method is an <init> method
@ -1910,13 +1793,11 @@ public class MethodAnalyzer {
private void handleIputObject(AnalyzedInstruction analyzedInstruction) {
TwoRegisterInstruction instruction = (TwoRegisterInstruction)analyzedInstruction.instruction;
RegisterType objectRegisterType = analyzedInstruction.getPreInstructionRegisterType(instruction.getRegisterB());
assert objectRegisterType != null;
checkRegister(objectRegisterType, ReferenceCategories);
RegisterType objectRegisterType = getAndCheckSourceRegister(analyzedInstruction, instruction.getRegisterB(),
ReferenceCategories);
RegisterType sourceRegisterType = analyzedInstruction.getPreInstructionRegisterType(instruction.getRegisterA());
assert sourceRegisterType != null;
checkRegister(sourceRegisterType, ReferenceCategories);
RegisterType sourceRegisterType = getAndCheckSourceRegister(analyzedInstruction, instruction.getRegisterB(),
ReferenceCategories);
//TODO: check access
//TODO: allow an uninitialized "this" reference, if the current method is an <init> method
@ -1983,7 +1864,7 @@ public class MethodAnalyzer {
field.getFieldString()));
}
setWideDestinationRegisterTypeAndPropagateChanges(analyzedInstruction, fieldType);
setDestinationRegisterTypeAndPropagateChanges(analyzedInstruction, fieldType);
}
private void handleSgetObject(AnalyzedInstruction analyzedInstruction) {
@ -2042,8 +1923,7 @@ public class MethodAnalyzer {
SingleRegisterInstruction instruction = (SingleRegisterInstruction)analyzedInstruction.instruction;
RegisterType sourceRegisterType = getAndCheckWideSourcePair(analyzedInstruction, instruction.getRegisterA());
assert sourceRegisterType != null;
getAndCheckSourceRegister(analyzedInstruction, instruction.getRegisterA(), WideLowCategories);
//TODO: check access
Item referencedItem = ((InstructionWithReference)analyzedInstruction.instruction).getReferencedItem();
@ -2058,15 +1938,14 @@ public class MethodAnalyzer {
field.getFieldString()));
}
setWideDestinationRegisterTypeAndPropagateChanges(analyzedInstruction, fieldType);
setDestinationRegisterTypeAndPropagateChanges(analyzedInstruction, fieldType);
}
private void handleSputObject(AnalyzedInstruction analyzedInstruction) {
SingleRegisterInstruction instruction = (SingleRegisterInstruction)analyzedInstruction.instruction;
RegisterType sourceRegisterType = analyzedInstruction.getPreInstructionRegisterType(instruction.getRegisterA());
assert sourceRegisterType != null;
checkRegister(sourceRegisterType, ReferenceCategories);
RegisterType sourceRegisterType = getAndCheckSourceRegister(analyzedInstruction, instruction.getRegisterA(),
ReferenceCategories);
//TODO: check access
Item referencedItem = ((InstructionWithReference)analyzedInstruction.instruction).getReferencedItem();
@ -2237,7 +2116,7 @@ public class MethodAnalyzer {
RegisterType parameterRegisterType;
if (WideLowCategories.contains(parameterType.category)) {
parameterRegisterType = getAndCheckWideSourcePair(analyzedInstruction, register);
parameterRegisterType = getAndCheckSourceRegister(analyzedInstruction, register, WideLowCategories);
if (!registers.moveNext()) {
throw new ValidationException(String.format("No 2nd register specified for wide register pair v%d",
@ -2310,51 +2189,39 @@ public class MethodAnalyzer {
return false;
}
private static void checkRegister(RegisterType registerType, EnumSet validCategories) {
if (!validCategories.contains(registerType.category)) {
//TODO: add expected categories to error message
throw new ValidationException("Invalid register type. Expecting one of: " + " but got \"" +
registerType.category + "\"");
}
}
private static RegisterType getAndCheckSourceRegister(AnalyzedInstruction analyzedInstruction, int registerNumber,
EnumSet validCategories) {
assert registerNumber >= 0 && registerNumber < analyzedInstruction.postRegisterMap.length;
private static void checkWideDestinationPair(AnalyzedInstruction analyzedInstruction) {
int register = analyzedInstruction.getDestinationRegister();
if (register == (analyzedInstruction.postRegisterMap.length - 1)) {
throw new ValidationException("v" + register + " is the last register and not a valid wide register " +
"pair.");
}
}
private static RegisterType getAndCheckWideSourcePair(AnalyzedInstruction analyzedInstruction, int firstRegister) {
assert firstRegister >= 0 && firstRegister < analyzedInstruction.postRegisterMap.length;
if (firstRegister == analyzedInstruction.postRegisterMap.length - 1) {
throw new ValidationException("v" + firstRegister + " is the last register and not a valid wide register " +
"pair.");
}
RegisterType registerType = analyzedInstruction.getPreInstructionRegisterType(firstRegister);
RegisterType registerType = analyzedInstruction.getPreInstructionRegisterType(registerNumber);
assert registerType != null;
if (registerType.category == RegisterType.Category.Unknown) {
return registerType;
}
checkRegister(registerType, WideLowCategories);
RegisterType secondRegisterType = analyzedInstruction.getPreInstructionRegisterType(firstRegister + 1);
assert secondRegisterType != null;
checkRegister(secondRegisterType, WideHighCategories);
checkRegister(registerType, registerNumber, validCategories);
if (( registerType.category == RegisterType.Category.LongLo &&
secondRegisterType.category == RegisterType.Category.DoubleHi)
|| ( registerType.category == RegisterType.Category.DoubleLo &&
secondRegisterType.category == RegisterType.Category.LongHi)) {
assert false;
throw new ValidationException("The first register in the wide register pair isn't the same type (long " +
"vs. double) as the second register in the pair");
if (validCategories == WideLowCategories) {
checkRegister(registerType, registerNumber, WideLowCategories);
checkWidePair(registerNumber, analyzedInstruction);
RegisterType secondRegisterType = analyzedInstruction.getPreInstructionRegisterType(registerNumber + 1);
assert secondRegisterType != null;
checkRegister(secondRegisterType, registerNumber+1, WideHighCategories);
}
return registerType;
}
private static void checkRegister(RegisterType registerType, int registerNumber, EnumSet validCategories) {
if (!validCategories.contains(registerType.category)) {
//TODO: add expected categories to error message
throw new ValidationException(String.format("Invalid register type for register v%d. Expecting one of: " +
"but got %s", registerNumber, registerType.toString()));
}
}
private static void checkWidePair(int registerNumber, AnalyzedInstruction analyzedInstruction) {
if (registerNumber + 1 >= analyzedInstruction.postRegisterMap.length) {
throw new ValidationException(String.format("v%d is the last register and not a valid wide register " +
"pair.", registerNumber));
}
}
}