add support for the new odex opcodes for volatile field access that were added in gingerbread

git-svn-id: https://smali.googlecode.com/svn/trunk@799 55b6fa8a-2a1e-11de-a435-ffa8d773f76a
This commit is contained in:
JesusFreke@JesusFreke.com 2010-12-21 17:33:30 +00:00
parent 595cdad3d6
commit d4417d7269
3 changed files with 329 additions and 89 deletions

View File

@ -999,6 +999,19 @@ public class MethodAnalyzer {
analyzeLiteralBinaryOp(analyzedInstruction, getDestTypeForLiteralShiftRight(analyzedInstruction, false),
false);
return true;
/*odexed instructions*/
case IGET_VOLATILE:
case IPUT_VOLATILE:
case SGET_VOLATILE:
case SPUT_VOLATILE:
case IGET_OBJECT_VOLATILE:
case IGET_WIDE_VOLATILE:
case IPUT_WIDE_VOLATILE:
case SGET_WIDE_VOLATILE:
case SPUT_WIDE_VOLATILE:
analyzePutGetVolatile(analyzedInstruction);
return true;
case EXECUTE_INLINE:
analyzeExecuteInline(analyzedInstruction);
return true;
@ -1011,11 +1024,10 @@ public class MethodAnalyzer {
case IGET_QUICK:
case IGET_WIDE_QUICK:
case IGET_OBJECT_QUICK:
return analyzeIputIgetQuick(analyzedInstruction, false);
case IPUT_QUICK:
case IPUT_WIDE_QUICK:
case IPUT_OBJECT_QUICK:
return analyzeIputIgetQuick(analyzedInstruction, true);
return analyzeIputIgetQuick(analyzedInstruction);
case INVOKE_VIRTUAL_QUICK:
return analyzeInvokeVirtualQuick(analyzedInstruction, false, false);
case INVOKE_SUPER_QUICK:
@ -1024,6 +1036,11 @@ public class MethodAnalyzer {
return analyzeInvokeVirtualQuick(analyzedInstruction, false, true);
case INVOKE_SUPER_QUICK_RANGE:
return analyzeInvokeVirtualQuick(analyzedInstruction, true, true);
case IPUT_OBJECT_VOLATILE:
case SGET_OBJECT_VOLATILE:
case SPUT_OBJECT_VOLATILE:
analyzePutGetVolatile(analyzedInstruction);
return true;
default:
assert false;
return true;
@ -1486,6 +1503,15 @@ public class MethodAnalyzer {
case USHR_INT_LIT8:
verifyLiteralBinaryOp(analyzedInstruction);
return;
case IGET_VOLATILE:
case IPUT_VOLATILE:
case SGET_VOLATILE:
case SPUT_VOLATILE:
case IGET_OBJECT_VOLATILE:
case IGET_WIDE_VOLATILE:
case IPUT_WIDE_VOLATILE:
case SGET_WIDE_VOLATILE:
case SPUT_WIDE_VOLATILE:
case EXECUTE_INLINE:
case EXECUTE_INLINE_RANGE:
case INVOKE_DIRECT_EMPTY:
@ -1499,6 +1525,9 @@ public class MethodAnalyzer {
case INVOKE_SUPER_QUICK:
case INVOKE_VIRTUAL_QUICK_RANGE:
case INVOKE_SUPER_QUICK_RANGE:
case IPUT_OBJECT_VOLATILE:
case SGET_OBJECT_VOLATILE:
case SPUT_OBJECT_VOLATILE:
//TODO: throw validation exception?
default:
assert false;
@ -3388,7 +3417,7 @@ public class MethodAnalyzer {
analyzeInstruction(analyzedInstruction);
}
private boolean analyzeIputIgetQuick(AnalyzedInstruction analyzedInstruction, boolean isIput) {
private boolean analyzeIputIgetQuick(AnalyzedInstruction analyzedInstruction) {
Instruction22cs instruction = (Instruction22cs)analyzedInstruction.instruction;
int fieldOffset = instruction.getFieldOffset();
@ -3407,7 +3436,7 @@ public class MethodAnalyzer {
String fieldType = fieldIdItem.getFieldType().getTypeDescriptor();
Opcode opcode = getAndCheckIgetIputOpcodeForType(fieldType, instruction.opcode, isIput);
Opcode opcode = OdexedFieldInstructionMapper.getAndCheckDeodexedOpcodeForOdexedOpcode(fieldType, instruction.opcode);
Instruction22c deodexedInstruction = new Instruction22c(opcode, (byte)instruction.getRegisterA(),
(byte)instruction.getRegisterB(), fieldIdItem);
@ -3499,87 +3528,33 @@ public class MethodAnalyzer {
return true;
}
private static Opcode getAndCheckIgetIputOpcodeForType(String fieldType, Opcode odexedOpcode, boolean isIput) {
Opcode opcode;
Opcode validOdexedOpcode;
switch (fieldType.charAt(0)) {
case 'Z':
if (isIput) {
validOdexedOpcode = Opcode.IPUT_QUICK;
opcode = Opcode.IPUT_BOOLEAN;
} else {
validOdexedOpcode = Opcode.IGET_QUICK;
opcode = Opcode.IGET_BOOLEAN;
}
break;
case 'B':
if (isIput) {
validOdexedOpcode = Opcode.IPUT_QUICK;
opcode = Opcode.IPUT_BYTE;
} else {
validOdexedOpcode = Opcode.IGET_QUICK;
opcode = Opcode.IGET_BYTE;
}
break;
case 'S':
if (isIput) {
validOdexedOpcode = Opcode.IPUT_QUICK;
opcode = Opcode.IPUT_SHORT;
} else {
validOdexedOpcode = Opcode.IGET_QUICK;
opcode = Opcode.IGET_SHORT;
}
break;
case 'C':
if (isIput) {
validOdexedOpcode = Opcode.IPUT_QUICK;
opcode = Opcode.IPUT_CHAR;
} else {
validOdexedOpcode = Opcode.IGET_QUICK;
opcode = Opcode.IGET_CHAR;
}
break;
case 'I':
case 'F':
if (isIput) {
validOdexedOpcode = Opcode.IPUT_QUICK;
opcode = Opcode.IPUT;
} else {
validOdexedOpcode = Opcode.IGET_QUICK;
opcode = Opcode.IGET;
}
break;
case 'J':
case 'D':
if (isIput) {
validOdexedOpcode = Opcode.IPUT_WIDE_QUICK;
opcode = Opcode.IPUT_WIDE;
} else {
validOdexedOpcode = Opcode.IGET_WIDE_QUICK;
opcode = Opcode.IGET_WIDE;
}
break;
case 'L':
case '[':
if (isIput) {
validOdexedOpcode = Opcode.IPUT_OBJECT_QUICK;
opcode = Opcode.IPUT_OBJECT;
} else {
validOdexedOpcode = Opcode.IGET_OBJECT_QUICK;
opcode = Opcode.IGET_OBJECT;
}
break;
default:
throw new RuntimeException(String.format("Unexpected field type %s for %s: ", fieldType,
odexedOpcode.name));
private boolean analyzePutGetVolatile(AnalyzedInstruction analyzedInstruction) {
FieldIdItem fieldIdItem =
(FieldIdItem)(((InstructionWithReference)analyzedInstruction.instruction).getReferencedItem());
String fieldType = fieldIdItem.getFieldType().getTypeDescriptor();
Opcode opcode = OdexedFieldInstructionMapper.getAndCheckDeodexedOpcodeForOdexedOpcode(fieldType,
analyzedInstruction.instruction.opcode);
Instruction deodexedInstruction;
if (analyzedInstruction.instruction.opcode.isOdexedStaticVolatile()) {
SingleRegisterInstruction instruction = (SingleRegisterInstruction)analyzedInstruction.instruction;
deodexedInstruction = new Instruction21c(opcode, (byte)instruction.getRegisterA(),
fieldIdItem);
} else {
TwoRegisterInstruction instruction = (TwoRegisterInstruction)analyzedInstruction.instruction;
deodexedInstruction = new Instruction22c(opcode, (byte)instruction.getRegisterA(),
(byte)instruction.getRegisterB(), fieldIdItem);
}
if (odexedOpcode != validOdexedOpcode) {
throw new ValidationException(String.format("Incorrect field type \"%s\" for %s", fieldType,
odexedOpcode.name));
}
analyzedInstruction.setDeodexedInstruction(deodexedInstruction);
analyzeInstruction(analyzedInstruction);
return opcode;
return true;
}
private static boolean checkArrayFieldAssignment(RegisterType.Category arrayFieldCategory,

View File

@ -0,0 +1,233 @@
/*
* [The "BSD licence"]
* Copyright (c) 2010 Ben Gruver
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package org.jf.dexlib.Code.Analysis;
import org.jf.dexlib.Code.Opcode;
public class OdexedFieldInstructionMapper {
private static Opcode[][][][] opcodeMap = new Opcode[][][][] {
//get opcodes
new Opcode[][][] {
//iget quick
new Opcode[][] {
//odexed
new Opcode[] {
/*Z*/ Opcode.IGET_QUICK,
/*B*/ Opcode.IGET_QUICK,
/*S*/ Opcode.IGET_QUICK,
/*C*/ Opcode.IGET_QUICK,
/*I,F*/ Opcode.IGET_QUICK,
/*J,D*/ Opcode.IGET_WIDE_QUICK,
/*L,[*/ Opcode.IGET_OBJECT_QUICK
},
//deodexed
new Opcode[] {
/*Z*/ Opcode.IGET_BOOLEAN,
/*B*/ Opcode.IGET_BYTE,
/*S*/ Opcode.IGET_SHORT,
/*C*/ Opcode.IGET_CHAR,
/*I,F*/ Opcode.IGET,
/*J,D*/ Opcode.IGET_WIDE,
/*L,[*/ Opcode.IGET_OBJECT
}
},
//iget volatile
new Opcode[][] {
//odexed
new Opcode[] {
/*Z*/ Opcode.IGET_VOLATILE,
/*B*/ Opcode.IGET_VOLATILE,
/*S*/ Opcode.IGET_VOLATILE,
/*C*/ Opcode.IGET_VOLATILE,
/*I,F*/ Opcode.IGET_VOLATILE,
/*J,D*/ Opcode.IGET_WIDE_VOLATILE,
/*L,[*/ Opcode.IGET_OBJECT_VOLATILE
},
//deodexed
new Opcode[] {
/*Z*/ Opcode.IGET_BOOLEAN,
/*B*/ Opcode.IGET_BYTE,
/*S*/ Opcode.IGET_SHORT,
/*C*/ Opcode.IGET_CHAR,
/*I,F*/ Opcode.IGET,
/*J,D*/ Opcode.IGET_WIDE,
/*L,[*/ Opcode.IGET_OBJECT
}
},
//sget volatile
new Opcode[][] {
//odexed
new Opcode[] {
/*Z*/ Opcode.SGET_VOLATILE,
/*B*/ Opcode.SGET_VOLATILE,
/*S*/ Opcode.SGET_VOLATILE,
/*C*/ Opcode.SGET_VOLATILE,
/*I,F*/ Opcode.SGET_VOLATILE,
/*J,D*/ Opcode.SGET_WIDE_VOLATILE,
/*L,[*/ Opcode.SGET_OBJECT_VOLATILE
},
//deodexed
new Opcode[] {
/*Z*/ Opcode.SGET_BOOLEAN,
/*B*/ Opcode.SGET_BYTE,
/*S*/ Opcode.SGET_SHORT,
/*C*/ Opcode.SGET_CHAR,
/*I,F*/ Opcode.SGET,
/*J,D*/ Opcode.SGET_WIDE,
/*L,[*/ Opcode.SGET_OBJECT
}
}
},
//put opcodes
new Opcode[][][] {
//iput quick
new Opcode[][] {
//odexed
new Opcode[] {
/*Z*/ Opcode.IPUT_QUICK,
/*B*/ Opcode.IPUT_QUICK,
/*S*/ Opcode.IPUT_QUICK,
/*C*/ Opcode.IPUT_QUICK,
/*I,F*/ Opcode.IPUT_QUICK,
/*J,D*/ Opcode.IPUT_WIDE_QUICK,
/*L,[*/ Opcode.IPUT_OBJECT_QUICK
},
//deodexed
new Opcode[] {
/*Z*/ Opcode.IPUT_BOOLEAN,
/*B*/ Opcode.IPUT_BYTE,
/*S*/ Opcode.IPUT_SHORT,
/*C*/ Opcode.IPUT_CHAR,
/*I,F*/ Opcode.IPUT,
/*J,D*/ Opcode.IPUT_WIDE,
/*L,[*/ Opcode.IPUT_OBJECT
}
},
//iput volatile
new Opcode[][] {
//odexed
new Opcode[] {
/*Z*/ Opcode.IPUT_VOLATILE,
/*B*/ Opcode.IPUT_VOLATILE,
/*S*/ Opcode.IPUT_VOLATILE,
/*C*/ Opcode.IPUT_VOLATILE,
/*I,F*/ Opcode.IPUT_VOLATILE,
/*J,D*/ Opcode.IPUT_WIDE_VOLATILE,
/*L,[*/ Opcode.IPUT_OBJECT_VOLATILE
},
//deodexed
new Opcode[] {
/*Z*/ Opcode.IPUT_BOOLEAN,
/*B*/ Opcode.IPUT_BYTE,
/*S*/ Opcode.IPUT_SHORT,
/*C*/ Opcode.IPUT_CHAR,
/*I,F*/ Opcode.IPUT,
/*J,D*/ Opcode.IPUT_WIDE,
/*L,[*/ Opcode.IPUT_OBJECT
}
},
//sput volatile
new Opcode[][] {
//odexed
new Opcode[] {
/*Z*/ Opcode.SPUT_VOLATILE,
/*B*/ Opcode.SPUT_VOLATILE,
/*S*/ Opcode.SPUT_VOLATILE,
/*C*/ Opcode.SPUT_VOLATILE,
/*I,F*/ Opcode.SPUT_VOLATILE,
/*J,D*/ Opcode.SPUT_WIDE_VOLATILE,
/*L,[*/ Opcode.SPUT_OBJECT_VOLATILE
},
//deodexed
new Opcode[] {
/*Z*/ Opcode.SPUT_BOOLEAN,
/*B*/ Opcode.SPUT_BYTE,
/*S*/ Opcode.SPUT_SHORT,
/*C*/ Opcode.SPUT_CHAR,
/*I,F*/ Opcode.SPUT,
/*J,D*/ Opcode.SPUT_WIDE,
/*L,[*/ Opcode.SPUT_OBJECT
}
}
}
};
private static int getTypeIndex(char type) {
switch (type) {
case 'Z':
return 0;
case 'B':
return 1;
case 'S':
return 2;
case 'C':
return 3;
case 'I':
case 'F':
return 4;
case 'J':
case 'D':
return 5;
case 'L':
case '[':
return 6;
default:
}
throw new RuntimeException(String.format("Unknown type %s: ", type));
}
private static int getOpcodeSubtype(Opcode opcode) {
if (opcode.isOdexedInstanceQuick()) {
return 0;
} else if (opcode.isOdexedInstanceVolatile()) {
return 1;
} else if (opcode.isOdexedStaticVolatile()) {
return 2;
}
throw new RuntimeException(String.format("Not an odexed field access opcode: %s", opcode.name));
}
static Opcode getAndCheckDeodexedOpcodeForOdexedOpcode(String fieldType, Opcode odexedOpcode) {
int opcodeType = odexedOpcode.setsRegister()?0:1;
int opcodeSubType = getOpcodeSubtype(odexedOpcode);
int typeIndex = getTypeIndex(fieldType.charAt(0));
Opcode correctOdexedOpcode = opcodeMap[opcodeType][opcodeSubType][0][typeIndex];
Opcode deodexedOpcode = opcodeMap[opcodeType][opcodeSubType][1][typeIndex];
if (correctOdexedOpcode != odexedOpcode) {
throw new ValidationException(String.format("Incorrect field type \"%s\" for %s", fieldType,
odexedOpcode.name));
}
return deodexedOpcode;
}
}

View File

@ -253,19 +253,33 @@ public enum Opcode
SHR_INT_LIT8((byte)0xe1, "shr-int/lit8", ReferenceType.none, Format.Format22b, Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER),
USHR_INT_LIT8((byte)0xe2, "ushr-int/lit8", ReferenceType.none, Format.Format22b, Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER),
IGET_VOLATILE((byte)0xe3, "iget-volatile", ReferenceType.field, Format.Format22c, Opcode.ODEX_ONLY | Opcode.ODEXED_INSTANCE_VOLATILE | Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER),
IPUT_VOLATILE((byte)0xe4, "iput-volatile", ReferenceType.field, Format.Format22c, Opcode.ODEX_ONLY | Opcode.ODEXED_INSTANCE_VOLATILE | Opcode.CAN_THROW | Opcode.CAN_CONTINUE),
SGET_VOLATILE((byte)0xe5, "sget-volatile", ReferenceType.field, Format.Format21c, Opcode.ODEX_ONLY | Opcode.ODEXED_STATIC_VOLATILE | Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER),
SPUT_VOLATILE((byte)0xe6, "sput-volatile", ReferenceType.field, Format.Format21c, Opcode.ODEX_ONLY | Opcode.ODEXED_STATIC_VOLATILE | Opcode.CAN_THROW | Opcode.CAN_CONTINUE),
IGET_OBJECT_VOLATILE((byte)0xe7, "iget-object-volatile", ReferenceType.field, Format.Format22c, Opcode.ODEX_ONLY | Opcode.ODEXED_INSTANCE_VOLATILE | Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER),
IGET_WIDE_VOLATILE((byte)0xe8, "iget-wide-volatile", ReferenceType.field, Format.Format22c, Opcode.ODEX_ONLY | Opcode.ODEXED_INSTANCE_VOLATILE | Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER | Opcode.SETS_WIDE_REGISTER),
IPUT_WIDE_VOLATILE((byte)0xe9, "iput-wide-volatile", ReferenceType.field, Format.Format22c, Opcode.ODEX_ONLY | Opcode.ODEXED_INSTANCE_VOLATILE | Opcode.CAN_THROW | Opcode.CAN_CONTINUE),
SGET_WIDE_VOLATILE((byte)0xea, "sget-wide-volatile", ReferenceType.field, Format.Format21c, Opcode.ODEX_ONLY | Opcode.ODEXED_STATIC_VOLATILE | Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER | Opcode.SETS_WIDE_REGISTER),
SPUT_WIDE_VOLATILE((byte)0xeb, "sput-wide-volatile", ReferenceType.field, Format.Format21c, Opcode.ODEX_ONLY | Opcode.ODEXED_STATIC_VOLATILE | Opcode.CAN_THROW | Opcode.CAN_CONTINUE),
EXECUTE_INLINE((byte)0xee, "execute-inline", ReferenceType.none, Format.Format35ms, Opcode.ODEX_ONLY | Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_RESULT),
EXECUTE_INLINE_RANGE((byte)0xef, "execute-inline/range", ReferenceType.none, Format.Format3rms, Opcode.ODEX_ONLY | Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_RESULT),
INVOKE_DIRECT_EMPTY((byte)0xf0, "invoke-direct-empty", ReferenceType.method, Format.Format35s, Opcode.ODEX_ONLY | Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_RESULT),
IGET_QUICK((byte)0xf2, "iget-quick", ReferenceType.none, Format.Format22cs, Opcode.ODEX_ONLY | Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER),
IGET_WIDE_QUICK((byte)0xf3, "iget-wide-quick", ReferenceType.none, Format.Format22cs, Opcode.ODEX_ONLY | Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER | Opcode.SETS_WIDE_REGISTER),
IGET_OBJECT_QUICK((byte)0xf4, "iget-object-quick", ReferenceType.none, Format.Format22cs, Opcode.ODEX_ONLY | Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER),
IPUT_QUICK((byte)0xf5, "iput-quick", ReferenceType.none, Format.Format22cs, Opcode.ODEX_ONLY | Opcode.CAN_THROW | Opcode.CAN_CONTINUE),
IPUT_WIDE_QUICK((byte)0xf6, "iput-wide-quick", ReferenceType.none, Format.Format22cs, Opcode.ODEX_ONLY | Opcode.CAN_THROW | Opcode.CAN_CONTINUE),
IPUT_OBJECT_QUICK((byte)0xf7, "iput-object-quick", ReferenceType.none, Format.Format22cs, Opcode.ODEX_ONLY | Opcode.CAN_THROW | Opcode.CAN_CONTINUE),
IGET_QUICK((byte)0xf2, "iget-quick", ReferenceType.none, Format.Format22cs, Opcode.ODEX_ONLY | Opcode.ODEXED_INSTANCE_QUICK | Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER),
IGET_WIDE_QUICK((byte)0xf3, "iget-wide-quick", ReferenceType.none, Format.Format22cs, Opcode.ODEX_ONLY | Opcode.ODEXED_INSTANCE_QUICK | Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER | Opcode.SETS_WIDE_REGISTER),
IGET_OBJECT_QUICK((byte)0xf4, "iget-object-quick", ReferenceType.none, Format.Format22cs, Opcode.ODEX_ONLY | Opcode.ODEXED_INSTANCE_QUICK | Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER),
IPUT_QUICK((byte)0xf5, "iput-quick", ReferenceType.none, Format.Format22cs, Opcode.ODEX_ONLY | Opcode.ODEXED_INSTANCE_QUICK | Opcode.CAN_THROW | Opcode.CAN_CONTINUE),
IPUT_WIDE_QUICK((byte)0xf6, "iput-wide-quick", ReferenceType.none, Format.Format22cs, Opcode.ODEX_ONLY | Opcode.ODEXED_INSTANCE_QUICK | Opcode.CAN_THROW | Opcode.CAN_CONTINUE),
IPUT_OBJECT_QUICK((byte)0xf7, "iput-object-quick", ReferenceType.none, Format.Format22cs, Opcode.ODEX_ONLY | Opcode.ODEXED_INSTANCE_QUICK | Opcode.CAN_THROW | Opcode.CAN_CONTINUE),
INVOKE_VIRTUAL_QUICK((byte)0xf8, "invoke-virtual-quick", ReferenceType.none, Format.Format35ms, Opcode.ODEX_ONLY | Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_RESULT),
INVOKE_VIRTUAL_QUICK_RANGE((byte)0xf9, "invoke-virtual-quick/range", ReferenceType.none, Format.Format3rms, Opcode.ODEX_ONLY | Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_RESULT),
INVOKE_SUPER_QUICK((byte)0xfa, "invoke-super-quick", ReferenceType.none, Format.Format35ms, Opcode.ODEX_ONLY | Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_RESULT),
INVOKE_SUPER_QUICK_RANGE((byte)0xfb, "invoke-super-quick/range", ReferenceType.none, Format.Format3rms, Opcode.ODEX_ONLY | Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_RESULT);
INVOKE_SUPER_QUICK_RANGE((byte)0xfb, "invoke-super-quick/range", ReferenceType.none, Format.Format3rms, Opcode.ODEX_ONLY | Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_RESULT),
IPUT_OBJECT_VOLATILE((byte)0xfc, "iput-object-volatile", ReferenceType.field, Format.Format22c, Opcode.ODEX_ONLY | Opcode.ODEXED_INSTANCE_VOLATILE | Opcode.CAN_THROW | Opcode.CAN_CONTINUE),
SGET_OBJECT_VOLATILE((byte)0xfd, "sget-object-volatile", ReferenceType.field, Format.Format21c, Opcode.ODEX_ONLY | Opcode.ODEXED_STATIC_VOLATILE | Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER),
SPUT_OBJECT_VOLATILE((byte)0xfe, "sput-object-volatile", ReferenceType.field, Format.Format21c, Opcode.ODEX_ONLY | Opcode.ODEXED_STATIC_VOLATILE | Opcode.CAN_THROW | Opcode.CAN_CONTINUE);
private static Opcode[] opcodesByValue;
@ -283,6 +297,12 @@ public enum Opcode
public static final int SETS_REGISTER = 0x10;
//if the instruction sets the value of it's first register to a wide type
public static final int SETS_WIDE_REGISTER = 0x20;
//if the instruction is an odexed iget-quick/iput-quick instruction
public static final int ODEXED_INSTANCE_QUICK = 0x40;
//if the instruction is an odexed iget-volatile/iput-volatile instruction
public static final int ODEXED_INSTANCE_VOLATILE = 0x80;
//if the instruction is an odexed sget-volatile/sput-volatile instruction
public static final int ODEXED_STATIC_VOLATILE = 0x100;
static {
opcodesByValue = new Opcode[256];
@ -343,4 +363,16 @@ public enum Opcode
public final boolean setsWideRegister() {
return (flags & SETS_WIDE_REGISTER) != 0;
}
public final boolean isOdexedInstanceQuick() {
return (flags & ODEXED_INSTANCE_QUICK) != 0;
}
public final boolean isOdexedInstanceVolatile() {
return (flags & ODEXED_INSTANCE_VOLATILE) != 0;
}
public final boolean isOdexedStaticVolatile() {
return (flags & ODEXED_STATIC_VOLATILE) != 0;
}
}